root/usr.bin/xlint/lint2/msg.c
/*      $NetBSD: msg.c,v 1.27 2025/05/24 07:00:32 rillig Exp $  */

/*
 * Copyright (c) 1994, 1995 Jochen Pohl
 * All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Jochen Pohl for
 *      The NetBSD Project.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif

#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: msg.c,v 1.27 2025/05/24 07:00:32 rillig Exp $");
#endif

#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include "lint2.h"

static const char *msgs[] = {
        "%s is used in %s but never defined",                           // 0
        "%s is defined in %s but never used",                           // 1
        "%s is declared in %s but never used or defined",               // 2
        "%s has multiple definitions in %s and %s",                     // 3
        "%s has its return value used inconsistently by %s and %s",     // 4
        "%s %s '%s' at %s, versus '%s' at %s",                          // 5
        "%s has argument %d with type '%s' at %s, versus '%s' at %s",   // 6
        "%s has %d parameters in %s, versus %d arguments in %s",        // 7
        "%s returns a value that is always ignored",                    // 8
        "%s returns a value that is sometimes ignored",                 // 9
        "%s has its return value used in %s but doesn't return one",    // 10
        "%s has parameter %d declared as '%s' in %s, versus '%s' in %s", // 11
        "%s has %d parameters in %s, versus %d in %s",                  // 12
        "%s is called with a malformed format string in %s",            // 13
        "%s is called in %s with argument %d being incompatible with format string", // 14
        "%s is called in %s with too few arguments for format string",  // 15
        "%s is called in %s with too many arguments for format string", // 16
        "%s's return type in %s must be declared before use in %s",     // 17
        "%s is renamed multiple times in %s and %s",                    // 18
};

void
msg(int n, ...)
{
        va_list ap;

        va_start(ap, n);

        (void)vprintf(msgs[n], ap);
        (void)printf(" [lint2:%03d]\n", n);

        va_end(ap);
}

/*
 * Return a pointer to the last component of a path.
 */
static const char *
lbasename(const char *path)
{

        if (Fflag)
                return path;

        const char *base = path;
        for (const char *p = path; *p != '\0'; p++)
                if (*p == '/')
                        base = p + 1;
        return base;
}

/*
 * Create a string which describes a position in a source file.
 */
const char *
mkpos(const pos_t *posp)
{
        static struct buffer {
                char *buf;
                size_t cap;
        } buffers[2];
        static unsigned int buf_index;

        struct buffer *buf = buffers + buf_index;
        buf_index ^= 1;

        int filename;
        int lineno;
        if (Hflag && posp->p_src != posp->p_isrc) {
                filename = posp->p_isrc;
                lineno = posp->p_iline;
        } else {
                filename = posp->p_src;
                lineno = posp->p_line;
        }

        bool qm = !Hflag && posp->p_src != posp->p_isrc;
        const char *fn = lbasename(fnames[filename]);
        size_t len = strlen(fn) + 1 + 1 + 3 * sizeof(int) + 1 + 1;

        if (len > buf->cap)
                buf->buf = xrealloc(buf->buf, buf->cap = len);
        if (lineno != 0)
                (void)snprintf(buf->buf, buf->cap, "%s%s(%d)",
                    fn, qm ? "?" : "", lineno);
        else
                (void)snprintf(buf->buf, buf->cap, "%s", fn);

        return buf->buf;
}