summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoerg <joerg@FreeBSD.org>1995-11-05 15:56:42 +0000
committerjoerg <joerg@FreeBSD.org>1995-11-05 15:56:42 +0000
commit97ea65b2cb83e7b5b2c4afcacc3a185482457c2a (patch)
treee48ecf34ec80fd6977218c2852e4419794cc64d7
downloadFreeBSD-src-97ea65b2cb83e7b5b2c4afcacc3a185482457c2a.zip
FreeBSD-src-97ea65b2cb83e7b5b2c4afcacc3a185482457c2a.tar.gz
Jochen Pohl's lint(1) from NetBSD. Yet another import.
This is just a vendor import by now. I'll wait until i'll get the imported files back via CTM before applying the FreeBSD patches. Don't use it yet. Submitted by: Jochen Pohl <jpo.drs@sni.de> Obtained from: (NetBSD -- this version is directly from Jochen)
-rw-r--r--usr.bin/xlint/Makefile5
-rw-r--r--usr.bin/xlint/lint1/Makefile19
-rw-r--r--usr.bin/xlint/lint1/cgram.y1675
-rw-r--r--usr.bin/xlint/lint1/decl.c3134
-rw-r--r--usr.bin/xlint/lint1/emit.c241
-rw-r--r--usr.bin/xlint/lint1/emit1.c587
-rw-r--r--usr.bin/xlint/lint1/err.c543
-rw-r--r--usr.bin/xlint/lint1/externs.h56
-rw-r--r--usr.bin/xlint/lint1/externs1.h281
-rw-r--r--usr.bin/xlint/lint1/func.c1261
-rw-r--r--usr.bin/xlint/lint1/init.c513
-rw-r--r--usr.bin/xlint/lint1/lint.h118
-rw-r--r--usr.bin/xlint/lint1/lint1.h380
-rw-r--r--usr.bin/xlint/lint1/main1.c183
-rw-r--r--usr.bin/xlint/lint1/mem.c91
-rw-r--r--usr.bin/xlint/lint1/mem1.c358
-rw-r--r--usr.bin/xlint/lint1/op.h120
-rw-r--r--usr.bin/xlint/lint1/param.h120
-rw-r--r--usr.bin/xlint/lint1/scan.l1426
-rw-r--r--usr.bin/xlint/lint1/tree.c3924
-rw-r--r--usr.bin/xlint/lint2/Makefile13
-rw-r--r--usr.bin/xlint/lint2/chk.c1462
-rw-r--r--usr.bin/xlint/lint2/emit2.c236
-rw-r--r--usr.bin/xlint/lint2/externs2.h87
-rw-r--r--usr.bin/xlint/lint2/hash.c123
-rw-r--r--usr.bin/xlint/lint2/lint2.h177
-rw-r--r--usr.bin/xlint/lint2/main2.c190
-rw-r--r--usr.bin/xlint/lint2/mem2.c97
-rw-r--r--usr.bin/xlint/lint2/msg.c157
-rw-r--r--usr.bin/xlint/lint2/read.c1133
-rw-r--r--usr.bin/xlint/llib/Makefile20
-rw-r--r--usr.bin/xlint/llib/llib-lposix311
-rw-r--r--usr.bin/xlint/llib/llib-lstdc252
-rw-r--r--usr.bin/xlint/xlint/Makefile17
-rw-r--r--usr.bin/xlint/xlint/lint.1509
-rw-r--r--usr.bin/xlint/xlint/pathnames.h38
-rw-r--r--usr.bin/xlint/xlint/xlint.c761
37 files changed, 20618 insertions, 0 deletions
diff --git a/usr.bin/xlint/Makefile b/usr.bin/xlint/Makefile
new file mode 100644
index 0000000..01557ad
--- /dev/null
+++ b/usr.bin/xlint/Makefile
@@ -0,0 +1,5 @@
+# $NetBSD: Makefile,v 1.2 1995/07/03 21:23:45 cgd Exp $
+
+SUBDIR= lint1 lint2 xlint llib
+
+.include <bsd.subdir.mk>
diff --git a/usr.bin/xlint/lint1/Makefile b/usr.bin/xlint/lint1/Makefile
new file mode 100644
index 0000000..d5e519a
--- /dev/null
+++ b/usr.bin/xlint/lint1/Makefile
@@ -0,0 +1,19 @@
+# $NetBSD: Makefile,v 1.3 1995/07/04 01:53:05 cgd Exp $
+
+PROG= lint1
+SRCS= cgram.c scan.c mem1.c mem.c err.c main1.c decl.c tree.c func.c \
+ init.c emit.c emit1.c
+NOMAN=
+LDADD+= -ll
+DPADD+= ${LIBL}
+YFLAGS= -d
+CFLAGS+=-I.
+LINTFLAGS=-aehpz
+CLEANFILES+=y.tab.h cgram.c scan.c
+
+BINDIR= /usr/libexec
+
+# XXX: -O causes the gcc to die on the i386, when compiling tree.o
+CFLAGS+= -DXXX_BROKEN_GCC
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/lint1/cgram.y b/usr.bin/xlint/lint1/cgram.y
new file mode 100644
index 0000000..e65584a
--- /dev/null
+++ b/usr.bin/xlint/lint1/cgram.y
@@ -0,0 +1,1675 @@
+%{
+/* $NetBSD: cgram.y,v 1.8 1995/10/02 17:31:35 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: cgram.y,v 1.8 1995/10/02 17:31:35 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+
+#include "lint1.h"
+
+/*
+ * Contains the level of current declaration. 0 is extern.
+ * Used for symbol table entries.
+ */
+int blklev;
+
+/*
+ * level for memory allocation. Normaly the same as blklev.
+ * An exeption is the declaration of arguments in prototypes. Memory
+ * for these can't be freed after the declaration, but symbols must
+ * be removed from the symbol table after the declaration.
+ */
+int mblklev;
+
+static int toicon __P((tnode_t *));
+static void idecl __P((sym_t *, int));
+static void ignuptorp __P((void));
+
+%}
+
+%union {
+ int y_int;
+ val_t *y_val;
+ sbuf_t *y_sb;
+ sym_t *y_sym;
+ op_t y_op;
+ scl_t y_scl;
+ tspec_t y_tspec;
+ tqual_t y_tqual;
+ type_t *y_type;
+ tnode_t *y_tnode;
+ strg_t *y_strg;
+ pqinf_t *y_pqinf;
+};
+
+%token T_LBRACE T_RBRACE T_LBRACK T_RBRACK T_LPARN T_RPARN
+%token <y_op> T_STROP
+%token <y_op> T_UNOP
+%token <y_op> T_INCDEC
+%token T_SIZEOF
+%token <y_op> T_MULT
+%token <y_op> T_DIVOP
+%token <y_op> T_ADDOP
+%token <y_op> T_SHFTOP
+%token <y_op> T_RELOP
+%token <y_op> T_EQOP
+%token <y_op> T_AND
+%token <y_op> T_XOR
+%token <y_op> T_OR
+%token <y_op> T_LOGAND
+%token <y_op> T_LOGOR
+%token T_QUEST
+%token T_COLON
+%token <y_op> T_ASSIGN
+%token <y_op> T_OPASS
+%token T_COMMA
+%token T_SEMI
+%token T_ELLIPSE
+
+/* storage classes (extern, static, auto, register and typedef) */
+%token <y_scl> T_SCLASS
+
+/* types (char, int, short, long, unsigned, signed, float, double, void) */
+%token <y_tspec> T_TYPE
+
+/* qualifiers (const, volatile) */
+%token <y_tqual> T_QUAL
+
+/* struct or union */
+%token <y_tspec> T_SOU
+
+/* enum */
+%token T_ENUM
+
+/* remaining keywords */
+%token T_CASE
+%token T_DEFAULT
+%token T_IF
+%token T_ELSE
+%token T_SWITCH
+%token T_DO
+%token T_WHILE
+%token T_FOR
+%token T_GOTO
+%token T_CONTINUE
+%token T_BREAK
+%token T_RETURN
+%token T_ASM
+
+%left T_COMMA
+%right T_ASSIGN T_OPASS
+%right T_QUEST T_COLON
+%left T_LOGOR
+%left T_LOGAND
+%left T_OR
+%left T_XOR
+%left T_AND
+%left T_EQOP
+%left T_RELOP
+%left T_SHFTOP
+%left T_ADDOP
+%left T_MULT T_DIVOP
+%right T_UNOP T_INCDEC T_SIZEOF
+%left T_LPARN T_LBRACK T_STROP
+
+%token <y_sb> T_NAME
+%token <y_sb> T_TYPENAME
+%token <y_val> T_CON
+%token <y_strg> T_STRING
+
+%type <y_sym> func_decl
+%type <y_sym> notype_decl
+%type <y_sym> type_decl
+%type <y_type> typespec
+%type <y_type> clrtyp_typespec
+%type <y_type> notype_typespec
+%type <y_type> struct_spec
+%type <y_type> enum_spec
+%type <y_sym> struct_tag
+%type <y_sym> enum_tag
+%type <y_tspec> struct
+%type <y_sym> struct_declaration
+%type <y_sb> identifier
+%type <y_sym> member_declaration_list_with_rbrace
+%type <y_sym> member_declaration_list
+%type <y_sym> member_declaration
+%type <y_sym> notype_member_decls
+%type <y_sym> type_member_decls
+%type <y_sym> notype_member_decl
+%type <y_sym> type_member_decl
+%type <y_tnode> constant
+%type <y_sym> enum_declaration
+%type <y_sym> enums_with_opt_comma
+%type <y_sym> enums
+%type <y_sym> enumerator
+%type <y_sym> ename
+%type <y_sym> notype_direct_decl
+%type <y_sym> type_direct_decl
+%type <y_pqinf> pointer
+%type <y_pqinf> asterisk
+%type <y_sym> param_decl
+%type <y_sym> param_list
+%type <y_sym> abs_decl_param_list
+%type <y_sym> direct_param_decl
+%type <y_sym> notype_param_decl
+%type <y_sym> direct_notype_param_decl
+%type <y_pqinf> type_qualifier_list
+%type <y_pqinf> type_qualifier
+%type <y_sym> identifier_list
+%type <y_sym> abs_decl
+%type <y_sym> direct_abs_decl
+%type <y_sym> vararg_parameter_type_list
+%type <y_sym> parameter_type_list
+%type <y_sym> parameter_declaration
+%type <y_tnode> expr
+%type <y_tnode> term
+%type <y_tnode> func_arg_list
+%type <y_op> point_or_arrow
+%type <y_type> type_name
+%type <y_sym> abstract_declaration
+%type <y_tnode> do_while_expr
+%type <y_tnode> opt_expr
+%type <y_strg> string
+%type <y_strg> string2
+
+
+%%
+
+program:
+ /* empty */ {
+ if (sflag) {
+ /* empty translation unit */
+ error(272);
+ } else if (!tflag) {
+ /* empty translation unit */
+ warning(272);
+ }
+ }
+ | translation_unit
+ ;
+
+translation_unit:
+ ext_decl
+ | translation_unit ext_decl
+ ;
+
+ext_decl:
+ func_def {
+ glclup(0);
+ clrwflgs();
+ }
+ | data_def {
+ glclup(0);
+ clrwflgs();
+ }
+ ;
+
+data_def:
+ T_SEMI {
+ if (sflag) {
+ /* syntax error: empty declaration */
+ error(0);
+ } else if (!tflag) {
+ /* syntax error: empty declaration */
+ warning(0);
+ }
+ }
+ | clrtyp deftyp notype_init_decls T_SEMI {
+ if (sflag) {
+ /* old style declaration; add "int" */
+ error(1);
+ } else if (!tflag) {
+ /* old style declaration; add "int" */
+ warning(1);
+ }
+ }
+ | declmods deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI
+ | error T_SEMI {
+ globclup();
+ }
+ | error T_RBRACE {
+ globclup();
+ }
+ ;
+
+func_def:
+ func_decl {
+ if ($1->s_type->t_tspec != FUNC) {
+ /* syntax error */
+ error(249);
+ YYERROR;
+ }
+ if ($1->s_type->t_typedef) {
+ /* ()-less function definition */
+ error(64);
+ YYERROR;
+ }
+ funcdef($1);
+ blklev++;
+ pushdecl(ARG);
+ } opt_arg_declaration_list {
+ popdecl();
+ blklev--;
+ cluparg();
+ pushctrl(0);
+ } comp_stmnt {
+ funcend();
+ popctrl(0);
+ }
+ ;
+
+func_decl:
+ clrtyp deftyp notype_decl {
+ $$ = $3;
+ }
+ | declmods deftyp notype_decl {
+ $$ = $3;
+ }
+ | declspecs deftyp type_decl {
+ $$ = $3;
+ }
+ ;
+
+opt_arg_declaration_list:
+ /* empty */
+ | arg_declaration_list
+ ;
+
+arg_declaration_list:
+ arg_declaration
+ | arg_declaration_list arg_declaration
+ /* XXX or better "arg_declaration error" ? */
+ | error
+ ;
+
+/*
+ * "arg_declaration" is separated from "declaration" because it
+ * needs other error handling.
+ */
+
+arg_declaration:
+ declmods deftyp T_SEMI {
+ /* empty declaration */
+ warning(2);
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ } else {
+ tspec_t ts = dcs->d_type->t_tspec;
+ /* %s declared in argument declaration list */
+ warning(3, ts == STRUCT ? "struct" :
+ (ts == UNION ? "union" : "enum"));
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI {
+ if (dcs->d_nedecl) {
+ tspec_t ts = dcs->d_type->t_tspec;
+ /* %s declared in argument declaration list */
+ warning(3, ts == STRUCT ? "struct" :
+ (ts == UNION ? "union" : "enum"));
+ }
+ }
+ | declmods error
+ | declspecs error
+ ;
+
+declaration:
+ declmods deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declmods deftyp notype_init_decls T_SEMI
+ | declspecs deftyp T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else if (!dcs->d_nedecl) {
+ /* empty declaration */
+ warning(2);
+ }
+ }
+ | declspecs deftyp type_init_decls T_SEMI
+ | error T_SEMI
+ ;
+
+clrtyp:
+ {
+ clrtyp();
+ }
+ ;
+
+deftyp:
+ /* empty */ {
+ deftyp();
+ }
+ ;
+
+declspecs:
+ clrtyp_typespec {
+ addtype($1);
+ }
+ | declmods typespec {
+ addtype($2);
+ }
+ | declspecs declmod
+ | declspecs notype_typespec {
+ addtype($2);
+ }
+ ;
+
+declmods:
+ clrtyp T_QUAL {
+ addqual($2);
+ }
+ | clrtyp T_SCLASS {
+ addscl($2);
+ }
+ | declmods declmod
+ ;
+
+declmod:
+ T_QUAL {
+ addqual($1);
+ }
+ | T_SCLASS {
+ addscl($1);
+ }
+ ;
+
+clrtyp_typespec:
+ clrtyp notype_typespec {
+ $$ = $2;
+ }
+ | T_TYPENAME clrtyp {
+ $$ = getsym($1)->s_type;
+ }
+ ;
+
+typespec:
+ notype_typespec {
+ $$ = $1;
+ }
+ | T_TYPENAME {
+ $$ = getsym($1)->s_type;
+ }
+ ;
+
+notype_typespec:
+ T_TYPE {
+ $$ = gettyp($1);
+ }
+ | struct_spec {
+ popdecl();
+ $$ = $1;
+ }
+ | enum_spec {
+ popdecl();
+ $$ = $1;
+ }
+ ;
+
+struct_spec:
+ struct struct_tag {
+ /*
+ * STDC requires that "struct a;" always introduces
+ * a new tag if "a" is not declared at current level
+ *
+ * yychar is valid because otherwise the parser would
+ * not been able to deceide if he must shift or reduce
+ */
+ $$ = mktag($2, $1, 0, yychar == T_SEMI);
+ }
+ | struct struct_tag {
+ dcs->d_tagtyp = mktag($2, $1, 1, 0);
+ } struct_declaration {
+ $$ = compltag(dcs->d_tagtyp, $4);
+ }
+ | struct {
+ dcs->d_tagtyp = mktag(NULL, $1, 1, 0);
+ } struct_declaration {
+ $$ = compltag(dcs->d_tagtyp, $3);
+ }
+ | struct error {
+ symtyp = FVFT;
+ $$ = gettyp(INT);
+ }
+ ;
+
+struct:
+ T_SOU {
+ symtyp = FTAG;
+ pushdecl($1 == STRUCT ? MOS : MOU);
+ dcs->d_offset = 0;
+ dcs->d_stralign = CHAR_BIT;
+ $$ = $1;
+ }
+ ;
+
+struct_tag:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+struct_declaration:
+ struct_decl_lbrace member_declaration_list_with_rbrace {
+ $$ = $2;
+ }
+ ;
+
+struct_decl_lbrace:
+ T_LBRACE {
+ symtyp = FVFT;
+ }
+ ;
+
+member_declaration_list_with_rbrace:
+ member_declaration_list T_SEMI T_RBRACE {
+ $$ = $1;
+ }
+ | member_declaration_list T_RBRACE {
+ if (sflag) {
+ /* syntax req. ";" after last struct/union member */
+ error(66);
+ } else {
+ /* syntax req. ";" after last struct/union member */
+ warning(66);
+ }
+ $$ = $1;
+ }
+ | T_RBRACE {
+ $$ = NULL;
+ }
+ ;
+
+member_declaration_list:
+ member_declaration {
+ $$ = $1;
+ }
+ | member_declaration_list T_SEMI member_declaration {
+ $$ = lnklst($1, $3);
+ }
+ ;
+
+member_declaration:
+ noclass_declmods deftyp {
+ /* too late, i know, but getsym() compensates it */
+ symtyp = FMOS;
+ } notype_member_decls {
+ symtyp = FVFT;
+ $$ = $4;
+ }
+ | noclass_declspecs deftyp {
+ symtyp = FMOS;
+ } type_member_decls {
+ symtyp = FVFT;
+ $$ = $4;
+ }
+ | noclass_declmods deftyp {
+ /* struct or union member must be named */
+ warning(49);
+ $$ = NULL;
+ }
+ | noclass_declspecs deftyp {
+ /* struct or union member must be named */
+ warning(49);
+ $$ = NULL;
+ }
+ | error {
+ symtyp = FVFT;
+ $$ = NULL;
+ }
+ ;
+
+noclass_declspecs:
+ clrtyp_typespec {
+ addtype($1);
+ }
+ | noclass_declmods typespec {
+ addtype($2);
+ }
+ | noclass_declspecs T_QUAL {
+ addqual($2);
+ }
+ | noclass_declspecs notype_typespec {
+ addtype($2);
+ }
+ ;
+
+noclass_declmods:
+ clrtyp T_QUAL {
+ addqual($2);
+ }
+ | noclass_declmods T_QUAL {
+ addqual($2);
+ }
+ ;
+
+notype_member_decls:
+ notype_member_decl {
+ $$ = decl1str($1);
+ }
+ | notype_member_decls {
+ symtyp = FMOS;
+ } T_COMMA type_member_decl {
+ $$ = lnklst($1, decl1str($4));
+ }
+ ;
+
+type_member_decls:
+ type_member_decl {
+ $$ = decl1str($1);
+ }
+ | type_member_decls {
+ symtyp = FMOS;
+ } T_COMMA type_member_decl {
+ $$ = lnklst($1, decl1str($4));
+ }
+ ;
+
+notype_member_decl:
+ notype_decl {
+ $$ = $1;
+ }
+ | notype_decl T_COLON constant {
+ $$ = bitfield($1, toicon($3));
+ }
+ | {
+ symtyp = FVFT;
+ } T_COLON constant {
+ $$ = bitfield(NULL, toicon($3));
+ }
+ ;
+
+type_member_decl:
+ type_decl {
+ $$ = $1;
+ }
+ | type_decl T_COLON constant {
+ $$ = bitfield($1, toicon($3));
+ }
+ | {
+ symtyp = FVFT;
+ } T_COLON constant {
+ $$ = bitfield(NULL, toicon($3));
+ }
+ ;
+
+enum_spec:
+ enum enum_tag {
+ $$ = mktag($2, ENUM, 0, 0);
+ }
+ | enum enum_tag {
+ dcs->d_tagtyp = mktag($2, ENUM, 1, 0);
+ } enum_declaration {
+ $$ = compltag(dcs->d_tagtyp, $4);
+ }
+ | enum {
+ dcs->d_tagtyp = mktag(NULL, ENUM, 1, 0);
+ } enum_declaration {
+ $$ = compltag(dcs->d_tagtyp, $3);
+ }
+ | enum error {
+ symtyp = FVFT;
+ $$ = gettyp(INT);
+ }
+ ;
+
+enum:
+ T_ENUM {
+ symtyp = FTAG;
+ pushdecl(ENUMCON);
+ }
+ ;
+
+enum_tag:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+enum_declaration:
+ enum_decl_lbrace enums_with_opt_comma T_RBRACE {
+ $$ = $2;
+ }
+ ;
+
+enum_decl_lbrace:
+ T_LBRACE {
+ symtyp = FVFT;
+ enumval = 0;
+ }
+ ;
+
+enums_with_opt_comma:
+ enums {
+ $$ = $1;
+ }
+ | enums T_COMMA {
+ if (sflag) {
+ /* trailing "," prohibited in enum declaration */
+ error(54);
+ } else {
+ /* trailing "," prohibited in enum declaration */
+ warning(54);
+ }
+ $$ = $1;
+ }
+ ;
+
+enums:
+ enumerator {
+ $$ = $1;
+ }
+ | enums T_COMMA enumerator {
+ $$ = lnklst($1, $3);
+ }
+ | error {
+ $$ = NULL;
+ }
+ ;
+
+enumerator:
+ ename {
+ $$ = ename($1, enumval, 1);
+ }
+ | ename T_ASSIGN constant {
+ $$ = ename($1, toicon($3), 0);
+ }
+ ;
+
+ename:
+ identifier {
+ $$ = getsym($1);
+ }
+ ;
+
+
+notype_init_decls:
+ notype_init_decl
+ | notype_init_decls T_COMMA type_init_decl
+ ;
+
+type_init_decls:
+ type_init_decl
+ | type_init_decls T_COMMA type_init_decl
+ ;
+
+notype_init_decl:
+ notype_decl opt_asm_spec {
+ idecl($1, 0);
+ chksz($1);
+ }
+ | notype_decl opt_asm_spec {
+ idecl($1, 1);
+ } T_ASSIGN initializer {
+ chksz($1);
+ }
+ ;
+
+type_init_decl:
+ type_decl opt_asm_spec {
+ idecl($1, 0);
+ chksz($1);
+ }
+ | type_decl opt_asm_spec {
+ idecl($1, 1);
+ } T_ASSIGN initializer {
+ chksz($1);
+ }
+ ;
+
+notype_decl:
+ notype_direct_decl {
+ $$ = $1;
+ }
+ | pointer notype_direct_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+notype_direct_decl:
+ T_NAME {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN type_decl T_RPARN {
+ $$ = $2;
+ }
+ | notype_direct_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | notype_direct_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | notype_direct_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+type_decl:
+ type_direct_decl {
+ $$ = $1;
+ }
+ | pointer type_direct_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+type_direct_decl:
+ identifier {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN type_decl T_RPARN {
+ $$ = $2;
+ }
+ | type_direct_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | type_direct_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | type_direct_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+/*
+ * param_decl and notype_param_decl exist to avoid a conflict in
+ * argument lists. A typename enclosed in parens should always be
+ * treated as a typename, not an argument.
+ * "typedef int a; f(int (a));" is "typedef int a; f(int foo(a));"
+ * not "typedef int a; f(int a);"
+ */
+param_decl:
+ direct_param_decl {
+ $$ = $1;
+ }
+ | pointer direct_param_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_param_decl:
+ identifier {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN notype_param_decl T_RPARN {
+ $$ = $2;
+ }
+ | direct_param_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_param_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | direct_param_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+notype_param_decl:
+ direct_notype_param_decl {
+ $$ = $1;
+ }
+ | pointer direct_notype_param_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_notype_param_decl:
+ T_NAME {
+ $$ = dname(getsym($1));
+ }
+ | T_LPARN notype_param_decl T_RPARN {
+ $$ = $2;
+ }
+ | direct_notype_param_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_notype_param_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | direct_notype_param_decl param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+pointer:
+ asterisk {
+ $$ = $1;
+ }
+ | asterisk type_qualifier_list {
+ $$ = mergepq($1, $2);
+ }
+ | asterisk pointer {
+ $$ = mergepq($1, $2);
+ }
+ | asterisk type_qualifier_list pointer {
+ $$ = mergepq(mergepq($1, $2), $3);
+ }
+ ;
+
+asterisk:
+ T_MULT {
+ $$ = xcalloc(1, sizeof (pqinf_t));
+ $$->p_pcnt = 1;
+ }
+ ;
+
+type_qualifier_list:
+ type_qualifier {
+ $$ = $1;
+ }
+ | type_qualifier_list type_qualifier {
+ $$ = mergepq($1, $2);
+ }
+ ;
+
+type_qualifier:
+ T_QUAL {
+ $$ = xcalloc(1, sizeof (pqinf_t));
+ if ($1 == CONST) {
+ $$->p_const = 1;
+ } else {
+ $$->p_volatile = 1;
+ }
+ }
+ ;
+
+param_list:
+ id_list_lparn identifier_list T_RPARN {
+ $$ = $2;
+ }
+ | abs_decl_param_list {
+ $$ = $1;
+ }
+ ;
+
+id_list_lparn:
+ T_LPARN {
+ blklev++;
+ pushdecl(PARG);
+ }
+ ;
+
+identifier_list:
+ T_NAME {
+ $$ = iname(getsym($1));
+ }
+ | identifier_list T_COMMA T_NAME {
+ $$ = lnklst($1, iname(getsym($3)));
+ }
+ | identifier_list error {
+ $$ = $1;
+ }
+ ;
+
+abs_decl_param_list:
+ abs_decl_lparn T_RPARN {
+ $$ = NULL;
+ }
+ | abs_decl_lparn vararg_parameter_type_list T_RPARN {
+ dcs->d_proto = 1;
+ $$ = $2;
+ }
+ | abs_decl_lparn error T_RPARN {
+ $$ = NULL;
+ }
+ ;
+
+abs_decl_lparn:
+ T_LPARN {
+ blklev++;
+ pushdecl(PARG);
+ }
+ ;
+
+vararg_parameter_type_list:
+ parameter_type_list {
+ $$ = $1;
+ }
+ | parameter_type_list T_COMMA T_ELLIPSE {
+ dcs->d_vararg = 1;
+ $$ = $1;
+ }
+ | T_ELLIPSE {
+ if (sflag) {
+ /* ANSI C requires formal parameter before "..." */
+ error(84);
+ } else if (!tflag) {
+ /* ANSI C requires formal parameter before "..." */
+ warning(84);
+ }
+ dcs->d_vararg = 1;
+ $$ = NULL;
+ }
+ ;
+
+parameter_type_list:
+ parameter_declaration opt_asm_spec {
+ $$ = $1;
+ }
+ | parameter_type_list T_COMMA parameter_declaration opt_asm_spec {
+ $$ = lnklst($1, $3);
+ }
+ ;
+
+parameter_declaration:
+ declmods deftyp {
+ $$ = decl1arg(aname(), 0);
+ }
+ | declspecs deftyp {
+ $$ = decl1arg(aname(), 0);
+ }
+ | declmods deftyp notype_param_decl {
+ $$ = decl1arg($3, 0);
+ }
+ /*
+ * param_decl is needed because of following conflict:
+ * "typedef int a; f(int (a));" could be parsed as
+ * "function with argument a of type int", or
+ * "function with an abstract argument of type function".
+ * This grammar realizes the second case.
+ */
+ | declspecs deftyp param_decl {
+ $$ = decl1arg($3, 0);
+ }
+ | declmods deftyp abs_decl {
+ $$ = decl1arg($3, 0);
+ }
+ | declspecs deftyp abs_decl {
+ $$ = decl1arg($3, 0);
+ }
+ ;
+
+opt_asm_spec:
+ /* empty */
+ | T_ASM T_LPARN T_STRING T_RPARN {
+ freeyyv(&$3, T_STRING);
+ }
+ ;
+
+initializer:
+ init_expr
+ ;
+
+init_expr:
+ expr %prec T_COMMA {
+ mkinit($1);
+ }
+ | init_lbrace init_expr_list init_rbrace
+ | init_lbrace init_expr_list T_COMMA init_rbrace
+ | error
+ ;
+
+init_expr_list:
+ init_expr %prec T_COMMA
+ | init_expr_list T_COMMA init_expr
+ ;
+
+init_lbrace:
+ T_LBRACE {
+ initlbr();
+ }
+ ;
+
+init_rbrace:
+ T_RBRACE {
+ initrbr();
+ }
+ ;
+
+type_name:
+ {
+ pushdecl(ABSTRACT);
+ } abstract_declaration {
+ popdecl();
+ $$ = $2->s_type;
+ }
+ ;
+
+abstract_declaration:
+ noclass_declmods deftyp {
+ $$ = decl1abs(aname());
+ }
+ | noclass_declspecs deftyp {
+ $$ = decl1abs(aname());
+ }
+ | noclass_declmods deftyp abs_decl {
+ $$ = decl1abs($3);
+ }
+ | noclass_declspecs deftyp abs_decl {
+ $$ = decl1abs($3);
+ }
+ ;
+
+abs_decl:
+ pointer {
+ $$ = addptr(aname(), $1);
+ }
+ | direct_abs_decl {
+ $$ = $1;
+ }
+ | pointer direct_abs_decl {
+ $$ = addptr($2, $1);
+ }
+ ;
+
+direct_abs_decl:
+ T_LPARN abs_decl T_RPARN {
+ $$ = $2;
+ }
+ | T_LBRACK T_RBRACK {
+ $$ = addarray(aname(), 0, 0);
+ }
+ | T_LBRACK constant T_RBRACK {
+ $$ = addarray(aname(), 1, toicon($2));
+ }
+ | direct_abs_decl T_LBRACK T_RBRACK {
+ $$ = addarray($1, 0, 0);
+ }
+ | direct_abs_decl T_LBRACK constant T_RBRACK {
+ $$ = addarray($1, 1, toicon($3));
+ }
+ | abs_decl_param_list {
+ $$ = addfunc(aname(), $1);
+ popdecl();
+ blklev--;
+ }
+ | direct_abs_decl abs_decl_param_list {
+ $$ = addfunc($1, $2);
+ popdecl();
+ blklev--;
+ }
+ ;
+
+stmnt:
+ labeled_stmnt
+ | expr_stmnt
+ | comp_stmnt
+ | selection_stmnt
+ | iteration_stmnt
+ | jump_stmnt {
+ ftflg = 0;
+ }
+ | asm_stmnt
+ ;
+
+labeled_stmnt:
+ label stmnt
+ ;
+
+label:
+ identifier T_COLON {
+ symtyp = FLAB;
+ label(T_NAME, getsym($1), NULL);
+ }
+ | T_CASE constant T_COLON {
+ label(T_CASE, NULL, $2);
+ ftflg = 1;
+ }
+ | T_DEFAULT T_COLON {
+ label(T_DEFAULT, NULL, NULL);
+ ftflg = 1;
+ }
+ ;
+
+comp_stmnt:
+ compstmnt_lbrace declaration_list opt_stmnt_list compstmnt_rbrace
+ | compstmnt_lbrace opt_stmnt_list compstmnt_rbrace
+ ;
+
+compstmnt_lbrace:
+ T_LBRACE {
+ blklev++;
+ mblklev++;
+ pushdecl(AUTO);
+ }
+ ;
+
+compstmnt_rbrace:
+ T_RBRACE {
+ popdecl();
+ freeblk();
+ mblklev--;
+ blklev--;
+ ftflg = 0;
+ }
+ ;
+
+opt_stmnt_list:
+ /* empty */
+ | stmnt_list
+ ;
+
+stmnt_list:
+ stmnt {
+ clrwflgs();
+ }
+ | stmnt_list stmnt {
+ clrwflgs();
+ }
+ | stmnt_list error T_SEMI {
+ clrwflgs();
+ }
+ ;
+
+expr_stmnt:
+ expr T_SEMI {
+ expr($1, 0, 0);
+ ftflg = 0;
+ }
+ | T_SEMI {
+ ftflg = 0;
+ }
+ ;
+
+selection_stmnt:
+ if_without_else {
+ if2();
+ if3(0);
+ }
+ | if_without_else T_ELSE {
+ if2();
+ } stmnt {
+ if3(1);
+ }
+ | if_without_else T_ELSE error {
+ if3(0);
+ }
+ | switch_expr stmnt {
+ switch2();
+ }
+ | switch_expr error {
+ switch2();
+ }
+ ;
+
+if_without_else:
+ if_expr stmnt
+ | if_expr error
+ ;
+
+if_expr:
+ T_IF T_LPARN expr T_RPARN {
+ if1($3);
+ clrwflgs();
+ }
+ ;
+
+switch_expr:
+ T_SWITCH T_LPARN expr T_RPARN {
+ switch1($3);
+ clrwflgs();
+ }
+ ;
+
+iteration_stmnt:
+ while_expr stmnt {
+ while2();
+ }
+ | while_expr error {
+ while2();
+ }
+ | do stmnt do_while_expr {
+ do2($3);
+ ftflg = 0;
+ }
+ | do error {
+ do2(NULL);
+ }
+ | for_exprs stmnt {
+ for2();
+ }
+ | for_exprs error {
+ for2();
+ }
+ ;
+
+while_expr:
+ T_WHILE T_LPARN expr T_RPARN {
+ while1($3);
+ clrwflgs();
+ }
+ ;
+
+do:
+ T_DO {
+ do1();
+ }
+ ;
+
+do_while_expr:
+ T_WHILE T_LPARN expr T_RPARN T_SEMI {
+ $$ = $3;
+ }
+ ;
+
+for_exprs:
+ T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN {
+ for1($3, $5, $7);
+ clrwflgs();
+ }
+ ;
+
+opt_expr:
+ /* empty */ {
+ $$ = NULL;
+ }
+ | expr {
+ $$ = $1;
+ }
+ ;
+
+jump_stmnt:
+ goto identifier T_SEMI {
+ dogoto(getsym($2));
+ }
+ | goto error T_SEMI {
+ symtyp = FVFT;
+ }
+ | T_CONTINUE T_SEMI {
+ docont();
+ }
+ | T_BREAK T_SEMI {
+ dobreak();
+ }
+ | T_RETURN T_SEMI {
+ doreturn(NULL);
+ }
+ | T_RETURN expr T_SEMI {
+ doreturn($2);
+ }
+ ;
+
+goto:
+ T_GOTO {
+ symtyp = FLAB;
+ }
+ ;
+
+asm_stmnt:
+ T_ASM T_LPARN read_until_rparn T_SEMI {
+ setasm();
+ }
+ | T_ASM T_QUAL T_LPARN read_until_rparn T_SEMI {
+ setasm();
+ }
+ | T_ASM error
+ ;
+
+read_until_rparn:
+ /* empty */ {
+ ignuptorp();
+ }
+ ;
+
+declaration_list:
+ declaration {
+ clrwflgs();
+ }
+ | declaration_list declaration {
+ clrwflgs();
+ }
+ ;
+
+constant:
+ expr %prec T_COMMA {
+ $$ = $1;
+ }
+ ;
+
+expr:
+ expr T_MULT expr {
+ $$ = build(MULT, $1, $3);
+ }
+ | expr T_DIVOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_ADDOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_SHFTOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_RELOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_EQOP expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_AND expr {
+ $$ = build(AND, $1, $3);
+ }
+ | expr T_XOR expr {
+ $$ = build(XOR, $1, $3);
+ }
+ | expr T_OR expr {
+ $$ = build(OR, $1, $3);
+ }
+ | expr T_LOGAND expr {
+ $$ = build(LOGAND, $1, $3);
+ }
+ | expr T_LOGOR expr {
+ $$ = build(LOGOR, $1, $3);
+ }
+ | expr T_QUEST expr T_COLON expr {
+ $$ = build(QUEST, $1, build(COLON, $3, $5));
+ }
+ | expr T_ASSIGN expr {
+ $$ = build(ASSIGN, $1, $3);
+ }
+ | expr T_OPASS expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_COMMA expr {
+ $$ = build(COMMA, $1, $3);
+ }
+ | term {
+ $$ = $1;
+ }
+ ;
+
+term:
+ T_NAME {
+ /* XXX realy neccessary? */
+ if (yychar < 0)
+ yychar = yylex();
+ $$ = getnnode(getsym($1), yychar);
+ }
+ | string {
+ $$ = getsnode($1);
+ }
+ | T_CON {
+ $$ = getcnode(gettyp($1->v_tspec), $1);
+ }
+ | T_LPARN expr T_RPARN {
+ if ($2 != NULL)
+ $2->tn_parn = 1;
+ $$ = $2;
+ }
+ | term T_INCDEC {
+ $$ = build($2 == INC ? INCAFT : DECAFT, $1, NULL);
+ }
+ | T_INCDEC term {
+ $$ = build($1 == INC ? INCBEF : DECBEF, $2, NULL);
+ }
+ | T_MULT term {
+ $$ = build(STAR, $2, NULL);
+ }
+ | T_AND term {
+ $$ = build(AMPER, $2, NULL);
+ }
+ | T_UNOP term {
+ $$ = build($1, $2, NULL);
+ }
+ | T_ADDOP term {
+ if (tflag && $1 == PLUS) {
+ /* unary + is illegal in traditional C */
+ warning(100);
+ }
+ $$ = build($1 == PLUS ? UPLUS : UMINUS, $2, NULL);
+ }
+ | term T_LBRACK expr T_RBRACK {
+ $$ = build(STAR, build(PLUS, $1, $3), NULL);
+ }
+ | term T_LPARN T_RPARN {
+ $$ = funccall($1, NULL);
+ }
+ | term T_LPARN func_arg_list T_RPARN {
+ $$ = funccall($1, $3);
+ }
+ | term point_or_arrow T_NAME {
+ if ($1 != NULL) {
+ sym_t *msym;
+ /* XXX strmemb should be integrated in build() */
+ if ($2 == ARROW) {
+ /* must to this before strmemb is called */
+ $1 = cconv($1);
+ }
+ msym = strmemb($1, $2, getsym($3));
+ $$ = build($2, $1, getnnode(msym, 0));
+ } else {
+ $$ = NULL;
+ }
+ }
+ | T_SIZEOF term %prec T_SIZEOF {
+ if (($$ = $2 == NULL ? NULL : bldszof($2->tn_type)) != NULL)
+ chkmisc($2, 0, 0, 0, 0, 0, 1);
+ }
+ | T_SIZEOF T_LPARN type_name T_RPARN %prec T_SIZEOF {
+ $$ = bldszof($3);
+ }
+ | T_LPARN type_name T_RPARN term %prec T_UNOP {
+ $$ = cast($4, $2);
+ }
+ ;
+
+string:
+ T_STRING {
+ $$ = $1;
+ }
+ | T_STRING string2 {
+ $$ = catstrg($1, $2);
+ }
+ ;
+
+string2:
+ T_STRING {
+ if (tflag) {
+ /* concatenated strings are illegal in traditional C */
+ warning(219);
+ }
+ $$ = $1;
+ }
+ | string2 T_STRING {
+ $$ = catstrg($1, $2);
+ }
+ ;
+
+func_arg_list:
+ expr %prec T_COMMA {
+ $$ = funcarg(NULL, $1);
+ }
+ | func_arg_list T_COMMA expr {
+ $$ = funcarg($1, $3);
+ }
+ ;
+
+point_or_arrow:
+ T_STROP {
+ symtyp = FMOS;
+ $$ = $1;
+ }
+ ;
+
+identifier:
+ T_NAME {
+ $$ = $1;
+ }
+ | T_TYPENAME {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* ARGSUSED */
+int
+yyerror(msg)
+ char *msg;
+{
+ error(249);
+ if (++sytxerr >= 5)
+ norecover();
+ return (0);
+}
+
+/*
+ * Gets a node for a constant and returns the value of this constant
+ * as integer.
+ * Is the node not constant or too large for int or of type float,
+ * a warning will be printed.
+ *
+ * toicon() should be used only inside declarations. If it is used in
+ * expressions, it frees the memory used for the expression.
+ */
+static int
+toicon(tn)
+ tnode_t *tn;
+{
+ int i;
+ tspec_t t;
+ val_t *v;
+
+ v = constant(tn);
+
+ /*
+ * Abstract declarations are used inside expression. To free
+ * the memory would be a fatal error.
+ */
+ if (dcs->d_ctx != ABSTRACT)
+ tfreeblk();
+
+ if ((t = v->v_tspec) == FLOAT || t == DOUBLE || t == LDOUBLE) {
+ i = (int)v->v_ldbl;
+ /* integral constant expression expected */
+ error(55);
+ } else {
+ i = (int)v->v_quad;
+ if (isutyp(t)) {
+ if ((u_quad_t)v->v_quad > INT_MAX) {
+ /* integral constant too large */
+ warning(56);
+ }
+ } else {
+ if (v->v_quad > INT_MAX || v->v_quad < INT_MIN) {
+ /* integral constant too large */
+ warning(56);
+ }
+ }
+ }
+ free(v);
+ return (i);
+}
+
+static void
+idecl(decl, initflg)
+ sym_t *decl;
+ int initflg;
+{
+ initerr = 0;
+ initsym = decl;
+
+ switch (dcs->d_ctx) {
+ case EXTERN:
+ decl1ext(decl, initflg);
+ break;
+ case ARG:
+ (void)decl1arg(decl, initflg);
+ break;
+ case AUTO:
+ decl1loc(decl, initflg);
+ break;
+ default:
+ lerror("idecl()");
+ }
+
+ if (initflg && !initerr)
+ prepinit();
+}
+
+/*
+ * Discard all input tokens up to and including the next
+ * unmatched right paren
+ */
+void
+ignuptorp()
+{
+ int level;
+
+ if (yychar < 0)
+ yychar = yylex();
+ freeyyv(&yylval, yychar);
+
+ level = 1;
+ while (yychar != T_RPARN || --level > 0) {
+ if (yychar == T_LPARN) {
+ level++;
+ } else if (yychar <= 0) {
+ break;
+ }
+ freeyyv(&yylval, yychar = yylex());
+ }
+
+ yyclearin;
+}
diff --git a/usr.bin/xlint/lint1/decl.c b/usr.bin/xlint/lint1/decl.c
new file mode 100644
index 0000000..fa023b7
--- /dev/null
+++ b/usr.bin/xlint/lint1/decl.c
@@ -0,0 +1,3134 @@
+/* $NetBSD: decl.c,v 1.11 1995/10/02 17:34:16 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: decl.c,v 1.11 1995/10/02 17:34:16 jpo Exp $";
+#endif
+
+#include <sys/param.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lint1.h"
+
+const char *unnamed = "<unnamed>";
+
+/* contains various information and classification on types */
+ttab_t ttab[NTSPEC];
+
+/* shared type structures for arithmtic types and void */
+static type_t *typetab;
+
+/* value of next enumerator during declaration of enum types */
+int enumval;
+
+/*
+ * pointer to top element of a stack which contains informations local
+ * to nested declarations
+ */
+dinfo_t *dcs;
+
+static type_t *tdeferr __P((type_t *, tspec_t));
+static void settdsym __P((type_t *, sym_t *));
+static tspec_t mrgtspec __P((tspec_t, tspec_t));
+static void align __P((int, int));
+static sym_t *newtag __P((sym_t *, scl_t, int, int));
+static int eqargs __P((type_t *, type_t *, int *));
+static int mnoarg __P((type_t *, int *));
+static int chkosdef __P((sym_t *, sym_t *));
+static int chkptdecl __P((sym_t *, sym_t *));
+static sym_t *nsfunc __P((sym_t *, sym_t *));
+static void osfunc __P((sym_t *, sym_t *));
+static void ledecl __P((sym_t *));
+static int chkinit __P((sym_t *));
+static void chkausg __P((int, sym_t *));
+static void chkvusg __P((int, sym_t *));
+static void chklusg __P((sym_t *));
+static void chktusg __P((sym_t *));
+static void chkglvar __P((sym_t *));
+static void glchksz __P((sym_t *));
+
+/*
+ * initializes all global vars used in declarations
+ */
+void
+initdecl()
+{
+ int i;
+ static struct {
+ tspec_t it_tspec;
+ ttab_t it_ttab;
+ } ittab[] = {
+ { SIGNED, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "signed" } },
+ { UNSIGN, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "unsigned" } },
+ { CHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "char" } },
+ { SCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "signed char" } },
+ { UCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 1, 0, 1, 1, "unsigned char" } },
+ { SHORT, { sizeof (short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 0, 0, 1, 1, "short" } },
+ { USHORT, { sizeof (u_short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 1, 0, 1, 1, "unsigned short" } },
+ { INT, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 0, 0, 1, 1, "int" } },
+ { UINT, { sizeof (u_int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 1, 0, 1, 1, "unsigned int" } },
+ { LONG, { sizeof (long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 0, 0, 1, 1, "long" } },
+ { ULONG, { sizeof (u_long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 1, 0, 1, 1, "unsigned long" } },
+ { QUAD, { sizeof (quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 0, 0, 1, 1, "long long" } },
+ { UQUAD, { sizeof (u_quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 1, 0, 1, 1, "unsigned long long" } },
+ { FLOAT, { sizeof (float) * CHAR_BIT, 4 * CHAR_BIT,
+ FLOAT, FLOAT,
+ 0, 0, 1, 1, 1, "float" } },
+ { DOUBLE, { sizeof (double) * CHAR_BIT, 8 * CHAR_BIT,
+ DOUBLE, DOUBLE,
+ 0, 0, 1, 1, 1, "double" } },
+ { LDOUBLE, { sizeof (ldbl_t) * CHAR_BIT, 10 * CHAR_BIT,
+ LDOUBLE, LDOUBLE,
+ 0, 0, 1, 1, 1, "long double" } },
+ { VOID, { -1, -1,
+ VOID, VOID,
+ 0, 0, 0, 0, 0, "void" } },
+ { STRUCT, { -1, -1,
+ STRUCT, STRUCT,
+ 0, 0, 0, 0, 0, "struct" } },
+ { UNION, { -1, -1,
+ UNION, UNION,
+ 0, 0, 0, 0, 0, "union" } },
+ { ENUM, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ ENUM, ENUM,
+ 1, 0, 0, 1, 1, "enum" } },
+ { PTR, { sizeof (void *) * CHAR_BIT, 4 * CHAR_BIT,
+ PTR, PTR,
+ 0, 1, 0, 0, 1, "pointer" } },
+ { ARRAY, { -1, -1,
+ ARRAY, ARRAY,
+ 0, 0, 0, 0, 0, "array" } },
+ { FUNC, { -1, -1,
+ FUNC, FUNC,
+ 0, 0, 0, 0, 0, "function" } },
+ };
+
+ /* declaration stack */
+ dcs = xcalloc(1, sizeof (dinfo_t));
+ dcs->d_ctx = EXTERN;
+ dcs->d_ldlsym = &dcs->d_dlsyms;
+
+ /* type information and classification */
+ for (i = 0; i < sizeof (ittab) / sizeof (ittab[0]); i++)
+ STRUCT_ASSIGN(ttab[ittab[i].it_tspec], ittab[i].it_ttab);
+ if (!pflag) {
+ for (i = 0; i < NTSPEC; i++)
+ ttab[i].tt_psz = ttab[i].tt_sz;
+ }
+
+ /* shared type structures */
+ typetab = xcalloc(NTSPEC, sizeof (type_t));
+ for (i = 0; i < NTSPEC; i++)
+ typetab[i].t_tspec = NOTSPEC;
+ typetab[CHAR].t_tspec = CHAR;
+ typetab[SCHAR].t_tspec = SCHAR;
+ typetab[UCHAR].t_tspec = UCHAR;
+ typetab[SHORT].t_tspec = SHORT;
+ typetab[USHORT].t_tspec = USHORT;
+ typetab[INT].t_tspec = INT;
+ typetab[UINT].t_tspec = UINT;
+ typetab[LONG].t_tspec = LONG;
+ typetab[ULONG].t_tspec = ULONG;
+ typetab[QUAD].t_tspec = QUAD;
+ typetab[UQUAD].t_tspec = UQUAD;
+ typetab[FLOAT].t_tspec = FLOAT;
+ typetab[DOUBLE].t_tspec = DOUBLE;
+ typetab[LDOUBLE].t_tspec = LDOUBLE;
+ typetab[VOID].t_tspec = VOID;
+ /*
+ * Next two are not real types. They are only used by the parser
+ * to return keywords "signed" and "unsigned"
+ */
+ typetab[SIGNED].t_tspec = SIGNED;
+ typetab[UNSIGN].t_tspec = UNSIGN;
+}
+
+/*
+ * Returns a shared type structure vor arithmetic types and void.
+ *
+ * It's important do duplicate this structure (using duptyp() or tdupdyp())
+ * if it is to be modified (adding qualifiers or anything else).
+ */
+type_t *
+gettyp(t)
+ tspec_t t;
+{
+ return (&typetab[t]);
+}
+
+type_t *
+duptyp(tp)
+ const type_t *tp;
+{
+ type_t *ntp;
+
+ ntp = getblk(sizeof (type_t));
+ STRUCT_ASSIGN(*ntp, *tp);
+ return (ntp);
+}
+
+/*
+ * Use tduptyp() instead of duptyp() inside expressions (if the
+ * allocated memory should be freed after the expr).
+ */
+type_t *
+tduptyp(tp)
+ const type_t *tp;
+{
+ type_t *ntp;
+
+ ntp = tgetblk(sizeof (type_t));
+ STRUCT_ASSIGN(*ntp, *tp);
+ return (ntp);
+}
+
+/*
+ * Returns 1 if the argument is void or an incomplete array,
+ * struct, union or enum type.
+ */
+int
+incompl(tp)
+ type_t *tp;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == VOID) {
+ return (1);
+ } else if (t == ARRAY) {
+ return (tp->t_aincompl);
+ } else if (t == STRUCT || t == UNION) {
+ return (tp->t_str->sincompl);
+ } else if (t == ENUM) {
+ return (tp->t_enum->eincompl);
+ }
+ return (0);
+}
+
+/*
+ * Set the flag for (in)complete array, struct, union or enum
+ * types.
+ */
+void
+setcompl(tp, ic)
+ type_t *tp;
+ int ic;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == ARRAY) {
+ tp->t_aincompl = ic;
+ } else if (t == STRUCT || t == UNION) {
+ tp->t_str->sincompl = ic;
+ } else {
+ if (t != ENUM)
+ lerror("setcompl() 1");
+ tp->t_enum->eincompl = ic;
+ }
+}
+
+/*
+ * Remember the storage class of the current declaration in dcs->d_scl
+ * (the top element of the declaration stack) and detect multiple
+ * storage classes.
+ */
+void
+addscl(sc)
+ scl_t sc;
+{
+ if (sc == INLINE) {
+ if (dcs->d_inline)
+ /* duplicate '%s' */
+ warning(10, "inline");
+ dcs->d_inline = 1;
+ return;
+ }
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_smod != NOTSPEC || dcs->d_lmod != NOTSPEC) {
+ /* storage class after type is obsolescent */
+ warning(83);
+ }
+ if (dcs->d_scl == NOSCL) {
+ dcs->d_scl = sc;
+ } else {
+ /*
+ * multiple storage classes. An error will be reported in
+ * deftyp().
+ */
+ dcs->d_mscl = 1;
+ }
+}
+
+/*
+ * Remember the type, modifier or typedef name returned by the parser
+ * in *dcs (top element of decl stack). This information is used in
+ * deftyp() to build the type used for all declarators in this
+ * declaration.
+ *
+ * Is tp->t_typedef 1, the type comes from a previously defined typename.
+ * Otherwise it comes from a type specifier (int, long, ...) or a
+ * struct/union/enum tag.
+ */
+void
+addtype(tp)
+ type_t *tp;
+{
+ tspec_t t;
+
+ if (tp->t_typedef) {
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) {
+ /*
+ * something like "typedef int a; int a b;"
+ * This should not happen with current grammar.
+ */
+ lerror("addtype()");
+ }
+ dcs->d_type = tp;
+ return;
+ }
+
+ t = tp->t_tspec;
+
+ if (t == STRUCT || t == UNION || t == ENUM) {
+ /*
+ * something like "int struct a ..."
+ * struct/union/enum with anything else is not allowed
+ */
+ if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
+ dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) {
+ /*
+ * remember that an error must be reported in
+ * deftyp().
+ */
+ dcs->d_terr = 1;
+ dcs->d_atyp = dcs->d_lmod = dcs->d_smod = NOTSPEC;
+ }
+ dcs->d_type = tp;
+ return;
+ }
+
+ if (dcs->d_type != NULL && !dcs->d_type->t_typedef) {
+ /*
+ * something like "struct a int"
+ * struct/union/enum with anything else is not allowed
+ */
+ dcs->d_terr = 1;
+ return;
+ }
+
+ if (t == LONG && dcs->d_lmod == LONG) {
+ /* "long long" or "long ... long" */
+ t = QUAD;
+ dcs->d_lmod = NOTSPEC;
+ if (!quadflg)
+ /* %s C does not support 'long long' */
+ (void)gnuism(265, tflag ? "traditional" : "ANSI");
+ }
+
+ if (dcs->d_type != NULL && dcs->d_type->t_typedef) {
+ /* something like "typedef int a; a long ..." */
+ dcs->d_type = tdeferr(dcs->d_type, t);
+ return;
+ }
+
+ /* now it can be only a combination of arithmetic types and void */
+ if (t == SIGNED || t == UNSIGN) {
+ /* remeber specifiers "signed" and "unsigned" in dcs->d_smod */
+ if (dcs->d_smod != NOTSPEC)
+ /*
+ * more then one "signed" and/or "unsigned"; print
+ * an error in deftyp()
+ */
+ dcs->d_terr = 1;
+ dcs->d_smod = t;
+ } else if (t == SHORT || t == LONG || t == QUAD) {
+ /*
+ * remember specifiers "short", "long" and "long long" in
+ * dcs->d_lmod
+ */
+ if (dcs->d_lmod != NOTSPEC)
+ /* more than one, print error in deftyp() */
+ dcs->d_terr = 1;
+ dcs->d_lmod = t;
+ } else {
+ /*
+ * remember specifiers "void", "char", "int", "float" or
+ * "double" int dcs->d_atyp
+ */
+ if (dcs->d_atyp != NOTSPEC)
+ /* more than one, print error in deftyp() */
+ dcs->d_terr = 1;
+ dcs->d_atyp = t;
+ }
+}
+
+/*
+ * called if a list of declaration specifiers contains a typedef name
+ * and other specifiers (except struct, union, enum, typedef name)
+ */
+static type_t *
+tdeferr(td, t)
+ type_t *td;
+ tspec_t t;
+{
+ tspec_t t2;
+
+ t2 = td->t_tspec;
+
+ switch (t) {
+ case SIGNED:
+ case UNSIGN:
+ if (t2 == CHAR || t2 == SHORT || t2 == INT || t2 == LONG ||
+ t2 == QUAD) {
+ if (!tflag)
+ /* modifying typedef with ... */
+ warning(5, ttab[t].tt_name);
+ td = duptyp(gettyp(mrgtspec(t2, t)));
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ case SHORT:
+ if (t2 == INT || t2 == UINT) {
+ /* modifying typedef with ... */
+ warning(5, "short");
+ td = duptyp(gettyp(t2 == INT ? SHORT : USHORT));
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ case LONG:
+ if (t2 == INT || t2 == UINT || t2 == LONG || t2 == ULONG ||
+ t2 == FLOAT || t2 == DOUBLE) {
+ /* modifying typedef with ... */
+ warning(5, "long");
+ if (t2 == INT) {
+ td = gettyp(LONG);
+ } else if (t2 == UINT) {
+ td = gettyp(ULONG);
+ } else if (t2 == LONG) {
+ td = gettyp(QUAD);
+ } else if (t2 == ULONG) {
+ td = gettyp(UQUAD);
+ } else if (t2 == FLOAT) {
+ td = gettyp(DOUBLE);
+ } else if (t2 == DOUBLE) {
+ td = gettyp(LDOUBLE);
+ }
+ td = duptyp(td);
+ td->t_typedef = 1;
+ return (td);
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ /* Anything other is not accepted. */
+
+ dcs->d_terr = 1;
+ return (td);
+}
+
+/*
+ * Remember the symbol of a typedef name (2nd arg) in a struct, union
+ * or enum tag if the typedef name is the first defined for this tag.
+ *
+ * If the tag is unnamed, the typdef name is used for identification
+ * of this tag in lint2. Although its possible that more then one typedef
+ * name is defined for one tag, the first name defined should be unique
+ * if the tag is unnamed.
+ */
+static void
+settdsym(tp, sym)
+ type_t *tp;
+ sym_t *sym;
+{
+ tspec_t t;
+
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ if (tp->t_str->stdef == NULL)
+ tp->t_str->stdef = sym;
+ } else if (t == ENUM) {
+ if (tp->t_enum->etdef == NULL)
+ tp->t_enum->etdef = sym;
+ }
+}
+
+/*
+ * Remember a qualifier which is part of the declaration specifiers
+ * (and not the declarator) in the top element of the declaration stack.
+ * Also detect multiple qualifiers of the same kind.
+
+ * The rememberd qualifier is used by deftyp() to construct the type
+ * for all declarators.
+ */
+void
+addqual(q)
+ tqual_t q;
+{
+ if (q == CONST) {
+ if (dcs->d_const) {
+ /* duplicate "%s" */
+ warning(10, "const");
+ }
+ dcs->d_const = 1;
+ } else {
+ if (q != VOLATILE)
+ lerror("addqual() 1");
+ if (dcs->d_volatile) {
+ /* duplicate "%s" */
+ warning(10, "volatile");
+ }
+ dcs->d_volatile = 1;
+ }
+}
+
+/*
+ * Go to the next declaration level (structs, nested structs, blocks,
+ * argument declaration lists ...)
+ */
+void
+pushdecl(sc)
+ scl_t sc;
+{
+ dinfo_t *di;
+
+ if (dflag)
+ (void)printf("pushdecl(%d)\n", (int)sc);
+
+ /* put a new element on the declaration stack */
+ di = xcalloc(1, sizeof (dinfo_t));
+ di->d_nxt = dcs;
+ dcs = di;
+ di->d_ctx = sc;
+ di->d_ldlsym = &di->d_dlsyms;
+}
+
+/*
+ * Go back to previous declaration level
+ */
+void
+popdecl()
+{
+ dinfo_t *di;
+
+ if (dflag)
+ (void)printf("popdecl(%d)\n", (int)dcs->d_ctx);
+
+ if (dcs->d_nxt == NULL)
+ lerror("popdecl() 1");
+ di = dcs;
+ dcs = di->d_nxt;
+ switch (di->d_ctx) {
+ case EXTERN:
+ /* there is nothing after external declarations */
+ lerror("popdecl() 2");
+ /* NOTREACHED */
+ case MOS:
+ case MOU:
+ case ENUMCON:
+ /*
+ * Symbols declared in (nested) structs or enums are
+ * part of the next level (they are removed from the
+ * symbol table if the symbols of the outher level are
+ * removed)
+ */
+ if ((*dcs->d_ldlsym = di->d_dlsyms) != NULL)
+ dcs->d_ldlsym = di->d_ldlsym;
+ break;
+ case ARG:
+ /*
+ * All symbols in dcs->d_dlsyms are introduced in old style
+ * argument declarations (it's not clean, but possible).
+ * They are appended to the list of symbols declared in
+ * an old style argument identifier list or a new style
+ * parameter type list.
+ */
+ if (di->d_dlsyms != NULL) {
+ *di->d_ldlsym = dcs->d_fpsyms;
+ dcs->d_fpsyms = di->d_dlsyms;
+ }
+ break;
+ case ABSTRACT:
+ /*
+ * casts and sizeof
+ * Append all symbols declared in the abstract declaration
+ * to the list of symbols declared in the surounding decl.
+ * or block.
+ * XXX I'm not sure whether they should be removed from the
+ * symbol table now or later.
+ */
+ if ((*dcs->d_ldlsym = di->d_dlsyms) != NULL)
+ dcs->d_ldlsym = di->d_ldlsym;
+ break;
+ case AUTO:
+ /* check usage of local vars */
+ chkusage(di);
+ /* FALLTHROUGH */
+ case PARG:
+ /* usage of arguments will be checked by funcend() */
+ rmsyms(di->d_dlsyms);
+ break;
+ default:
+ lerror("popdecl() 3");
+ }
+ free(di);
+}
+
+/*
+ * Set flag d_asm in all declaration stack elements up to the
+ * outermost one.
+ *
+ * This is used to mark compound statements which have, possibly in
+ * nested compound statements, asm statements. For these compound
+ * statements no warnings about unused or unitialized variables are
+ * printed.
+ *
+ * There is no need to clear d_asm in dinfo structs with context AUTO,
+ * because these structs are freed at the end of the compound statement.
+ * But it must be cleard in the outermost dinfo struct, which has
+ * context EXTERN. This could be done in clrtyp() and would work for
+ * C, but not for C++ (due to mixed statements and declarations). Thus
+ * we clear it in glclup(), which is used to do some cleanup after
+ * global declarations/definitions.
+ */
+void
+setasm()
+{
+ dinfo_t *di;
+
+ for (di = dcs; di != NULL; di = di->d_nxt)
+ di->d_asm = 1;
+}
+
+/*
+ * Clean all elements of the top element of declaration stack which
+ * will be used by the next declaration
+ */
+void
+clrtyp()
+{
+ dcs->d_atyp = dcs->d_smod = dcs->d_lmod = NOTSPEC;
+ dcs->d_scl = NOSCL;
+ dcs->d_type = NULL;
+ dcs->d_const = dcs->d_volatile = 0;
+ dcs->d_inline = 0;
+ dcs->d_mscl = dcs->d_terr = 0;
+ dcs->d_nedecl = 0;
+ dcs->d_notyp = 0;
+}
+
+/*
+ * Create a type structure from the informations gathered in
+ * the declaration stack.
+ * Complain about storage classes which are not possible in current
+ * context.
+ */
+void
+deftyp()
+{
+ tspec_t t, s, l;
+ type_t *tp;
+ scl_t scl;
+
+ t = dcs->d_atyp; /* CHAR, INT, FLOAT, DOUBLE, VOID */
+ s = dcs->d_smod; /* SIGNED, UNSIGNED */
+ l = dcs->d_lmod; /* SHORT, LONG, QUAD */
+ tp = dcs->d_type;
+ scl = dcs->d_scl;
+
+ if (t == NOTSPEC && s == NOTSPEC && l == NOTSPEC && tp == NULL)
+ dcs->d_notyp = 1;
+
+ if (tp != NULL && (t != NOTSPEC || s != NOTSPEC || l != NOTSPEC)) {
+ /* should never happen */
+ lerror("deftyp() 1");
+ }
+
+ if (tp == NULL) {
+ switch (t) {
+ case NOTSPEC:
+ t = INT;
+ /* FALLTHROUGH */
+ case INT:
+ if (s == NOTSPEC)
+ s = SIGNED;
+ break;
+ case CHAR:
+ if (l != NOTSPEC) {
+ dcs->d_terr = 1;
+ l = NOTSPEC;
+ }
+ break;
+ case FLOAT:
+ if (l == LONG) {
+ l = NOTSPEC;
+ t = DOUBLE;
+ if (!tflag)
+ /* use 'double' instead of ... */
+ warning(6);
+ }
+ break;
+ case DOUBLE:
+ if (l == LONG) {
+ l = NOTSPEC;
+ t = LDOUBLE;
+ if (tflag)
+ /* 'long double' is illegal in ... */
+ warning(266);
+ }
+ break;
+ case VOID:
+ break;
+ default:
+ lerror("deftyp() 2");
+ }
+ if (t != INT && t != CHAR && (s != NOTSPEC || l != NOTSPEC)) {
+ dcs->d_terr = 1;
+ l = s = NOTSPEC;
+ }
+ if (l != NOTSPEC)
+ t = l;
+ dcs->d_type = gettyp(mrgtspec(t, s));
+ }
+
+ if (dcs->d_mscl) {
+ /* only one storage class allowed */
+ error(7);
+ }
+ if (dcs->d_terr) {
+ /* illegal type combination */
+ error(4);
+ }
+
+ if (dcs->d_ctx == EXTERN) {
+ if (scl == REG || scl == AUTO) {
+ /* illegal storage class */
+ error(8);
+ scl = NOSCL;
+ }
+ } else if (dcs->d_ctx == ARG || dcs->d_ctx == PARG) {
+ if (scl != NOSCL && scl != REG) {
+ /* only "register" valid ... */
+ error(9);
+ scl = NOSCL;
+ }
+ }
+
+ dcs->d_scl = scl;
+
+ if (dcs->d_const && dcs->d_type->t_const) {
+ if (!dcs->d_type->t_typedef)
+ lerror("deftyp() 3");
+ /* typedef already qualified with "%s" */
+ warning(68, "const");
+ }
+ if (dcs->d_volatile && dcs->d_type->t_volatile) {
+ if (!dcs->d_type->t_typedef)
+ lerror("deftyp() 4");
+ /* typedef already qualified with "%s" */
+ warning(68, "volatile");
+ }
+
+ if (dcs->d_const || dcs->d_volatile) {
+ dcs->d_type = duptyp(dcs->d_type);
+ dcs->d_type->t_const |= dcs->d_const;
+ dcs->d_type->t_volatile |= dcs->d_volatile;
+ }
+}
+
+/*
+ * Merge type specifiers (char, ..., long long, signed, unsigned).
+ */
+static tspec_t
+mrgtspec(t, s)
+ tspec_t t, s;
+{
+ if (s == SIGNED || s == UNSIGN) {
+ if (t == CHAR) {
+ t = s == SIGNED ? SCHAR : UCHAR;
+ } else if (t == SHORT) {
+ t = s == SIGNED ? SHORT : USHORT;
+ } else if (t == INT) {
+ t = s == SIGNED ? INT : UINT;
+ } else if (t == LONG) {
+ t = s == SIGNED ? LONG : ULONG;
+ } else if (t == QUAD) {
+ t = s == SIGNED ? QUAD : UQUAD;
+ }
+ }
+
+ return (t);
+}
+
+/*
+ * Return the length of a type in bit.
+ *
+ * Printing a message if the outhermost dimension of an array is 0 must
+ * be done by the caller. All other problems are reported by length()
+ * if name is not NULL.
+ */
+int
+length(tp, name)
+ type_t *tp;
+ const char *name;
+{
+ int elem, elsz;
+
+ elem = 1;
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* compiler takes size of function */
+ lerror(msgs[12]);
+ /* NOTREACHED */
+ case STRUCT:
+ case UNION:
+ if (incompl(tp) && name != NULL) {
+ /* incomplete structure or union %s: %s */
+ error(31, tp->t_str->stag->s_name, name);
+ }
+ elsz = tp->t_str->size;
+ break;
+ case ENUM:
+ if (incompl(tp) && name != NULL) {
+ /* incomplete enum type: %s */
+ warning(13, name);
+ }
+ /* FALLTHROUGH */
+ default:
+ elsz = size(tp->t_tspec);
+ if (elsz <= 0)
+ lerror("length()");
+ break;
+ }
+ return (elem * elsz);
+}
+
+/*
+ * Get the alignment of the given Type in bits.
+ */
+int
+getbound(tp)
+ type_t *tp;
+{
+ int a;
+ tspec_t t;
+
+ while (tp->t_tspec == ARRAY)
+ tp = tp->t_subt;
+
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ a = tp->t_str->align;
+ } else if (t == FUNC) {
+ /* compiler takes alignment of function */
+ error(14);
+ a = ALIGN(1) * CHAR_BIT;
+ } else {
+ if ((a = size(t)) == 0) {
+ a = CHAR_BIT;
+ } else if (a > ALIGN(1) * CHAR_BIT) {
+ a = ALIGN(1) * CHAR_BIT;
+ }
+ }
+ if (a < CHAR_BIT || a > ALIGN(1) * CHAR_BIT)
+ lerror("getbound() 1");
+ return (a);
+}
+
+/*
+ * Concatenate two lists of symbols by s_nxt. Used by declarations of
+ * struct/union/enum elements and parameters.
+ */
+sym_t *
+lnklst(l1, l2)
+ sym_t *l1, *l2;
+{
+ sym_t *l;
+
+ if ((l = l1) == NULL)
+ return (l2);
+ while (l1->s_nxt != NULL)
+ l1 = l1->s_nxt;
+ l1->s_nxt = l2;
+ return (l);
+}
+
+/*
+ * Check if the type of the given symbol is valid and print an error
+ * message if it is not.
+ *
+ * Invalid types are:
+ * - arrays of incomlete types or functions
+ * - functions returning arrays or functions
+ * - void types other than type of function or pointer
+ */
+void
+chktyp(sym)
+ sym_t *sym;
+{
+ tspec_t to, t;
+ type_t **tpp, *tp;
+
+ tpp = &sym->s_type;
+ to = NOTSPEC;
+ while ((tp = *tpp) != NULL) {
+ t = tp->t_tspec;
+ /*
+ * If this is the type of an old style function definition,
+ * a better warning is printed in funcdef().
+ */
+ if (t == FUNC && !tp->t_proto &&
+ !(to == NOTSPEC && sym->s_osdef)) {
+ if (sflag && hflag)
+ /* function declaration is not a prototype */
+ warning(287);
+ }
+ if (to == FUNC) {
+ if (t == FUNC || t == ARRAY) {
+ /* function returns illegal type */
+ error(15);
+ if (t == FUNC) {
+ *tpp = incref(*tpp, PTR);
+ } else {
+ *tpp = incref((*tpp)->t_subt, PTR);
+ }
+ return;
+ } else if (tp->t_const || tp->t_volatile) {
+ if (sflag) { /* XXX oder better !tflag ? */
+ /* function cannot return const... */
+ warning(228);
+ }
+ }
+ } if (to == ARRAY) {
+ if (t == FUNC) {
+ /* array of function is illegal */
+ error(16);
+ *tpp = gettyp(INT);
+ return;
+ } else if (t == ARRAY && tp->t_dim == 0) {
+ /* null dimension */
+ error(17);
+ return;
+ } else if (t == VOID) {
+ /* illegal use of void */
+ error(18);
+ *tpp = gettyp(INT);
+#if 0 /* errors are produced by length() */
+ } else if (incompl(tp)) {
+ /* array of incomplete type */
+ if (sflag) {
+ error(301);
+ } else {
+ warning(301);
+ }
+#endif
+ }
+ } else if (to == NOTSPEC && t == VOID) {
+ if (dcs->d_ctx == PARG) {
+ if (sym->s_scl != ABSTRACT) {
+ if (sym->s_name == unnamed)
+ lerror("chktyp()");
+ /* void param cannot have name: %s */
+ error(61, sym->s_name);
+ *tpp = gettyp(INT);
+ }
+ } else if (dcs->d_ctx == ABSTRACT) {
+ /* ok */
+ } else if (sym->s_scl != TYPEDEF) {
+ /* void type for %s */
+ error(19, sym->s_name);
+ *tpp = gettyp(INT);
+ }
+ }
+ if (t == VOID && to != PTR) {
+ if (tp->t_const || tp->t_volatile) {
+ /* inappropriate qualifiers with "void" */
+ warning(69);
+ tp->t_const = tp->t_volatile = 0;
+ }
+ }
+ tpp = &tp->t_subt;
+ to = t;
+ }
+}
+
+/*
+ * Process the declarator of a struct/union element.
+ */
+sym_t *
+decl1str(dsym)
+ sym_t *dsym;
+{
+ type_t *tp;
+ tspec_t t;
+ int sz, o, len;
+ scl_t sc;
+
+ if ((sc = dsym->s_scl) != MOS && sc != MOU)
+ lerror("decl1str() 1");
+
+ if (dcs->d_rdcsym != NULL) {
+ if ((sc = dcs->d_rdcsym->s_scl) != MOS && sc != MOU)
+ /* should be ensured by storesym() */
+ lerror("decl1str() 2");
+ if (dsym->s_styp == dcs->d_rdcsym->s_styp) {
+ /* duplicate member name: %s */
+ error(33, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+ }
+ }
+
+ chktyp(dsym);
+
+ t = (tp = dsym->s_type)->t_tspec;
+
+ if (dsym->s_field) {
+ /*
+ * bit field
+ *
+ * only unsigned und signed int are protable bit-field types
+ *(at least in ANSI C, in traditional C only unsigned int)
+ */
+ if (t == CHAR || t == UCHAR || t == SCHAR ||
+ t == SHORT || t == USHORT || t == ENUM) {
+ if (sflag) {
+ /* bit-field type '%s' invalid in ANSI C */
+ warning(273, tyname(tp));
+ } else if (pflag) {
+ /* nonportable bit-field type */
+ warning(34);
+ }
+ } else if (t == INT && dcs->d_smod == NOTSPEC) {
+ if (pflag) {
+ /* nonportable bit-field type */
+ warning(34);
+ }
+ } else if (t != INT && t != UINT) {
+ /* illegal bit-field type */
+ error(35);
+ sz = tp->t_flen;
+ dsym->s_type = tp = duptyp(gettyp(t = INT));
+ if ((tp->t_flen = sz) > size(t))
+ tp->t_flen = size(t);
+ }
+ if ((len = tp->t_flen) < 0 || len > size(t)) {
+ /* illegal bit-field size */
+ error(36);
+ tp->t_flen = size(t);
+ } else if (len == 0 && dsym->s_name != unnamed) {
+ /* zero size bit-field */
+ error(37);
+ tp->t_flen = size(t);
+ }
+ if (dsym->s_scl == MOU) {
+ /* illegal use of bit-field */
+ error(41);
+ dsym->s_type->t_isfield = 0;
+ dsym->s_field = 0;
+ }
+ } else if (t == FUNC) {
+ /* function illegal in structure or union */
+ error(38);
+ dsym->s_type = tp = incref(tp, t = PTR);
+ }
+
+ /*
+ * bit-fields of length 0 are not warned about because length()
+ * does not return the length of the bit-field but the length
+ * of the type the bit-field is packed in (its ok)
+ */
+ if ((sz = length(dsym->s_type, dsym->s_name)) == 0) {
+ if (t == ARRAY && dsym->s_type->t_dim == 0) {
+ /* illegal zero sized structure member: %s */
+ warning(39, dsym->s_name);
+ }
+ }
+
+ if (dcs->d_ctx == MOU) {
+ o = dcs->d_offset;
+ dcs->d_offset = 0;
+ }
+ if (dsym->s_field) {
+ align(getbound(tp), tp->t_flen);
+ dsym->s_value.v_quad = (dcs->d_offset / size(t)) * size(t);
+ tp->t_foffs = dcs->d_offset - (int)dsym->s_value.v_quad;
+ dcs->d_offset += tp->t_flen;
+ } else {
+ align(getbound(tp), 0);
+ dsym->s_value.v_quad = dcs->d_offset;
+ dcs->d_offset += sz;
+ }
+ if (dcs->d_ctx == MOU) {
+ if (o > dcs->d_offset)
+ dcs->d_offset = o;
+ }
+
+ chkfdef(dsym, 0);
+
+ return (dsym);
+}
+
+/*
+ * Aligns next structure element as required.
+ *
+ * al contains the required alignment, len the length of a bit-field.
+ */
+static void
+align(al, len)
+ int al, len;
+{
+ int no;
+
+ /*
+ * The alignment of the current element becomes the alignment of
+ * the struct/union if it is larger than the current alignment
+ * of the struct/union.
+ */
+ if (al > dcs->d_stralign)
+ dcs->d_stralign = al;
+
+ no = (dcs->d_offset + (al - 1)) & ~(al - 1);
+ if (len == 0 || dcs->d_offset + len > no)
+ dcs->d_offset = no;
+}
+
+/*
+ * Remember the width of the field in its type structure.
+ */
+sym_t *
+bitfield(dsym, len)
+ sym_t *dsym;
+ int len;
+{
+ if (dsym == NULL) {
+ dsym = getblk(sizeof (sym_t));
+ dsym->s_name = unnamed;
+ dsym->s_kind = FMOS;
+ dsym->s_scl = MOS;
+ dsym->s_type = gettyp(INT);
+ dsym->s_blklev = -1;
+ }
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_isfield = 1;
+ dsym->s_type->t_flen = len;
+ dsym->s_field = 1;
+ return (dsym);
+}
+
+/*
+ * Collect informations about a sequence of asterisks and qualifiers
+ * in a list of type pqinf_t.
+ * Qualifiers refer always to the left asterisk. The rightmost asterisk
+ * will be at the top of the list.
+ */
+pqinf_t *
+mergepq(p1, p2)
+ pqinf_t *p1, *p2;
+{
+ pqinf_t *p;
+
+ if (p2->p_pcnt != 0) {
+ /* left '*' at the end of the list */
+ for (p = p2; p->p_nxt != NULL; p = p->p_nxt) ;
+ p->p_nxt = p1;
+ return (p2);
+ } else {
+ if (p2->p_const) {
+ if (p1->p_const) {
+ /* duplicate %s */
+ warning(10, "const");
+ }
+ p1->p_const = 1;
+ }
+ if (p2->p_volatile) {
+ if (p1->p_volatile) {
+ /* duplicate %s */
+ warning(10, "volatile");
+ }
+ p1->p_volatile = 1;
+ }
+ free(p2);
+ return (p1);
+ }
+}
+
+/*
+ * Followint 3 functions extend the type of a declarator with
+ * pointer, function and array types.
+ *
+ * The current type is the Type built by deftyp() (dcs->d_type) and
+ * pointer, function and array types already added for this
+ * declarator. The new type extension is inserted between both.
+ */
+sym_t *
+addptr(decl, pi)
+ sym_t *decl;
+ pqinf_t *pi;
+{
+ type_t **tpp, *tp;
+ pqinf_t *npi;
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ while (pi != NULL) {
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = PTR;
+ tp->t_const = pi->p_const;
+ tp->t_volatile = pi->p_volatile;
+ *(tpp = &tp->t_subt) = dcs->d_type;
+ npi = pi->p_nxt;
+ free(pi);
+ pi = npi;
+ }
+ return (decl);
+}
+
+/*
+ * If a dimension was specified, dim is 1, otherwise 0
+ * n is the specified dimension
+ */
+sym_t *
+addarray(decl, dim, n)
+ sym_t *decl;
+ int dim, n;
+{
+ type_t **tpp, *tp;
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = ARRAY;
+ tp->t_subt = dcs->d_type;
+ tp->t_dim = n;
+
+ if (n < 0) {
+ /* zero or negative array dimension */
+ error(20);
+ n = 0;
+ } else if (n == 0 && dim) {
+ /* zero or negative array dimension */
+ warning(20);
+ } else if (n == 0 && !dim) {
+ /* is incomplete type */
+ setcompl(tp, 1);
+ }
+
+ return (decl);
+}
+
+sym_t *
+addfunc(decl, args)
+ sym_t *decl, *args;
+{
+ type_t **tpp, *tp;
+
+ if (dcs->d_proto) {
+ if (tflag)
+ /* function prototypes are illegal in traditional C */
+ warning(270);
+ args = nsfunc(decl, args);
+ } else {
+ osfunc(decl, args);
+ }
+
+ /*
+ * The symbols are removed from the symbol table by popdecl() after
+ * addfunc(). To be able to restore them if this is a function
+ * definition, a pointer to the list of all symbols is stored in
+ * dcs->d_nxt->d_fpsyms. Also a list of the arguments (concatenated
+ * by s_nxt) is stored in dcs->d_nxt->d_fargs.
+ * (dcs->d_nxt must be used because *dcs is the declaration stack
+ * element created for the list of params and is removed after
+ * addfunc())
+ */
+ if (dcs->d_nxt->d_ctx == EXTERN &&
+ decl->s_type == dcs->d_nxt->d_type) {
+ dcs->d_nxt->d_fpsyms = dcs->d_dlsyms;
+ dcs->d_nxt->d_fargs = args;
+ }
+
+ tpp = &decl->s_type;
+ while (*tpp != dcs->d_nxt->d_type)
+ tpp = &(*tpp)->t_subt;
+
+ *tpp = tp = getblk(sizeof (type_t));
+ tp->t_tspec = FUNC;
+ tp->t_subt = dcs->d_nxt->d_type;
+ if ((tp->t_proto = dcs->d_proto) != 0)
+ tp->t_args = args;
+ tp->t_vararg = dcs->d_vararg;
+
+ return (decl);
+}
+
+/*
+ * Called for new style function declarations.
+ */
+/* ARGSUSED */
+static sym_t *
+nsfunc(decl, args)
+ sym_t *decl, *args;
+{
+ sym_t *arg, *sym;
+ scl_t sc;
+ int n;
+
+ /*
+ * Declarations of structs/unions/enums in param lists are legal,
+ * but senseless.
+ */
+ for (sym = dcs->d_dlsyms; sym != NULL; sym = sym->s_dlnxt) {
+ sc = sym->s_scl;
+ if (sc == STRTAG || sc == UNIONTAG || sc == ENUMTAG) {
+ /* dubious tag declaration: %s %s */
+ warning(85, scltoa(sc), sym->s_name);
+ }
+ }
+
+ n = 1;
+ for (arg = args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_type->t_tspec == VOID) {
+ if (n > 1 || arg->s_nxt != NULL) {
+ /* "void" must be sole parameter */
+ error(60);
+ arg->s_type = gettyp(INT);
+ }
+ }
+ n++;
+ }
+
+ /* return NULL if first param is VOID */
+ return (args != NULL && args->s_type->t_tspec != VOID ? args : NULL);
+}
+
+/*
+ * Called for old style function declarations.
+ */
+static void
+osfunc(decl, args)
+ sym_t *decl, *args;
+{
+ /*
+ * Remember list of params only if this is really seams to be
+ * a function definition.
+ */
+ if (dcs->d_nxt->d_ctx == EXTERN &&
+ decl->s_type == dcs->d_nxt->d_type) {
+ /*
+ * We assume that this becomes a function definition. If
+ * we are wrong, its corrected in chkfdef().
+ */
+ if (args != NULL) {
+ decl->s_osdef = 1;
+ decl->s_args = args;
+ }
+ } else {
+ if (args != NULL)
+ /* function prototype parameters must have types */
+ warning(62);
+ }
+}
+
+/*
+ * Lists of Identifiers in functions declarations are allowed only if
+ * its also a function definition. If this is not the case, print a
+ * error message.
+ */
+void
+chkfdef(sym, msg)
+ sym_t *sym;
+ int msg;
+{
+ if (sym->s_osdef) {
+ if (msg) {
+ /* incomplete or misplaced function definition */
+ error(22);
+ }
+ sym->s_osdef = 0;
+ sym->s_args = NULL;
+ }
+}
+
+/*
+ * Process the name in a declarator.
+ * If the symbol does already exists, a new one is created.
+ * The symbol becomes one of the storage classes EXTERN, STATIC, AUTO or
+ * TYPEDEF.
+ * s_def and s_reg are valid after dname().
+ */
+sym_t *
+dname(sym)
+ sym_t *sym;
+{
+ scl_t sc;
+
+ if (sym->s_scl == NOSCL) {
+ dcs->d_rdcsym = NULL;
+ } else if (sym->s_defarg) {
+ sym->s_defarg = 0;
+ dcs->d_rdcsym = NULL;
+ } else {
+ dcs->d_rdcsym = sym;
+ sym = pushdown(sym);
+ }
+
+ switch (dcs->d_ctx) {
+ case MOS:
+ case MOU:
+ /* Parent setzen */
+ sym->s_styp = dcs->d_tagtyp->t_str;
+ sym->s_def = DEF;
+ sym->s_value.v_tspec = INT;
+ sc = dcs->d_ctx;
+ break;
+ case EXTERN:
+ /*
+ * static and external symbols without "extern" are
+ * considered to be tentative defined, external
+ * symbols with "extern" are declared, and typedef names
+ * are defined. Tentative defined and declared symbols
+ * may become defined if an initializer is present or
+ * this is a function definition.
+ */
+ if ((sc = dcs->d_scl) == NOSCL) {
+ sc = EXTERN;
+ sym->s_def = TDEF;
+ } else if (sc == STATIC) {
+ sym->s_def = TDEF;
+ } else if (sc == TYPEDEF) {
+ sym->s_def = DEF;
+ } else if (sc == EXTERN) {
+ sym->s_def = DECL;
+ } else {
+ lerror("dname() 1");
+ }
+ break;
+ case PARG:
+ sym->s_arg = 1;
+ /* FALLTHROUGH */
+ case ARG:
+ if ((sc = dcs->d_scl) == NOSCL) {
+ sc = AUTO;
+ } else if (sc == REG) {
+ sym->s_reg = 1;
+ sc = AUTO;
+ } else {
+ lerror("dname() 2");
+ }
+ sym->s_def = DEF;
+ break;
+ case AUTO:
+ if ((sc = dcs->d_scl) == NOSCL) {
+ /*
+ * XXX somewhat ugly because we dont know whether
+ * this is AUTO or EXTERN (functions). If we are
+ * wrong it must be corrected in decl1loc(), where
+ * we have the neccessary type information.
+ */
+ sc = AUTO;
+ sym->s_def = DEF;
+ } else if (sc == AUTO || sc == STATIC || sc == TYPEDEF) {
+ sym->s_def = DEF;
+ } else if (sc == REG) {
+ sym->s_reg = 1;
+ sc = AUTO;
+ sym->s_def = DEF;
+ } else if (sc == EXTERN) {
+ sym->s_def = DECL;
+ } else {
+ lerror("dname() 3");
+ }
+ break;
+ default:
+ lerror("dname() 4");
+ }
+ sym->s_scl = sc;
+
+ sym->s_type = dcs->d_type;
+
+ dcs->d_fpsyms = NULL;
+
+ return (sym);
+}
+
+/*
+ * Process a name in the list of formal params in an old style function
+ * definition.
+ */
+sym_t *
+iname(sym)
+ sym_t *sym;
+{
+ if (sym->s_scl != NOSCL) {
+ if (blklev == sym->s_blklev) {
+ /* redeclaration of formal parameter %s */
+ error(21, sym->s_name);
+ if (!sym->s_defarg)
+ lerror("iname()");
+ }
+ sym = pushdown(sym);
+ }
+ sym->s_type = gettyp(INT);
+ sym->s_scl = AUTO;
+ sym->s_def = DEF;
+ sym->s_defarg = sym->s_arg = 1;
+ return (sym);
+}
+
+/*
+ * Create the type of a tag.
+ *
+ * tag points to the symbol table entry of the tag
+ * kind is the kind of the tag (STRUCT/UNION/ENUM)
+ * decl is 1 if the type of the tag will be completed in this declaration
+ * (the following token is T_LBRACE)
+ * semi is 1 if the following token is T_SEMI
+ */
+type_t *
+mktag(tag, kind, decl, semi)
+ sym_t *tag;
+ tspec_t kind;
+ int decl, semi;
+{
+ scl_t scl;
+ type_t *tp;
+
+ if (kind == STRUCT) {
+ scl = STRTAG;
+ } else if (kind == UNION) {
+ scl = UNIONTAG;
+ } else if (kind == ENUM) {
+ scl = ENUMTAG;
+ } else {
+ lerror("mktag()");
+ }
+
+ if (tag != NULL) {
+ if (tag->s_scl != NOSCL) {
+ tag = newtag(tag, scl, decl, semi);
+ } else {
+ /* a new tag, no empty declaration */
+ dcs->d_nxt->d_nedecl = 1;
+ if (scl == ENUMTAG && !decl) {
+ if (!tflag && (sflag || pflag))
+ /* forward reference to enum type */
+ warning(42);
+ }
+ }
+ if (tag->s_scl == NOSCL) {
+ tag->s_scl = scl;
+ tag->s_type = tp = getblk(sizeof (type_t));
+ } else {
+ tp = tag->s_type;
+ }
+ } else {
+ tag = getblk(sizeof (sym_t));
+ tag->s_name = unnamed;
+ STRUCT_ASSIGN(tag->s_dpos, curr_pos);
+ tag->s_kind = FTAG;
+ tag->s_scl = scl;
+ tag->s_blklev = -1;
+ tag->s_type = tp = getblk(sizeof (type_t));
+ dcs->d_nxt->d_nedecl = 1;
+ }
+
+ if (tp->t_tspec == NOTSPEC) {
+ tp->t_tspec = kind;
+ if (kind != ENUM) {
+ tp->t_str = getblk(sizeof (str_t));
+ tp->t_str->align = CHAR_BIT;
+ tp->t_str->stag = tag;
+ } else {
+ tp->t_isenum = 1;
+ tp->t_enum = getblk(sizeof (enum_t));
+ tp->t_enum->etag = tag;
+ }
+ /* ist unvollstaendiger Typ */
+ setcompl(tp, 1);
+ }
+
+ return (tp);
+}
+
+/*
+ * Checks all possible cases of tag redeclarations.
+ * decl is 1 if T_LBRACE follows
+ * semi is 1 if T_SEMI follows
+ */
+static sym_t *
+newtag(tag, scl, decl, semi)
+ sym_t *tag;
+ scl_t scl;
+ int decl, semi;
+{
+ if (tag->s_blklev < blklev) {
+ if (semi) {
+ /* "struct a;" */
+ if (!tflag) {
+ if (!sflag)
+ /* decl. introduces new type ... */
+ warning(44, scltoa(scl), tag->s_name);
+ tag = pushdown(tag);
+ } else if (tag->s_scl != scl) {
+ /* base type is really "%s %s" */
+ warning(45, scltoa(tag->s_scl), tag->s_name);
+ }
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (decl) {
+ /* "struct a { ..." */
+ if (hflag)
+ /* redefinition hides earlier one: %s */
+ warning(43, tag->s_name);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (tag->s_scl != scl) {
+ /* base type is really "%s %s" */
+ warning(45, scltoa(tag->s_scl), tag->s_name);
+ /* declaration introduces new type in ANSI C: %s %s */
+ if (!sflag)
+ warning(44, scltoa(scl), tag->s_name);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ }
+ } else {
+ if (tag->s_scl != scl) {
+ /* (%s) tag redeclared */
+ error(46, scltoa(tag->s_scl));
+ prevdecl(-1, tag);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (decl && !incompl(tag->s_type)) {
+ /* (%s) tag redeclared */
+ error(46, scltoa(tag->s_scl));
+ prevdecl(-1, tag);
+ tag = pushdown(tag);
+ dcs->d_nxt->d_nedecl = 1;
+ } else if (semi || decl) {
+ dcs->d_nxt->d_nedecl = 1;
+ }
+ }
+ return (tag);
+}
+
+const char *
+scltoa(sc)
+ scl_t sc;
+{
+ const char *s;
+
+ switch (sc) {
+ case EXTERN: s = "extern"; break;
+ case STATIC: s = "static"; break;
+ case AUTO: s = "auto"; break;
+ case REG: s = "register"; break;
+ case TYPEDEF: s = "typedef"; break;
+ case STRTAG: s = "struct"; break;
+ case UNIONTAG: s = "union"; break;
+ case ENUMTAG: s = "enum"; break;
+ default: lerror("tagttoa()");
+ }
+ return (s);
+}
+
+/*
+ * Completes the type of a tag in a struct/union/enum declaration.
+ * tp points to the type of the, tag, fmem to the list of members/enums.
+ */
+type_t *
+compltag(tp, fmem)
+ type_t *tp;
+ sym_t *fmem;
+{
+ tspec_t t;
+ str_t *sp;
+ int n;
+ sym_t *mem;
+
+ /* from now a complete type */
+ setcompl(tp, 0);
+
+ if ((t = tp->t_tspec) != ENUM) {
+ align(dcs->d_stralign, 0);
+ sp = tp->t_str;
+ sp->align = dcs->d_stralign;
+ sp->size = dcs->d_offset;
+ sp->memb = fmem;
+ if (sp->size == 0) {
+ /* zero sized %s */
+ (void)gnuism(47, ttab[t].tt_name);
+ } else {
+ n = 0;
+ for (mem = fmem; mem != NULL; mem = mem->s_nxt) {
+ if (mem->s_name != unnamed)
+ n++;
+ }
+ if (n == 0) {
+ /* %s has no named members */
+ warning(65,
+ t == STRUCT ? "structure" : "union");
+ }
+ }
+ } else {
+ tp->t_enum->elem = fmem;
+ }
+ return (tp);
+}
+
+/*
+ * Processes the name of an enumerator in en enum declaration.
+ *
+ * sym points to the enumerator
+ * val is the value of the enumerator
+ * impl is 1 if the the value of the enumerator was not explicit specified.
+ */
+sym_t *
+ename(sym, val, impl)
+ sym_t *sym;
+ int val, impl;
+{
+ if (sym->s_scl) {
+ if (sym->s_blklev == blklev) {
+ /* no hflag, because this is illegal!!! */
+ if (sym->s_arg) {
+ /* enumeration constant hides parameter: %s */
+ warning(57, sym->s_name);
+ } else {
+ /* redeclaration of %s */
+ error(27, sym->s_name);
+ /*
+ * inside blocks it should not too complicated
+ * to find the position of the previous
+ * declaration
+ */
+ if (blklev == 0)
+ prevdecl(-1, sym);
+ }
+ } else {
+ if (hflag)
+ /* redefinition hides earlier one: %s */
+ warning(43, sym->s_name);
+ }
+ sym = pushdown(sym);
+ }
+ sym->s_scl = ENUMCON;
+ sym->s_type = dcs->d_tagtyp;
+ sym->s_value.v_tspec = INT;
+ sym->s_value.v_quad = val;
+ if (impl && val - 1 == INT_MAX) {
+ /* overflow in enumeration values: %s */
+ warning(48, sym->s_name);
+ }
+ enumval = val + 1;
+ return (sym);
+}
+
+/*
+ * Process a single external declarator.
+ */
+void
+decl1ext(dsym, initflg)
+ sym_t *dsym;
+ int initflg;
+{
+ int warn, rval, redec;
+ sym_t *rdsym;
+
+ chkfdef(dsym, 1);
+
+ chktyp(dsym);
+
+ if (initflg && !(initerr = chkinit(dsym)))
+ dsym->s_def = DEF;
+
+ /*
+ * Declarations of functions are marked as "tentative" in dname().
+ * This is wrong because there are no tentative function
+ * definitions.
+ */
+ if (dsym->s_type->t_tspec == FUNC && dsym->s_def == TDEF)
+ dsym->s_def = DECL;
+
+ if (dcs->d_inline) {
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_inline = 1;
+ } else {
+ /* variable declared inline: %s */
+ warning(268, dsym->s_name);
+ }
+ }
+
+ /* Write the declaration into the output file */
+ if (plibflg && llibflg &&
+ dsym->s_type->t_tspec == FUNC && dsym->s_type->t_proto) {
+ /*
+ * With both LINTLIBRARY and PROTOLIB the prototyp is
+ * written as a function definition to the output file.
+ */
+ rval = dsym->s_type->t_subt->t_tspec != VOID;
+ outfdef(dsym, &dsym->s_dpos, rval, 0, NULL);
+ } else {
+ outsym(dsym, dsym->s_scl, dsym->s_def);
+ }
+
+ if ((rdsym = dcs->d_rdcsym) != NULL) {
+
+ /*
+ * If the old symbol stems from a old style function definition
+ * we have remembered the params in rdsmy->s_args and compare
+ * them with the params of the prototype.
+ */
+ if (rdsym->s_osdef && dsym->s_type->t_proto) {
+ redec = chkosdef(rdsym, dsym);
+ } else {
+ redec = 0;
+ }
+
+ if (!redec && !isredec(dsym, (warn = 0, &warn))) {
+
+ if (warn) {
+ /* redeclaration of %s */
+ (*(sflag ? error : warning))(27, dsym->s_name);
+ prevdecl(-1, rdsym);
+ }
+
+ /*
+ * Overtake the rememberd params if the new symbol
+ * is not a prototype.
+ */
+ if (rdsym->s_osdef && !dsym->s_type->t_proto) {
+ dsym->s_osdef = rdsym->s_osdef;
+ dsym->s_args = rdsym->s_args;
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ }
+
+ /*
+ * Remember the position of the declaration if the
+ * old symbol was a prototype and the new is not.
+ * Also remember the position if the old symbol
+ * was defined and the new is not.
+ */
+ if (rdsym->s_type->t_proto && !dsym->s_type->t_proto) {
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ } else if (rdsym->s_def == DEF && dsym->s_def != DEF) {
+ STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
+ }
+
+ /*
+ * Copy informations about usage of the name into
+ * the new symbol.
+ */
+ cpuinfo(dsym, rdsym);
+
+ /* Once a name is defined, it remains defined. */
+ if (rdsym->s_def == DEF)
+ dsym->s_def = DEF;
+
+ /* once a function is inline, it remains inline */
+ if (rdsym->s_inline)
+ dsym->s_inline = 1;
+
+ compltyp(dsym, rdsym);
+
+ }
+
+ rmsym(rdsym);
+ }
+
+ if (dsym->s_scl == TYPEDEF) {
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_typedef = 1;
+ settdsym(dsym->s_type, dsym);
+ }
+
+}
+
+/*
+ * Copies informations about usage into a new symbol table entry of
+ * the same symbol.
+ */
+void
+cpuinfo(sym, rdsym)
+ sym_t *sym, *rdsym;
+{
+ sym->s_spos = rdsym->s_spos;
+ sym->s_upos = rdsym->s_upos;
+ sym->s_set = rdsym->s_set;
+ sym->s_used = rdsym->s_used;
+}
+
+/*
+ * Prints an error and returns 1 if a symbol is redeclared/redefined.
+ * Otherwise returns 0 and, in some cases of minor problems, prints
+ * a warning.
+ */
+int
+isredec(dsym, warn)
+ sym_t *dsym;
+ int *warn;
+{
+ sym_t *rsym;
+
+ if ((rsym = dcs->d_rdcsym)->s_scl == ENUMCON) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (rsym->s_scl == TYPEDEF) {
+ /* typedef redeclared: %s */
+ error(89, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (dsym->s_scl == TYPEDEF) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return (1);
+ }
+ if (rsym->s_def == DEF && dsym->s_def == DEF) {
+ /* redefinition of %s */
+ error(28, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (!eqtype(rsym->s_type, dsym->s_type, 0, 0, warn)) {
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (rsym->s_scl == EXTERN && dsym->s_scl == EXTERN)
+ return(0);
+ if (rsym->s_scl == STATIC && dsym->s_scl == STATIC)
+ return(0);
+ if (rsym->s_scl == STATIC && dsym->s_def == DECL)
+ return(0);
+ if (rsym->s_scl == EXTERN && rsym->s_def == DEF) {
+ /*
+ * All cases except "int a = 1; static int a;" are catched
+ * above with or without a warning
+ */
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(1);
+ }
+ if (rsym->s_scl == EXTERN) {
+ /* previously declared extern, becomes static: %s */
+ warning(29, dsym->s_name);
+ prevdecl(-1, rsym);
+ return(0);
+ }
+ /*
+ * Now its on of:
+ * "static a; int a;", "static a; int a = 1;", "static a = 1; int a;"
+ */
+ /* redeclaration of %s; ANSI C requires "static" */
+ if (sflag) {
+ warning(30, dsym->s_name);
+ prevdecl(-1, rsym);
+ }
+ dsym->s_scl = STATIC;
+ return (0);
+}
+
+/*
+ * Checks if two types are compatible. Returns 0 if not, otherwise 1.
+ *
+ * ignqual ignore qualifiers of type; used for function params
+ * promot promote left type; used for comparision of params of
+ * old style function definitions with params of prototypes.
+ * *warn set to 1 if an old style function declaration is not
+ * compatible with a prototype
+ */
+int
+eqtype(tp1, tp2, ignqual, promot, warn)
+ type_t *tp1, *tp2;
+ int ignqual, promot, *warn;
+{
+ tspec_t t;
+
+ while (tp1 != NULL && tp2 != NULL) {
+
+ t = tp1->t_tspec;
+ if (promot) {
+ if (t == FLOAT) {
+ t = DOUBLE;
+ } else if (t == CHAR || t == SCHAR) {
+ t = INT;
+ } else if (t == UCHAR) {
+ t = tflag ? UINT : INT;
+ } else if (t == SHORT) {
+ t = INT;
+ } else if (t == USHORT) {
+ /* CONSTCOND */
+ t = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
+ }
+ }
+
+ if (t != tp2->t_tspec)
+ return (0);
+
+ if (tp1->t_const != tp2->t_const && !ignqual && !tflag)
+ return (0);
+
+ if (tp1->t_volatile != tp2->t_volatile && !ignqual && !tflag)
+ return (0);
+
+ if (t == STRUCT || t == UNION)
+ return (tp1->t_str == tp2->t_str);
+
+ if (t == ARRAY && tp1->t_dim != tp2->t_dim) {
+ if (tp1->t_dim != 0 && tp2->t_dim != 0)
+ return (0);
+ }
+
+ /* dont check prototypes for traditional */
+ if (t == FUNC && !tflag) {
+ if (tp1->t_proto && tp2->t_proto) {
+ if (!eqargs(tp1, tp2, warn))
+ return (0);
+ } else if (tp1->t_proto) {
+ if (!mnoarg(tp1, warn))
+ return (0);
+ } else if (tp2->t_proto) {
+ if (!mnoarg(tp2, warn))
+ return (0);
+ }
+ }
+
+ tp1 = tp1->t_subt;
+ tp2 = tp2->t_subt;
+ ignqual = promot = 0;
+
+ }
+
+ return (tp1 == tp2);
+}
+
+/*
+ * Compares the parameter types of two prototypes.
+ */
+static int
+eqargs(tp1, tp2, warn)
+ type_t *tp1, *tp2;
+ int *warn;
+{
+ sym_t *a1, *a2;
+
+ if (tp1->t_vararg != tp2->t_vararg)
+ return (0);
+
+ a1 = tp1->t_args;
+ a2 = tp2->t_args;
+
+ while (a1 != NULL && a2 != NULL) {
+
+ if (eqtype(a1->s_type, a2->s_type, 1, 0, warn) == 0)
+ return (0);
+
+ a1 = a1->s_nxt;
+ a2 = a2->s_nxt;
+
+ }
+
+ return (a1 == a2);
+}
+
+/*
+ * mnoarg() (matches functions with no argument type information)
+ * returns 1 if all parameters of a prototype are compatible with
+ * and old style function declaration.
+ * This is the case if following conditions are met:
+ * 1. the prototype must have a fixed number of parameters
+ * 2. no parameter is of type float
+ * 3. no parameter is converted to another type if integer promotion
+ * is applied on it
+ */
+static int
+mnoarg(tp, warn)
+ type_t *tp;
+ int *warn;
+{
+ sym_t *arg;
+ tspec_t t;
+
+ if (tp->t_vararg) {
+ if (warn != NULL)
+ *warn = 1;
+ }
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt) {
+ if ((t = arg->s_type->t_tspec) == FLOAT ||
+ t == CHAR || t == SCHAR || t == UCHAR ||
+ t == SHORT || t == USHORT) {
+ if (warn != NULL)
+ *warn = 1;
+ }
+ }
+ return (1);
+}
+
+/*
+ * Compares a prototype declaration with the remembered arguments of
+ * a previous old style function definition.
+ */
+static int
+chkosdef(rdsym, dsym)
+ sym_t *rdsym, *dsym;
+{
+ sym_t *args, *pargs, *arg, *parg;
+ int narg, nparg, n;
+ int warn, msg;
+
+ args = rdsym->s_args;
+ pargs = dsym->s_type->t_args;
+
+ msg = 0;
+
+ narg = nparg = 0;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ for (parg = pargs; parg != NULL; parg = parg->s_nxt)
+ nparg++;
+ if (narg != nparg) {
+ /* prototype does not match old-style definition */
+ error(63);
+ msg = 1;
+ goto end;
+ }
+
+ arg = args;
+ parg = pargs;
+ n = 1;
+ while (narg--) {
+ warn = 0;
+ /*
+ * If it does not match due to promotion and sflag is
+ * not set we print only a warning.
+ */
+ if (!eqtype(arg->s_type, parg->s_type, 1, 1, &warn) || warn) {
+ /* prototype does not match old-style def., arg #%d */
+ error(299, n);
+ msg = 1;
+ }
+ arg = arg->s_nxt;
+ parg = parg->s_nxt;
+ n++;
+ }
+
+ end:
+ if (msg)
+ /* old style definition */
+ prevdecl(300, rdsym);
+
+ return (msg);
+}
+
+/*
+ * Complets a type by copying the dimension and prototype information
+ * from a second compatible type.
+ *
+ * Following lines are legal:
+ * "typedef a[]; a b; a b[10]; a c; a c[20];"
+ * "typedef ft(); ft f; f(int); ft g; g(long);"
+ * This means that, if a type is completed, the type structure must
+ * be duplicated.
+ */
+void
+compltyp(dsym, ssym)
+ sym_t *dsym, *ssym;
+{
+ type_t **dstp, *src;
+ type_t *dst;
+
+ dstp = &dsym->s_type;
+ src = ssym->s_type;
+
+ while ((dst = *dstp) != NULL) {
+ if (src == NULL || dst->t_tspec != src->t_tspec)
+ lerror("compltyp() 1");
+ if (dst->t_tspec == ARRAY) {
+ if (dst->t_dim == 0 && src->t_dim != 0) {
+ *dstp = dst = duptyp(dst);
+ dst->t_dim = src->t_dim;
+ /* now a complete Typ */
+ setcompl(dst, 0);
+ }
+ } else if (dst->t_tspec == FUNC) {
+ if (!dst->t_proto && src->t_proto) {
+ *dstp = dst = duptyp(dst);
+ dst->t_proto = 1;
+ dst->t_args = src->t_args;
+ }
+ }
+ dstp = &dst->t_subt;
+ src = src->t_subt;
+ }
+}
+
+/*
+ * Completes the declaration of a single argument.
+ */
+sym_t *
+decl1arg(sym, initflg)
+ sym_t *sym;
+ int initflg;
+{
+ tspec_t t;
+
+ chkfdef(sym, 1);
+
+ chktyp(sym);
+
+ if (dcs->d_rdcsym != NULL && dcs->d_rdcsym->s_blklev == blklev) {
+ /* redeclaration of formal parameter %s */
+ error(237, sym->s_name);
+ rmsym(dcs->d_rdcsym);
+ sym->s_arg = 1;
+ }
+
+ if (!sym->s_arg) {
+ /* declared argument %s is missing */
+ error(53, sym->s_name);
+ sym->s_arg = 1;
+ }
+
+ if (initflg) {
+ /* cannot initialize parameter: %s */
+ error(52, sym->s_name);
+ initerr = 1;
+ }
+
+ if ((t = sym->s_type->t_tspec) == ARRAY) {
+ sym->s_type = incref(sym->s_type->t_subt, PTR);
+ } else if (t == FUNC) {
+ if (tflag)
+ /* a function is declared as an argument: %s */
+ warning(50, sym->s_name);
+ sym->s_type = incref(sym->s_type, PTR);
+ } else if (t == FLOAT) {
+ if (tflag)
+ sym->s_type = gettyp(DOUBLE);
+ }
+
+ if (dcs->d_inline)
+ /* argument declared inline: %s */
+ warning(269, sym->s_name);
+
+ /*
+ * Arguments must have complete types. lengths() prints the needed
+ * error messages (null dimension is impossible because arrays are
+ * converted to pointers).
+ */
+ if (sym->s_type->t_tspec != VOID)
+ (void)length(sym->s_type, sym->s_name);
+
+ setsflg(sym);
+
+ return (sym);
+}
+
+/*
+ * Does some checks for lint directives which apply to functions.
+ * Processes arguments in old style function definitions which default
+ * to int.
+ * Checks compatiblility of old style function definition with previous
+ * prototype.
+ */
+void
+cluparg()
+{
+ sym_t *args, *arg, *pargs, *parg;
+ int narg, nparg, n, msg;
+ tspec_t t;
+
+ args = funcsym->s_args;
+ pargs = funcsym->s_type->t_args;
+
+ /* check for illegal combinations of lint directives */
+ if (prflstrg != -1 && scflstrg != -1) {
+ /* can't be used together: ** PRINTFLIKE ** ** SCANFLIKE ** */
+ warning(289);
+ prflstrg = scflstrg = -1;
+ }
+ if (nvararg != -1 && (prflstrg != -1 || scflstrg != -1)) {
+ /* dubious use of ** VARARGS ** with ** %s ** */
+ warning(288, prflstrg != -1 ? "PRINTFLIKE" : "SCANFLIKE");
+ nvararg = -1;
+ }
+
+ /*
+ * check if the argument of a lint directive is compatible with the
+ * number of arguments.
+ */
+ narg = 0;
+ for (arg = dcs->d_fargs; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ if (nargusg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "ARGSUSED");
+ nargusg = 0;
+ }
+ if (nvararg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "VARARGS");
+ nvararg = 0;
+ }
+ if (prflstrg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "PRINTFLIKE");
+ prflstrg = -1;
+ } else if (prflstrg == 0) {
+ prflstrg = -1;
+ }
+ if (scflstrg > narg) {
+ /* argument number mismatch with directive: ** %s ** */
+ warning(283, "SCANFLIKE");
+ scflstrg = -1;
+ } else if (scflstrg == 0) {
+ scflstrg = -1;
+ }
+ if (prflstrg != -1 || scflstrg != -1) {
+ narg = prflstrg != -1 ? prflstrg : scflstrg;
+ arg = dcs->d_fargs;
+ for (n = 1; n < narg; n++)
+ arg = arg->s_nxt;
+ if (arg->s_type->t_tspec != PTR ||
+ ((t = arg->s_type->t_subt->t_tspec) != CHAR &&
+ t != UCHAR && t != SCHAR)) {
+ /* arg. %d must be 'char *' for PRINTFLIKE/SCANFLIKE */
+ warning(293, narg);
+ prflstrg = scflstrg = -1;
+ }
+ }
+
+ /*
+ * print a warning for each argument off an old style function
+ * definition which defaults to int
+ */
+ for (arg = args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_defarg) {
+ /* argument type defaults to int: %s */
+ warning(32, arg->s_name);
+ arg->s_defarg = 0;
+ setsflg(arg);
+ }
+ }
+
+ /*
+ * If this is an old style function definition and a prototyp
+ * exists, compare the types of arguments.
+ */
+ if (funcsym->s_osdef && funcsym->s_type->t_proto) {
+ /*
+ * If the number of arguments does not macht, we need not
+ * continue.
+ */
+ narg = nparg = 0;
+ msg = 0;
+ for (parg = pargs; parg != NULL; parg = parg->s_nxt)
+ nparg++;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ if (narg != nparg) {
+ /* parameter mismatch: %d declared, %d defined */
+ error(51, nparg, narg);
+ msg = 1;
+ } else {
+ parg = pargs;
+ arg = args;
+ while (narg--) {
+ msg |= chkptdecl(arg, parg);
+ parg = parg->s_nxt;
+ arg = arg->s_nxt;
+ }
+ }
+ if (msg)
+ /* prototype declaration */
+ prevdecl(285, dcs->d_rdcsym);
+
+ /* from now the prototype is valid */
+ funcsym->s_osdef = 0;
+ funcsym->s_args = NULL;
+
+ }
+
+}
+
+/*
+ * Checks compatibility of an old style function definition with a previous
+ * prototype declaration.
+ * Returns 1 if the position of the previous declaration should be reported.
+ */
+static int
+chkptdecl(arg, parg)
+ sym_t *arg, *parg;
+{
+ type_t *tp, *ptp;
+ int warn, msg;
+
+ tp = arg->s_type;
+ ptp = parg->s_type;
+
+ msg = 0;
+ warn = 0;
+
+ if (!eqtype(tp, ptp, 1, 1, &warn)) {
+ if (eqtype(tp, ptp, 1, 0, &warn)) {
+ /* type does not match prototype: %s */
+ msg = gnuism(58, arg->s_name);
+ } else {
+ /* type does not match prototype: %s */
+ error(58, arg->s_name);
+ msg = 1;
+ }
+ } else if (warn) {
+ /* type does not match prototype: %s */
+ (*(sflag ? error : warning))(58, arg->s_name);
+ msg = 1;
+ }
+
+ return (msg);
+}
+
+/*
+ * Completes a single local declaration/definition.
+ */
+void
+decl1loc(dsym, initflg)
+ sym_t *dsym;
+ int initflg;
+{
+ /* Correct a mistake done in dname(). */
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_def = DECL;
+ if (dcs->d_scl == NOSCL)
+ dsym->s_scl = EXTERN;
+ }
+
+ if (dsym->s_type->t_tspec == FUNC) {
+ if (dsym->s_scl == STATIC) {
+ /* dubious static function at block level: %s */
+ warning(93, dsym->s_name);
+ dsym->s_scl = EXTERN;
+ } else if (dsym->s_scl != EXTERN && dsym->s_scl != TYPEDEF) {
+ /* function has illegal storage class: %s */
+ error(94, dsym->s_name);
+ dsym->s_scl = EXTERN;
+ }
+ }
+
+ /*
+ * functions may be declared inline at local scope, although
+ * this has no effect for a later definition of the same
+ * function.
+ * XXX it should have an effect if tflag is set. this would
+ * also be the way gcc behaves.
+ */
+ if (dcs->d_inline) {
+ if (dsym->s_type->t_tspec == FUNC) {
+ dsym->s_inline = 1;
+ } else {
+ /* variable declared inline: %s */
+ warning(268, dsym->s_name);
+ }
+ }
+
+ chkfdef(dsym, 1);
+
+ chktyp(dsym);
+
+ if (dcs->d_rdcsym != NULL && dsym->s_scl == EXTERN)
+ ledecl(dsym);
+
+ if (dsym->s_scl == EXTERN) {
+ /*
+ * XXX wenn die statische Variable auf Ebene 0 erst
+ * spaeter definiert wird, haben wir die Brille auf.
+ */
+ if (dsym->s_xsym == NULL) {
+ outsym(dsym, EXTERN, dsym->s_def);
+ } else {
+ outsym(dsym, dsym->s_xsym->s_scl, dsym->s_def);
+ }
+ }
+
+ if (dcs->d_rdcsym != NULL) {
+
+ if (dcs->d_rdcsym->s_blklev == 0) {
+
+ switch (dsym->s_scl) {
+ case AUTO:
+ /* automatic hides external declaration: %s */
+ if (hflag)
+ warning(86, dsym->s_name);
+ break;
+ case STATIC:
+ /* static hides external declaration: %s */
+ if (hflag)
+ warning(87, dsym->s_name);
+ break;
+ case TYPEDEF:
+ /* typedef hides external declaration: %s */
+ if (hflag)
+ warning(88, dsym->s_name);
+ break;
+ case EXTERN:
+ /*
+ * Warnings and errors are printed in ledecl()
+ */
+ break;
+ default:
+ lerror("decl1loc() 1");
+ }
+
+ } else if (dcs->d_rdcsym->s_blklev == blklev) {
+
+ /* no hflag, because its illegal! */
+ if (dcs->d_rdcsym->s_arg) {
+ /*
+ * if !tflag, a "redeclaration of %s" error
+ * is produced below
+ */
+ if (tflag) {
+ if (hflag)
+ /* decl. hides parameter: %s */
+ warning(91, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+ }
+ }
+
+ } else if (dcs->d_rdcsym->s_blklev < blklev) {
+
+ if (hflag)
+ /* declaration hides earlier one: %s */
+ warning(95, dsym->s_name);
+
+ }
+
+ if (dcs->d_rdcsym->s_blklev == blklev) {
+
+ /* redeclaration of %s */
+ error(27, dsym->s_name);
+ rmsym(dcs->d_rdcsym);
+
+ }
+
+ }
+
+ if (initflg && !(initerr = chkinit(dsym))) {
+ dsym->s_def = DEF;
+ setsflg(dsym);
+ }
+
+ if (dsym->s_scl == TYPEDEF) {
+ dsym->s_type = duptyp(dsym->s_type);
+ dsym->s_type->t_typedef = 1;
+ settdsym(dsym->s_type, dsym);
+ }
+
+ /*
+ * Before we can check the size we must wait for a initialisation
+ * which may follow.
+ */
+}
+
+/*
+ * Processes (re)declarations of external Symbols inside blocks.
+ */
+static void
+ledecl(dsym)
+ sym_t *dsym;
+{
+ int eqt, warn;
+ sym_t *esym;
+
+ /* look for a symbol with the same name */
+ esym = dcs->d_rdcsym;
+ while (esym != NULL && esym->s_blklev != 0) {
+ while ((esym = esym->s_link) != NULL) {
+ if (esym->s_kind != FVFT)
+ continue;
+ if (strcmp(dsym->s_name, esym->s_name) == 0)
+ break;
+ }
+ }
+ if (esym == NULL)
+ return;
+ if (esym->s_scl != EXTERN && esym->s_scl != STATIC) {
+ /* gcc accepts this without a warning, pcc prints an error. */
+ /* redeclaration of %s */
+ warning(27, dsym->s_name);
+ prevdecl(-1, esym);
+ return;
+ }
+
+ warn = 0;
+ eqt = eqtype(esym->s_type, dsym->s_type, 0, 0, &warn);
+
+ if (!eqt || warn) {
+ if (esym->s_scl == EXTERN) {
+ /* inconsistent redeclaration of extern: %s */
+ warning(90, dsym->s_name);
+ prevdecl(-1, esym);
+ } else {
+ /* inconsistent redeclaration of static: %s */
+ warning(92, dsym->s_name);
+ prevdecl(-1, esym);
+ }
+ }
+
+ if (eqt) {
+ /*
+ * Remember the external symbol so we can update usage
+ * information at the end of the block.
+ */
+ dsym->s_xsym = esym;
+ }
+}
+
+/*
+ * Print an error or a warning if the symbol cant be initialized due
+ * to type/storage class. Returnvalue is 1 if an error has been
+ * detected.
+ */
+static int
+chkinit(sym)
+ sym_t *sym;
+{
+ int err;
+
+ err = 0;
+
+ if (sym->s_type->t_tspec == FUNC) {
+ /* cannot initialize function: %s */
+ error(24, sym->s_name);
+ err = 1;
+ } else if (sym->s_scl == TYPEDEF) {
+ /* cannot initialize typedef: %s */
+ error(25, sym->s_name);
+ err = 1;
+ } else if (sym->s_scl == EXTERN && sym->s_def == DECL) {
+ /* cannot initialize "extern" declaration: %s */
+ if (dcs->d_ctx == EXTERN) {
+ warning(26, sym->s_name);
+ } else {
+ error(26, sym->s_name);
+ err = 1;
+ }
+ }
+
+ return (err);
+}
+
+/*
+ * Create a symbole for an abstract declaration.
+ */
+sym_t *
+aname()
+{
+ sym_t *sym;
+
+ if (dcs->d_ctx != ABSTRACT && dcs->d_ctx != PARG)
+ lerror("aname()");
+
+ sym = getblk(sizeof (sym_t));
+
+ sym->s_name = unnamed;
+ sym->s_def = DEF;
+ sym->s_scl = ABSTRACT;
+ sym->s_blklev = -1;
+
+ if (dcs->d_ctx == PARG)
+ sym->s_arg = 1;
+
+ sym->s_type = dcs->d_type;
+ dcs->d_rdcsym = NULL;
+ dcs->d_vararg = 0;
+
+ return (sym);
+}
+
+/*
+ * Removes anything which has nothing to do on global level.
+ */
+void
+globclup()
+{
+ while (dcs->d_nxt != NULL)
+ popdecl();
+
+ cleanup();
+ blklev = 0;
+ mblklev = 0;
+
+ /*
+ * remove all informations about pending lint directives without
+ * warnings.
+ */
+ glclup(1);
+}
+
+/*
+ * Process an abstract type declaration
+ */
+sym_t *
+decl1abs(sym)
+ sym_t *sym;
+{
+ chkfdef(sym, 1);
+ chktyp(sym);
+ return (sym);
+}
+
+/*
+ * Checks size after declarations of variables and their initialisation.
+ */
+void
+chksz(dsym)
+ sym_t *dsym;
+{
+ /*
+ * check size only for symbols which are defined and no function and
+ * not typedef name
+ */
+ if (dsym->s_def != DEF)
+ return;
+ if (dsym->s_scl == TYPEDEF)
+ return;
+ if (dsym->s_type->t_tspec == FUNC)
+ return;
+
+ if (length(dsym->s_type, dsym->s_name) == 0 &&
+ dsym->s_type->t_tspec == ARRAY && dsym->s_type->t_dim == 0) {
+ /* empty array declaration: %s */
+ if (tflag) {
+ warning(190, dsym->s_name);
+ } else {
+ error(190, dsym->s_name);
+ }
+ }
+}
+
+/*
+ * Mark an object as set if it is not already
+ */
+void
+setsflg(sym)
+ sym_t *sym;
+{
+ if (!sym->s_set) {
+ sym->s_set = 1;
+ STRUCT_ASSIGN(sym->s_spos, curr_pos);
+ }
+}
+
+/*
+ * Mark an object as used if it is not already
+ */
+void
+setuflg(sym, fcall, szof)
+ sym_t *sym;
+ int fcall, szof;
+{
+ if (!sym->s_used) {
+ sym->s_used = 1;
+ STRUCT_ASSIGN(sym->s_upos, curr_pos);
+ }
+ /*
+ * for function calls another record is written
+ *
+ * XXX Should symbols used in sizeof() treated as used or not?
+ * Probably not, because there is no sense to declare an
+ * external variable only to get their size.
+ */
+ if (!fcall && !szof && sym->s_kind == FVFT && sym->s_scl == EXTERN)
+ outusg(sym);
+}
+
+/*
+ * Prints warnings for a list of variables and labels (concatenated
+ * with s_dlnxt) if these are not used or only set.
+ */
+void
+chkusage(di)
+ dinfo_t *di;
+{
+ sym_t *sym;
+ int mknowarn;
+
+ /* for this warnings LINTED has no effect */
+ mknowarn = nowarn;
+ nowarn = 0;
+
+ for (sym = di->d_dlsyms; sym != NULL; sym = sym->s_dlnxt)
+ chkusg1(di->d_asm, sym);
+
+ nowarn = mknowarn;
+}
+
+/*
+ * Prints a warning for a single variable or label if it is not used or
+ * only set.
+ */
+void
+chkusg1(novar, sym)
+ int novar;
+ sym_t *sym;
+{
+ pos_t cpos;
+
+ if (sym->s_blklev == -1)
+ return;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ if (sym->s_kind == FVFT) {
+ if (sym->s_arg) {
+ chkausg(novar, sym);
+ } else {
+ chkvusg(novar, sym);
+ }
+ } else if (sym->s_kind == FLAB) {
+ chklusg(sym);
+ } else if (sym->s_kind == FTAG) {
+ chktusg(sym);
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
+
+static void
+chkausg(novar, arg)
+ int novar;
+ sym_t *arg;
+{
+ if (!arg->s_set)
+ lerror("chkausg() 1");
+
+ if (novar)
+ return;
+
+ if (!arg->s_used && vflag) {
+ STRUCT_ASSIGN(curr_pos, arg->s_dpos);
+ /* argument %s unused in function %s */
+ warning(231, arg->s_name, funcsym->s_name);
+ }
+}
+
+static void
+chkvusg(novar, sym)
+ int novar;
+ sym_t *sym;
+{
+ scl_t sc;
+ sym_t *xsym;
+
+ if (blklev == 0 || sym->s_blklev == 0)
+ lerror("chkvusg() 1");
+
+ /* errors in expressions easily cause lots of these warnings */
+ if (nerr != 0)
+ return;
+
+ /*
+ * XXX Only variables are checkd, although types should
+ * probably also be checked
+ */
+ if ((sc = sym->s_scl) != EXTERN && sc != STATIC &&
+ sc != AUTO && sc != REG) {
+ return;
+ }
+
+ if (novar)
+ return;
+
+ if (sc == EXTERN) {
+ if (!sym->s_used && !sym->s_set) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* %s unused in function %s */
+ warning(192, sym->s_name, funcsym->s_name);
+ }
+ } else {
+ if (sym->s_set && !sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_spos);
+ /* %s set but not used in function %s */
+ warning(191, sym->s_name, funcsym->s_name);
+ } else if (!sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* %s unused in function %s */
+ warning(192, sym->s_name, funcsym->s_name);
+ }
+ }
+
+ if (sc == EXTERN) {
+ /*
+ * information about usage is taken over into the symbol
+ * tabel entry at level 0 if the symbol was locally declared
+ * as an external symbol.
+ *
+ * XXX This is wrong for symbols declared static at level 0
+ * if the usage information stems from sizeof(). This is
+ * because symbols at level 0 only used in sizeof() are
+ * considered to not be used.
+ */
+ if ((xsym = sym->s_xsym) != NULL) {
+ if (sym->s_used && !xsym->s_used) {
+ xsym->s_used = 1;
+ STRUCT_ASSIGN(xsym->s_upos, sym->s_upos);
+ }
+ if (sym->s_set && !xsym->s_set) {
+ xsym->s_set = 1;
+ STRUCT_ASSIGN(xsym->s_spos, sym->s_spos);
+ }
+ }
+ }
+}
+
+static void
+chklusg(lab)
+ sym_t *lab;
+{
+ if (blklev != 1 || lab->s_blklev != 1)
+ lerror("chklusg() 1");
+
+ if (lab->s_set && !lab->s_used) {
+ STRUCT_ASSIGN(curr_pos, lab->s_spos);
+ /* label %s unused in function %s */
+ warning(192, lab->s_name, funcsym->s_name);
+ } else if (!lab->s_set) {
+ STRUCT_ASSIGN(curr_pos, lab->s_upos);
+ /* undefined label %s */
+ warning(23, lab->s_name);
+ }
+}
+
+static void
+chktusg(sym)
+ sym_t *sym;
+{
+ if (!incompl(sym->s_type))
+ return;
+
+ /* complain alwasy about incomplet tags declared inside blocks */
+ if (!zflag || dcs->d_ctx != EXTERN)
+ return;
+
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ switch (sym->s_type->t_tspec) {
+ case STRUCT:
+ /* struct %s never defined */
+ warning(233, sym->s_name);
+ break;
+ case UNION:
+ /* union %s never defined */
+ warning(234, sym->s_name);
+ break;
+ case ENUM:
+ /* enum %s never defined */
+ warning(235, sym->s_name);
+ break;
+ default:
+ lerror("chktusg() 1");
+ }
+}
+
+/*
+ * Called after the entire translation unit has been parsed.
+ * Changes tentative definitions in definitions.
+ * Performs some tests on global Symbols. Detected Problems are:
+ * - defined variables of incomplete type
+ * - constant variables which are not initialized
+ * - static symbols which are never used
+ */
+void
+chkglsyms()
+{
+ sym_t *sym;
+ pos_t cpos;
+
+ if (blklev != 0 || dcs->d_nxt != NULL)
+ norecover();
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ for (sym = dcs->d_dlsyms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev == -1)
+ continue;
+ if (sym->s_kind == FVFT) {
+ chkglvar(sym);
+ } else if (sym->s_kind == FTAG) {
+ chktusg(sym);
+ } else {
+ if (sym->s_kind != FMOS)
+ lerror("chkglsyms() 1");
+ }
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
+
+static void
+chkglvar(sym)
+ sym_t *sym;
+{
+ if (sym->s_scl == TYPEDEF || sym->s_scl == ENUMCON)
+ return;
+
+ if (sym->s_scl != EXTERN && sym->s_scl != STATIC)
+ lerror("chkglvar() 1");
+
+ glchksz(sym);
+
+ if (sym->s_scl == STATIC) {
+ if (sym->s_type->t_tspec == FUNC) {
+ if (sym->s_used && sym->s_def != DEF) {
+ STRUCT_ASSIGN(curr_pos, sym->s_upos);
+ /* static func. called but not def.. */
+ error(225, sym->s_name);
+ }
+ }
+ if (!sym->s_used) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ if (sym->s_type->t_tspec == FUNC) {
+ if (sym->s_def == DEF) {
+ if (!sym->s_inline)
+ /* static function %s unused */
+ warning(236, sym->s_name);
+ } else {
+ /* static function %s decl. but ... */
+ warning(290, sym->s_name);
+ }
+ } else if (!sym->s_set) {
+ /* static variable %s unused */
+ warning(226, sym->s_name);
+ } else {
+ /* static variable %s set but not used */
+ warning(307, sym->s_name);
+ }
+ }
+ if (!tflag && sym->s_def == TDEF && sym->s_type->t_const) {
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ /* const object %s should have initializer */
+ warning(227, sym->s_name);
+ }
+ }
+}
+
+static void
+glchksz(sym)
+ sym_t *sym;
+{
+ if (sym->s_def == TDEF) {
+ if (sym->s_type->t_tspec == FUNC)
+ /*
+ * this can happen if an syntax error occured
+ * after a function declaration
+ */
+ return;
+ STRUCT_ASSIGN(curr_pos, sym->s_dpos);
+ if (length(sym->s_type, sym->s_name) == 0 &&
+ sym->s_type->t_tspec == ARRAY && sym->s_type->t_dim == 0) {
+ /* empty array declaration: %s */
+ if (tflag || (sym->s_scl == EXTERN && !sflag)) {
+ warning(190, sym->s_name);
+ } else {
+ error(190, sym->s_name);
+ }
+ }
+ }
+}
+
+/*
+ * Prints information about location of previous definition/declaration.
+ */
+void
+prevdecl(msg, psym)
+ int msg;
+ sym_t *psym;
+{
+ pos_t cpos;
+
+ if (!rflag)
+ return;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+ STRUCT_ASSIGN(curr_pos, psym->s_dpos);
+ if (msg != -1) {
+ message(msg, psym->s_name);
+ } else if (psym->s_def == DEF || psym->s_def == TDEF) {
+ /* previous definition of %s */
+ message(261, psym->s_name);
+ } else {
+ /* previous declaration of %s */
+ message(260, psym->s_name);
+ }
+ STRUCT_ASSIGN(curr_pos, cpos);
+}
diff --git a/usr.bin/xlint/lint1/emit.c b/usr.bin/xlint/lint1/emit.c
new file mode 100644
index 0000000..f98f540
--- /dev/null
+++ b/usr.bin/xlint/lint1/emit.c
@@ -0,0 +1,241 @@
+/* $NetBSD: emit.c,v 1.2 1995/07/03 21:24:00 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: emit.c,v 1.2 1995/07/03 21:24:00 cgd Exp $";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+
+#include "lint.h"
+
+/* name and handle of output file */
+static const char *loname;
+static FILE *lout;
+
+/* output buffer data */
+ob_t ob;
+
+static void outxbuf __P((void));
+
+
+/*
+ * initialize output
+ */
+void
+outopen(name)
+ const char *name;
+{
+ loname = name;
+
+ /* Ausgabedatei oeffnen */
+ if ((lout = fopen(name, "w")) == NULL)
+ err(1, "cannot open '%s'", name);
+
+ /* Ausgabepuffer anlegen */
+ ob.o_len = 1024;
+ ob.o_end = (ob.o_buf = ob.o_nxt = xmalloc(ob.o_len)) + ob.o_len;
+}
+
+/*
+ * flush output buffer and close file
+ */
+void
+outclose()
+{
+ outclr();
+ if (fclose(lout) == EOF)
+ err(1, "cannot close '%s'", loname);
+}
+
+/*
+ * resize output buffer
+ */
+static void
+outxbuf()
+{
+ ptrdiff_t coffs;
+
+ coffs = ob.o_nxt - ob.o_buf;
+ ob.o_len *= 2;
+ ob.o_end = (ob.o_buf = xrealloc(ob.o_buf, ob.o_len)) + ob.o_len;
+ ob.o_nxt = ob.o_buf + coffs;
+}
+
+/*
+ * reset output buffer
+ * if it is not empty, it is flushed
+ */
+void
+outclr()
+{
+ size_t sz;
+
+ if (ob.o_buf != ob.o_nxt) {
+ outchar('\n');
+ sz = ob.o_nxt - ob.o_buf;
+ if (sz > ob.o_len)
+ errx(1, "internal error: outclr() 1");
+ if (fwrite(ob.o_buf, sz, 1, lout) != 1)
+ err(1, "cannot write to %s", loname);
+ ob.o_nxt = ob.o_buf;
+ }
+}
+
+/*
+ * write a character to the output buffer
+ */
+void
+outchar(c)
+ int c;
+{
+ if (ob.o_nxt == ob.o_end)
+ outxbuf();
+ *ob.o_nxt++ = (char)c;
+}
+
+/*
+ * write a character to the output buffer, qouted if necessary
+ */
+void
+outqchar(c)
+ int c;
+{
+ if (isprint(c) && c != '\\' && c != '"' && c != '\'') {
+ outchar(c);
+ } else {
+ outchar('\\');
+ switch (c) {
+ case '\\':
+ outchar('\\');
+ break;
+ case '"':
+ outchar('"');
+ break;
+ case '\'':
+ outchar('\'');
+ break;
+ case '\b':
+ outchar('b');
+ break;
+ case '\t':
+ outchar('t');
+ break;
+ case '\n':
+ outchar('n');
+ break;
+ case '\f':
+ outchar('f');
+ break;
+ case '\r':
+ outchar('r');
+ break;
+#ifdef __STDC__
+ case '\v':
+#else
+ case '\013':
+#endif
+ outchar('v');
+ break;
+#ifdef __STDC__
+ case '\a':
+#else
+ case '\007':
+#endif
+ outchar('a');
+ break;
+ default:
+ outchar((((u_int)c >> 6) & 07) + '0');
+ outchar((((u_int)c >> 3) & 07) + '0');
+ outchar((c & 07) + '0');
+ break;
+ }
+ }
+}
+
+/*
+ * write a strint to the output buffer
+ * the string must not contain any characters which
+ * should be quoted
+ */
+void
+outstrg(s)
+ const char *s;
+{
+ while (*s != '\0') {
+ if (ob.o_nxt == ob.o_end)
+ outxbuf();
+ *ob.o_nxt++ = *s++;
+ }
+}
+
+/*
+ * write an integer value to toe output buffer
+ */
+void
+outint(i)
+ int i;
+{
+ if ((ob.o_end - ob.o_nxt) < 3 * sizeof (int))
+ outxbuf();
+ ob.o_nxt += sprintf(ob.o_nxt, "%d", i);
+}
+
+/*
+ * write the name of a symbol to the output buffer
+ * the name is preceeded by its length
+ */
+void
+outname(name)
+ const char *name;
+{
+ if (name == NULL)
+ errx(1, "internal error: outname() 1");
+ outint((int)strlen(name));
+ outstrg(name);
+}
+
+/*
+ * write the name of the .c source
+ */
+void
+outsrc(name)
+ const char *name;
+{
+ outclr();
+ outchar('S');
+ outstrg(name);
+}
diff --git a/usr.bin/xlint/lint1/emit1.c b/usr.bin/xlint/lint1/emit1.c
new file mode 100644
index 0000000..ee2434e
--- /dev/null
+++ b/usr.bin/xlint/lint1/emit1.c
@@ -0,0 +1,587 @@
+/* $NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $";
+#endif
+
+#include <ctype.h>
+
+#include "lint1.h"
+
+static void outtt __P((sym_t *, sym_t *));
+static void outfstrg __P((strg_t *));
+
+/*
+ * Write type into the output buffer.
+ * The type is written as a sequence of substrings, each of which describes a
+ * node of type type_t
+ * a node is coded as follows:
+ * char C
+ * signed char s C
+ * unsigned char u C
+ * short S
+ * unsigned short u S
+ * int I
+ * unsigned int u I
+ * long L
+ * unsigned long u L
+ * long long Q
+ * unsigned long long u Q
+ * float s D
+ * double D
+ * long double l D
+ * void V
+ * * P
+ * [n] A n
+ * () F
+ * (void) F 0
+ * (n arguments) F n arg1 arg2 ... argn
+ * (n arguments, ...) F n arg1 arg2 ... argn-1 E
+ * (a, b, c, ...) f n arg1 arg2 ...
+ * enum tag e T tag_or_typename
+ * struct tag s T tag_or_typename
+ * union tag u T tag_or_typename
+ *
+ * tag_or_typename 0 no tag or type name
+ * 1 n tag Tag
+ * 2 n typename only type name
+ *
+ * spaces are only for better readability
+ * additionaly it is possible to prepend the characters 'c' (for const)
+ * and 'v' (for volatile)
+ */
+void
+outtype(tp)
+ type_t *tp;
+{
+ int t, s, na;
+ sym_t *arg;
+ tspec_t ts;
+
+ while (tp != NULL) {
+ if ((ts = tp->t_tspec) == INT && tp->t_isenum)
+ ts = ENUM;
+ switch (ts) {
+ case CHAR: t = 'C'; s = '\0'; break;
+ case SCHAR: t = 'C'; s = 's'; break;
+ case UCHAR: t = 'C'; s = 'u'; break;
+ case SHORT: t = 'S'; s = '\0'; break;
+ case USHORT: t = 'S'; s = 'u'; break;
+ case INT: t = 'I'; s = '\0'; break;
+ case UINT: t = 'I'; s = 'u'; break;
+ case LONG: t = 'L'; s = '\0'; break;
+ case ULONG: t = 'L'; s = 'u'; break;
+ case QUAD: t = 'Q'; s = '\0'; break;
+ case UQUAD: t = 'Q'; s = 'u'; break;
+ case FLOAT: t = 'D'; s = 's'; break;
+ case DOUBLE: t = 'D'; s = '\0'; break;
+ case LDOUBLE: t = 'D'; s = 'l'; break;
+ case VOID: t = 'V'; s = '\0'; break;
+ case PTR: t = 'P'; s = '\0'; break;
+ case ARRAY: t = 'A'; s = '\0'; break;
+ case FUNC: t = 'F'; s = '\0'; break;
+ case ENUM: t = 'T'; s = 'e'; break;
+ case STRUCT: t = 'T'; s = 's'; break;
+ case UNION: t = 'T'; s = 'u'; break;
+ default:
+ lerror("outtyp() 1");
+ }
+ if (tp->t_const)
+ outchar('c');
+ if (tp->t_volatile)
+ outchar('v');
+ if (s != '\0')
+ outchar(s);
+ outchar(t);
+ if (ts == ARRAY) {
+ outint(tp->t_dim);
+ } else if (ts == ENUM) {
+ outtt(tp->t_enum->etag, tp->t_enum->etdef);
+ } else if (ts == STRUCT || ts == UNION) {
+ outtt(tp->t_str->stag, tp->t_str->stdef);
+ } else if (ts == FUNC && tp->t_proto) {
+ na = 0;
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
+ na++;
+ if (tp->t_vararg)
+ na++;
+ outint(na);
+ for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt)
+ outtype(arg->s_type);
+ if (tp->t_vararg)
+ outchar('E');
+ }
+ tp = tp->t_subt;
+ }
+}
+
+/*
+ * type to string
+ * used for debugging output
+ *
+ * it uses its own output buffer for conversion
+ */
+const char *
+ttos(tp)
+ type_t *tp;
+{
+ static ob_t tob;
+ ob_t tmp;
+
+ if (tob.o_buf == NULL) {
+ tob.o_len = 64;
+ tob.o_buf = tob.o_nxt = xmalloc(tob.o_len);
+ tob.o_end = tob.o_buf + tob.o_len;
+ }
+
+ tmp = ob;
+ ob = tob;
+ ob.o_nxt = ob.o_buf;
+ outtype(tp);
+ outchar('\0');
+ tob = ob;
+ ob = tmp;
+
+ return (tob.o_buf);
+}
+
+/*
+ * write the name of a tag or typename
+ *
+ * if the tag is named, the name of the
+ * tag is written, otherwise, if a typename exists which
+ * refers to this tag, this typename is written
+ */
+static void
+outtt(tag, tdef)
+ sym_t *tag, *tdef;
+{
+ if (tag->s_name != unnamed) {
+ outint(1);
+ outname(tag->s_name);
+ } else if (tdef != NULL) {
+ outint(2);
+ outname(tdef->s_name);
+ } else {
+ outint(0);
+ }
+}
+
+/*
+ * write information about an global declared/defined symbol
+ * with storage class extern
+ *
+ * informations about function definitions are written in outfdef(),
+ * not here
+ */
+void
+outsym(sym, sc, def)
+ sym_t *sym;
+ scl_t sc;
+ def_t def;
+{
+ /*
+ * Static function declarations must also be written to the output
+ * file. Compatibility of function declarations (for both static
+ * and extern functions) must be checked in lint2. Lint1 can't do
+ * this, especially not, if functions are declared at block level
+ * before their first declaration at level 0.
+ */
+ if (sc != EXTERN && !(sc == STATIC && sym->s_type->t_tspec == FUNC))
+ return;
+
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'd' for declaration, Id of current
+ * source (.c or .h), and line in current source.
+ */
+ outint(csrc_pos.p_line);
+ outchar('d');
+ outint(getfnid(sym->s_dpos.p_file));
+ outchar('.');
+ outint(sym->s_dpos.p_line);
+
+ /* flags */
+
+ switch (def) {
+ case DEF:
+ /* defined */
+ outchar('d');
+ break;
+ case TDEF:
+ /* tentative defined */
+ outchar('t');
+ break;
+ case DECL:
+ /* declared */
+ outchar('e');
+ break;
+ default:
+ lerror("outsym() 2");
+ }
+ if (llibflg && def != DECL) {
+ /*
+ * mark it as used so we get no warnings from lint2 about
+ * unused symbols in libraries.
+ */
+ outchar('u');
+ }
+
+ if (sc == STATIC)
+ outchar('s');
+
+ /* name of the symbol */
+ outname(sym->s_name);
+
+ /* type of the symbol */
+ outtype(sym->s_type);
+}
+
+/*
+ * write information about function definition
+ *
+ * this is also done for static functions so we are able to check if
+ * they are called with proper argument types
+ */
+void
+outfdef(fsym, posp, rval, osdef, args)
+ sym_t *fsym, *args;
+ pos_t *posp;
+ int rval, osdef;
+{
+ int narg;
+ sym_t *arg;
+
+ /* reset the buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'd' for declaration, Id of current
+ * source (.c or .h), and line in current source
+ *
+ * we are already at the end of the function. If we are in the
+ * .c source, posp->p_line is correct, otherwise csrc_pos.p_line
+ * (for functions defined in header files).
+ */
+ if (posp->p_file == csrc_pos.p_file) {
+ outint(posp->p_line);
+ } else {
+ outint(csrc_pos.p_line);
+ }
+ outchar('d');
+ outint(getfnid(posp->p_file));
+ outchar('.');
+ outint(posp->p_line);
+
+ /* flags */
+
+ /* both SCANFLIKE and PRINTFLIKE imply VARARGS */
+ if (prflstrg != -1) {
+ nvararg = prflstrg;
+ } else if (scflstrg != -1) {
+ nvararg = scflstrg;
+ }
+
+ if (nvararg != -1) {
+ outchar('v');
+ outint(nvararg);
+ }
+ if (scflstrg != -1) {
+ outchar('S');
+ outint(scflstrg);
+ }
+ if (prflstrg != -1) {
+ outchar('P');
+ outint(prflstrg);
+ }
+ nvararg = prflstrg = scflstrg = -1;
+
+ outchar('d');
+
+ if (rval)
+ /* has return value */
+ outchar('r');
+
+ if (llibflg)
+ /*
+ * mark it as used so lint2 does not complain about
+ * unused symbols in libraries
+ */
+ outchar('u');
+
+ if (osdef)
+ /* old style function definition */
+ outchar('o');
+
+ if (fsym->s_scl == STATIC)
+ outchar('s');
+
+ /* name of function */
+ outname(fsym->s_name);
+
+ /* argument types and return value */
+ if (osdef) {
+ narg = 0;
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ narg++;
+ outchar('f');
+ outint(narg);
+ for (arg = args; arg != NULL; arg = arg->s_nxt)
+ outtype(arg->s_type);
+ outtype(fsym->s_type->t_subt);
+ } else {
+ outtype(fsym->s_type);
+ }
+}
+
+/*
+ * write out all information necessary for lint2 to check function
+ * calls
+ *
+ * rvused is set if the return value is used (asigned to a variable)
+ * rvdisc is set if the return value is not used and not ignored
+ * (casted to void)
+ */
+void
+outcall(tn, rvused, rvdisc)
+ tnode_t *tn;
+ int rvused, rvdisc;
+{
+ tnode_t *args, *arg;
+ int narg, n, i;
+ quad_t q;
+ tspec_t t;
+
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'c' for function call, Id of current
+ * source (.c or .h), and line in current source
+ */
+ outint(csrc_pos.p_line);
+ outchar('c');
+ outint(getfnid(curr_pos.p_file));
+ outchar('.');
+ outint(curr_pos.p_line);
+
+ /*
+ * flags; 'u' and 'i' must be last to make sure a letter
+ * is between the numeric argument of a flag and the name of
+ * the function
+ */
+ narg = 0;
+ args = tn->tn_right;
+ for (arg = args; arg != NULL; arg = arg->tn_right)
+ narg++;
+ /* informations about arguments */
+ for (n = 1; n <= narg; n++) {
+ /* the last argument is the top one in the tree */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+ arg = arg->tn_left;
+ if (arg->tn_op == CON) {
+ if (isityp(t = arg->tn_type->t_tspec)) {
+ /*
+ * XXX it would probably be better to
+ * explizitly test the sign
+ */
+ if ((q = arg->tn_val->v_quad) == 0) {
+ /* zero constant */
+ outchar('z');
+ } else if (msb(q, t, 0) == 0) {
+ /* positive if casted to signed */
+ outchar('p');
+ } else {
+ /* negative if casted to signed */
+ outchar('n');
+ }
+ outint(n);
+ }
+ } else if (arg->tn_op == AMPER &&
+ arg->tn_left->tn_op == STRING &&
+ arg->tn_left->tn_strg->st_tspec == CHAR) {
+ /* constant string, write all format specifiers */
+ outchar('s');
+ outint(n);
+ outfstrg(arg->tn_left->tn_strg);
+ }
+
+ }
+ /* return value discarded/used/ignored */
+ outchar(rvdisc ? 'd' : (rvused ? 'u' : 'i'));
+
+ /* name of the called function */
+ outname(tn->tn_left->tn_left->tn_sym->s_name);
+
+ /* types of arguments */
+ outchar('f');
+ outint(narg);
+ for (n = 1; n <= narg; n++) {
+ /* the last argument is the top one in the tree */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+ outtype(arg->tn_left->tn_type);
+ }
+ /* expected type of return value */
+ outtype(tn->tn_type);
+}
+
+/*
+ * extracts potential format specifiers for printf() and scanf() and
+ * writes them, enclosed in "" and qouted if necessary, to the output buffer
+ */
+static void
+outfstrg(strg)
+ strg_t *strg;
+{
+ int c, oc, first;
+ u_char *cp;
+
+ if (strg->st_tspec != CHAR)
+ lerror("outfstrg() 1");
+
+ cp = strg->st_cp;
+
+ outchar('"');
+
+ c = *cp++;
+
+ while (c != '\0') {
+
+ if (c != '%') {
+ c = *cp++;
+ continue;
+ }
+
+ outqchar('%');
+ c = *cp++;
+
+ /* flags for printf and scanf and *-fieldwidth for printf */
+ while (c != '\0' && (c == '-' || c == '+' || c == ' ' ||
+ c == '#' || c == '0' || c == '*')) {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /* numeric field width */
+ while (c != '\0' && isdigit(c)) {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /* precision for printf */
+ if (c == '.') {
+ outqchar(c);
+ if ((c = *cp++) == '*') {
+ outqchar(c);
+ c = *cp++;
+ } else {
+ while (c != '\0' && isdigit(c)) {
+ outqchar(c);
+ c = *cp++;
+ }
+ }
+ }
+
+ /* h, l, L and q flags fpr printf and scanf */
+ if (c == 'h' || c == 'l' || c == 'L' || c == 'q') {
+ outqchar(c);
+ c = *cp++;
+ }
+
+ /*
+ * The last character. It is always written so we can detect
+ * invalid format specifiers.
+ */
+ if (c != '\0') {
+ outqchar(c);
+ oc = c;
+ c = *cp++;
+ /*
+ * handle [ for scanf. [-] means that a minus sign
+ * was found at an undefined position.
+ */
+ if (oc == '[') {
+ if (c == '^')
+ c = *cp++;
+ if (c == ']')
+ c = *cp++;
+ first = 1;
+ while (c != '\0' && c != ']') {
+ if (c == '-') {
+ if (!first && *cp != ']')
+ outqchar(c);
+ }
+ first = 0;
+ c = *cp++;
+ }
+ if (c == ']') {
+ outqchar(c);
+ c = *cp++;
+ }
+ }
+ }
+
+ }
+
+ outchar('"');
+}
+
+/*
+ * writes a record if sym was used
+ */
+void
+outusg(sym)
+ sym_t *sym;
+{
+ /* reset buffer */
+ outclr();
+
+ /*
+ * line number of .c source, 'u' for used, Id of current
+ * source (.c or .h), and line in current source
+ */
+ outint(csrc_pos.p_line);
+ outchar('u');
+ outint(getfnid(curr_pos.p_file));
+ outchar('.');
+ outint(curr_pos.p_line);
+
+ /* necessary to delimit both numbers */
+ outchar('x');
+
+ /* Den Namen des Symbols ausgeben */
+ outname(sym->s_name);
+}
diff --git a/usr.bin/xlint/lint1/err.c b/usr.bin/xlint/lint1/err.c
new file mode 100644
index 0000000..32c80c4
--- /dev/null
+++ b/usr.bin/xlint/lint1/err.c
@@ -0,0 +1,543 @@
+/* $NetBSD: err.c,v 1.8 1995/10/02 17:37:00 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: err.c,v 1.8 1995/10/02 17:37:00 jpo Exp $";
+#endif
+
+/* number of errors found */
+int nerr;
+
+/* number of syntax errors */
+int sytxerr;
+
+#include <stdlib.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "lint1.h"
+
+static const char *basename __P((const char *));
+static void verror __P((int, va_list));
+static void vwarning __P((int, va_list));
+
+
+const char *msgs[] = {
+ "syntax error: empty declaration", /* 0 */
+ "old style declaration; add int", /* 1 */
+ "empty declaration", /* 2 */
+ "%s declared in argument declaration list", /* 3 */
+ "illegal type combination", /* 4 */
+ "modifying typedef with '%s'; only qualifiers allowed", /* 5 */
+ "use 'double' instead of 'long float'", /* 6 */
+ "only one storage class allowed", /* 7 */
+ "illegal storage class", /* 8 */
+ "only register valid as formal parameter storage class", /* 9 */
+ "duplicate '%s'", /* 10 */
+ "bit-field initializer out of range", /* 11 */
+ "compiler takes size of function", /* 12 */
+ "incomplete enum type: %s", /* 13 */
+ "compiler takes alignment of function", /* 14 */
+ "function returns illegal type", /* 15 */
+ "array of function is illegal", /* 16 */
+ "null dimension", /* 17 */
+ "illegal use of 'void'", /* 18 */
+ "void type for %s", /* 19 */
+ "zero or negative array dimension", /* 20 */
+ "redeclaration of formal parameter %s", /* 21 */
+ "incomplete or misplaced function definition", /* 22 */
+ "undefined label %s", /* 23 */
+ "cannot initialize function: %s", /* 24 */
+ "cannot initialize typedef: %s", /* 25 */
+ "cannot initialize extern declaration: %s", /* 26 */
+ "redeclaration of %s", /* 27 */
+ "redefinition of %s", /* 28 */
+ "previously declared extern, becomes static: %s", /* 29 */
+ "redeclaration of %s; ANSI C requires static", /* 30 */
+ "incomplete structure or union %s: %s", /* 31 */
+ "argument type defaults to 'int': %s", /* 32 */
+ "duplicate member name: %s", /* 33 */
+ "nonportable bit-field type", /* 34 */
+ "illegal bit-field type", /* 35 */
+ "illegal bit-field size", /* 36 */
+ "zero size bit-field", /* 37 */
+ "function illegal in structure or union", /* 38 */
+ "illegal zero sized structure member: %s", /* 39 */
+ "unknown size: %s", /* 40 */
+ "illegal use of bit-field", /* 41 */
+ "forward reference to enum type", /* 42 */
+ "redefinition hides earlier one: %s", /* 43 */
+ "declaration introduces new type in ANSI C: %s %s", /* 44 */
+ "base type is really '%s %s'", /* 45 */
+ "(%s) tag redeclared", /* 46 */
+ "zero sized %s", /* 47 */
+ "overflow in enumeration values: %s", /* 48 */
+ "struct or union member must be named", /* 49 */
+ "a function is declared as an argument: %s", /* 50 */
+ "parameter mismatch: %d declared, %d defined", /* 51 */
+ "cannot initialize parameter: %s", /* 52 */
+ "declared argument %s is missing", /* 53 */
+ "trailing ',' prohibited in enum declaration", /* 54 */
+ "integral constant expression expected", /* 55 */
+ "integral constant too large", /* 56 */
+ "enumeration constant hides parameter: %s", /* 57 */
+ "type does not match prototype: %s", /* 58 */
+ "formal parameter lacks name: param #%d", /* 59 */
+ "void must be sole parameter", /* 60 */
+ "void parameter cannot have name: %s", /* 61 */
+ "function prototype parameters must have types", /* 62 */
+ "prototype does not match old-style definition", /* 63 */
+ "()-less function definition", /* 64 */
+ "%s has no named members", /* 65 */
+ "syntax requires ';' after last struct/union member", /* 66 */
+ "cannot return incomplete type", /* 67 */
+ "typedef already qualified with '%s'", /* 68 */
+ "inappropriate qualifiers with 'void'", /* 69 */
+ "%soperand of '%s' is unsigned in ANSI C", /* 70 */
+ "too many characters in character constant", /* 71 */
+ "typedef declares no type name", /* 72 */
+ "empty character constant", /* 73 */
+ "no hex digits follow \\x", /* 74 */
+ "overflow in hex escape", /* 75 */
+ "character escape does not fit in character", /* 76 */
+ "bad octal digit %c", /* 77 */
+ "nonportable character escape", /* 78 */
+ "dubious escape \\%c", /* 79 */
+ "dubious escape \\%o", /* 80 */
+ "\\a undefined in traditional C", /* 81 */
+ "\\x undefined in traditional C", /* 82 */
+ "storage class after type is obsolescent", /* 83 */
+ "ANSI C requires formal parameter before '...'", /* 84 */
+ "dubious tag declaration: %s %s", /* 85 */
+ "automatic hides external declaration: %s", /* 86 */
+ "static hides external declaration: %s", /* 87 */
+ "typedef hides external declaration: %s", /* 88 */
+ "typedef redeclared: %s", /* 89 */
+ "inconsistent redeclaration of extern: %s", /* 90 */
+ "declaration hides parameter: %s", /* 91 */
+ "inconsistent redeclaration of static: %s", /* 92 */
+ "dubious static function at block level: %s", /* 93 */
+ "function has illegal storage class: %s", /* 94 */
+ "declaration hides earlier one: %s", /* 95 */
+ "cannot dereference non-pointer type", /* 96 */
+ "suffix U is illegal in traditional C", /* 97 */
+ "suffixes F and L are illegal in traditional C", /* 98 */
+ "%s undefined", /* 99 */
+ "unary + is illegal in traditional C", /* 100 */
+ "undefined struct/union member: %s", /* 101 */
+ "illegal member use: %s", /* 102 */
+ "left operand of '.' must be struct/union object", /* 103 */
+ "left operand of '->' must be pointer to struct/union", /* 104 */
+ "non-unique member requires struct/union %s", /* 105 */
+ "left operand of '->' must be pointer", /* 106 */
+ "operands of '%s' have incompatible types", /* 107 */
+ "operand of '%s' has incompatible type", /* 108 */
+ "void type illegal in expression", /* 109 */
+ "pointer to function is not allowed here", /* 110 */
+ "unacceptable operand of '%s'", /* 111 */
+ "cannot take address of bit-field", /* 112 */
+ "cannot take address of register %s", /* 113 */
+ "%soperand of '%s' must be lvalue", /* 114 */
+ "%soperand of '%s' must be modifiable lvalue", /* 115 */
+ "illegal pointer subtraction", /* 116 */
+ "bitwise operation on signed value possibly nonportable", /* 117 */
+ "semantics of '%s' change in ANSI C; use explicit cast", /* 118 */
+ "conversion of '%s' to '%s' is out of range", /* 119 */
+ "bitwise operation on signed value nonportable", /* 120 */
+ "negative shift", /* 121 */
+ "shift greater than size of object", /* 122 */
+ "illegal combination of pointer and integer, op %s", /* 123 */
+ "illegal pointer combination, op %s", /* 124 */
+ "ANSI C forbids ordered comparisons of pointers to functions",/* 125 */
+ "incompatible types in conditional", /* 126 */
+ "'&' before array or function: ignored", /* 127 */
+ "operands have incompatible pointer types, op %s", /* 128 */
+ "expression has null effect", /* 129 */
+ "enum type mismatch, op %s", /* 130 */
+ "conversion to '%s' may sign-extend incorrectly", /* 131 */
+ "conversion from '%s' may lose accuracy", /* 132 */
+ "conversion of pointer to '%s' loses bits", /* 133 */
+ "conversion of pointer to '%s' may lose bits", /* 134 */
+ "possible pointer alignment problem", /* 135 */
+ "cannot do pointer arithmetic on operand of unknown size", /* 136 */
+ "use of incomplete enum type, op %s", /* 137 */
+ "unknown operand size, op %s", /* 138 */
+ "division by 0", /* 139 */
+ "modulus by 0", /* 140 */
+ "integer overflow detected, op %s", /* 141 */
+ "floating point overflow detected, op %s", /* 142 */
+ "cannot take size of incomplete type", /* 143 */
+ "cannot take size of function", /* 144 */
+ "cannot take size of bit-field", /* 145 */
+ "cannot take size of void", /* 146 */
+ "invalid cast expression", /* 147 */
+ "improper cast of void expression", /* 148 */
+ "illegal function", /* 149 */
+ "argument mismatch: %d arg%s passed, %d expected", /* 150 */
+ "void expressions may not be arguments, arg #%d", /* 151 */
+ "argument cannot have unknown size, arg #%d", /* 152 */
+ "argument has incompatible pointer type, arg #%d", /* 153 */
+ "illegal combination of pointer and integer, arg #%d", /* 154 */
+ "argument is incompatible with prototype, arg #%d", /* 155 */
+ "enum type mismatch, arg #%d", /* 156 */
+ "ANSI C treats constant as unsigned", /* 157 */
+ "%s may be used before set", /* 158 */
+ "assignment in conditional context", /* 159 */
+ "operator '==' found where '=' was expected", /* 160 */
+ "constant in conditional context", /* 161 */
+ "comparision of %s with %s, op %s", /* 162 */
+ "a cast does not yield an lvalue", /* 163 */
+ "assignment of negative constant to unsigned type", /* 164 */
+ "constant truncated by assignment", /* 165 */
+ "precision lost in bit-field assignment", /* 166 */
+ "array subscript cannot be negative: %ld", /* 167 */
+ "array subscript cannot be > %d: %ld", /* 168 */
+ "precedence confusion possible: parenthesize!", /* 169 */
+ "first operand must have scalar type, op ? :", /* 170 */
+ "assignment type mismatch", /* 171 */
+ "too many struct/union initializers", /* 172 */
+ "too many array initializers", /* 173 */
+ "too many initializers", /* 174 */
+ "initialisation of an incomplete type", /* 175 */
+ "invalid initializer", /* 176 */
+ "non-constant initializer", /* 177 */
+ "initializer does not fit", /* 178 */
+ "cannot initialize struct/union with no named member", /* 179 */
+ "bit-field initializer does not fit", /* 180 */
+ "{}-enclosed initializer required", /* 181 */
+ "incompatible pointer types", /* 182 */
+ "illegal combination of pointer and integer", /* 183 */
+ "illegal pointer combination", /* 184 */
+ "initialisation type mismatch", /* 185 */
+ "bit-field initialisation is illegal in traditional C", /* 186 */
+ "non-null byte ignored in string initializer", /* 187 */
+ "no automatic aggregate initialization in traditional C", /* 188 */
+ "assignment of struct/union illegal in traditional C", /* 189 */
+ "empty array declaration: %s", /* 190 */
+ "%s set but not used in function %s", /* 191 */
+ "%s unused in function %s", /* 192 */
+ "statement not reached", /* 193 */
+ "label %s redefined", /* 194 */
+ "case not in switch", /* 195 */
+ "case label affected by conversion", /* 196 */
+ "non-constant case expression", /* 197 */
+ "non-integral case expression", /* 198 */
+ "duplicate case in switch: %ld", /* 199 */
+ "duplicate case in switch: %lu", /* 200 */
+ "default outside switch", /* 201 */
+ "duplicate default in switch", /* 202 */
+ "case label must be of type `int' in traditional C", /* 203 */
+ "controlling expressions must have scalar type", /* 204 */
+ "switch expression must have integral type", /* 205 */
+ "enumeration value(s) not handled in switch", /* 206 */
+ "loop not entered at top", /* 207 */
+ "break outside loop or switch", /* 208 */
+ "continue outside loop", /* 209 */
+ "enum type mismatch in initialisation", /* 210 */
+ "return value type mismatch", /* 211 */
+ "cannot return incomplete type", /* 212 */
+ "void function %s cannot return value", /* 213 */
+ "function %s expects to return value", /* 214 */
+ "function implicitly declared to return int", /* 215 */
+ "function %s has return (e); and return;", /* 216 */
+ "function %s falls off bottom without returning value", /* 217 */
+ "ANSI C treats constant as unsigned, op %s", /* 218 */
+ "concatenated strings are illegal in traditional C", /* 219 */
+ "fallthrough on case statement", /* 220 */
+ "initialisation of unsigned with negative constant", /* 221 */
+ "conversion of negative constant to unsigned type", /* 222 */
+ "end-of-loop code not reached", /* 223 */
+ "cannot recover from previous errors", /* 224 */
+ "static function called but not defined: %s()", /* 225 */
+ "static variable %s unused", /* 226 */
+ "const object %s should have initializer", /* 227 */
+ "function cannot return const or volatile object", /* 228 */
+ "questionable conversion of function pointer", /* 229 */
+ "nonportable character comparision, op %s", /* 230 */
+ "argument %s unused in function %s", /* 231 */
+ "label %s unused in function %s", /* 232 */
+ "struct %s never defined", /* 233 */
+ "union %s never defined", /* 234 */
+ "enum %s never defined", /* 235 */
+ "static function %s unused", /* 236 */
+ "redeclaration of formal parameter %s", /* 237 */
+ "initialisation of union is illegal in traditional C", /* 238 */
+ "constant argument to NOT", /* 239 */
+ "assignment of different structures", /* 240 */
+ "dubious operation on enum, op %s", /* 241 */
+ "combination of '%s' and '%s', op %s", /* 242 */
+ "dubious comparision of enums, op %s", /* 243 */
+ "illegal structure pointer combination", /* 244 */
+ "illegal structure pointer combination, op %s", /* 245 */
+ "dubious conversion of enum to '%s'", /* 246 */
+ "pointer casts may be troublesome", /* 247 */
+ "floating-point constant out of range", /* 248 */
+ "syntax error", /* 249 */
+ "unknown character \\%o", /* 250 */
+ "malformed integer constant", /* 251 */
+ "integer constant out of range", /* 252 */
+ "unterminated character constant", /* 253 */
+ "newline in string or char constant", /* 254 */
+ "undefined or invalid # directive", /* 255 */
+ "unterminated comment", /* 256 */
+ "extra characters in lint comment", /* 257 */
+ "unterminated string constant", /* 258 */
+ "conversion to '%s' due to prototype, arg #%d", /* 259 */
+ "previous declaration of %s", /* 260 */
+ "previous definition of %s", /* 261 */
+ "\\\" inside character constants undefined in traditional C", /* 262 */
+ "\\? undefined in traditional C", /* 263 */
+ "\\v undefined in traditional C", /* 264 */
+ "%s C does not support 'long long'", /* 265 */
+ "'long double' is illegal in traditional C", /* 266 */
+ "shift equal to size of object", /* 267 */
+ "variable declared inline: %s", /* 268 */
+ "argument declared inline: %s", /* 269 */
+ "function prototypes are illegal in traditional C", /* 270 */
+ "switch expression must be of type `int' in traditional C", /* 271 */
+ "empty translation unit", /* 272 */
+ "bit-field type '%s' invalid in ANSI C", /* 273 */
+ "ANSI C forbids comparision of %s with %s", /* 274 */
+ "cast discards 'const' from pointer target type", /* 275 */
+ "", /* 276 */
+ "initialisation of '%s' with '%s'", /* 277 */
+ "combination of '%s' and '%s', arg #%d", /* 278 */
+ "combination of '%s' and '%s' in return", /* 279 */
+ "must be outside function: /* %s */", /* 280 */
+ "duplicate use of /* %s */", /* 281 */
+ "must precede function definition: /* %s */", /* 282 */
+ "argument number mismatch with directive: /* %s */", /* 283 */
+ "fallthrough on default statement", /* 284 */
+ "prototype declaration", /* 285 */
+ "function definition is not a prototype", /* 286 */
+ "function declaration is not a prototype", /* 287 */
+ "dubious use of /* VARARGS */ with /* %s */", /* 288 */
+ "can't be used together: /* PRINTFLIKE */ /* SCANFLIKE */", /* 289 */
+ "static function %s declared but not defined", /* 290 */
+ "invalid multibyte character", /* 291 */
+ "cannot concatenate wide and regular string literals", /* 292 */
+ "argument %d must be 'char *' for PRINTFLIKE/SCANFLIKE", /* 293 */
+ "multi-character character constant", /* 294 */
+ "conversion of '%s' to '%s' is out of range, arg #%d", /* 295 */
+ "conversion of negative constant to unsigned type, arg #%d", /* 296 */
+ "conversion to '%s' may sign-extend incorrectly, arg #%d", /* 297 */
+ "conversion from '%s' may lose accuracy, arg #%d", /* 298 */
+ "prototype does not match old style definition, arg #%d", /* 299 */
+ "old style definition", /* 300 */
+ "array of incomplete type", /* 301 */
+ "%s returns pointer to automatic object", /* 302 */
+ "ANSI C forbids conversion of %s to %s", /* 303 */
+ "ANSI C forbids conversion of %s to %s, arg #%d", /* 304 */
+ "ANSI C forbids conversion of %s to %s, op %s", /* 305 */
+ "constant truncated by conversion, op %s", /* 306 */
+ "static variable %s set but not used", /* 307 */
+ "", /* 308 */
+ "extra bits set to 0 in conversion of '%s' to '%s', op %s", /* 309 */
+};
+
+/*
+ * If Fflag is not set basename() returns a pointer to the last
+ * component of the path, otherwise it returns the argument.
+ */
+static const char *
+basename(path)
+ const char *path;
+{
+ const char *cp, *cp1, *cp2;
+
+ if (Fflag)
+ return (path);
+
+ cp = cp1 = cp2 = path;
+ while (*cp != '\0') {
+ if (*cp++ == '/') {
+ cp2 = cp1;
+ cp1 = cp;
+ }
+ }
+ return (*cp1 == '\0' ? cp2 : cp1);
+}
+
+static void
+verror(n, ap)
+ int n;
+ va_list ap;
+{
+ const char *fn;
+
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s(%d): ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+ nerr++;
+}
+
+static void
+vwarning(n, ap)
+ int n;
+ va_list ap;
+{
+ const char *fn;
+
+ if (nowarn)
+ /* this warning is suppressed by a LINTED comment */
+ return;
+
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s(%d): warning: ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+}
+
+void
+#ifdef __STDC__
+error(int n, ...)
+#else
+error(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ verror(n, ap);
+ va_end(ap);
+}
+
+void
+#ifdef __STDC__
+lerror(const char *msg, ...)
+#else
+lerror(msg, va_alist)
+ const char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+ const char *fn;
+
+#ifdef __STDC__
+ va_start(ap, msg);
+#else
+ va_start(ap);
+#endif
+ fn = basename(curr_pos.p_file);
+ (void)fprintf(stderr, "%s(%d): lint error: ", fn, curr_pos.p_line);
+ (void)vfprintf(stderr, msg, ap);
+ (void)fprintf(stderr, "\n");
+ va_end(ap);
+ exit(1);
+}
+
+void
+#ifdef __STDC__
+warning(int n, ...)
+#else
+warning(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ vwarning(n, ap);
+ va_end(ap);
+}
+
+void
+#ifdef __STDC__
+message(int n, ...)
+#else
+message(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+ const char *fn;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ fn = basename(curr_pos.p_file);
+ (void)printf("%s(%d): ", fn, curr_pos.p_line);
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+ va_end(ap);
+}
+
+int
+#ifdef __STDC__
+gnuism(int n, ...)
+#else
+gnuism(n, va_alist)
+ int n;
+ va_dcl
+#endif
+{
+ va_list ap;
+ int msg;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+#endif
+ if (sflag && !gflag) {
+ verror(n, ap);
+ msg = 1;
+ } else if (!sflag && gflag) {
+ msg = 0;
+ } else {
+ vwarning(n, ap);
+ msg = 1;
+ }
+ va_end(ap);
+
+ return (msg);
+}
diff --git a/usr.bin/xlint/lint1/externs.h b/usr.bin/xlint/lint1/externs.h
new file mode 100644
index 0000000..e61f8d0
--- /dev/null
+++ b/usr.bin/xlint/lint1/externs.h
@@ -0,0 +1,56 @@
+/* $NetBSD: externs.h,v 1.2 1995/07/03 21:24:06 cgd 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.
+ */
+
+/*
+ * mem.c
+ */
+extern void *xmalloc __P((size_t));
+extern void *xcalloc __P((size_t, size_t));
+extern void *xrealloc __P((void *, size_t));
+extern char *xstrdup __P((const char *));
+extern void nomem __P((void));
+
+/*
+ * emit.c
+ */
+extern ob_t ob;
+
+extern void outopen __P((const char *));
+extern void outclose __P((void));
+extern void outclr __P((void));
+extern void outchar __P((int));
+extern void outqchar __P((int));
+extern void outstrg __P((const char *));
+extern void outint __P((int));
+extern void outname __P((const char *));
+extern void outsrc __P((const char *));
diff --git a/usr.bin/xlint/lint1/externs1.h b/usr.bin/xlint/lint1/externs1.h
new file mode 100644
index 0000000..e9923c7
--- /dev/null
+++ b/usr.bin/xlint/lint1/externs1.h
@@ -0,0 +1,281 @@
+/* $NetBSD: externs1.h,v 1.7 1995/10/02 17:31:39 jpo 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.
+ */
+
+/*
+ * main.c
+ */
+extern int aflag;
+extern int bflag;
+extern int cflag;
+extern int dflag;
+extern int eflag;
+extern int Fflag;
+extern int gflag;
+extern int hflag;
+extern int pflag;
+extern int rflag;
+extern int sflag;
+extern int tflag;
+extern int uflag;
+extern int vflag;
+extern int yflag;
+extern int zflag;
+
+extern void norecover __P((void));
+
+/*
+ * cgram.y
+ */
+extern int blklev;
+extern int mblklev;
+extern int yydebug;
+
+extern int yyerror __P((char *));
+extern int yyparse __P((void));
+
+/*
+ * scan.l
+ */
+extern pos_t curr_pos;
+extern pos_t csrc_pos;
+extern symt_t symtyp;
+extern FILE *yyin;
+extern u_quad_t qbmasks[], qlmasks[], qumasks[];
+
+extern void initscan __P((void));
+extern int sign __P((quad_t, tspec_t, int));
+extern int msb __P((quad_t, tspec_t, int));
+extern quad_t xsign __P((quad_t, tspec_t, int));
+extern void clrwflgs __P((void));
+extern sym_t *getsym __P((sbuf_t *));
+extern void cleanup __P((void));
+extern sym_t *pushdown __P((sym_t *));
+extern void rmsym __P((sym_t *));
+extern void rmsyms __P((sym_t *));
+extern void inssym __P((int, sym_t *));
+extern void freeyyv __P((void *, int));
+extern int yylex __P((void));
+
+/*
+ * mem1.c
+ */
+extern const char *fnalloc __P((const char *));
+extern const char *fnnalloc __P((const char *, size_t));
+extern int getfnid __P((const char *));
+
+extern void initmem __P((void));
+
+extern void *getblk __P((size_t));
+extern void *getlblk __P((int, size_t));
+extern void freeblk __P((void));
+extern void freelblk __P((int));
+
+extern void *tgetblk __P((size_t));
+extern tnode_t *getnode __P((void));
+extern void tfreeblk __P((void));
+extern struct mbl *tsave __P((void));
+extern void trestor __P((struct mbl *));
+
+/*
+ * err.c
+ */
+extern int nerr;
+extern int sytxerr;
+extern const char *msgs[];
+
+extern void error __P((int, ...));
+extern void warning __P((int, ...));
+extern void message __P((int, ...));
+extern int gnuism __P((int, ...));
+extern void lerror __P((const char *, ...));
+
+/*
+ * decl.c
+ */
+extern dinfo_t *dcs;
+extern const char *unnamed;
+extern int enumval;
+
+extern void initdecl __P((void));
+extern type_t *gettyp __P((tspec_t));
+extern type_t *duptyp __P((const type_t *));
+extern type_t *tduptyp __P((const type_t *));
+extern int incompl __P((type_t *));
+extern void setcompl __P((type_t *, int));
+extern void addscl __P((scl_t));
+extern void addtype __P((type_t *));
+extern void addqual __P((tqual_t));
+extern void pushdecl __P((scl_t));
+extern void popdecl __P((void));
+extern void setasm __P((void));
+extern void clrtyp __P((void));
+extern void deftyp __P((void));
+extern int length __P((type_t *, const char *));
+extern int getbound __P((type_t *));
+extern sym_t *lnklst __P((sym_t *, sym_t *));
+extern void chktyp __P((sym_t *));
+extern sym_t *decl1str __P((sym_t *));
+extern sym_t *bitfield __P((sym_t *, int));
+extern pqinf_t *mergepq __P((pqinf_t *, pqinf_t *));
+extern sym_t *addptr __P((sym_t *, pqinf_t *));
+extern sym_t *addarray __P((sym_t *, int, int));
+extern sym_t *addfunc __P((sym_t *, sym_t *));
+extern void chkfdef __P((sym_t *, int));
+extern sym_t *dname __P((sym_t *));
+extern sym_t *iname __P((sym_t *));
+extern type_t *mktag __P((sym_t *, tspec_t, int, int));
+extern const char *scltoa __P((scl_t));
+extern type_t *compltag __P((type_t *, sym_t *));
+extern sym_t *ename __P((sym_t *, int, int));
+extern void decl1ext __P((sym_t *, int));
+extern void cpuinfo __P((sym_t *, sym_t *));
+extern int isredec __P((sym_t *, int *));
+extern int eqtype __P((type_t *, type_t *, int, int, int *));
+extern void compltyp __P((sym_t *, sym_t *));
+extern sym_t *decl1arg __P((sym_t *, int));
+extern void cluparg __P((void));
+extern void decl1loc __P((sym_t *, int));
+extern sym_t *aname __P((void));
+extern void globclup __P((void));
+extern sym_t *decl1abs __P((sym_t *));
+extern void chksz __P((sym_t *));
+extern void setsflg __P((sym_t *));
+extern void setuflg __P((sym_t *, int, int));
+extern void chkusage __P((dinfo_t *));
+extern void chkusg1 __P((int, sym_t *));
+extern void chkglsyms __P((void));
+extern void prevdecl __P((int, sym_t *));
+
+/*
+ * tree.c
+ */
+extern void initmtab __P((void));
+extern type_t *incref __P((type_t *, tspec_t));
+extern type_t *tincref __P((type_t *, tspec_t));
+extern tnode_t *getcnode __P((type_t *, val_t *));
+extern tnode_t *getnnode __P((sym_t *, int));
+extern tnode_t *getsnode __P((strg_t *));
+extern sym_t *strmemb __P((tnode_t *, op_t, sym_t *));
+extern tnode_t *build __P((op_t, tnode_t *, tnode_t *));
+extern tnode_t *cconv __P((tnode_t *));
+extern int typeok __P((op_t, int, tnode_t *, tnode_t *));
+extern tnode_t *promote __P((op_t, int, tnode_t *));
+extern tnode_t *convert __P((op_t, int, type_t *, tnode_t *));
+extern void cvtcon __P((op_t, int, type_t *, val_t *, val_t *));
+extern const char *tyname __P((type_t *));
+extern tnode_t *bldszof __P((type_t *));
+extern tnode_t *cast __P((tnode_t *, type_t *));
+extern tnode_t *funcarg __P((tnode_t *, tnode_t *));
+extern tnode_t *funccall __P((tnode_t *, tnode_t *));
+extern val_t *constant __P((tnode_t *));
+extern void expr __P((tnode_t *, int, int));
+extern void chkmisc __P((tnode_t *, int, int, int, int, int, int));
+extern int conaddr __P((tnode_t *, sym_t **, ptrdiff_t *));
+extern strg_t *catstrg __P((strg_t *, strg_t *));
+
+/*
+ * func.c
+ */
+extern sym_t *funcsym;
+extern int reached;
+extern int rchflg;
+extern int ftflg;
+extern int nargusg;
+extern pos_t aupos;
+extern int nvararg;
+extern pos_t vapos;
+extern int prflstrg;
+extern pos_t prflpos;
+extern int scflstrg;
+extern pos_t scflpos;
+extern int ccflg;
+extern int llibflg;
+extern int nowarn;
+extern int plibflg;
+extern int quadflg;
+
+extern void pushctrl __P((int));
+extern void popctrl __P((int));
+extern void chkreach __P((void));
+extern void funcdef __P((sym_t *));
+extern void funcend __P((void));
+extern void label __P((int, sym_t *, tnode_t *));
+extern void if1 __P((tnode_t *));
+extern void if2 __P((void));
+extern void if3 __P((int));
+extern void switch1 __P((tnode_t *));
+extern void switch2 __P((void));
+extern void while1 __P((tnode_t *));
+extern void while2 __P((void));
+extern void do1 __P((void));
+extern void do2 __P((tnode_t *));
+extern void for1 __P((tnode_t *, tnode_t *, tnode_t *));
+extern void for2 __P((void));
+extern void dogoto __P((sym_t *));
+extern void docont __P((void));
+extern void dobreak __P((void));
+extern void doreturn __P((tnode_t *));
+extern void glclup __P((int));
+extern void argsused __P((int));
+extern void constcond __P((int));
+extern void fallthru __P((int));
+extern void notreach __P((int));
+extern void lintlib __P((int));
+extern void linted __P((int));
+extern void varargs __P((int));
+extern void printflike __P((int));
+extern void scanflike __P((int));
+extern void protolib __P((int));
+extern void longlong __P((int));
+
+/*
+ * init.c
+ */
+extern int initerr;
+extern sym_t *initsym;
+extern int startinit;
+
+extern void prepinit __P((void));
+extern void initrbr __P((void));
+extern void initlbr __P((void));
+extern void mkinit __P((tnode_t *));
+
+/*
+ * emit.c
+ */
+extern void outtype __P((type_t *));
+extern const char *ttos __P((type_t *));
+extern void outsym __P((sym_t *, scl_t, def_t));
+extern void outfdef __P((sym_t *, pos_t *, int, int, sym_t *));
+extern void outcall __P((tnode_t *, int, int));
+extern void outusg __P((sym_t *));
diff --git a/usr.bin/xlint/lint1/func.c b/usr.bin/xlint/lint1/func.c
new file mode 100644
index 0000000..5d3a172
--- /dev/null
+++ b/usr.bin/xlint/lint1/func.c
@@ -0,0 +1,1261 @@
+/* $NetBSD: func.c,v 1.7 1995/10/02 17:31:40 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: func.c,v 1.7 1995/10/02 17:31:40 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+/*
+ * Contains a pointer to the symbol table entry of the current function
+ * definition.
+ */
+sym_t *funcsym;
+
+/* Is set as long as a statement can be reached. Must be set at level 0. */
+int reached = 1;
+
+/*
+ * Is set as long as NOTREACHED is in effect.
+ * Is reset everywhere where reached can become 0.
+ */
+int rchflg;
+
+/*
+ * In conjunction with reached ontrols printing of "fallthrough on ..."
+ * warnings.
+ * Reset by each statement and set by FALLTHROUGH, switch (switch1())
+ * and case (label()).
+ *
+ * Control statements if, for, while and switch do not reset ftflg because
+ * this must be done by the controled statement. At least for if this is
+ * important because ** FALLTHROUGH ** after "if (expr) stmnt" is evaluated
+ * befor the following token, wich causes reduction of above, is read.
+ * This means that ** FALLTHROUGH ** after "if ..." would always be ignored.
+ */
+int ftflg;
+
+/* Top element of stack for control statements */
+cstk_t *cstk;
+
+/*
+ * Number of arguments which will be checked for usage in following
+ * function definition. -1 stands for all arguments.
+ *
+ * The position of the last ARGSUSED comment is stored in aupos.
+ */
+int nargusg = -1;
+pos_t aupos;
+
+/*
+ * Number of arguments of the following function definition whose types
+ * shall be checked by lint2. -1 stands for all arguments.
+ *
+ * The position of the last VARARGS comment is stored in vapos.
+ */
+int nvararg = -1;
+pos_t vapos;
+
+/*
+ * Both prflstr and scflstrg contain the number of the argument which
+ * shall be used to check the types of remaining arguments (for PRINTFLIKE
+ * and SCANFLIKE).
+ *
+ * prflpos and scflpos are the positions of the last PRINTFLIKE or
+ * SCANFLIKE comment.
+ */
+int prflstrg = -1;
+int scflstrg = -1;
+pos_t prflpos;
+pos_t scflpos;
+
+/*
+ * Are both plibflg and llibflg set, prototypes are writen as function
+ * definitions to the output file.
+ */
+int plibflg;
+
+/*
+ * Nonzero means that no warnings about constands in conditional
+ * context are printed.
+ */
+int ccflg;
+
+/*
+ * llibflg is set if a lint library shall be created. The effect of
+ * llibflg is that all defined symbols are treated as used.
+ * (The LINTLIBRARY comment also resets vflag.)
+ */
+int llibflg;
+
+/*
+ * Nonzero if warnings are suppressed by a LINTED directive
+ */
+int nowarn;
+
+/*
+ * Nonzero if complaints about use of "long long" are suppressed in
+ * the next statement or declaration.
+ */
+int quadflg;
+
+/*
+ * Puts a new element at the top of the stack used for control statements.
+ */
+void
+pushctrl(env)
+ int env;
+{
+ cstk_t *ci;
+
+ ci = xcalloc(1, sizeof (cstk_t));
+ ci->c_env = env;
+ ci->c_nxt = cstk;
+ cstk = ci;
+}
+
+/*
+ * Removes the top element of the stack used for control statements.
+ */
+void
+popctrl(env)
+ int env;
+{
+ cstk_t *ci;
+ clst_t *cl;
+
+ if (cstk == NULL || cstk->c_env != env)
+ lerror("popctrl() 1");
+
+ cstk = (ci = cstk)->c_nxt;
+
+ while ((cl = ci->c_clst) != NULL) {
+ ci->c_clst = cl->cl_nxt;
+ free(cl);
+ }
+
+ if (ci->c_swtype != NULL)
+ free(ci->c_swtype);
+
+ free(ci);
+}
+
+/*
+ * Prints a warning if a statement cannot be reached.
+ */
+void
+chkreach()
+{
+ if (!reached && !rchflg) {
+ /* statement not reached */
+ warning(193);
+ reached = 1;
+ }
+}
+
+/*
+ * Called after a function declaration which introduces a function definition
+ * and before an (optional) old style argument declaration list.
+ *
+ * Puts all symbols declared in the Prototype or in an old style argument
+ * list back to the symbol table.
+ *
+ * Does the usual checking of storage class, type (return value),
+ * redeclaration etc..
+ */
+void
+funcdef(fsym)
+ sym_t *fsym;
+{
+ int n, warn;
+ sym_t *arg, *sym, *rdsym;
+
+ funcsym = fsym;
+
+ /*
+ * Put all symbols declared in the argument list back to the
+ * symbol table.
+ */
+ for (sym = dcs->d_fpsyms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev != -1) {
+ if (sym->s_blklev != 1)
+ lerror("funcdef() 1");
+ inssym(1, sym);
+ }
+ }
+
+ /*
+ * In osfunc() we did not know whether it is an old style function
+ * definition or only an old style declaration, if there are no
+ * arguments inside the argument list ("f()").
+ */
+ if (!fsym->s_type->t_proto && fsym->s_args == NULL)
+ fsym->s_osdef = 1;
+
+ chktyp(fsym);
+
+ /*
+ * chktyp() checks for almost all possible errors, but not for
+ * incomplete return values (these are allowed in declarations)
+ */
+ if (fsym->s_type->t_subt->t_tspec != VOID &&
+ incompl(fsym->s_type->t_subt)) {
+ /* cannot return incomplete type */
+ error(67);
+ }
+
+ fsym->s_def = DEF;
+
+ if (fsym->s_scl == TYPEDEF) {
+ fsym->s_scl = EXTERN;
+ /* illegal storage class */
+ error(8);
+ }
+
+ if (dcs->d_inline)
+ fsym->s_inline = 1;
+
+ /*
+ * Arguments in new style function declarations need a name.
+ * (void is already removed from the list of arguments)
+ */
+ n = 1;
+ for (arg = fsym->s_type->t_args; arg != NULL; arg = arg->s_nxt) {
+ if (arg->s_scl == ABSTRACT) {
+ if (arg->s_name != unnamed)
+ lerror("funcdef() 2");
+ /* formal parameter lacks name: param #%d */
+ error(59, n);
+ } else {
+ if (arg->s_name == unnamed)
+ lerror("funcdef() 3");
+ }
+ n++;
+ }
+
+ /*
+ * We must also remember the position. s_dpos is overwritten
+ * if this is an old style definition and we had already a
+ * prototype.
+ */
+ STRUCT_ASSIGN(dcs->d_fdpos, fsym->s_dpos);
+
+ if ((rdsym = dcs->d_rdcsym) != NULL) {
+
+ if (!isredec(fsym, (warn = 0, &warn))) {
+
+ /*
+ * Print nothing if the newly defined function
+ * is defined in old style. A better warning will
+ * be printed in cluparg().
+ */
+ if (warn && !fsym->s_osdef) {
+ /* redeclaration of %s */
+ (*(sflag ? error : warning))(27, fsym->s_name);
+ prevdecl(-1, rdsym);
+ }
+
+ /* copy usage information */
+ cpuinfo(fsym, rdsym);
+
+ /*
+ * If the old symbol was a prototype and the new
+ * one is none, overtake the position of the
+ * declaration of the prototype.
+ */
+ if (fsym->s_osdef && rdsym->s_type->t_proto)
+ STRUCT_ASSIGN(fsym->s_dpos, rdsym->s_dpos);
+
+ /* complete the type */
+ compltyp(fsym, rdsym);
+
+ /* once a function is inline it remains inline */
+ if (rdsym->s_inline)
+ fsym->s_inline = 1;
+
+ }
+
+ /* remove the old symbol from the symbol table */
+ rmsym(rdsym);
+
+ }
+
+ if (fsym->s_osdef && !fsym->s_type->t_proto) {
+ if (sflag && hflag && strcmp(fsym->s_name, "main") != 0)
+ /* function definition is not a prototyp */
+ warning(286);
+ }
+
+ if (dcs->d_notyp)
+ /* return value is implizitly declared to be int */
+ fsym->s_rimpl = 1;
+
+ reached = 1;
+}
+
+/*
+ * Called at the end of a function definition.
+ */
+void
+funcend()
+{
+ sym_t *arg;
+ int n;
+
+ if (reached) {
+ cstk->c_noretval = 1;
+ if (funcsym->s_type->t_subt->t_tspec != VOID &&
+ !funcsym->s_rimpl) {
+ /* func. %s falls off bottom without returning value */
+ warning(217, funcsym->s_name);
+ }
+ }
+
+ /*
+ * This warning is printed only if the return value was implizitly
+ * declared to be int. Otherwise the wrong return statement
+ * has already printed a warning.
+ */
+ if (cstk->c_noretval && cstk->c_retval && funcsym->s_rimpl)
+ /* function %s has return (e); and return; */
+ warning(216, funcsym->s_name);
+
+ /* Print warnings for unused arguments */
+ arg = dcs->d_fargs;
+ n = 0;
+ while (arg != NULL && (nargusg == -1 || n < nargusg)) {
+ chkusg1(dcs->d_asm, arg);
+ arg = arg->s_nxt;
+ n++;
+ }
+ nargusg = -1;
+
+ /*
+ * write the information about the function definition to the
+ * output file
+ * inline functions explicitely declared extern are written as
+ * declarations only.
+ */
+ if (dcs->d_scl == EXTERN && funcsym->s_inline) {
+ outsym(funcsym, funcsym->s_scl, DECL);
+ } else {
+ outfdef(funcsym, &dcs->d_fdpos, cstk->c_retval,
+ funcsym->s_osdef, dcs->d_fargs);
+ }
+
+ /*
+ * remove all symbols declared during argument declaration from
+ * the symbol table
+ */
+ if (dcs->d_nxt != NULL || dcs->d_ctx != EXTERN)
+ lerror("funcend() 1");
+ rmsyms(dcs->d_fpsyms);
+
+ /* must be set on level 0 */
+ reached = 1;
+}
+
+/*
+ * Process a label.
+ *
+ * typ type of the label (T_NAME, T_DEFAULT or T_CASE).
+ * sym symbol table entry of label if typ == T_NAME
+ * tn expression if typ == T_CASE
+ */
+void
+label(typ, sym, tn)
+ int typ;
+ sym_t *sym;
+ tnode_t *tn;
+{
+ cstk_t *ci;
+ clst_t *cl;
+ val_t *v, *nv;
+ tspec_t t;
+
+ switch (typ) {
+
+ case T_NAME:
+ if (sym->s_set) {
+ /* label %s redefined */
+ error(194, sym->s_name);
+ } else {
+ setsflg(sym);
+ }
+ break;
+
+ case T_CASE:
+
+ /* find the stack entry for the innermost switch statement */
+ for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* case not in switch */
+ error(195);
+ tn = NULL;
+ } else if (tn != NULL && tn->tn_op != CON) {
+ /* non-constant case expression */
+ error(197);
+ tn = NULL;
+ } else if (tn != NULL && !isityp(tn->tn_type->t_tspec)) {
+ /* non-integral case expression */
+ error(198);
+ tn = NULL;
+ }
+
+ if (tn != NULL) {
+
+ if (ci->c_swtype == NULL)
+ lerror("label() 1");
+
+ if (reached && !ftflg) {
+ if (hflag)
+ /* fallthrough on case statement */
+ warning(220);
+ }
+
+ t = tn->tn_type->t_tspec;
+ if (t == LONG || t == ULONG ||
+ t == QUAD || t == UQUAD) {
+ if (tflag)
+ /* case label must be of type ... */
+ warning(203);
+ }
+
+ /*
+ * get the value of the expression and convert it
+ * to the type of the switch expression
+ */
+ v = constant(tn);
+ nv = xcalloc(1, sizeof (val_t));
+ cvtcon(CASE, 0, ci->c_swtype, nv, v);
+ free(v);
+
+ /* look if we had this value already */
+ for (cl = ci->c_clst; cl != NULL; cl = cl->cl_nxt) {
+ if (cl->cl_val.v_quad == nv->v_quad)
+ break;
+ }
+ if (cl != NULL && isutyp(nv->v_tspec)) {
+ /* duplicate case in switch, %lu */
+ error(200, (u_long)nv->v_quad);
+ } else if (cl != NULL) {
+ /* duplicate case in switch, %ld */
+ error(199, (long)nv->v_quad);
+ } else {
+ /*
+ * append the value to the list of
+ * case values
+ */
+ cl = xcalloc(1, sizeof (clst_t));
+ STRUCT_ASSIGN(cl->cl_val, *nv);
+ cl->cl_nxt = ci->c_clst;
+ ci->c_clst = cl;
+ }
+ }
+ tfreeblk();
+ break;
+
+ case T_DEFAULT:
+
+ /* find the stack entry for the innermost switch statement */
+ for (ci = cstk; ci != NULL && !ci->c_switch; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* default outside switch */
+ error(201);
+ } else if (ci->c_default) {
+ /* duplicate default in switch */
+ error(202);
+ } else {
+ if (reached && !ftflg) {
+ if (hflag)
+ /* fallthrough on default statement */
+ warning(284);
+ }
+ ci->c_default = 1;
+ }
+ break;
+ };
+ reached = 1;
+}
+
+/*
+ * T_IF T_LPARN expr T_RPARN
+ */
+void
+if1(tn)
+ tnode_t *tn;
+{
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ expr(tn, 0, 1);
+ pushctrl(T_IF);
+}
+
+/*
+ * if_without_else
+ * if_without_else T_ELSE
+ */
+void
+if2()
+{
+ cstk->c_rchif = reached ? 1 : 0;
+ reached = 1;
+}
+
+/*
+ * if_without_else
+ * if_without_else T_ELSE stmnt
+ */
+void
+if3(els)
+ int els;
+{
+ if (els) {
+ reached |= cstk->c_rchif;
+ } else {
+ reached = 1;
+ }
+ popctrl(T_IF);
+}
+
+/*
+ * T_SWITCH T_LPARN expr T_RPARN
+ */
+void
+switch1(tn)
+ tnode_t *tn;
+{
+ tspec_t t;
+ type_t *tp;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !isityp(tn->tn_type->t_tspec)) {
+ /* switch expression must have integral type */
+ error(205);
+ tn = NULL;
+ }
+ if (tn != NULL && tflag) {
+ t = tn->tn_type->t_tspec;
+ if (t == LONG || t == ULONG || t == QUAD || t == UQUAD) {
+ /* switch expr. must be of type `int' in trad. C */
+ warning(271);
+ }
+ }
+
+ /*
+ * Remember the type of the expression. Because its possible
+ * that (*tp) is allocated on tree memory the type must be
+ * duplicated. This is not too complicated because it is
+ * only an integer type.
+ */
+ tp = xcalloc(1, sizeof (type_t));
+ if (tn != NULL) {
+ tp->t_tspec = tn->tn_type->t_tspec;
+ if ((tp->t_isenum = tn->tn_type->t_isenum) != 0)
+ tp->t_enum = tn->tn_type->t_enum;
+ } else {
+ tp->t_tspec = INT;
+ }
+
+ expr(tn, 1, 0);
+
+ pushctrl(T_SWITCH);
+ cstk->c_switch = 1;
+ cstk->c_swtype = tp;
+
+ reached = rchflg = 0;
+ ftflg = 1;
+}
+
+/*
+ * switch_expr stmnt
+ */
+void
+switch2()
+{
+ int nenum, nclab;
+ sym_t *esym;
+ clst_t *cl;
+
+ if (cstk->c_swtype == NULL)
+ lerror("switch2() 1");
+
+ /*
+ * If the switch expression was of type enumeration, count the case
+ * labels and the number of enumerators. If both counts are not
+ * equal print a warning.
+ */
+ if (cstk->c_swtype->t_isenum) {
+ nenum = nclab = 0;
+ if (cstk->c_swtype->t_enum == NULL)
+ lerror("switch2() 2");
+ for (esym = cstk->c_swtype->t_enum->elem;
+ esym != NULL; esym = esym->s_nxt) {
+ nenum++;
+ }
+ for (cl = cstk->c_clst; cl != NULL; cl = cl->cl_nxt)
+ nclab++;
+ if (hflag && eflag && nenum != nclab && !cstk->c_default) {
+ /* enumeration value(s) not handled in switch */
+ warning(206);
+ }
+ }
+
+ if (cstk->c_break) {
+ /*
+ * end of switch alway reached (c_break is only set if the
+ * break statement can be reached).
+ */
+ reached = 1;
+ } else if (!cstk->c_default &&
+ (!hflag || !cstk->c_swtype->t_isenum || nenum != nclab)) {
+ /*
+ * there are possible values which are not handled in
+ * switch
+ */
+ reached = 1;
+ } /*
+ * otherwise the end of the switch expression is reached
+ * if the end of the last statement inside it is reached.
+ */
+
+ popctrl(T_SWITCH);
+}
+
+/*
+ * T_WHILE T_LPARN expr T_RPARN
+ */
+void
+while1(tn)
+ tnode_t *tn;
+{
+ if (!reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !issclt(tn->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn = NULL;
+ }
+
+ pushctrl(T_WHILE);
+ cstk->c_loop = 1;
+ if (tn != NULL && tn->tn_op == CON) {
+ if (isityp(tn->tn_type->t_tspec)) {
+ cstk->c_infinite = tn->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ expr(tn, 0, 1);
+}
+
+/*
+ * while_expr stmnt
+ * while_expr error
+ */
+void
+while2()
+{
+ /*
+ * The end of the loop can be reached if it is no endless loop
+ * or there was a break statement which was reached.
+ */
+ reached = !cstk->c_infinite || cstk->c_break;
+ rchflg = 0;
+
+ popctrl(T_WHILE);
+}
+
+/*
+ * T_DO
+ */
+void
+do1()
+{
+ if (!reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ pushctrl(T_DO);
+ cstk->c_loop = 1;
+}
+
+/*
+ * do stmnt do_while_expr
+ * do error
+ */
+void
+do2(tn)
+ tnode_t *tn;
+{
+ /*
+ * If there was a continue statement the expression controlling the
+ * loop is reached.
+ */
+ if (cstk->c_cont)
+ reached = 1;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+ if (tn != NULL && !issclt(tn->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn = NULL;
+ }
+
+ if (tn != NULL && tn->tn_op == CON) {
+ if (isityp(tn->tn_type->t_tspec)) {
+ cstk->c_infinite = tn->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ expr(tn, 0, 1);
+
+ /*
+ * The end of the loop is only reached if it is no endless loop
+ * or there was a break statement which could be reached.
+ */
+ reached = !cstk->c_infinite || cstk->c_break;
+ rchflg = 0;
+
+ popctrl(T_DO);
+}
+
+/*
+ * T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN
+ */
+void
+for1(tn1, tn2, tn3)
+ tnode_t *tn1, *tn2, *tn3;
+{
+ /*
+ * If there is no initialisation expression it is possible that
+ * it is intended not to enter the loop at top.
+ */
+ if (tn1 != NULL && !reached) {
+ /* loop not entered at top */
+ warning(207);
+ reached = 1;
+ }
+
+ pushctrl(T_FOR);
+ cstk->c_loop = 1;
+
+ /*
+ * Store the tree memory for the reinitialisation expression.
+ * Also remember this expression itself. We must check it at
+ * the end of the loop to get "used but not set" warnings correct.
+ */
+ cstk->c_fexprm = tsave();
+ cstk->c_f3expr = tn3;
+ STRUCT_ASSIGN(cstk->c_fpos, curr_pos);
+ STRUCT_ASSIGN(cstk->c_cfpos, csrc_pos);
+
+ if (tn1 != NULL)
+ expr(tn1, 0, 0);
+
+ if (tn2 != NULL)
+ tn2 = cconv(tn2);
+ if (tn2 != NULL)
+ tn2 = promote(NOOP, 0, tn2);
+ if (tn2 != NULL && !issclt(tn2->tn_type->t_tspec)) {
+ /* controlling expressions must have scalar type */
+ error(204);
+ tn2 = NULL;
+ }
+ if (tn2 != NULL)
+ expr(tn2, 0, 1);
+
+ if (tn2 == NULL) {
+ cstk->c_infinite = 1;
+ } else if (tn2->tn_op == CON) {
+ if (isityp(tn2->tn_type->t_tspec)) {
+ cstk->c_infinite = tn2->tn_val->v_quad != 0;
+ } else {
+ cstk->c_infinite = tn2->tn_val->v_ldbl != 0.0;
+ }
+ }
+
+ /* Checking the reinitialisation expression is done in for2() */
+
+ reached = 1;
+}
+
+/*
+ * for_exprs stmnt
+ * for_exprs error
+ */
+void
+for2()
+{
+ pos_t cpos, cspos;
+ tnode_t *tn3;
+
+ if (cstk->c_cont)
+ reached = 1;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+ STRUCT_ASSIGN(cspos, csrc_pos);
+
+ /* Restore the tree memory for the reinitialisation expression */
+ trestor(cstk->c_fexprm);
+ tn3 = cstk->c_f3expr;
+ STRUCT_ASSIGN(curr_pos, cstk->c_fpos);
+ STRUCT_ASSIGN(csrc_pos, cstk->c_cfpos);
+
+ /* simply "statement not reached" would be confusing */
+ if (!reached && !rchflg) {
+ /* end-of-loop code not reached */
+ warning(223);
+ reached = 1;
+ }
+
+ if (tn3 != NULL) {
+ expr(tn3, 0, 0);
+ } else {
+ tfreeblk();
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+ STRUCT_ASSIGN(csrc_pos, cspos);
+
+ /* An endless loop without break will never terminate */
+ reached = cstk->c_break || !cstk->c_infinite;
+ rchflg = 0;
+
+ popctrl(T_FOR);
+}
+
+/*
+ * T_GOTO identifier T_SEMI
+ * T_GOTO error T_SEMI
+ */
+void
+dogoto(lab)
+ sym_t *lab;
+{
+ setuflg(lab, 0, 0);
+
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_BREAK T_SEMI
+ */
+void
+dobreak()
+{
+ cstk_t *ci;
+
+ ci = cstk;
+ while (ci != NULL && !ci->c_loop && !ci->c_switch)
+ ci = ci->c_nxt;
+
+ if (ci == NULL) {
+ /* break outside loop or switch */
+ error(208);
+ } else {
+ if (reached)
+ ci->c_break = 1;
+ }
+
+ if (bflag)
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_CONTINUE T_SEMI
+ */
+void
+docont()
+{
+ cstk_t *ci;
+
+ for (ci = cstk; ci != NULL && !ci->c_loop; ci = ci->c_nxt) ;
+
+ if (ci == NULL) {
+ /* continue outside loop */
+ error(209);
+ } else {
+ ci->c_cont = 1;
+ }
+
+ chkreach();
+
+ reached = rchflg = 0;
+}
+
+/*
+ * T_RETURN T_SEMI
+ * T_RETURN expr T_SEMI
+ */
+void
+doreturn(tn)
+ tnode_t *tn;
+{
+ tnode_t *ln, *rn;
+ cstk_t *ci;
+ op_t op;
+
+ for (ci = cstk; ci->c_nxt != NULL; ci = ci->c_nxt) ;
+
+ if (tn != NULL) {
+ ci->c_retval = 1;
+ } else {
+ ci->c_noretval = 1;
+ }
+
+ if (tn != NULL && funcsym->s_type->t_subt->t_tspec == VOID) {
+ /* void function %s cannot return value */
+ error(213, funcsym->s_name);
+ tfreeblk();
+ tn = NULL;
+ } else if (tn == NULL && funcsym->s_type->t_subt->t_tspec != VOID) {
+ /*
+ * Assume that the function has a return value only if it
+ * is explicitly declared.
+ */
+ if (!funcsym->s_rimpl)
+ /* function %s expects to return value */
+ warning(214, funcsym->s_name);
+ }
+
+ if (tn != NULL) {
+
+ /* Create a temporary node for the left side */
+ ln = tgetblk(sizeof (tnode_t));
+ ln->tn_op = NAME;
+ ln->tn_type = tduptyp(funcsym->s_type->t_subt);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ ln->tn_sym = funcsym; /* better than nothing */
+
+ tn = build(RETURN, ln, tn);
+
+ if (tn != NULL) {
+ rn = tn->tn_right;
+ while ((op = rn->tn_op) == CVT || op == PLUS)
+ rn = rn->tn_left;
+ if (rn->tn_op == AMPER && rn->tn_left->tn_op == NAME &&
+ rn->tn_left->tn_sym->s_scl == AUTO) {
+ /* %s returns pointer to automatic object */
+ warning(302, funcsym->s_name);
+ }
+ }
+
+ expr(tn, 1, 0);
+
+ } else {
+
+ chkreach();
+
+ }
+
+ reached = rchflg = 0;
+}
+
+/*
+ * Do some cleanup after a global declaration or definition.
+ * Especially remove informations about unused lint comments.
+ */
+void
+glclup(silent)
+ int silent;
+{
+ pos_t cpos;
+
+ STRUCT_ASSIGN(cpos, curr_pos);
+
+ if (nargusg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, aupos);
+ /* must precede function definition: %s */
+ warning(282, "ARGSUSED");
+ }
+ nargusg = -1;
+ }
+ if (nvararg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, vapos);
+ /* must precede function definition: %s */
+ warning(282, "VARARGS");
+ }
+ nvararg = -1;
+ }
+ if (prflstrg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, prflpos);
+ /* must precede function definition: %s */
+ warning(282, "PRINTFLIKE");
+ }
+ prflstrg = -1;
+ }
+ if (scflstrg != -1) {
+ if (!silent) {
+ STRUCT_ASSIGN(curr_pos, scflpos);
+ /* must precede function definition: %s */
+ warning(282, "SCANFLIKE");
+ }
+ scflstrg = -1;
+ }
+
+ STRUCT_ASSIGN(curr_pos, cpos);
+
+ dcs->d_asm = 0;
+}
+
+/*
+ * ARGSUSED comment
+ *
+ * Only the first n arguments of the following function are checked
+ * for usage. A missing argument is taken to be 0.
+ */
+void
+argsused(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "ARGSUSED");
+ return;
+ }
+ if (nargusg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "ARGSUSED");
+ }
+ nargusg = n;
+ STRUCT_ASSIGN(aupos, curr_pos);
+}
+
+/*
+ * VARARGS comment
+ *
+ * Makes that lint2 checks only the first n arguments for compatibility
+ * to the function definition. A missing argument is taken to be 0.
+ */
+void
+varargs(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "VARARGS");
+ return;
+ }
+ if (nvararg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "VARARGS");
+ }
+ nvararg = n;
+ STRUCT_ASSIGN(vapos, curr_pos);
+}
+
+/*
+ * PRINTFLIKE comment
+ *
+ * Check all arguments until the (n-1)-th as usual. The n-th argument is
+ * used the check the types of remaining arguments.
+ */
+void
+printflike(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "PRINTFLIKE");
+ return;
+ }
+ if (prflstrg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "PRINTFLIKE");
+ }
+ prflstrg = n;
+ STRUCT_ASSIGN(prflpos, curr_pos);
+}
+
+/*
+ * SCANFLIKE comment
+ *
+ * Check all arguments until the (n-1)-th as usual. The n-th argument is
+ * used the check the types of remaining arguments.
+ */
+void
+scanflike(n)
+ int n;
+{
+ if (n == -1)
+ n = 0;
+
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "SCANFLIKE");
+ return;
+ }
+ if (scflstrg != -1) {
+ /* duplicate use of ** %s ** */
+ warning(281, "SCANFLIKE");
+ }
+ scflstrg = n;
+ STRUCT_ASSIGN(scflpos, curr_pos);
+}
+
+/*
+ * Set the linenumber for a CONSTCOND comment. At this and the following
+ * line no warnings about constants in conditional contexts are printed.
+ */
+/* ARGSUSED */
+void
+constcond(n)
+ int n;
+{
+ ccflg = 1;
+}
+
+/*
+ * Suppress printing of "fallthrough on ..." warnings until next
+ * statement.
+ */
+/* ARGSUSED */
+void
+fallthru(n)
+ int n;
+{
+ ftflg = 1;
+}
+
+/*
+ * Stop warnings about statements which cannot be reached. Also tells lint
+ * that the following statements cannot be reached (e.g. after exit()).
+ */
+/* ARGSUSED */
+void
+notreach(n)
+ int n;
+{
+ reached = 0;
+ rchflg = 1;
+}
+
+/* ARGSUSED */
+void
+lintlib(n)
+ int n;
+{
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "LINTLIBRARY");
+ return;
+ }
+ llibflg = 1;
+ vflag = 0;
+}
+
+/*
+ * Suppress most warnings at the current and the following line.
+ */
+/* ARGSUSED */
+void
+linted(n)
+ int n;
+{
+ nowarn = 1;
+}
+
+/*
+ * PROTOTLIB in conjunction with LINTLIBRARY can be used to handle
+ * prototypes like function definitions. This is done if the argument
+ * to PROTOLIB is nonzero. Otherwise prototypes are handled normaly.
+ */
+void
+protolib(n)
+ int n;
+{
+ if (dcs->d_ctx != EXTERN) {
+ /* must be outside function: ** %s ** */
+ warning(280, "PROTOLIB");
+ return;
+ }
+ plibflg = n == 0 ? 0 : 1;
+}
+
+/*
+ * Set quadflg to nonzero which means that the next statement/declaration
+ * may use "long long" without an error or warning.
+ */
+/* ARGSUSED */
+void
+longlong(n)
+ int n;
+{
+ quadflg = 1;
+}
diff --git a/usr.bin/xlint/lint1/init.c b/usr.bin/xlint/lint1/init.c
new file mode 100644
index 0000000..dbd216b
--- /dev/null
+++ b/usr.bin/xlint/lint1/init.c
@@ -0,0 +1,513 @@
+/* $NetBSD: init.c,v 1.4 1995/10/02 17:21:37 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: init.c,v 1.4 1995/10/02 17:21:37 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+
+#include "lint1.h"
+
+/*
+ * initerr is set as soon as a fatal error occured in an initialisation.
+ * The effect is that the rest of the initialisation is ignored (parsed
+ * by yacc, expression trees built, but no initialisation takes place).
+ */
+int initerr;
+
+/* Pointer to the symbol which is to be initialized. */
+sym_t *initsym;
+
+/* Points to the top element of the initialisation stack. */
+istk_t *initstk;
+
+
+static void popi2 __P((void));
+static void popinit __P((int));
+static void pushinit __P((void));
+static void testinit __P((void));
+static void nextinit __P((int));
+static int strginit __P((tnode_t *));
+
+
+/*
+ * Initialize the initialisation stack by putting an entry for the variable
+ * which is to be initialized on it.
+ */
+void
+prepinit()
+{
+ istk_t *istk;
+
+ if (initerr)
+ return;
+
+ /* free memory used in last initialisation */
+ while ((istk = initstk) != NULL) {
+ initstk = istk->i_nxt;
+ free(istk);
+ }
+
+ /*
+ * If the type which is to be initialized is an incomplete type,
+ * it must be duplicated.
+ */
+ if (initsym->s_type->t_tspec == ARRAY && incompl(initsym->s_type))
+ initsym->s_type = duptyp(initsym->s_type);
+
+ istk = initstk = xcalloc(1, sizeof (istk_t));
+ istk->i_subt = initsym->s_type;
+ istk->i_cnt = 1;
+
+}
+
+static void
+popi2()
+{
+ istk_t *istk;
+ sym_t *m;
+
+ initstk = (istk = initstk)->i_nxt;
+ if (initstk == NULL)
+ lerror("popi2() 1");
+ free(istk);
+
+ istk = initstk;
+
+ istk->i_cnt--;
+ if (istk->i_cnt < 0)
+ lerror("popi2() 3");
+
+ /*
+ * If the removed element was a structure member, we must go
+ * to the next structure member.
+ */
+ if (istk->i_cnt > 0 && istk->i_type->t_tspec == STRUCT) {
+ do {
+ m = istk->i_mem = istk->i_mem->s_nxt;
+ if (m == NULL)
+ lerror("popi2() 2");
+ } while (m->s_field && m->s_name == unnamed);
+ istk->i_subt = m->s_type;
+ }
+}
+
+static void
+popinit(brace)
+ int brace;
+{
+ if (brace) {
+ /*
+ * Take all entries, including the first which requires
+ * a closing brace, from the stack.
+ */
+ do {
+ brace = initstk->i_brace;
+ popi2();
+ } while (!brace);
+ } else {
+ /*
+ * Take all entries which cannot be used for further
+ * initializers from the stack, but do this only if
+ * they do not require a closing brace.
+ */
+ while (!initstk->i_brace &&
+ initstk->i_cnt == 0 && !initstk->i_nolimit) {
+ popi2();
+ }
+ }
+}
+
+static void
+pushinit()
+{
+ istk_t *istk;
+ int cnt;
+ sym_t *m;
+
+ istk = initstk;
+
+ /* Extend an incomplete array type by one element */
+ if (istk->i_cnt == 0) {
+ /*
+ * Inside of other aggregate types must not be an incomplete
+ * type.
+ */
+ if (istk->i_nxt->i_nxt != NULL)
+ lerror("pushinit() 1");
+ istk->i_cnt = 1;
+ if (istk->i_type->t_tspec != ARRAY)
+ lerror("pushinit() 2");
+ istk->i_type->t_dim++;
+ /* from now its an complete type */
+ setcompl(istk->i_type, 0);
+ }
+
+ if (istk->i_cnt <= 0)
+ lerror("pushinit() 3");
+ if (istk->i_type != NULL && issclt(istk->i_type->t_tspec))
+ lerror("pushinit() 4");
+
+ initstk = xcalloc(1, sizeof (istk_t));
+ initstk->i_nxt = istk;
+ initstk->i_type = istk->i_subt;
+ if (initstk->i_type->t_tspec == FUNC)
+ lerror("pushinit() 5");
+
+ istk = initstk;
+
+ switch (istk->i_type->t_tspec) {
+ case ARRAY:
+ if (incompl(istk->i_type) && istk->i_nxt->i_nxt != NULL) {
+ /* initialisation of an incomplete type */
+ error(175);
+ initerr = 1;
+ return;
+ }
+ istk->i_subt = istk->i_type->t_subt;
+ istk->i_nolimit = incompl(istk->i_type);
+ istk->i_cnt = istk->i_type->t_dim;
+ break;
+ case UNION:
+ if (tflag)
+ /* initialisation of union is illegal in trad. C */
+ warning(238);
+ /* FALLTHROUGH */
+ case STRUCT:
+ if (incompl(istk->i_type)) {
+ /* initialisation of an incomplete type */
+ error(175);
+ initerr = 1;
+ return;
+ }
+ cnt = 0;
+ for (m = istk->i_type->t_str->memb; m != NULL; m = m->s_nxt) {
+ if (m->s_field && m->s_name == unnamed)
+ continue;
+ if (++cnt == 1) {
+ istk->i_mem = m;
+ istk->i_subt = m->s_type;
+ }
+ }
+ if (cnt == 0) {
+ /* cannot init. struct/union with no named member */
+ error(179);
+ initerr = 1;
+ return;
+ }
+ istk->i_cnt = istk->i_type->t_tspec == STRUCT ? cnt : 1;
+ break;
+ default:
+ istk->i_cnt = 1;
+ break;
+ }
+}
+
+static void
+testinit()
+{
+ istk_t *istk;
+
+ istk = initstk;
+
+ /*
+ * If a closing brace is expected we have at least one initializer
+ * too much.
+ */
+ if (istk->i_cnt == 0 && !istk->i_nolimit) {
+ switch (istk->i_type->t_tspec) {
+ case ARRAY:
+ /* too many array initializers */
+ error(173);
+ break;
+ case STRUCT:
+ case UNION:
+ /* too many struct/union initializers */
+ error(172);
+ break;
+ default:
+ /* too many initializers */
+ error(174);
+ break;
+ }
+ initerr = 1;
+ }
+}
+
+static void
+nextinit(brace)
+ int brace;
+{
+ if (!brace) {
+ if (initstk->i_type == NULL &&
+ !issclt(initstk->i_subt->t_tspec)) {
+ /* {}-enclosed initializer required */
+ error(181);
+ }
+ /*
+ * Make sure an entry with a scalar type is at the top
+ * of the stack.
+ */
+ if (!initerr)
+ testinit();
+ while (!initerr && (initstk->i_type == NULL ||
+ !issclt(initstk->i_type->t_tspec))) {
+ if (!initerr)
+ pushinit();
+ }
+ } else {
+ if (initstk->i_type != NULL &&
+ issclt(initstk->i_type->t_tspec)) {
+ /* invalid initializer */
+ error(176);
+ initerr = 1;
+ }
+ if (!initerr)
+ testinit();
+ if (!initerr)
+ pushinit();
+ if (!initerr)
+ initstk->i_brace = 1;
+ }
+}
+
+void
+initlbr()
+{
+ if (initerr)
+ return;
+
+ if ((initsym->s_scl == AUTO || initsym->s_scl == REG) &&
+ initstk->i_nxt == NULL) {
+ if (tflag && !issclt(initstk->i_subt->t_tspec))
+ /* no automatic aggregate initialization in trad. C*/
+ warning(188);
+ }
+
+ /*
+ * Remove all entries which cannot be used for further initializers
+ * and do not expect a closing brace.
+ */
+ popinit(0);
+
+ nextinit(1);
+}
+
+void
+initrbr()
+{
+ if (initerr)
+ return;
+
+ popinit(1);
+}
+
+void
+mkinit(tn)
+ tnode_t *tn;
+{
+ ptrdiff_t offs;
+ sym_t *sym;
+ tspec_t lt, rt;
+ tnode_t *ln;
+ struct mbl *tmem;
+ scl_t sc;
+
+ if (initerr || tn == NULL)
+ goto end;
+
+ sc = initsym->s_scl;
+
+ /*
+ * Do not test for automatic aggregat initialisation. If the
+ * initalizer starts with a brace we have the warning already.
+ * If not, an error will be printed that the initializer must
+ * be enclosed by braces.
+ */
+
+ /*
+ * Local initialisation of non-array-types with only one expression
+ * without braces is done by ASSIGN
+ */
+ if ((sc == AUTO || sc == REG) &&
+ initsym->s_type->t_tspec != ARRAY && initstk->i_nxt == NULL) {
+ ln = getnnode(initsym, 0);
+ ln->tn_type = tduptyp(ln->tn_type);
+ ln->tn_type->t_const = 0;
+ tn = build(ASSIGN, ln, tn);
+ expr(tn, 0, 0);
+ goto end;
+ }
+
+ /*
+ * Remove all entries which cannot be used for further initializers
+ * and do not require a closing brace.
+ */
+ popinit(0);
+
+ /* Initialisations by strings are done in strginit(). */
+ if (strginit(tn))
+ goto end;
+
+ nextinit(0);
+ if (initerr || tn == NULL)
+ goto end;
+
+ initstk->i_cnt--;
+
+ /* Create a temporary node for the left side. */
+ ln = tgetblk(sizeof (tnode_t));
+ ln->tn_op = NAME;
+ ln->tn_type = tduptyp(initstk->i_type);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ ln->tn_sym = initsym; /* better than nothing */
+
+ tn = cconv(tn);
+
+ lt = ln->tn_type->t_tspec;
+ rt = tn->tn_type->t_tspec;
+
+ if (!issclt(lt))
+ lerror("mkinit() 1");
+
+ if (!typeok(INIT, 0, ln, tn))
+ goto end;
+
+ /*
+ * Store the tree memory. This is nessesary because otherwise
+ * expr() would free it.
+ */
+ tmem = tsave();
+ expr(tn, 1, 0);
+ trestor(tmem);
+
+ if (isityp(lt) && ln->tn_type->t_isfield && !isityp(rt)) {
+ /*
+ * Bit-fields can be initialized in trad. C only by integer
+ * constants.
+ */
+ if (tflag)
+ /* bit-field initialisation is illegal in trad. C */
+ warning(186);
+ }
+
+ if (lt != rt || (initstk->i_type->t_isfield && tn->tn_op == CON))
+ tn = convert(INIT, 0, initstk->i_type, tn);
+
+ if (tn != NULL && tn->tn_op != CON) {
+ sym = NULL;
+ offs = 0;
+ if (conaddr(tn, &sym, &offs) == -1) {
+ if (sc == AUTO || sc == REG) {
+ /* non-constant initializer */
+ (void)gnuism(177);
+ } else {
+ /* non-constant initializer */
+ error(177);
+ }
+ }
+ }
+
+ end:
+ tfreeblk();
+}
+
+
+static int
+strginit(tn)
+ tnode_t *tn;
+{
+ tspec_t t;
+ istk_t *istk;
+ int len;
+ strg_t *strg;
+
+ if (tn->tn_op != STRING)
+ return (0);
+
+ istk = initstk;
+ strg = tn->tn_strg;
+
+ /*
+ * Check if we have an array type which can be initialized by
+ * the string.
+ */
+ if (istk->i_subt->t_tspec == ARRAY) {
+ t = istk->i_subt->t_subt->t_tspec;
+ if (!((strg->st_tspec == CHAR &&
+ (t == CHAR || t == UCHAR || t == SCHAR)) ||
+ (strg->st_tspec == WCHAR && t == WCHAR))) {
+ return (0);
+ }
+ /* Put the array at top of stack */
+ pushinit();
+ istk = initstk;
+ } else if (istk->i_type != NULL && istk->i_type->t_tspec == ARRAY) {
+ t = istk->i_type->t_subt->t_tspec;
+ if (!((strg->st_tspec == CHAR &&
+ (t == CHAR || t == UCHAR || t == SCHAR)) ||
+ (strg->st_tspec == WCHAR && t == WCHAR))) {
+ return (0);
+ }
+ /*
+ * If the array is already partly initialized, we are
+ * wrong here.
+ */
+ if (istk->i_cnt != istk->i_type->t_dim)
+ return (0);
+ } else {
+ return (0);
+ }
+
+ /* Get length without trailing NUL character. */
+ len = strg->st_len;
+
+ if (istk->i_nolimit) {
+ istk->i_nolimit = 0;
+ istk->i_type->t_dim = len + 1;
+ /* from now complete type */
+ setcompl(istk->i_type, 0);
+ } else {
+ if (istk->i_type->t_dim < len) {
+ /* non-null byte ignored in string initializer */
+ warning(187);
+ }
+ }
+
+ /* In every case the array is initialized completely. */
+ istk->i_cnt = 0;
+
+ return (1);
+}
diff --git a/usr.bin/xlint/lint1/lint.h b/usr.bin/xlint/lint1/lint.h
new file mode 100644
index 0000000..cadcd7a
--- /dev/null
+++ b/usr.bin/xlint/lint1/lint.h
@@ -0,0 +1,118 @@
+/* $NetBSD: lint.h,v 1.2 1995/07/03 21:24:18 cgd 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.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "param.h"
+
+/*
+ * Type specifiers, used in type structures (type_t) and otherwere.
+ */
+typedef enum {
+ NOTSPEC,
+ SIGNED, /* keyword "signed", only used in the parser */
+ UNSIGN, /* keyword "unsigned", only used in the parser */
+ CHAR, /* char */
+ SCHAR, /* signed char */
+ UCHAR, /* unsigned char */
+ SHORT, /* (signed) short */
+ USHORT, /* unsigned short */
+ INT, /* (signed) int */
+ UINT, /* unsigned int */
+ LONG, /* (signed) long */
+ ULONG, /* unsigned long */
+ QUAD, /* (signed) long long */
+ UQUAD, /* unsigned long long */
+ FLOAT, /* float */
+ DOUBLE, /* double or, with tflag, long float */
+ LDOUBLE, /* long double */
+ VOID, /* void */
+ STRUCT, /* structure tag */
+ UNION, /* union tag */
+ ENUM, /* enum tag */
+ PTR, /* pointer */
+ ARRAY, /* array */
+ FUNC /* function */
+#define NTSPEC ((int)FUNC + 1)
+} tspec_t;
+
+/*
+ * size of types, name and classification
+ */
+typedef struct {
+ int tt_sz; /* size in bits */
+ int tt_psz; /* size, different from tt_sz
+ if pflag is set */
+ tspec_t tt_styp; /* signed counterpart */
+ tspec_t tt_utyp; /* unsigned counterpart */
+ u_int tt_isityp : 1; /* 1 if integer type */
+ u_int tt_isutyp : 1; /* 1 if unsigned integer type */
+ u_int tt_isftyp : 1; /* 1 if floating point type */
+ u_int tt_isatyp : 1; /* 1 if arithmetic type */
+ u_int tt_issclt : 1; /* 1 if scalar type */
+ char *tt_name; /* Bezeichnung des Typs */
+} ttab_t;
+
+#define size(t) (ttab[t].tt_sz)
+#define psize(t) (ttab[t].tt_psz)
+#define styp(t) (ttab[t].tt_styp)
+#define utyp(t) (ttab[t].tt_utyp)
+#define isityp(t) (ttab[t].tt_isityp)
+#define isutyp(t) (ttab[t].tt_isutyp)
+#define isftyp(t) (ttab[t].tt_isftyp)
+#define isatyp(t) (ttab[t].tt_isatyp)
+#define issclt(t) (ttab[t].tt_issclt)
+
+extern ttab_t ttab[];
+
+
+typedef enum {
+ NODECL, /* until now not declared */
+ DECL, /* declared */
+ TDEF, /* tentative defined */
+ DEF /* defined */
+} def_t;
+
+/*
+ * Following structure contains some data used for the output buffer.
+ */
+typedef struct ob {
+ char *o_buf; /* buffer */
+ char *o_end; /* first byte after buffer */
+ size_t o_len; /* length of buffer */
+ char *o_nxt; /* next free byte in buffer */
+} ob_t;
+
+#include "externs.h"
diff --git a/usr.bin/xlint/lint1/lint1.h b/usr.bin/xlint/lint1/lint1.h
new file mode 100644
index 0000000..019c98d
--- /dev/null
+++ b/usr.bin/xlint/lint1/lint1.h
@@ -0,0 +1,380 @@
+/* $NetBSD: lint1.h,v 1.6 1995/10/02 17:31:41 jpo 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.
+ */
+
+#include "lint.h"
+#include "op.h"
+
+/*
+ * Describes the position of a declaration or anything else.
+ */
+typedef struct {
+ int p_line;
+ const char *p_file;
+} pos_t;
+
+/*
+ * Strings cannot be referenced to simply by a pointer to its first
+ * char. This is because strings can contain NUL characters other than the
+ * trailing NUL.
+ *
+ * Strings are stored with a trailing NUL.
+ */
+typedef struct strg {
+ tspec_t st_tspec; /* CHAR or WCHAR */
+ size_t st_len; /* length without trailing NUL */
+ union {
+ u_char *_st_cp;
+ wchar_t *_st_wcp;
+ } st_u;
+} strg_t;
+
+#define st_cp st_u._st_cp
+#define st_wcp st_u._st_wcp
+
+/*
+ * qualifiers (only for lex/yacc interface)
+ */
+typedef enum {
+ CONST, VOLATILE
+} tqual_t;
+
+/*
+ * Integer and floating point values are stored in this structure
+ */
+typedef struct {
+ tspec_t v_tspec;
+ int v_ansiu; /* set if an integer constant is
+ unsigned in ANSI C */
+ union {
+ quad_t _v_quad; /* integers */
+ ldbl_t _v_ldbl; /* floats */
+ } v_u;
+} val_t;
+
+#define v_quad v_u._v_quad
+#define v_ldbl v_u._v_ldbl
+
+/*
+ * Structures of type str_t uniqely identify structures. This can't
+ * be done in structures of type type_t, because these are copied
+ * if they must be modified. So it would not be possible to check
+ * if to structures are identical by comparing the pointers to
+ * the type structures.
+ *
+ * The typename is used if the structure is unnamed to identify
+ * the structure type in pass 2.
+ */
+typedef struct {
+ u_int size; /* size in bit */
+ u_int align : 15; /* alignment in bit */
+ u_int sincompl : 1; /* set if incomplete type */
+ struct sym *memb; /* list of members */
+ struct sym *stag; /* symbol table entry of tag */
+ struct sym *stdef; /* symbol table entry of first typename */
+} str_t;
+
+/*
+ * same as above for enums
+ */
+typedef struct {
+ u_int eincompl : 1; /* incomplete enum type */
+ struct sym *elem; /* list of enumerators */
+ struct sym *etag; /* symbol table entry of tag */
+ struct sym *etdef; /* symbol table entry of first typename */
+} enum_t;
+
+/*
+ * Types are represented by concatenation of structures of type type_t
+ * via t_subt.
+ */
+typedef struct type {
+ tspec_t t_tspec; /* type specifier */
+ u_int t_aincompl : 1; /* incomplete array type */
+ u_int t_const : 1; /* const modifier */
+ u_int t_volatile : 1; /* volatile modifier */
+ u_int t_proto : 1; /* function prototype (t_args valid) */
+ u_int t_vararg : 1; /* protoype with ... */
+ u_int t_typedef : 1; /* type defined with typedef */
+ u_int t_isfield : 1; /* type is bitfield */
+ u_int t_isenum : 1; /* type is (or was) enum (t_enum valid) */
+ union {
+ int _t_dim; /* dimension */
+ str_t *_t_str; /* struct/union tag */
+ enum_t *_t_enum; /* enum tag */
+ struct sym *_t_args; /* arguments (if t_proto) */
+ struct {
+ u_int _t_flen : 8; /* length of bit-field */
+ u_int _t_foffs : 24; /* offset of bit-field */
+ } _t_u;
+ } t_u;
+ struct type *t_subt; /* element type (arrays), return value
+ (functions), or type pointer points to */
+} type_t;
+
+#define t_dim t_u._t_dim
+#define t_str t_u._t_str
+#define t_field t_u._t_field
+#define t_enum t_u._t_enum
+#define t_args t_u._t_args
+#define t_flen t_u._t_u._t_flen
+#define t_foffs t_u._t_u._t_foffs
+
+/*
+ * types of symbols
+ */
+typedef enum {
+ FVFT, /* variables, functions, type names, enums */
+ FMOS, /* members of structs or unions */
+ FTAG, /* tags */
+ FLAB /* labels */
+} symt_t;
+
+/*
+ * storage classes
+ */
+typedef enum {
+ NOSCL,
+ EXTERN, /* external symbols (indep. of decl_t) */
+ STATIC, /* static symbols (local and global) */
+ AUTO, /* automatic symbols (except register) */
+ REG, /* register */
+ TYPEDEF, /* typedef */
+ STRTAG,
+ UNIONTAG,
+ ENUMTAG,
+ MOS, /* member of struct */
+ MOU, /* member of union */
+ ENUMCON, /* enumerator */
+ ABSTRACT, /* abstract symbol (sizeof, casts, unnamed argument) */
+ ARG, /* argument */
+ PARG, /* used in declaration stack during prototype
+ declaration */
+ INLINE /* only used by the parser */
+} scl_t;
+
+/*
+ * symbol table entry
+ */
+typedef struct sym {
+ const char *s_name; /* name */
+ pos_t s_dpos; /* position of last (prototype)definition,
+ prototypedeclaration, no-prototype-def.,
+ tentative definition or declaration,
+ in this order */
+ pos_t s_spos; /* position of first initialisation */
+ pos_t s_upos; /* position of first use */
+ symt_t s_kind; /* type of symbol */
+ u_int s_keyw : 1; /* keyword */
+ u_int s_field : 1; /* bit-field */
+ u_int s_set : 1; /* variable set, label defined */
+ u_int s_used : 1; /* variable/label used */
+ u_int s_arg : 1; /* symbol is function argument */
+ u_int s_reg : 1; /* symbol is register variable */
+ u_int s_defarg : 1; /* undefined symbol in old style function
+ definition */
+ u_int s_rimpl : 1; /* return value of function implizit decl. */
+ u_int s_osdef : 1; /* symbol stems from old style function def. */
+ u_int s_inline : 1; /* true if this is a inline function */
+ struct sym *s_xsym; /* for local declared external symbols pointer
+ to external symbol with same name */
+ def_t s_def; /* declared, tentative defined, defined */
+ scl_t s_scl; /* storage class */
+ int s_blklev; /* level of declaration, -1 if not in symbol
+ table */
+ type_t *s_type; /* type */
+ val_t s_value; /* value (if enumcon) */
+ union {
+ str_t *_s_st; /* tag, if it is a struct/union member */
+ enum_t *_s_et; /* tag, if it is a enumerator */
+ tspec_t _s_tsp; /* type (only for keywords) */
+ tqual_t _s_tqu; /* qualifier (only for keywords) */
+ struct sym *_s_args; /* arguments in old style function
+ definitions */
+ } u;
+ struct sym *s_link; /* next symbol with same hash value */
+ struct sym **s_rlink; /* pointer to s_link of prev. symbol */
+ struct sym *s_nxt; /* next struct/union member, enumerator,
+ argument */
+ struct sym *s_dlnxt; /* next symbol declared on same level */
+} sym_t;
+
+#define s_styp u._s_st
+#define s_etyp u._s_et
+#define s_tspec u._s_tsp
+#define s_tqual u._s_tqu
+#define s_args u._s_args
+
+/*
+ * Used to keep some informations about symbols before they are entered
+ * into the symbol table.
+ */
+typedef struct sbuf {
+ const char *sb_name; /* name of symbol */
+ size_t sb_len; /* length (without '\0') */
+ int sb_hash; /* hash value */
+ sym_t *sb_sym; /* symbol table entry */
+ struct sbuf *sb_nxt; /* for freelist */
+} sbuf_t;
+
+
+/*
+ * tree node
+ */
+typedef struct tnode {
+ op_t tn_op; /* operator */
+ type_t *tn_type; /* type */
+ u_int tn_lvalue : 1; /* node is lvalue */
+ u_int tn_cast : 1; /* if tn_op == CVT its an explizit cast */
+ u_int tn_parn : 1; /* node parenthesized */
+ union {
+ struct {
+ struct tnode *_tn_left; /* (left) operand */
+ struct tnode *_tn_right; /* right operand */
+ } tn_s;
+ sym_t *_tn_sym; /* symbol if op == NAME */
+ val_t *_tn_val; /* value if op == CON */
+ strg_t *_tn_strg; /* string if op == STRING */
+ } tn_u;
+} tnode_t;
+
+#define tn_left tn_u.tn_s._tn_left
+#define tn_right tn_u.tn_s._tn_right
+#define tn_sym tn_u._tn_sym
+#define tn_val tn_u._tn_val
+#define tn_strg tn_u._tn_strg
+
+/*
+ * For nested declarations a stack exists, which holds all information
+ * needed for the current level. dcs points to the top element of this
+ * stack.
+ *
+ * ctx describes the context of the current declaration. Its value is
+ * one of
+ * EXTERN global declarations
+ * MOS oder MOU declarations of struct or union members
+ * ENUMCON declarations of enums
+ * ARG declaration of arguments in old style function definitions
+ * PARG declaration of arguments in function prototypes
+ * AUTO declaration of local symbols
+ * ABSTRACT abstract declarations (sizeof, casts)
+ *
+ */
+typedef struct dinfo {
+ tspec_t d_atyp; /* VOID, CHAR, INT, FLOAT or DOUBLE */
+ tspec_t d_smod; /* SIGNED or UNSIGN */
+ tspec_t d_lmod; /* SHORT, LONG or QUAD */
+ scl_t d_scl; /* storage class */
+ type_t *d_type; /* after deftyp() pointer to the type used
+ for all declarators */
+ sym_t *d_rdcsym; /* redeclared symbol */
+ int d_offset; /* offset of next structure member */
+ int d_stralign; /* alignment required for current structure */
+ scl_t d_ctx; /* context of declaration */
+ u_int d_const : 1; /* const in declaration specifiers */
+ u_int d_volatile : 1; /* volatile in declaration specifiers */
+ u_int d_inline : 1; /* inline in declaration specifiers */
+ u_int d_mscl : 1; /* multiple storage classes */
+ u_int d_terr : 1; /* invalid type combination */
+ u_int d_nedecl : 1; /* 1 if at least a tag is declared */
+ u_int d_vararg : 1; /* ... in in current function decl. */
+ u_int d_proto : 1; /* current funct. decl. is prototype */
+ u_int d_notyp : 1; /* set if no type specifier was present */
+ u_int d_asm : 1; /* set if d_ctx == AUTO and asm() present */
+ type_t *d_tagtyp; /* tag during member declaration */
+ sym_t *d_fargs; /* list of arguments during function def. */
+ pos_t d_fdpos; /* position of function definition */
+ sym_t *d_dlsyms; /* first symbol declared at this level */
+ sym_t **d_ldlsym; /* points to s_dlnxt in last symbol decl.
+ at this level */
+ sym_t *d_fpsyms; /* symbols defined in prototype */
+ struct dinfo *d_nxt; /* next level */
+} dinfo_t;
+
+/*
+ * Type of stack which is used for initialisation of aggregate types.
+ */
+typedef struct istk {
+ type_t *i_type; /* type of initialisation */
+ type_t *i_subt; /* type of next level */
+ u_int i_brace : 1; /* need } for pop */
+ u_int i_nolimit : 1; /* incomplete array type */
+ sym_t *i_mem; /* next structure member */
+ int i_cnt; /* # of remaining elements */
+ struct istk *i_nxt; /* previous level */
+} istk_t;
+
+/*
+ * Used to collect information about pointers and qualifiers in
+ * declarators.
+ */
+typedef struct pqinf {
+ int p_pcnt; /* number of asterisks */
+ u_int p_const : 1;
+ u_int p_volatile : 1;
+ struct pqinf *p_nxt;
+} pqinf_t;
+
+/*
+ * Case values are stored in a list of type clst_t.
+ */
+typedef struct clst {
+ val_t cl_val;
+ struct clst *cl_nxt;
+} clst_t;
+
+/*
+ * Used to keep informations about nested control statements.
+ */
+typedef struct cstk {
+ int c_env; /* type of statement (T_IF, ...) */
+ u_int c_loop : 1; /* continue && break are valid */
+ u_int c_switch : 1; /* case && break are valid */
+ u_int c_break : 1; /* loop/switch has break */
+ u_int c_cont : 1; /* loop has continue */
+ u_int c_default : 1; /* switch has default */
+ u_int c_infinite : 1; /* break condition always false
+ (for (;;), while (1)) */
+ u_int c_rchif : 1; /* end of if-branch reached */
+ u_int c_noretval : 1; /* had "return;" */
+ u_int c_retval : 1; /* had "return (e);" */
+ type_t *c_swtype; /* type of switch expression */
+ clst_t *c_clst; /* list of case values */
+ struct mbl *c_fexprm; /* saved memory for end of loop
+ expression in for() */
+ tnode_t *c_f3expr; /* end of loop expr in for() */
+ pos_t c_fpos; /* position of end of loop expr */
+ pos_t c_cfpos; /* same for csrc_pos */
+ struct cstk *c_nxt; /* outer control statement */
+} cstk_t;
+
+#include "externs1.h"
diff --git a/usr.bin/xlint/lint1/main1.c b/usr.bin/xlint/lint1/main1.c
new file mode 100644
index 0000000..0add206
--- /dev/null
+++ b/usr.bin/xlint/lint1/main1.c
@@ -0,0 +1,183 @@
+/* $NetBSD: main1.c,v 1.3 1995/10/02 17:29:56 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: main1.c,v 1.3 1995/10/02 17:29:56 jpo Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "lint1.h"
+
+/* set yydebug to 1*/
+int yflag;
+
+/*
+ * Print warnings if an assignment of an integertype to another integertype
+ * causes an implizit narrowing conversion. If aflag is 1, these warnings
+ * are printed only if the source type is at least as wide as long. If aflag
+ * is greather then 1, they are always printed.
+ */
+int aflag;
+
+/* Print a warning if a break statement cannot be reached. */
+int bflag;
+
+/* Print warnings for pointer casts. */
+int cflag;
+
+/* Print various debug information. */
+int dflag;
+
+/* Perform stricter checking of enum types and operations on enum types. */
+int eflag;
+
+/* Print complete pathnames, not only the basename. */
+int Fflag;
+
+/* Enable some extensions of gcc */
+int gflag;
+
+/*
+ * Apply a number of heuristic tests to attempt to intuit bugs, improve
+ * style, and reduce waste.
+ */
+int hflag;
+
+/* Attempt to check portability to other dialects of C. */
+int pflag;
+
+/*
+ * In case of redeclarations/redefinitions print the location of the
+ * previous declaration/definition.
+ */
+int rflag;
+
+/* Strict ANSI C mode. */
+int sflag;
+
+/* Traditional C mode. */
+int tflag;
+
+/*
+ * Complain about functions and external variables used and not defined,
+ * or defined and not used.
+ */
+int uflag = 1;
+
+/* Complain about unused function arguments. */
+int vflag = 1;
+
+/* Complain about structures which are never defined. */
+int zflag = 1;
+
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "abcdeghprstuvyzF")) != -1) {
+ switch (c) {
+ case 'a': aflag++; break;
+ case 'b': bflag = 1; break;
+ case 'c': cflag = 1; break;
+ case 'd': dflag = 1; break;
+ case 'e': eflag = 1; break;
+ case 'F': Fflag = 1; break;
+ case 'g': gflag = 1; break;
+ case 'h': hflag = 1; break;
+ case 'p': pflag = 1; break;
+ case 'r': rflag = 1; break;
+ case 's': sflag = 1; break;
+ case 't': tflag = 1; break;
+ case 'u': uflag = 0; break;
+ case 'v': vflag = 0; break;
+ case 'y': yflag = 1; break;
+ case 'z': zflag = 0; break;
+ case '?': usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ /* open the input file */
+ if ((yyin = fopen(argv[0], "r")) == NULL)
+ err(1, "cannot open '%s'", argv[0]);
+
+ /* initialize output */
+ outopen(argv[1]);
+
+ if (yflag)
+ yydebug = 1;
+
+ initmem();
+ initdecl();
+ initscan();
+ initmtab();
+
+ yyparse();
+
+ /* Following warnings cannot be suppressed by LINTED */
+ nowarn = 0;
+
+ chkglsyms();
+
+ outclose();
+
+ return (nerr != 0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: lint1 [-abcdeghprstuvyzF] src dest\n");
+ exit(1);
+}
+
+void
+norecover()
+{
+ /* cannot recover from previous errors */
+ error(224);
+ exit(1);
+}
diff --git a/usr.bin/xlint/lint1/mem.c b/usr.bin/xlint/lint1/mem.c
new file mode 100644
index 0000000..71fba06
--- /dev/null
+++ b/usr.bin/xlint/lint1/mem.c
@@ -0,0 +1,91 @@
+/* $NetBSD: mem.c,v 1.2 1995/07/03 21:24:24 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: mem.c,v 1.2 1995/07/03 21:24:24 cgd Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#include "lint.h"
+
+void *
+xmalloc(s)
+ size_t s;
+{
+ void *p;
+
+ if ((p = malloc(s)) == NULL)
+ nomem();
+ return (p);
+}
+
+void *
+xcalloc(n, s)
+ size_t n, s;
+{
+ void *p;
+
+ if ((p = calloc(n, s)) == NULL)
+ nomem();
+ return (p);
+}
+
+void *
+xrealloc(p, s)
+ void *p;
+ size_t s;
+{
+ if ((p = realloc(p, s)) == NULL)
+ nomem();
+ return (p);
+}
+
+char *
+xstrdup(s)
+ const char *s;
+{
+ char *s2;
+
+ if ((s2 = strdup(s)) == NULL)
+ nomem();
+ return (s2);
+}
+
+void
+nomem()
+{
+ errx(1, "virtual memory exhausted");
+}
diff --git a/usr.bin/xlint/lint1/mem1.c b/usr.bin/xlint/lint1/mem1.c
new file mode 100644
index 0000000..df880b1
--- /dev/null
+++ b/usr.bin/xlint/lint1/mem1.c
@@ -0,0 +1,358 @@
+/* $NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "lint1.h"
+
+/*
+ * Filenames allocated by fnalloc() and fnnalloc() are shared.
+ */
+typedef struct fn {
+ char *fn_name;
+ size_t fn_len;
+ int fn_id;
+ struct fn *fn_nxt;
+} fn_t;
+
+static fn_t *fnames;
+
+static fn_t *srchfn __P((const char *, size_t));
+
+/*
+ * Look for a Filename of length l.
+ */
+static fn_t *
+srchfn(s, len)
+ const char *s;
+ size_t len;
+{
+ fn_t *fn;
+
+ for (fn = fnames; fn != NULL; fn = fn->fn_nxt) {
+ if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
+ break;
+ }
+ return (fn);
+}
+
+/*
+ * Return a shared string for filename s.
+ */
+const char *
+fnalloc(s)
+ const char *s;
+{
+ return (s != NULL ? fnnalloc(s, strlen(s)) : NULL);
+}
+
+const char *
+fnnalloc(s, len)
+ const char *s;
+ size_t len;
+{
+ fn_t *fn;
+
+ static int nxt_id = 0;
+
+ if (s == NULL)
+ return (NULL);
+
+ if ((fn = srchfn(s, len)) == NULL) {
+ fn = xmalloc(sizeof (fn_t));
+ /* Do not used strdup() because string is not NUL-terminated.*/
+ fn->fn_name = xmalloc(len + 1);
+ (void)memcpy(fn->fn_name, s, len);
+ fn->fn_name[len] = '\0';
+ fn->fn_len = len;
+ fn->fn_id = nxt_id++;
+ fn->fn_nxt = fnames;
+ fnames = fn;
+ /* Write id of this filename to the output file. */
+ outclr();
+ outint(fn->fn_id);
+ outchar('s');
+ outstrg(fn->fn_name);
+ }
+ return (fn->fn_name);
+}
+
+/*
+ * Get id of a filename.
+ */
+int
+getfnid(s)
+ const char *s;
+{
+ fn_t *fn;
+
+ if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
+ return (-1);
+ return (fn->fn_id);
+}
+
+/*
+ * Memory for declarations and other things which must be available
+ * until the end of a block (or the end of the translation unit)
+ * are assoziated with the level (mblklev) of the block (or wiht 0).
+ * Because these memory is allocated in large blocks associated with
+ * a given level it can be freed easily at the end of a block.
+ */
+#define ML_INC ((size_t)32) /* Increment for length of *mblks */
+
+typedef struct mbl {
+ void *blk; /* beginning of memory block */
+ void *ffree; /* first free byte */
+ size_t nfree; /* # of free bytes */
+ size_t size; /* total size of memory block */
+ struct mbl *nxt; /* next block */
+} mbl_t;
+
+/*
+ * Array of pointers to lists of memory blocks. mblklev is used as
+ * index into this array.
+ */
+static mbl_t **mblks;
+
+/* number of elements in *mblks */
+static size_t nmblks;
+
+/* free list for memory blocks */
+static mbl_t *frmblks;
+
+/* length of new allocated memory blocks */
+static size_t mblklen;
+
+static void *xgetblk __P((mbl_t **, size_t));
+static void xfreeblk __P((mbl_t **));
+static mbl_t *xnewblk __P((void));
+
+static mbl_t *
+xnewblk()
+{
+ mbl_t *mb;
+ int prot, flags;
+
+ mb = xmalloc(sizeof (mbl_t));
+
+ /* use mmap instead of malloc to avoid malloc's size overhead */
+
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_ANON | MAP_PRIVATE;
+ mb->blk = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
+ if (mb->blk == (void *)-1)
+ err(1, "can't map memory");
+ if (ALIGN((u_long)mb->blk) != (u_long)mb->blk)
+ errx(1, "mapped address is not aligned");
+
+ mb->size = mblklen;
+
+ return (mb);
+}
+
+/*
+ * Allocate new memory. If the first block of the list has not enough
+ * free space, or there is no first block, get a new block. The new
+ * block is taken from the free list or, if there is no block on the
+ * free list, is allocated using xnewblk(). If a new block is allocated
+ * it is initialized with zero. Blocks taken from the free list are
+ * zero'd in xfreeblk().
+ */
+static void *
+xgetblk(mbp, s)
+ mbl_t **mbp;
+ size_t s;
+{
+ mbl_t *mb;
+ void *p;
+
+ s = ALIGN(s);
+ if ((mb = *mbp) == NULL || mb->nfree < s) {
+ if ((mb = frmblks) == NULL) {
+ mb = xnewblk();
+ (void)memset(mb->blk, 0, mb->size);
+ } else {
+ frmblks = mb->nxt;
+ }
+ mb->ffree = mb->blk;
+ mb->nfree = mb->size;;
+ mb->nxt = *mbp;
+ *mbp = mb;
+ }
+ p = mb->ffree;
+ mb->ffree = (char *)mb->ffree + s;
+ mb->nfree -= s;
+ return (p);
+}
+
+/*
+ * Move all blocks from list *fmbp to free list. For each block, set all
+ * used memory to zero.
+ */
+static void
+xfreeblk(fmbp)
+ mbl_t **fmbp;
+{
+ mbl_t *mb;
+
+ while ((mb = *fmbp) != NULL) {
+ *fmbp = mb->nxt;
+ mb->nxt = frmblks;
+ frmblks = mb;
+ (void)memset(mb->blk, 0, mb->size - mb->nfree);
+ }
+}
+
+void
+initmem()
+{
+ int pgsz;
+
+ pgsz = getpagesize();
+ mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
+
+ mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
+}
+
+
+/*
+ * Allocate memory associated with level l.
+ */
+void *
+getlblk(l, s)
+ int l;
+ size_t s;
+{
+ while (l >= nmblks) {
+ mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
+ (void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
+ nmblks += ML_INC;
+ }
+ return (xgetblk(&mblks[l], s));
+}
+
+void *
+getblk(s)
+ size_t s;
+{
+ return (getlblk(mblklev, s));
+}
+
+/*
+ * Free all memory associated with level l.
+ */
+void
+freelblk(l)
+ int l;
+{
+ xfreeblk(&mblks[l]);
+}
+
+void
+freeblk()
+{
+ freelblk(mblklev);
+}
+
+/*
+ * tgetblk() returns memory which is associated with the current
+ * expression.
+ */
+static mbl_t *tmblk;
+
+void *
+tgetblk(s)
+ size_t s;
+{
+ return (xgetblk(&tmblk, s));
+}
+
+/*
+ * Get memory for a new tree node.
+ */
+tnode_t *
+getnode()
+{
+ return (tgetblk(sizeof (tnode_t)));
+}
+
+/*
+ * Free all memory which is allocated by the the current expression.
+ */
+void
+tfreeblk()
+{
+ xfreeblk(&tmblk);
+}
+
+/*
+ * Save the memory which is used by the current expression. This memory
+ * is not freed by the next tfreeblk() call. The pointer returned can be
+ * used to restore the memory.
+ */
+mbl_t *
+tsave()
+{
+ mbl_t *tmem;
+
+ tmem = tmblk;
+ tmblk = NULL;
+ return (tmem);
+}
+
+/*
+ * Free all memory used for the current expression and the memory used
+ * be a previous expression and saved by tsave(). The next call to
+ * tfreeblk() frees the restored memory.
+ */
+void
+trestor(tmem)
+ mbl_t *tmem;
+{
+ tfreeblk();
+ if (tmblk != NULL) {
+ free(tmblk->blk);
+ free(tmblk);
+ }
+ tmblk = tmem;
+}
diff --git a/usr.bin/xlint/lint1/op.h b/usr.bin/xlint/lint1/op.h
new file mode 100644
index 0000000..11f05a5
--- /dev/null
+++ b/usr.bin/xlint/lint1/op.h
@@ -0,0 +1,120 @@
+/* $NetBSD: op.h,v 1.2 1995/07/03 21:24:27 cgd 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.
+ */
+
+/*
+ * Various information about operators
+ */
+typedef struct {
+ u_int m_binary : 1; /* binary op. */
+ u_int m_logop : 1; /* logical op., result is int */
+ u_int m_rqint : 1; /* operands must have integer type */
+ u_int m_rqsclt : 1; /* operands must have scalar type */
+ u_int m_rqatyp : 1; /* operands must have arithmetic type */
+ u_int m_fold : 1; /* operands should be folded */
+ u_int m_vctx : 1; /* value context for left operand */
+ u_int m_tctx : 1; /* test context for left operand */
+ u_int m_balance : 1; /* op. requires balancing */
+ u_int m_sideeff : 1; /* op. has side effect */
+ u_int m_tlansiu : 1; /* warning if left op. is unsign. in ANSI C */
+ u_int m_transiu : 1; /* warning if right op. is unsign. in ANSI C */
+ u_int m_tpconf : 1; /* test possible precedence confusion */
+ u_int m_comp : 1; /* op. performs comparision */
+ u_int m_enumop : 1; /* valid operation on enums */
+ u_int m_badeop : 1; /* dubious operation on enums */
+ u_int m_eqwarn : 1; /* warning if on operand stems from == */
+ const char *m_name; /* name of op. */
+} mod_t;
+
+typedef enum {
+ NOOP = 0,
+ ARROW,
+ POINT,
+ NOT,
+ COMPL,
+ INC,
+ DEC,
+ INCBEF,
+ DECBEF,
+ INCAFT,
+ DECAFT,
+ UPLUS,
+ UMINUS,
+ STAR,
+ AMPER,
+ MULT,
+ DIV,
+ MOD,
+ PLUS,
+ MINUS,
+ SHL,
+ SHR,
+ LT,
+ LE,
+ GT,
+ GE,
+ EQ,
+ NE,
+ AND,
+ XOR,
+ OR,
+ LOGAND,
+ LOGOR,
+ QUEST,
+ COLON,
+ ASSIGN,
+ MULASS,
+ DIVASS,
+ MODASS,
+ ADDASS,
+ SUBASS,
+ SHLASS,
+ SHRASS,
+ ANDASS,
+ XORASS,
+ ORASS,
+ NAME,
+ CON,
+ STRING,
+ FSEL,
+ CALL,
+ COMMA,
+ CVT,
+ ICALL,
+ LOAD,
+ PUSH,
+ RETURN,
+ INIT, /* pseudo op, not used in trees */
+ CASE, /* pseudo op, not used in trees */
+ FARG /* pseudo op, not used in trees */
+#define NOPS ((int)FARG + 1)
+} op_t;
diff --git a/usr.bin/xlint/lint1/param.h b/usr.bin/xlint/lint1/param.h
new file mode 100644
index 0000000..17e266e
--- /dev/null
+++ b/usr.bin/xlint/lint1/param.h
@@ -0,0 +1,120 @@
+/* $NetBSD: param.h,v 1.4 1995/07/23 18:14:41 ragge 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.
+ */
+
+/*
+ * Minimun size of string buffer. If this is not enough, the buffer
+ * is enlarged in steps of STRBLEN bytes.
+ */
+#define STRBLEN 256
+
+/*
+ * This defines the size of memory blocks which are used to allocate
+ * memory in larger chunks.
+ */
+#define MBLKSIZ ((size_t)0x4000)
+
+/*
+ * Sizes of hash tables
+ * Should be a prime. Possible primes are
+ * 307, 401, 503, 601, 701, 809, 907, 1009, 1103, 1201, 1301, 1409, 1511.
+ *
+ * HSHSIZ1 symbol table 1st pass
+ * HSHSIZ2 symbol table 2nd pass
+ * THSHSIZ2 type table 2nd pass
+ */
+#define HSHSIZ1 503
+#define HSHSIZ2 1009
+#define THSHSIZ2 1009
+
+/*
+ * Should be set to 1 if the difference of two pointers is of type long
+ * or the value of sizeof is of type unsigned long.
+ */
+#ifdef __alpha__
+#define PTRDIFF_IS_LONG 1
+#define SIZEOF_IS_ULONG 1
+#elif __i386__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __m68k__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __ns32k__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __sparc__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#elif __vax__
+#define PTRDIFF_IS_LONG 0
+#define SIZEOF_IS_ULONG 0
+#else
+#error unknown machine type
+#endif
+
+/*
+ * Make sure this matches wchar_t.
+ */
+#define WCHAR SHORT
+
+#ifndef __GNUC__
+#ifndef lint
+#ifndef QUAD_MAX /* necessary for mkdep */
+#define QUAD_MAX LONG_MAX
+#define QUAD_MIN LONG_MIN
+#define UQUAD_MAX ULONG_MAX
+#endif
+typedef long quad_t;
+typedef u_long u_quad_t;
+#endif
+#endif
+
+
+/*
+ * long double only in ANSI C.
+ */
+#ifdef __STDC__
+typedef long double ldbl_t;
+#else
+typedef double ldbl_t;
+#endif
+
+/*
+ * Some traditional compilers are not able to assign structures.
+ */
+#ifdef __STDC__
+#define STRUCT_ASSIGN(dest, src) (dest) = (src)
+#else
+#define STRUCT_ASSIGN(dest, src) (void)memcpy(&(dest), &(src), \
+ sizeof (dest));
+#endif
diff --git a/usr.bin/xlint/lint1/scan.l b/usr.bin/xlint/lint1/scan.l
new file mode 100644
index 0000000..5e23c6b
--- /dev/null
+++ b/usr.bin/xlint/lint1/scan.l
@@ -0,0 +1,1426 @@
+%{
+/* $NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <float.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <err.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+#define CHAR_MASK (~(~0 << CHAR_BIT))
+
+/* XXX declaration of strtouq() is missing in stdlib.h ? */
+extern u_quad_t strtouq __P((const char *, char **, int));
+
+/* Current position (its also updated when an included file is parsed) */
+pos_t curr_pos = { 1, "" };
+
+/*
+ * Current position in C source (not updated when an included file is
+ * parsed).
+ */
+pos_t csrc_pos = { 1, "" };
+
+static void incline __P((void));
+static void badchar __P((int));
+static sbuf_t *allocsb __P((void));
+static void freesb __P((sbuf_t *));
+static int inpc __P((void));
+static int hash __P((const char *));
+static sym_t *search __P((sbuf_t *));
+static int name __P((void));
+static int keyw __P((sym_t *));
+static int icon __P((int));
+static int fcon __P((void));
+static int operator __P((int, op_t));
+static int ccon __P((void));
+static int wccon __P((void));
+static int getescc __P((int));
+static void directive __P((void));
+static void comment __P((void));
+static int string __P((void));
+static int wcstrg __P((void));
+
+%}
+
+L [_A-Za-z]
+D [0-9]
+NZD [1-9]
+OD [0-7]
+HD [0-9A-Fa-f]
+EX ([eE][+-]?[0-9]+)
+
+%%
+
+{L}({L}|{D})* return (name());
+0{OD}*[lLuU]* return (icon(8));
+{NZD}{D}*[lLuU]* return (icon(10));
+0[xX]{HD}+[lLuU]* return (icon(16));
+{D}+\.{D}*{EX}?[fFlL]? |
+{D}+{EX}[fFlL]? |
+\.{D}+{EX}?[fFlL]? return (fcon());
+"=" return (operator(T_ASSIGN, ASSIGN));
+"*=" return (operator(T_OPASS, MULASS));
+"/=" return (operator(T_OPASS, DIVASS));
+"%=" return (operator(T_OPASS, MODASS));
+"+=" return (operator(T_OPASS, ADDASS));
+"-=" return (operator(T_OPASS, SUBASS));
+"<<=" return (operator(T_OPASS, SHLASS));
+">>=" return (operator(T_OPASS, SHRASS));
+"&=" return (operator(T_OPASS, ANDASS));
+"^=" return (operator(T_OPASS, XORASS));
+"|=" return (operator(T_OPASS, ORASS));
+"||" return (operator(T_LOGOR, LOGOR));
+"&&" return (operator(T_LOGAND, LOGAND));
+"|" return (operator(T_OR, OR));
+"&" return (operator(T_AND, AND));
+"^" return (operator(T_XOR, XOR));
+"==" return (operator(T_EQOP, EQ));
+"!=" return (operator(T_EQOP, NE));
+"<" return (operator(T_RELOP, LT));
+">" return (operator(T_RELOP, GT));
+"<=" return (operator(T_RELOP, LE));
+">=" return (operator(T_RELOP, GE));
+"<<" return (operator(T_SHFTOP, SHL));
+">>" return (operator(T_SHFTOP, SHR));
+"++" return (operator(T_INCDEC, INC));
+"--" return (operator(T_INCDEC, DEC));
+"->" return (operator(T_STROP, ARROW));
+"." return (operator(T_STROP, POINT));
+"+" return (operator(T_ADDOP, PLUS));
+"-" return (operator(T_ADDOP, MINUS));
+"*" return (operator(T_MULT, MULT));
+"/" return (operator(T_DIVOP, DIV));
+"%" return (operator(T_DIVOP, MOD));
+"!" return (operator(T_UNOP, NOT));
+"~" return (operator(T_UNOP, COMPL));
+"\"" return (string());
+"L\"" return (wcstrg());
+";" return (T_SEMI);
+"{" return (T_LBRACE);
+"}" return (T_RBRACE);
+"," return (T_COMMA);
+":" return (T_COLON);
+"?" return (T_QUEST);
+"[" return (T_LBRACK);
+"]" return (T_RBRACK);
+"(" return (T_LPARN);
+")" return (T_RPARN);
+"..." return (T_ELLIPSE);
+"'" return (ccon());
+"L'" return (wccon());
+^#.*$ directive();
+\n incline();
+\t|" "|\f|\v ;
+"/*" comment();
+. badchar(yytext[0]);
+
+%%
+
+static void
+incline()
+{
+ curr_pos.p_line++;
+ if (curr_pos.p_file == csrc_pos.p_file)
+ csrc_pos.p_line++;
+}
+
+static void
+badchar(c)
+ int c;
+{
+ /* unknown character \%o */
+ error(250, c);
+}
+
+/*
+ * Keywords.
+ * During initialisation they are written to the symbol table.
+ */
+static struct kwtab {
+ const char *kw_name; /* keyword */
+ int kw_token; /* token returned by yylex() */
+ scl_t kw_scl; /* storage class if kw_token T_SCLASS */
+ tspec_t kw_tspec; /* type spec. if kw_token T_TYPE or T_SOU */
+ tqual_t kw_tqual; /* type qual. fi kw_token T_QUAL */
+ u_int kw_stdc : 1; /* STDC keyword */
+ u_int kw_gcc : 1; /* GCC keyword */
+} kwtab[] = {
+ { "asm", T_ASM, 0, 0, 0, 0, 1 },
+ { "__asm", T_ASM, 0, 0, 0, 0, 0 },
+ { "__asm__", T_ASM, 0, 0, 0, 0, 0 },
+ { "auto", T_SCLASS, AUTO, 0, 0, 0, 0 },
+ { "break", T_BREAK, 0, 0, 0, 0, 0 },
+ { "case", T_CASE, 0, 0, 0, 0, 0 },
+ { "char", T_TYPE, 0, CHAR, 0, 0, 0 },
+ { "const", T_QUAL, 0, 0, CONST, 1, 0 },
+ { "__const__", T_QUAL, 0, 0, CONST, 0, 0 },
+ { "__const", T_QUAL, 0, 0, CONST, 0, 0 },
+ { "continue", T_CONTINUE, 0, 0, 0, 0, 0 },
+ { "default", T_DEFAULT, 0, 0, 0, 0, 0 },
+ { "do", T_DO, 0, 0, 0, 0, 0 },
+ { "double", T_TYPE, 0, DOUBLE, 0, 0, 0 },
+ { "else", T_ELSE, 0, 0, 0, 0, 0 },
+ { "enum", T_ENUM, 0, 0, 0, 0, 0 },
+ { "extern", T_SCLASS, EXTERN, 0, 0, 0, 0 },
+ { "float", T_TYPE, 0, FLOAT, 0, 0, 0 },
+ { "for", T_FOR, 0, 0, 0, 0, 0 },
+ { "goto", T_GOTO, 0, 0, 0, 0, 0 },
+ { "if", T_IF, 0, 0, 0, 0, 0 },
+ { "inline", T_SCLASS, INLINE, 0, 0, 0, 1 },
+ { "__inline__", T_SCLASS, INLINE, 0, 0, 0, 0 },
+ { "__inline", T_SCLASS, INLINE, 0, 0, 0, 0 },
+ { "int", T_TYPE, 0, INT, 0, 0, 0 },
+ { "long", T_TYPE, 0, LONG, 0, 0, 0 },
+ { "register", T_SCLASS, REG, 0, 0, 0, 0 },
+ { "return", T_RETURN, 0, 0, 0, 0, 0 },
+ { "short", T_TYPE, 0, SHORT, 0, 0, 0 },
+ { "signed", T_TYPE, 0, SIGNED, 0, 1, 0 },
+ { "__signed__", T_TYPE, 0, SIGNED, 0, 0, 0 },
+ { "__signed", T_TYPE, 0, SIGNED, 0, 0, 0 },
+ { "sizeof", T_SIZEOF, 0, 0, 0, 0, 0 },
+ { "static", T_SCLASS, STATIC, 0, 0, 0, 0 },
+ { "struct", T_SOU, 0, STRUCT, 0, 0, 0 },
+ { "switch", T_SWITCH, 0, 0, 0, 0, 0 },
+ { "typedef", T_SCLASS, TYPEDEF, 0, 0, 0, 0 },
+ { "union", T_SOU, 0, UNION, 0, 0, 0 },
+ { "unsigned", T_TYPE, 0, UNSIGN, 0, 0, 0 },
+ { "void", T_TYPE, 0, VOID, 0, 0, 0 },
+ { "volatile", T_QUAL, 0, 0, VOLATILE, 1, 0 },
+ { "__volatile__", T_QUAL, 0, 0, VOLATILE, 0, 0 },
+ { "__volatile", T_QUAL, 0, 0, VOLATILE, 0, 0 },
+ { "while", T_WHILE, 0, 0, 0, 0, 0 },
+ { NULL, 0, 0, 0, 0, 0, 0 }
+};
+
+/* Symbol table */
+static sym_t *symtab[HSHSIZ1];
+
+/* bit i of the entry with index i is set */
+u_quad_t qbmasks[sizeof(u_quad_t) * CHAR_BIT];
+
+/* least significant i bits are set in the entry with index i */
+u_quad_t qlmasks[sizeof(u_quad_t) * CHAR_BIT + 1];
+
+/* least significant i bits are not set in the entry with index i */
+u_quad_t qumasks[sizeof(u_quad_t) * CHAR_BIT + 1];
+
+/* free list for sbuf structures */
+static sbuf_t *sbfrlst;
+
+/* Typ of next expected symbol */
+symt_t symtyp;
+
+
+/*
+ * All keywords are written to the symbol table. This saves us looking
+ * in a extra table for each name we found.
+ */
+void
+initscan()
+{
+ struct kwtab *kw;
+ sym_t *sym;
+ int h, i;
+ u_quad_t uq;
+
+ for (kw = kwtab; kw->kw_name != NULL; kw++) {
+ if (kw->kw_stdc && tflag)
+ continue;
+ if (kw->kw_gcc && !gflag)
+ continue;
+ sym = getblk(sizeof (sym_t));
+ sym->s_name = kw->kw_name;
+ sym->s_keyw = 1;
+ sym->s_value.v_quad = kw->kw_token;
+ if (kw->kw_token == T_TYPE || kw->kw_token == T_SOU) {
+ sym->s_tspec = kw->kw_tspec;
+ } else if (kw->kw_token == T_SCLASS) {
+ sym->s_scl = kw->kw_scl;
+ } else if (kw->kw_token == T_QUAL) {
+ sym->s_tqual = kw->kw_tqual;
+ }
+ h = hash(sym->s_name);
+ if ((sym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &sym->s_link;
+ (symtab[h] = sym)->s_rlink = &symtab[h];
+ }
+
+ /* initialize bit-masks for quads */
+ for (i = 0; i < sizeof (u_quad_t) * CHAR_BIT; i++) {
+ qbmasks[i] = (u_quad_t)1 << i;
+ uq = ~(u_quad_t)0 << i;
+ qumasks[i] = uq;
+ qlmasks[i] = ~uq;
+ }
+ qumasks[i] = 0;
+ qlmasks[i] = ~(u_quad_t)0;
+}
+
+/*
+ * Get a free sbuf structure, if possible from the free list
+ */
+static sbuf_t *
+allocsb()
+{
+ sbuf_t *sb;
+
+ if ((sb = sbfrlst) != NULL) {
+ sbfrlst = sb->sb_nxt;
+ } else {
+ sb = xmalloc(sizeof (sbuf_t));
+ }
+ (void)memset(sb, 0, sizeof (sb));
+ return (sb);
+}
+
+/*
+ * Put a sbuf structure to the free list
+ */
+static void
+freesb(sb)
+ sbuf_t *sb;
+{
+ sb->sb_nxt = sbfrlst;
+ sbfrlst = sb;
+}
+
+/*
+ * Read a character and ensure that it is positive (except EOF).
+ * Increment line count(s) if necessary.
+ */
+static int
+inpc()
+{
+ int c;
+
+ if ((c = input()) != EOF && (c &= CHAR_MASK) == '\n')
+ incline();
+ return (c);
+}
+
+static int
+hash(s)
+ const char *s;
+{
+ u_int v;
+ const u_char *us;
+
+ v = 0;
+ for (us = (const u_char *)s; *us != '\0'; us++) {
+ v = (v << sizeof (v)) + *us;
+ v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
+ }
+ return (v % HSHSIZ1);
+}
+
+/*
+ * Lex has found a letter followed by zero or more letters or digits.
+ * It looks for a symbol in the symbol table with the same name. This
+ * symbol must either be a keyword or a symbol of the type required by
+ * symtyp (label, member, tag, ...).
+ *
+ * If it is a keyword, the token is returned. In some cases it is described
+ * more deeply by data written to yylval.
+ *
+ * If it is a symbol, T_NAME is returned and the pointer to a sbuf struct
+ * is stored in yylval. This struct contains the name of the symbol, it's
+ * length and hash value. If there is already a symbol of the same name
+ * and type in the symbol table, the sbuf struct also contains a pointer
+ * to the symbol table entry.
+ */
+static int
+name()
+{
+ char *s;
+ sbuf_t *sb;
+ sym_t *sym;
+ int tok;
+
+ sb = allocsb();
+ sb->sb_name = yytext;
+ sb->sb_len = yyleng;
+ sb->sb_hash = hash(yytext);
+
+ if ((sym = search(sb)) != NULL && sym->s_keyw) {
+ freesb(sb);
+ return (keyw(sym));
+ }
+
+ sb->sb_sym = sym;
+
+ if (sym != NULL) {
+ if (blklev < sym->s_blklev)
+ lerror("name() 1");
+ sb->sb_name = sym->s_name;
+ sb->sb_len = strlen(sym->s_name);
+ tok = sym->s_scl == TYPEDEF ? T_TYPENAME : T_NAME;
+ } else {
+ s = getblk(yyleng + 1);
+ (void)memcpy(s, yytext, yyleng + 1);
+ sb->sb_name = s;
+ sb->sb_len = yyleng;
+ tok = T_NAME;
+ }
+
+ yylval.y_sb = sb;
+ return (tok);
+}
+
+static sym_t *
+search(sb)
+ sbuf_t *sb;
+{
+ sym_t *sym;
+
+ for (sym = symtab[sb->sb_hash]; sym != NULL; sym = sym->s_link) {
+ if (strcmp(sym->s_name, sb->sb_name) == 0) {
+ if (sym->s_keyw || sym->s_kind == symtyp)
+ return (sym);
+ }
+ }
+
+ return (NULL);
+}
+
+static int
+keyw(sym)
+ sym_t *sym;
+{
+ int t;
+
+ if ((t = (int)sym->s_value.v_quad) == T_SCLASS) {
+ yylval.y_scl = sym->s_scl;
+ } else if (t == T_TYPE || t == T_SOU) {
+ yylval.y_tspec = sym->s_tspec;
+ } else if (t == T_QUAL) {
+ yylval.y_tqual = sym->s_tqual;
+ }
+ return (t);
+}
+
+/*
+ * Convert a string representing an integer into internal representation.
+ * The value is returned in yylval. icon() (and yylex()) returns T_CON.
+ */
+static int
+icon(base)
+ int base;
+{
+ int l_suffix, u_suffix;
+ int len;
+ const char *cp;
+ char c, *eptr;
+ tspec_t typ;
+ u_long ul;
+ u_quad_t uq;
+ int ansiu;
+ static tspec_t contypes[2][3] = {
+ { INT, LONG, QUAD },
+ { UINT, ULONG, UQUAD }
+ };
+
+ cp = yytext;
+ len = yyleng;
+
+ /* skip 0x */
+ if (base == 16) {
+ cp += 2;
+ len -= 2;
+ }
+
+ /* read suffixes */
+ l_suffix = u_suffix = 0;
+ for ( ; ; ) {
+ if ((c = cp[len - 1]) == 'l' || c == 'L') {
+ l_suffix++;
+ } else if (c == 'u' || c == 'U') {
+ u_suffix++;
+ } else {
+ break;
+ }
+ len--;
+ }
+ if (l_suffix > 2 || u_suffix > 1) {
+ /* malformed integer constant */
+ warning(251);
+ if (l_suffix > 2)
+ l_suffix = 2;
+ if (u_suffix > 1)
+ u_suffix = 1;
+ }
+ if (tflag && u_suffix != 0) {
+ /* suffix U is illegal in traditional C */
+ warning(97);
+ }
+ typ = contypes[u_suffix][l_suffix];
+
+ errno = 0;
+ if (l_suffix < 2) {
+ ul = strtoul(cp, &eptr, base);
+ } else {
+ uq = strtouq(cp, &eptr, base);
+ }
+ if (eptr != cp + len)
+ lerror("icon() 1");
+ if (errno != 0)
+ /* integer constant out of range */
+ warning(252);
+
+ /*
+ * If the value is to big for the current type, we must choose
+ * another type.
+ */
+ ansiu = 0;
+ switch (typ) {
+ case INT:
+ if (ul <= INT_MAX) {
+ /* ok */
+ } else if (ul <= (unsigned)UINT_MAX && base != 10) {
+ typ = UINT;
+ } else if (ul <= LONG_MAX) {
+ typ = LONG;
+ } else {
+ typ = ULONG;
+ }
+ if (typ == UINT || typ == ULONG) {
+ if (tflag) {
+ typ = LONG;
+ } else if (!sflag) {
+ /*
+ * Remember that the constant is unsigned
+ * only in ANSI C
+ */
+ ansiu = 1;
+ }
+ }
+ break;
+ case UINT:
+ if (ul > (u_int)UINT_MAX)
+ typ = ULONG;
+ break;
+ case LONG:
+ if (ul > LONG_MAX && !tflag) {
+ typ = ULONG;
+ if (!sflag)
+ ansiu = 1;
+ }
+ break;
+ case QUAD:
+ if (uq > QUAD_MAX && !tflag) {
+ typ = UQUAD;
+ if (!sflag)
+ ansiu = 1;
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ if (typ != QUAD && typ != UQUAD) {
+ if (isutyp(typ)) {
+ uq = ul;
+ } else {
+ uq = (quad_t)(long)ul;
+ }
+ }
+
+ uq = (u_quad_t)xsign((quad_t)uq, typ, -1);
+
+ (yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ;
+ yylval.y_val->v_ansiu = ansiu;
+ yylval.y_val->v_quad = (quad_t)uq;
+
+ return (T_CON);
+}
+
+/*
+ * Returns 1 if t is a signed type and the value is negative.
+ *
+ * len is the number of significant bits. If len is -1, len is set
+ * to the width of type t.
+ */
+int
+sign(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (t == PTR || isutyp(t))
+ return (0);
+ return (msb(q, t, len));
+}
+
+int
+msb(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (len <= 0)
+ len = size(t);
+ return ((q & qbmasks[len - 1]) != 0);
+}
+
+/*
+ * Extends the sign of q.
+ */
+quad_t
+xsign(q, t, len)
+ quad_t q;
+ tspec_t t;
+ int len;
+{
+ if (len <= 0)
+ len = size(t);
+
+ if (t == PTR || isutyp(t) || !sign(q, t, len)) {
+ q &= qlmasks[len];
+ } else {
+ q |= qumasks[len];
+ }
+ return (q);
+}
+
+/*
+ * Convert a string representing a floating point value into its interal
+ * representation. Type and value are returned in yylval. fcon()
+ * (and yylex()) returns T_CON.
+ * XXX Currently it is not possible to convert constants of type
+ * long double which are greater then DBL_MAX.
+ */
+static int
+fcon()
+{
+ const char *cp;
+ int len;
+ tspec_t typ;
+ char c, *eptr;
+ double d;
+ float f;
+
+ cp = yytext;
+ len = yyleng;
+
+ if ((c = cp[len - 1]) == 'f' || c == 'F') {
+ typ = FLOAT;
+ len--;
+ } else if (c == 'l' || c == 'L') {
+ typ = LDOUBLE;
+ len--;
+ } else {
+ typ = DOUBLE;
+ }
+
+ if (tflag && typ != DOUBLE) {
+ /* suffixes F and L are illegal in traditional C */
+ warning(98);
+ }
+
+ errno = 0;
+ d = strtod(cp, &eptr);
+ if (eptr != cp + len)
+ lerror("fcon() 1");
+ if (errno != 0)
+ /* floating-point constant out of range */
+ warning(248);
+
+ if (typ == FLOAT) {
+ f = (float)d;
+ if (isinf(f)) {
+ /* floating-point constant out of range */
+ warning(248);
+ f = f > 0 ? FLT_MAX : -FLT_MAX;
+ }
+ }
+
+ (yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ;
+ if (typ == FLOAT) {
+ yylval.y_val->v_ldbl = f;
+ } else {
+ yylval.y_val->v_ldbl = d;
+ }
+
+ return (T_CON);
+}
+
+static int
+operator(t, o)
+ int t;
+ op_t o;
+{
+ yylval.y_op = o;
+ return (t);
+}
+
+/*
+ * Called if lex found a leading \'.
+ */
+static int
+ccon()
+{
+ int n, val, c;
+ char cv;
+
+ n = 0;
+ val = 0;
+ while ((c = getescc('\'')) >= 0) {
+ val = (val << CHAR_BIT) + c;
+ n++;
+ }
+ if (c == -2) {
+ /* unterminated character constant */
+ error(253);
+ } else {
+ if (n > sizeof (int) || (n > 1 && (pflag || hflag))) {
+ /* too many characters in character constant */
+ error(71);
+ } else if (n > 1) {
+ /* multi-character character constant */
+ warning(294);
+ } else if (n == 0) {
+ /* empty character constant */
+ error(73);
+ }
+ }
+ if (n == 1) {
+ cv = (char)val;
+ val = cv;
+ }
+
+ yylval.y_val = xcalloc(1, sizeof (val_t));
+ yylval.y_val->v_tspec = INT;
+ yylval.y_val->v_quad = val;
+
+ return (T_CON);
+}
+
+/*
+ * Called if lex found a leading L\'
+ */
+static int
+wccon()
+{
+ static char buf[MB_LEN_MAX + 1];
+ int i, c;
+ wchar_t wc;
+
+ i = 0;
+ while ((c = getescc('\'')) >= 0) {
+ if (i < MB_CUR_MAX)
+ buf[i] = (char)c;
+ i++;
+ }
+
+ wc = 0;
+
+ if (c == -2) {
+ /* unterminated character constant */
+ error(253);
+ } else if (c == 0) {
+ /* empty character constant */
+ error(73);
+ } else {
+ if (i > MB_CUR_MAX) {
+ i = MB_CUR_MAX;
+ /* too many characters in character constant */
+ error(71);
+ } else {
+ buf[i] = '\0';
+ (void)mbtowc(NULL, NULL, 0);
+ if (mbtowc(&wc, buf, MB_CUR_MAX) < 0)
+ /* invalid multibyte character */
+ error(291);
+ }
+ }
+
+ yylval.y_val = xcalloc(1, sizeof (val_t));
+ yylval.y_val->v_tspec = WCHAR;
+ yylval.y_val->v_quad = wc;
+
+ return (T_CON);
+}
+
+/*
+ * Read a character which is part of a character constant or of a string
+ * and handle escapes.
+ *
+ * The Argument is the character which delimits the character constant or
+ * string.
+ *
+ * Returns -1 if the end of the character constant or string is reached,
+ * -2 if the EOF is reached, and the charachter otherwise.
+ */
+static int
+getescc(d)
+ int d;
+{
+ static int pbc = -1;
+ int n, c, v;
+
+ if (pbc == -1) {
+ c = inpc();
+ } else {
+ c = pbc;
+ pbc = -1;
+ }
+ if (c == d)
+ return (-1);
+ switch (c) {
+ case '\n':
+ /* newline in string or char constant */
+ error(254);
+ return (-2);
+ case EOF:
+ return (-2);
+ case '\\':
+ switch (c = inpc()) {
+ case '"':
+ if (tflag && d == '\'')
+ /* \" inside character constant undef. ... */
+ warning(262);
+ return ('"');
+ case '\'':
+ return ('\'');
+ case '?':
+ if (tflag)
+ /* \? undefined in traditional C */
+ warning(263);
+ return ('?');
+ case '\\':
+ return ('\\');
+ case 'a':
+ if (tflag)
+ /* \a undefined in traditional C */
+ warning(81);
+#ifdef __STDC__
+ return ('\a');
+#else
+ return ('\007');
+#endif
+ case 'b':
+ return ('\b');
+ case 'f':
+ return ('\f');
+ case 'n':
+ return ('\n');
+ case 'r':
+ return ('\r');
+ case 't':
+ return ('\t');
+ case 'v':
+ if (tflag)
+ /* \v undefined in traditional C */
+ warning(264);
+#ifdef __STDC__
+ return ('\v');
+#else
+ return ('\013');
+#endif
+ case '8': case '9':
+ /* bad octal digit %c */
+ warning(77, c);
+ /* FALLTHROUGH */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ n = 3;
+ v = 0;
+ do {
+ v = (v << 3) + (c - '0');
+ c = inpc();
+ } while (--n && isdigit(c) && (tflag || c <= '7'));
+ if (tflag && n > 0 && isdigit(c))
+ /* bad octal digit %c */
+ warning(77, c);
+ pbc = c;
+ if (v > UCHAR_MAX) {
+ /* character escape does not fit in char. */
+ warning(76);
+ v &= CHAR_MASK;
+ }
+ return (v);
+ case 'x':
+ if (tflag)
+ /* \x undefined in traditional C */
+ warning(82);
+ v = 0;
+ n = 0;
+ while ((c = inpc()) >= 0 && isxdigit(c)) {
+ c = isdigit(c) ?
+ c - '0' : toupper(c) - 'A' + 10;
+ v = (v << 4) + c;
+ if (n >= 0) {
+ if ((v & ~CHAR_MASK) != 0) {
+ /* overflow in hex escape */
+ warning(75);
+ n = -1;
+ } else {
+ n++;
+ }
+ }
+ }
+ pbc = c;
+ if (n == 0) {
+ /* no hex digits follow \x */
+ error(74);
+ } if (n == -1) {
+ v &= CHAR_MASK;
+ }
+ return (v);
+ case '\n':
+ return (getescc(d));
+ case EOF:
+ return (-2);
+ default:
+ if (isprint(c)) {
+ /* dubious escape \%c */
+ warning(79, c);
+ } else {
+ /* dubious escape \%o */
+ warning(80, c);
+ }
+ }
+ }
+ return (c);
+}
+
+/*
+ * Called for preprocessor directives. Currently implemented are:
+ * # lineno
+ * # lineno "filename"
+ */
+static void
+directive()
+{
+ const char *cp, *fn;
+ char c, *eptr;
+ size_t fnl;
+ long ln;
+ static int first = 1;
+
+ /* Go to first non-whitespace after # */
+ for (cp = yytext + 1; (c = *cp) == ' ' || c == '\t'; cp++) ;
+
+ if (!isdigit(c)) {
+ error:
+ /* undefined or invalid # directive */
+ warning(255);
+ return;
+ }
+ ln = strtol(--cp, &eptr, 10);
+ if (cp == eptr)
+ goto error;
+ if ((c = *(cp = eptr)) != ' ' && c != '\t' && c != '\0')
+ goto error;
+ while ((c = *cp++) == ' ' || c == '\t') ;
+ if (c != '\0') {
+ if (c != '"')
+ goto error;
+ fn = cp;
+ while ((c = *cp) != '"' && c != '\0')
+ cp++;
+ if (c != '"')
+ goto error;
+ if ((fnl = cp++ - fn) > PATH_MAX)
+ goto error;
+ while ((c = *cp++) == ' ' || c == '\t') ;
+#if 0
+ if (c != '\0')
+ warning("extra character(s) after directive");
+#endif
+ curr_pos.p_file = fnnalloc(fn, fnl);
+ /*
+ * If this is the first directive, the name is the name
+ * of the C source file as specified at the command line.
+ * It is written to the output file.
+ */
+ if (first) {
+ csrc_pos.p_file = curr_pos.p_file;
+ outsrc(curr_pos.p_file);
+ first = 0;
+ }
+ }
+ curr_pos.p_line = (int)ln - 1;
+ if (curr_pos.p_file == csrc_pos.p_file)
+ csrc_pos.p_line = (int)ln - 1;
+}
+
+/*
+ * Handle lint comments. Following comments are currently understood:
+ * ARGSUSEDn
+ * CONSTCOND CONSTANTCOND CONSTANTCONDITION
+ * FALLTHRU FALLTHROUGH
+ * LINTLIBRARY
+ * LINTED NOSTRICT
+ * LONGLONG
+ * NOTREACHED
+ * PRINTFLIKEn
+ * PROTOLIB
+ * SCANFLIKEn
+ * VARARGSn
+ * If one of this comments is recognized, the arguments, if any, are
+ * parsed and a function which handles this comment is called.
+ */
+static void
+comment()
+{
+ int c, lc;
+ static struct {
+ const char *keywd;
+ int arg;
+ void (*func) __P((int));
+ } keywtab[] = {
+ { "ARGSUSED", 1, argsused },
+ { "CONSTCOND", 0, constcond },
+ { "CONSTANTCOND", 0, constcond },
+ { "CONSTANTCONDITION", 0, constcond },
+ { "FALLTHRU", 0, fallthru },
+ { "FALLTHROUGH", 0, fallthru },
+ { "LINTLIBRARY", 0, lintlib },
+ { "LINTED", 0, linted },
+ { "LONGLONG", 0, longlong },
+ { "NOSTRICT", 0, linted },
+ { "NOTREACHED", 0, notreach },
+ { "PRINTFLIKE", 1, printflike },
+ { "PROTOLIB", 1, protolib },
+ { "SCANFLIKE", 1, scanflike },
+ { "VARARGS", 1, varargs },
+ };
+ char keywd[32];
+ char arg[32];
+ int l, i, a;
+ int eoc;
+
+ eoc = 0;
+
+ /* Skip white spaces after the start of the comment */
+ while ((c = inpc()) != EOF && isspace(c)) ;
+
+ /* Read the potential keyword to keywd */
+ l = 0;
+ while (c != EOF && isupper(c) && l < sizeof (keywd) - 1) {
+ keywd[l++] = (char)c;
+ c = inpc();
+ }
+ keywd[l] = '\0';
+
+ /* look for the keyword */
+ for (i = 0; i < sizeof (keywtab) / sizeof (keywtab[0]); i++) {
+ if (strcmp(keywtab[i].keywd, keywd) == 0)
+ break;
+ }
+ if (i == sizeof (keywtab) / sizeof (keywtab[0]))
+ goto skip_rest;
+
+ /* skip white spaces after the keyword */
+ while (c != EOF && isspace(c))
+ c = inpc();
+
+ /* read the argument, if the keyword accepts one and there is one */
+ l = 0;
+ if (keywtab[i].arg) {
+ while (c != EOF && isdigit(c) && l < sizeof (arg) - 1) {
+ arg[l++] = (char)c;
+ c = inpc();
+ }
+ }
+ arg[l] = '\0';
+ a = l != 0 ? atoi(arg) : -1;
+
+ /* skip white spaces after the argument */
+ while (c != EOF && isspace(c))
+ c = inpc();
+
+ if (c != '*' || (c = inpc()) != '/') {
+ if (keywtab[i].func != linted)
+ /* extra characters in lint comment */
+ warning(257);
+ } else {
+ /*
+ * remember that we have already found the end of the
+ * comment
+ */
+ eoc = 1;
+ }
+
+ if (keywtab[i].func != NULL)
+ (*keywtab[i].func)(a);
+
+ skip_rest:
+ while (!eoc) {
+ lc = c;
+ if ((c = inpc()) == EOF) {
+ /* unterminated comment */
+ error(256);
+ break;
+ }
+ if (lc == '*' && c == '/')
+ eoc = 1;
+ }
+}
+
+/*
+ * Clear flags for lint comments LINTED, LONGLONG and CONSTCOND.
+ * clrwflgs() is called after function definitions and global and
+ * local declarations and definitions. It is also called between
+ * the controlling expression and the body of control statements
+ * (if, switch, for, while).
+ */
+void
+clrwflgs()
+{
+ nowarn = 0;
+ quadflg = 0;
+ ccflg = 0;
+}
+
+/*
+ * Strings are stored in a dynamically alloceted buffer and passed
+ * in yylval.y_xstrg to the parser. The parser or the routines called
+ * by the parser are responsible for freeing this buffer.
+ */
+static int
+string()
+{
+ u_char *s;
+ int c;
+ size_t len, max;
+ strg_t *strg;
+
+ s = xmalloc(max = 64);
+
+ len = 0;
+ while ((c = getescc('"')) >= 0) {
+ /* +1 to reserve space for a trailing NUL character */
+ if (len + 1 == max)
+ s = xrealloc(s, max *= 2);
+ s[len++] = (char)c;
+ }
+ s[len] = '\0';
+ if (c == -2)
+ /* unterminated string constant */
+ error(258);
+
+ strg = xcalloc(1, sizeof (strg_t));
+ strg->st_tspec = CHAR;
+ strg->st_len = len;
+ strg->st_cp = s;
+
+ yylval.y_strg = strg;
+ return (T_STRING);
+}
+
+static int
+wcstrg()
+{
+ char *s;
+ int c, i, n, wi;
+ size_t len, max, wlen;
+ wchar_t *ws;
+ strg_t *strg;
+
+ s = xmalloc(max = 64);
+ len = 0;
+ while ((c = getescc('"')) >= 0) {
+ /* +1 to save space for a trailing NUL character */
+ if (len + 1 >= max)
+ s = xrealloc(s, max *= 2);
+ s[len++] = (char)c;
+ }
+ s[len] = '\0';
+ if (c == -2)
+ /* unterminated string constant */
+ error(258);
+
+ /* get length of wide character string */
+ (void)mblen(NULL, 0);
+ for (i = 0, wlen = 0; i < len; i += n, wlen++) {
+ if ((n = mblen(&s[i], MB_CUR_MAX)) == -1) {
+ /* invalid multibyte character */
+ error(291);
+ break;
+ }
+ if (n == 0)
+ n = 1;
+ }
+
+ ws = xmalloc((wlen + 1) * sizeof (wchar_t));
+
+ /* convert from multibyte to wide char */
+ (void)mbtowc(NULL, NULL, 0);
+ for (i = 0, wi = 0; i < len; i += n, wi++) {
+ if ((n = mbtowc(&ws[wi], &s[i], MB_CUR_MAX)) == -1)
+ break;
+ if (n == 0)
+ n = 1;
+ }
+ ws[wi] = 0;
+ free(s);
+
+ strg = xcalloc(1, sizeof (strg_t));
+ strg->st_tspec = WCHAR;
+ strg->st_len = wlen;
+ strg->st_wcp = ws;
+
+ yylval.y_strg = strg;
+ return (T_STRING);
+}
+
+/*
+ * As noted above the scanner does not create new symbol table entries
+ * for symbols it cannot find in the symbol table. This is to avoid
+ * putting undeclared symbols into the symbol table if a syntax error
+ * occurs.
+ *
+ * getsym() is called as soon as it is probably ok to put the symbol to
+ * the symbol table. This does not mean that it is not possible that
+ * symbols are put to the symbol table which are than not completely
+ * declared due to syntax errors. To avoid too many problems in this
+ * case symbols get type int in getsym().
+ *
+ * XXX calls to getsym() should be delayed until decl1*() is called
+ */
+sym_t *
+getsym(sb)
+ sbuf_t *sb;
+{
+ dinfo_t *di;
+ char *s;
+ sym_t *sym;
+
+ sym = sb->sb_sym;
+
+ /*
+ * During member declaration it is possible that name() looked
+ * for symbols of type FVFT, although it should have looked for
+ * symbols of type FTAG. Same can happen for labels. Both cases
+ * are compensated here.
+ */
+ if (symtyp == FMOS || symtyp == FLAB) {
+ if (sym == NULL || sym->s_kind == FVFT)
+ sym = search(sb);
+ }
+
+ if (sym != NULL) {
+ if (sym->s_kind != symtyp)
+ lerror("storesym() 1");
+ symtyp = FVFT;
+ freesb(sb);
+ return (sym);
+ }
+
+ /* create a new symbol table entry */
+
+ /* labels must always be allocated at level 1 (outhermost block) */
+ if (symtyp == FLAB) {
+ sym = getlblk(1, sizeof (sym_t));
+ s = getlblk(1, sb->sb_len + 1);
+ (void)memcpy(s, sb->sb_name, sb->sb_len + 1);
+ sym->s_name = s;
+ sym->s_blklev = 1;
+ di = dcs;
+ while (di->d_nxt != NULL && di->d_nxt->d_nxt != NULL)
+ di = di->d_nxt;
+ if (di->d_ctx != AUTO)
+ lerror("storesym() 2");
+ } else {
+ sym = getblk(sizeof (sym_t));
+ sym->s_name = sb->sb_name;
+ sym->s_blklev = blklev;
+ di = dcs;
+ }
+
+ STRUCT_ASSIGN(sym->s_dpos, curr_pos);
+ if ((sym->s_kind = symtyp) != FLAB)
+ sym->s_type = gettyp(INT);
+
+ symtyp = FVFT;
+
+ if ((sym->s_link = symtab[sb->sb_hash]) != NULL)
+ symtab[sb->sb_hash]->s_rlink = &sym->s_link;
+ (symtab[sb->sb_hash] = sym)->s_rlink = &symtab[sb->sb_hash];
+
+ *di->d_ldlsym = sym;
+ di->d_ldlsym = &sym->s_dlnxt;
+
+ freesb(sb);
+ return (sym);
+}
+
+/*
+ * Remove a symbol forever from the symbol table. s_blklev
+ * is set to -1 to avoid that the symbol will later be put
+ * back to the symbol table.
+ */
+void
+rmsym(sym)
+ sym_t *sym;
+{
+ if ((*sym->s_rlink = sym->s_link) != NULL)
+ sym->s_link->s_rlink = sym->s_rlink;
+ sym->s_blklev = -1;
+ sym->s_link = NULL;
+}
+
+/*
+ * Remove a list of symbols declared at one level from the symbol
+ * table.
+ */
+void
+rmsyms(syms)
+ sym_t *syms;
+{
+ sym_t *sym;
+
+ for (sym = syms; sym != NULL; sym = sym->s_dlnxt) {
+ if (sym->s_blklev != -1) {
+ if ((*sym->s_rlink = sym->s_link) != NULL)
+ sym->s_link->s_rlink = sym->s_rlink;
+ sym->s_link = NULL;
+ sym->s_rlink = NULL;
+ }
+ }
+}
+
+/*
+ * Put a symbol into the symbol table
+ */
+void
+inssym(bl, sym)
+ int bl;
+ sym_t *sym;
+{
+ int h;
+
+ h = hash(sym->s_name);
+ if ((sym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &sym->s_link;
+ (symtab[h] = sym)->s_rlink = &symtab[h];
+ sym->s_blklev = bl;
+ if (sym->s_link != NULL && sym->s_blklev < sym->s_link->s_blklev)
+ lerror("inssym()");
+}
+
+/*
+ * Called at level 0 after syntax errors
+ * Removes all symbols which are not declared at level 0 from the
+ * symbol table. Also frees all memory which is not associated with
+ * level 0.
+ */
+void
+cleanup()
+{
+ sym_t *sym, *nsym;
+ int i;
+
+ for (i = 0; i < HSHSIZ1; i++) {
+ for (sym = symtab[i]; sym != NULL; sym = nsym) {
+ nsym = sym->s_link;
+ if (sym->s_blklev >= 1) {
+ if ((*sym->s_rlink = nsym) != NULL)
+ nsym->s_rlink = sym->s_rlink;
+ }
+ }
+ }
+
+ for (i = mblklev; i > 0; i--)
+ freelblk(i);
+}
+
+/*
+ * Create a new symbol with the name of an existing symbol.
+ */
+sym_t *
+pushdown(sym)
+ sym_t *sym;
+{
+ int h;
+ sym_t *nsym;
+
+ h = hash(sym->s_name);
+ nsym = getblk(sizeof (sym_t));
+ if (sym->s_blklev > blklev)
+ lerror("pushdown()");
+ nsym->s_name = sym->s_name;
+ STRUCT_ASSIGN(nsym->s_dpos, curr_pos);
+ nsym->s_kind = sym->s_kind;
+ nsym->s_blklev = blklev;
+
+ if ((nsym->s_link = symtab[h]) != NULL)
+ symtab[h]->s_rlink = &nsym->s_link;
+ (symtab[h] = nsym)->s_rlink = &symtab[h];
+
+ *dcs->d_ldlsym = nsym;
+ dcs->d_ldlsym = &nsym->s_dlnxt;
+
+ return (nsym);
+}
+
+/*
+ * Free any dynamically allocated memory referenced by
+ * the value stack or yylval.
+ * The type of information in yylval is described by tok.
+ */
+void
+freeyyv(sp, tok)
+ void *sp;
+ int tok;
+{
+ if (tok == T_NAME || tok == T_TYPENAME) {
+ sbuf_t *sb = *(sbuf_t **)sp;
+ freesb(sb);
+ } else if (tok == T_CON) {
+ val_t *val = *(val_t **)sp;
+ free(val);
+ } else if (tok == T_STRING) {
+ strg_t *strg = *(strg_t **)sp;
+ if (strg->st_tspec == CHAR) {
+ free(strg->st_cp);
+ } else if (strg->st_tspec == WCHAR) {
+ free(strg->st_wcp);
+ } else {
+ lerror("fryylv() 1");
+ }
+ free(strg);
+ }
+}
diff --git a/usr.bin/xlint/lint1/tree.c b/usr.bin/xlint/lint1/tree.c
new file mode 100644
index 0000000..525e407
--- /dev/null
+++ b/usr.bin/xlint/lint1/tree.c
@@ -0,0 +1,3924 @@
+/* $NetBSD: tree.c,v 1.12 1995/10/02 17:37:57 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: tree.c,v 1.12 1995/10/02 17:37:57 jpo Exp $";
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+
+#include "lint1.h"
+#include "y.tab.h"
+
+/* Various flags for each operator. */
+static mod_t modtab[NOPS];
+
+static tnode_t *getinode __P((tspec_t, quad_t));
+static void ptrcmpok __P((op_t, tnode_t *, tnode_t *));
+static int asgntypok __P((op_t, int, tnode_t *, tnode_t *));
+static void chkbeop __P((op_t, tnode_t *, tnode_t *));
+static void chkeop2 __P((op_t, int, tnode_t *, tnode_t *));
+static void chkeop1 __P((op_t, int, tnode_t *, tnode_t *));
+static tnode_t *mktnode __P((op_t, type_t *, tnode_t *, tnode_t *));
+static void balance __P((op_t, tnode_t **, tnode_t **));
+static void incompat __P((op_t, tspec_t, tspec_t));
+static void illptrc __P((mod_t *, type_t *, type_t *));
+static void mrgqual __P((type_t **, type_t *, type_t *));
+static int conmemb __P((type_t *));
+static void ptconv __P((int, tspec_t, tspec_t, type_t *, tnode_t *));
+static void iiconv __P((op_t, int, tspec_t, tspec_t, type_t *, tnode_t *));
+static void piconv __P((op_t, tspec_t, type_t *, tnode_t *));
+static void ppconv __P((op_t, tnode_t *, type_t *));
+static tnode_t *bldstr __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldincdec __P((op_t, tnode_t *));
+static tnode_t *bldamper __P((tnode_t *, int));
+static tnode_t *bldplmi __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldshft __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *bldcol __P((tnode_t *, tnode_t *));
+static tnode_t *bldasgn __P((op_t, tnode_t *, tnode_t *));
+static tnode_t *plength __P((type_t *));
+static tnode_t *fold __P((tnode_t *));
+static tnode_t *foldtst __P((tnode_t *));
+static tnode_t *foldflt __P((tnode_t *));
+static tnode_t *chkfarg __P((type_t *, tnode_t *));
+static tnode_t *parg __P((int, type_t *, tnode_t *));
+static void nulleff __P((tnode_t *));
+static void displexpr __P((tnode_t *, int));
+static void chkaidx __P((tnode_t *, int));
+static void chkcomp __P((op_t, tnode_t *, tnode_t *));
+static void precconf __P((tnode_t *));
+
+/*
+ * Initialize mods of operators.
+ */
+void
+initmtab()
+{
+ static struct {
+ op_t op;
+ mod_t m;
+ } imods[] = {
+ { ARROW, { 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "->" } },
+ { POINT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "." } },
+ { NOT, { 0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,
+ "!" } },
+ { COMPL, { 0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1,
+ "~" } },
+ { INCBEF, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "prefix++" } },
+ { DECBEF, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "prefix--" } },
+ { INCAFT, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "postfix++" } },
+ { DECAFT, { 0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "postfix--" } },
+ { UPLUS, { 0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,
+ "unary +" } },
+ { UMINUS, { 0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,1,1,
+ "unary -" } },
+ { STAR, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "unary *" } },
+ { AMPER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "unary &" } },
+ { MULT, { 1,0,0,0,1,1,1,0,1,0,0,1,0,0,0,1,1,
+ "*" } },
+ { DIV, { 1,0,0,0,1,1,1,0,1,0,1,1,0,0,0,1,1,
+ "/" } },
+ { MOD, { 1,0,1,0,0,1,1,0,1,0,1,1,0,0,0,1,1,
+ "%" } },
+ { PLUS, { 1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,0,
+ "+" } },
+ { MINUS, { 1,0,0,1,0,1,1,0,1,0,0,0,0,0,0,1,0,
+ "-" } },
+ { SHL, { 1,0,1,0,0,1,1,0,0,0,0,0,1,0,0,1,1,
+ "<<" } },
+ { SHR, { 1,0,1,0,0,1,1,0,0,0,1,0,1,0,0,1,1,
+ ">>" } },
+ { LT, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ "<" } },
+ { LE, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ "<=" } },
+ { GT, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ ">" } },
+ { GE, { 1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,
+ ">=" } },
+ { EQ, { 1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,0,1,
+ "==" } },
+ { NE, { 1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,0,1,
+ "!=" } },
+ { AND, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "&" } },
+ { XOR, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "^" } },
+ { OR, { 1,0,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,
+ "|" } },
+ { LOGAND, { 1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,1,0,
+ "&&" } },
+ { LOGOR, { 1,1,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,
+ "||" } },
+ { QUEST, { 1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,
+ "?" } },
+ { COLON, { 1,0,0,0,0,0,1,0,1,0,0,0,0,0,1,0,0,
+ ":" } },
+ { ASSIGN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,
+ "=" } },
+ { MULASS, { 1,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,
+ "*=" } },
+ { DIVASS, { 1,0,0,0,1,0,0,0,0,1,0,1,0,0,0,1,0,
+ "/=" } },
+ { MODASS, { 1,0,1,0,0,0,0,0,0,1,0,1,0,0,0,1,0,
+ "%=" } },
+ { ADDASS, { 1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "+=" } },
+ { SUBASS, { 1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "-=" } },
+ { SHLASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "<<=" } },
+ { SHRASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ ">>=" } },
+ { ANDASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "&=" } },
+ { XORASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "^=" } },
+ { ORASS, { 1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,
+ "|=" } },
+ { NAME, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "NAME" } },
+ { CON, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "CON" } },
+ { STRING, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "STRING" } },
+ { FSEL, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "FSEL" } },
+ { CALL, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
+ "CALL" } },
+ { COMMA, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
+ "," } },
+ { CVT, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "CVT" } },
+ { ICALL, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
+ "ICALL" } },
+ { LOAD, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ "LOAD" } },
+ { PUSH, { 0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
+ "PUSH" } },
+ { RETURN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,
+ "RETURN" } },
+ { INIT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
+ "INIT" } },
+ { FARG, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
+ "FARG" } },
+ { NOOP }
+ };
+ int i;
+
+ for (i = 0; imods[i].op != NOOP; i++)
+ STRUCT_ASSIGN(modtab[imods[i].op], imods[i].m);
+}
+
+/*
+ * Increase degree of reference.
+ * This is most often used to change type "T" in type "pointer to T".
+ */
+type_t *
+incref(tp, t)
+ type_t *tp;
+ tspec_t t;
+{
+ type_t *tp2;
+
+ tp2 = getblk(sizeof (type_t));
+ tp2->t_tspec = t;
+ tp2->t_subt = tp;
+ return (tp2);
+}
+
+/*
+ * same for use in expressions
+ */
+type_t *
+tincref(tp, t)
+ type_t *tp;
+ tspec_t t;
+{
+ type_t *tp2;
+
+ tp2 = tgetblk(sizeof (type_t));
+ tp2->t_tspec = t;
+ tp2->t_subt = tp;
+ return (tp2);
+}
+
+/*
+ * Create a node for a constant.
+ */
+tnode_t *
+getcnode(tp, v)
+ type_t *tp;
+ val_t *v;
+{
+ tnode_t *n;
+
+ n = getnode();
+ n->tn_op = CON;
+ n->tn_type = tp;
+ n->tn_val = tgetblk(sizeof (val_t));
+ n->tn_val->v_tspec = tp->t_tspec;
+ n->tn_val->v_ansiu = v->v_ansiu;
+ n->tn_val->v_u = v->v_u;
+ free(v);
+ return (n);
+}
+
+/*
+ * Create a node for a integer constant.
+ */
+static tnode_t *
+getinode(t, q)
+ tspec_t t;
+ quad_t q;
+{
+ tnode_t *n;
+
+ n = getnode();
+ n->tn_op = CON;
+ n->tn_type = gettyp(t);
+ n->tn_val = tgetblk(sizeof (val_t));
+ n->tn_val->v_tspec = t;
+ n->tn_val->v_quad = q;
+ return (n);
+}
+
+/*
+ * Create a node for a name (symbol table entry).
+ * ntok is the token which follows the name.
+ */
+tnode_t *
+getnnode(sym, ntok)
+ sym_t *sym;
+ int ntok;
+{
+ tnode_t *n;
+
+ if (sym->s_scl == NOSCL) {
+ sym->s_scl = EXTERN;
+ sym->s_def = DECL;
+ if (ntok == T_LPARN) {
+ if (sflag) {
+ /* function implicitly declared to ... */
+ warning(215);
+ }
+ /*
+ * XXX if tflag is set the symbol should be
+ * exported to level 0
+ */
+ sym->s_type = incref(sym->s_type, FUNC);
+ } else {
+ /* %s undefined */
+ error(99, sym->s_name);
+ }
+ }
+
+ if (sym->s_kind != FVFT && sym->s_kind != FMOS)
+ lerror("getnnode() 1");
+
+ n = getnode();
+ n->tn_type = sym->s_type;
+ if (sym->s_scl != ENUMCON) {
+ n->tn_op = NAME;
+ n->tn_sym = sym;
+ if (sym->s_kind == FVFT && sym->s_type->t_tspec != FUNC)
+ n->tn_lvalue = 1;
+ } else {
+ n->tn_op = CON;
+ n->tn_val = tgetblk(sizeof (val_t));
+ *n->tn_val = sym->s_value;
+ }
+
+ return (n);
+}
+
+/*
+ * Create a node for a string.
+ */
+tnode_t *
+getsnode(strg)
+ strg_t *strg;
+{
+ size_t len;
+ tnode_t *n;
+
+ len = strg->st_len;
+
+ n = getnode();
+
+ n->tn_op = STRING;
+ n->tn_type = tincref(gettyp(strg->st_tspec), ARRAY);
+ n->tn_type->t_dim = len + 1;
+ n->tn_lvalue = 1;
+
+ n->tn_strg = tgetblk(sizeof (strg_t));
+ n->tn_strg->st_tspec = strg->st_tspec;
+ n->tn_strg->st_len = len;
+
+ if (strg->st_tspec == CHAR) {
+ n->tn_strg->st_cp = tgetblk(len + 1);
+ (void)memcpy(n->tn_strg->st_cp, strg->st_cp, len + 1);
+ free(strg->st_cp);
+ } else {
+ n->tn_strg->st_wcp = tgetblk((len + 1) * sizeof (wchar_t));
+ (void)memcpy(n->tn_strg->st_wcp, strg->st_wcp,
+ (len + 1) * sizeof (wchar_t));
+ free(strg->st_wcp);
+ }
+ free(strg);
+
+ return (n);
+}
+
+/*
+ * Returns a symbol which has the same name as the msym argument and is a
+ * member of the struct or union specified by the tn argument.
+ */
+sym_t *
+strmemb(tn, op, msym)
+ tnode_t *tn;
+ op_t op;
+ sym_t *msym;
+{
+ str_t *str;
+ type_t *tp;
+ sym_t *sym, *csym;
+ int eq;
+ tspec_t t;
+
+ /*
+ * Remove the member if it was unknown until now (Which means
+ * that no defined struct or union has a member with the same name).
+ */
+ if (msym->s_scl == NOSCL) {
+ /* undefined struct/union member: %s */
+ error(101, msym->s_name);
+ rmsym(msym);
+ msym->s_kind = FMOS;
+ msym->s_scl = MOS;
+ msym->s_styp = tgetblk(sizeof (str_t));
+ msym->s_styp->stag = tgetblk(sizeof (sym_t));
+ msym->s_styp->stag->s_name = unnamed;
+ msym->s_value.v_tspec = INT;
+ return (msym);
+ }
+
+ /* Set str to the tag of which msym is expected to be a member. */
+ str = NULL;
+ t = (tp = tn->tn_type)->t_tspec;
+ if (op == POINT) {
+ if (t == STRUCT || t == UNION)
+ str = tp->t_str;
+ } else if (op == ARROW && t == PTR) {
+ t = (tp = tp->t_subt)->t_tspec;
+ if (t == STRUCT || t == UNION)
+ str = tp->t_str;
+ }
+
+ /*
+ * If this struct/union has a member with the name of msym, return
+ * return this it.
+ */
+ if (str != NULL) {
+ for (sym = msym; sym != NULL; sym = sym->s_link) {
+ if (sym->s_scl != MOS && sym->s_scl != MOU)
+ continue;
+ if (sym->s_styp != str)
+ continue;
+ if (strcmp(sym->s_name, msym->s_name) != 0)
+ continue;
+ return (sym);
+ }
+ }
+
+ /*
+ * Set eq to 0 if there are struct/union members with the same name
+ * and different types and/or offsets.
+ */
+ eq = 1;
+ for (csym = msym; csym != NULL; csym = csym->s_link) {
+ if (csym->s_scl != MOS && csym->s_scl != MOU)
+ continue;
+ if (strcmp(msym->s_name, csym->s_name) != 0)
+ continue;
+ for (sym = csym->s_link ; sym != NULL; sym = sym->s_link) {
+ int w;
+
+ if (sym->s_scl != MOS && sym->s_scl != MOU)
+ continue;
+ if (strcmp(csym->s_name, sym->s_name) != 0)
+ continue;
+ if (csym->s_value.v_quad != sym->s_value.v_quad) {
+ eq = 0;
+ break;
+ }
+ w = 0;
+ eq = eqtype(csym->s_type, sym->s_type, 0, 0, &w) && !w;
+ if (!eq)
+ break;
+ if (csym->s_field != sym->s_field) {
+ eq = 0;
+ break;
+ }
+ if (csym->s_field) {
+ type_t *tp1, *tp2;
+
+ tp1 = csym->s_type;
+ tp2 = sym->s_type;
+ if (tp1->t_flen != tp2->t_flen) {
+ eq = 0;
+ break;
+ }
+ if (tp1->t_foffs != tp2->t_foffs) {
+ eq = 0;
+ break;
+ }
+ }
+ }
+ if (!eq)
+ break;
+ }
+
+ /*
+ * Now handle the case in which the left operand refers really
+ * to a struct/union, but the right operand is not member of it.
+ */
+ if (str != NULL) {
+ /* illegal member use: %s */
+ if (eq && tflag) {
+ warning(102, msym->s_name);
+ } else {
+ error(102, msym->s_name);
+ }
+ return (msym);
+ }
+
+ /*
+ * Now the left operand of ARROW does not point to a struct/union
+ * or the left operand of POINT is no struct/union.
+ */
+ if (eq) {
+ if (op == POINT) {
+ /* left operand of "." must be struct/union object */
+ if (tflag) {
+ warning(103);
+ } else {
+ error(103);
+ }
+ } else {
+ /* left operand of "->" must be pointer to ... */
+ if (tflag && tn->tn_type->t_tspec == PTR) {
+ warning(104);
+ } else {
+ error(104);
+ }
+ }
+ } else {
+ if (tflag) {
+ /* non-unique member requires struct/union %s */
+ error(105, op == POINT ? "object" : "pointer");
+ } else {
+ /* unacceptable operand of %s */
+ error(111, modtab[op].m_name);
+ }
+ }
+
+ return (msym);
+}
+
+/*
+ * Create a tree node. Called for most operands except function calls,
+ * sizeof and casts.
+ *
+ * op operator
+ * ln left operand
+ * rn if not NULL, right operand
+ */
+tnode_t *
+build(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+ tnode_t *ntn;
+ type_t *rtp;
+
+ mp = &modtab[op];
+
+ /* If there was an error in one of the operands, return. */
+ if (ln == NULL || (mp->m_binary && rn == NULL))
+ return (NULL);
+
+ /*
+ * Apply class conversions to the left operand, but only if its
+ * value is needed or it is compaired with null.
+ */
+ if (mp->m_vctx || mp->m_tctx)
+ ln = cconv(ln);
+ /*
+ * The right operand is almost always in a test or value context,
+ * except if it is a struct or union member.
+ */
+ if (mp->m_binary && op != ARROW && op != POINT)
+ rn = cconv(rn);
+
+ /*
+ * Print some warnings for comparisions of unsigned values with
+ * constants lower than or equal to null. This must be done
+ * before promote() because otherwise unsigned char and unsigned
+ * short would be promoted to int. Also types are tested to be
+ * CHAR, which would also become int.
+ */
+ if (mp->m_comp)
+ chkcomp(op, ln, rn);
+
+ /*
+ * Promote the left operand if it is in a test or value context
+ */
+ if (mp->m_vctx || mp->m_tctx)
+ ln = promote(op, 0, ln);
+ /*
+ * Promote the right operand, but only if it is no struct or
+ * union member, or if it is not to be assigned to the left operand
+ */
+ if (mp->m_binary && op != ARROW && op != POINT &&
+ op != ASSIGN && op != RETURN) {
+ rn = promote(op, 0, rn);
+ }
+
+ /*
+ * If the result of the operation is different for signed or
+ * unsigned operands and one of the operands is signed only in
+ * ANSI C, print a warning.
+ */
+ if (mp->m_tlansiu && ln->tn_op == CON && ln->tn_val->v_ansiu) {
+ /* ANSI C treats constant as unsigned, op %s */
+ warning(218, mp->m_name);
+ ln->tn_val->v_ansiu = 0;
+ }
+ if (mp->m_transiu && rn->tn_op == CON && rn->tn_val->v_ansiu) {
+ /* ANSI C treats constant as unsigned, op %s */
+ warning(218, mp->m_name);
+ rn->tn_val->v_ansiu = 0;
+ }
+
+ /* Make sure both operands are of the same type */
+ if (mp->m_balance || (tflag && (op == SHL || op == SHR)))
+ balance(op, &ln, &rn);
+
+ /*
+ * Check types for compatibility with the operation and mutual
+ * compatibility. Return if there are serios problems.
+ */
+ if (!typeok(op, 0, ln, rn))
+ return (NULL);
+
+ /* And now create the node. */
+ switch (op) {
+ case POINT:
+ case ARROW:
+ ntn = bldstr(op, ln, rn);
+ break;
+ case INCAFT:
+ case DECAFT:
+ case INCBEF:
+ case DECBEF:
+ ntn = bldincdec(op, ln);
+ break;
+ case AMPER:
+ ntn = bldamper(ln, 0);
+ break;
+ case STAR:
+ ntn = mktnode(STAR, ln->tn_type->t_subt, ln, NULL);
+ break;
+ case PLUS:
+ case MINUS:
+ ntn = bldplmi(op, ln, rn);
+ break;
+ case SHL:
+ case SHR:
+ ntn = bldshft(op, ln, rn);
+ break;
+ case COLON:
+ ntn = bldcol(ln, rn);
+ break;
+ case ASSIGN:
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ case ADDASS:
+ case SUBASS:
+ case SHLASS:
+ case SHRASS:
+ case ANDASS:
+ case XORASS:
+ case ORASS:
+ case RETURN:
+ ntn = bldasgn(op, ln, rn);
+ break;
+ case COMMA:
+ case QUEST:
+ ntn = mktnode(op, rn->tn_type, ln, rn);
+ break;
+ default:
+ rtp = mp->m_logop ? gettyp(INT) : ln->tn_type;
+ if (!mp->m_binary && rn != NULL)
+ lerror("build() 1");
+ ntn = mktnode(op, rtp, ln, rn);
+ break;
+ }
+
+ /* Return if an error occured. */
+ if (ntn == NULL)
+ return (NULL);
+
+ /* Print a warning if precedence confusion is possible */
+ if (mp->m_tpconf)
+ precconf(ntn);
+
+ /*
+ * Print a warning if one of the operands is in a context where
+ * it is compared with null and if this operand is a constant.
+ */
+ if (mp->m_tctx) {
+ if (ln->tn_op == CON ||
+ ((mp->m_binary && op != QUEST) && rn->tn_op == CON)) {
+ if (hflag && !ccflg)
+ /* constant in conditional context */
+ warning(161);
+ }
+ }
+
+ /* Fold if the operator requires it */
+ if (mp->m_fold) {
+ if (ln->tn_op == CON && (!mp->m_binary || rn->tn_op == CON)) {
+ if (mp->m_tctx) {
+ ntn = foldtst(ntn);
+ } else if (isftyp(ntn->tn_type->t_tspec)) {
+ ntn = foldflt(ntn);
+ } else {
+ ntn = fold(ntn);
+ }
+ } else if (op == QUEST && ln->tn_op == CON) {
+ ntn = ln->tn_val->v_quad ? rn->tn_left : rn->tn_right;
+ }
+ }
+
+ return (ntn);
+}
+
+/*
+ * Perform class conversions.
+ *
+ * Arrays of type T are converted into pointers to type T.
+ * Functions are converted to pointers to functions.
+ * Lvalues are converted to rvalues.
+ */
+tnode_t *
+cconv(tn)
+ tnode_t *tn;
+{
+ type_t *tp;
+
+ /*
+ * Array-lvalue (array of type T) is converted into rvalue
+ * (pointer to type T)
+ */
+ if (tn->tn_type->t_tspec == ARRAY) {
+ if (!tn->tn_lvalue) {
+ /* %soperand of '%s' must be lvalue */
+ /* XXX print correct operator */
+ (void)gnuism(114, "", modtab[AMPER].m_name);
+ }
+ tn = mktnode(AMPER, tincref(tn->tn_type->t_subt, PTR),
+ tn, NULL);
+ }
+
+ /*
+ * Expression of type function (function with return value of type T)
+ * in rvalue-expression (pointer to function with return value
+ * of type T)
+ */
+ if (tn->tn_type->t_tspec == FUNC)
+ tn = bldamper(tn, 1);
+
+ /* lvalue to rvalue */
+ if (tn->tn_lvalue) {
+ tp = tduptyp(tn->tn_type);
+ tp->t_const = tp->t_volatile = 0;
+ tn = mktnode(LOAD, tp, tn, NULL);
+ }
+
+ return (tn);
+}
+
+/*
+ * Perform most type checks. First the types are checked using
+ * informations from modtab[]. After that it is done by hand for
+ * more complicated operators and type combinations.
+ *
+ * If the types are ok, typeok() returns 1, otherwise 0.
+ */
+int
+typeok(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+ tspec_t lt, rt, lst, rst, olt, ort;
+ type_t *ltp, *rtp, *lstp, *rstp;
+ tnode_t *tn;
+
+ mp = &modtab[op];
+
+ if ((lt = (ltp = ln->tn_type)->t_tspec) == PTR)
+ lst = (lstp = ltp->t_subt)->t_tspec;
+ if (mp->m_binary) {
+ if ((rt = (rtp = rn->tn_type)->t_tspec) == PTR)
+ rst = (rstp = rtp->t_subt)->t_tspec;
+ }
+
+ if (mp->m_rqint) {
+ /* integertypes required */
+ if (!isityp(lt) || (mp->m_binary && !isityp(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (mp->m_rqsclt) {
+ /* scalar types required */
+ if (!issclt(lt) || (mp->m_binary && !issclt(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (mp->m_rqatyp) {
+ /* arithmetic types required */
+ if (!isatyp(lt) || (mp->m_binary && !isatyp(rt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ }
+
+ if (op == SHL || op == SHR || op == SHLASS || op == SHRASS) {
+ /*
+ * For these operations we need the types before promotion
+ * and balancing.
+ */
+ for (tn=ln; tn->tn_op==CVT && !tn->tn_cast; tn=tn->tn_left) ;
+ olt = tn->tn_type->t_tspec;
+ for (tn=rn; tn->tn_op==CVT && !tn->tn_cast; tn=tn->tn_left) ;
+ ort = tn->tn_type->t_tspec;
+ }
+
+ switch (op) {
+ case POINT:
+ /*
+ * Most errors required by ANSI C are reported in strmemb().
+ * Here we only must check for totaly wrong things.
+ */
+ if (lt == FUNC || lt == VOID || ltp->t_isfield ||
+ ((lt != STRUCT && lt != UNION) && !ln->tn_lvalue)) {
+ /* Without tflag we got already an error */
+ if (tflag)
+ /* unacceptable operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ /* Now we have an object we can create a pointer to */
+ break;
+ case ARROW:
+ if (lt != PTR && !(tflag && isityp(lt))) {
+ /* Without tflag we got already an error */
+ if (tflag)
+ /* unacceptabel operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ break;
+ case INCAFT:
+ case DECAFT:
+ case INCBEF:
+ case DECBEF:
+ /* operands have scalar types (checked above) */
+ if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "", mp->m_name);
+ return (0);
+ } else if (ltp->t_const) {
+ /* %soperand of %s must be modifiable lvalue */
+ if (!tflag)
+ warning(115, "", mp->m_name);
+ }
+ break;
+ case AMPER:
+ if (lt == ARRAY || lt == FUNC) {
+ /* ok, a warning comes later (in bldamper()) */
+ } else if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "", mp->m_name);
+ return (0);
+ } else if (issclt(lt)) {
+ if (ltp->t_isfield) {
+ /* cannot take address of bit-field */
+ error(112);
+ return (0);
+ }
+ } else if (lt != STRUCT && lt != UNION) {
+ /* unacceptable operand of %s */
+ error(111, mp->m_name);
+ return (0);
+ }
+ if (ln->tn_op == NAME && ln->tn_sym->s_reg) {
+ /* cannot take address of register %s */
+ error(113, ln->tn_sym->s_name);
+ return (0);
+ }
+ break;
+ case STAR:
+ /* until now there were no type checks for this operator */
+ if (lt != PTR) {
+ /* cannot dereference non-pointer type */
+ error(96);
+ return (0);
+ }
+ break;
+ case PLUS:
+ /* operands have scalar types (checked above) */
+ if ((lt == PTR && !isityp(rt)) || (rt == PTR && !isityp(lt))) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ break;
+ case MINUS:
+ /* operands have scalar types (checked above) */
+ if (lt == PTR && (!isityp(rt) && rt != PTR)) {
+ incompat(op, lt, rt);
+ return (0);
+ } else if (rt == PTR && lt != PTR) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ if (lt == PTR && rt == PTR) {
+ if (!eqtype(lstp, rstp, 1, 0, NULL)) {
+ /* illegal pointer subtraction */
+ error(116);
+ }
+ }
+ break;
+ case SHR:
+ /* operands have integer types (checked above) */
+ if (pflag && !isutyp(lt)) {
+ /*
+ * The left operand is signed. This means that
+ * the operation is (possibly) nonportable.
+ */
+ /* bitwise operation on signed value nonportable */
+ if (ln->tn_op != CON) {
+ /* possibly nonportable */
+ warning(117);
+ } else if (ln->tn_val->v_quad < 0) {
+ warning(120);
+ }
+ } else if (!tflag && !sflag && !isutyp(olt) && isutyp(ort)) {
+ /*
+ * The left operand would become unsigned in
+ * traditional C.
+ */
+ if (hflag &&
+ (ln->tn_op != CON || ln->tn_val->v_quad < 0)) {
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ } else if (!tflag && !sflag && !isutyp(olt) && !isutyp(ort) &&
+ psize(lt) < psize(rt)) {
+ /*
+ * In traditional C the left operand would be extended,
+ * possibly with 1, and then shifted.
+ */
+ if (hflag &&
+ (ln->tn_op != CON || ln->tn_val->v_quad < 0)) {
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ }
+ goto shift;
+ case SHL:
+ /*
+ * ANSI C does not perform balancing for shift operations,
+ * but traditional C does. If the width of the right operand
+ * is greather than the width of the left operand, than in
+ * traditional C the left operand would be extendet to the
+ * width of the right operand. For SHL this may result in
+ * different results.
+ */
+ if (psize(lt) < psize(rt)) {
+ /*
+ * XXX If both operands are constant make sure
+ * that there is really a differencs between
+ * ANSI C and traditional C.
+ */
+ if (hflag)
+ /* semantics of %s change in ANSI C; use ... */
+ warning(118, mp->m_name);
+ }
+ shift:
+ if (rn->tn_op == CON) {
+ if (!isutyp(rt) && rn->tn_val->v_quad < 0) {
+ /* negative shift */
+ warning(121);
+ } else if ((u_quad_t)rn->tn_val->v_quad == size(lt)) {
+ /* shift equal to size fo object */
+ warning(267);
+ } else if ((u_quad_t)rn->tn_val->v_quad > size(lt)) {
+ /* shift greater than size of object */
+ warning(122);
+ }
+ }
+ break;
+ case EQ:
+ case NE:
+ /*
+ * Accept some things which are allowed with EQ and NE,
+ * but not with ordered comparisions.
+ */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ break;
+ }
+ if (rt == PTR && ((lt == PTR && lst == VOID) || isityp(lt))) {
+ if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
+ break;
+ }
+ /* FALLTHROUGH */
+ case LT:
+ case GT:
+ case LE:
+ case GE:
+ if ((lt == PTR || rt == PTR) && lt != rt) {
+ if (isityp(lt) || isityp(rt)) {
+ /* illegal comb. of pointer and int., op %s */
+ warning(123, mp->m_name);
+ } else {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ } else if (lt == PTR && rt == PTR) {
+ ptrcmpok(op, ln, rn);
+ }
+ break;
+ case QUEST:
+ if (!issclt(lt)) {
+ /* first operand must have scalar type, op ? : */
+ error(170);
+ return (0);
+ }
+ if (rn->tn_op != COLON)
+ lerror("typeok() 2");
+ break;
+ case COLON:
+
+ if (isatyp(lt) && isatyp(rt))
+ break;
+
+ if (lt == STRUCT && rt == STRUCT && ltp->t_str == rtp->t_str)
+ break;
+ if (lt == UNION && rt == UNION && ltp->t_str == rtp->t_str)
+ break;
+
+ /* combination of any pointer and 0, 0L or (void *)0 is ok */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ break;
+ }
+ if (rt == PTR && ((lt == PTR && lst == VOID) || isityp(lt))) {
+ if (ln->tn_op == CON && ln->tn_val->v_quad == 0)
+ break;
+ }
+
+ if ((lt == PTR && isityp(rt)) || (isityp(lt) && rt == PTR)) {
+ /* illegal comb. of ptr. and int., op %s */
+ warning(123, mp->m_name);
+ break;
+ }
+
+ if (lt == VOID || rt == VOID) {
+ if (lt != VOID || rt != VOID)
+ /* incompatible types in conditional */
+ warning(126);
+ break;
+ }
+
+ if (lt == PTR && rt == PTR && ((lst == VOID && rst == FUNC) ||
+ (lst == FUNC && rst == VOID))) {
+ /* (void *)0 handled above */
+ if (sflag)
+ /* ANSI C forbids conv. of %s to %s, op %s */
+ warning(305, "function pointer", "'void *'",
+ mp->m_name);
+ break;
+ }
+
+ if (rt == PTR && lt == PTR) {
+ if (!eqtype(lstp, rstp, 1, 0, NULL))
+ illptrc(mp, ltp, rtp);
+ break;
+ }
+
+ /* incompatible types in conditional */
+ error(126);
+ return (0);
+
+ case ASSIGN:
+ case INIT:
+ case FARG:
+ case RETURN:
+ if (!asgntypok(op, arg, ln, rn))
+ return (0);
+ goto assign;
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ goto assign;
+ case ADDASS:
+ case SUBASS:
+ /* operands have scalar types (checked above) */
+ if ((lt == PTR && !isityp(rt)) || rt == PTR) {
+ incompat(op, lt, rt);
+ return (0);
+ }
+ goto assign;
+ case SHLASS:
+ goto assign;
+ case SHRASS:
+ if (pflag && !isutyp(lt) && !(tflag && isutyp(rt))) {
+ /* bitwise operation on s.v. possibly nonportabel */
+ warning(117);
+ }
+ goto assign;
+ case ANDASS:
+ case XORASS:
+ case ORASS:
+ goto assign;
+ assign:
+ if (!ln->tn_lvalue) {
+ if (ln->tn_op == CVT && ln->tn_cast &&
+ ln->tn_left->tn_op == LOAD) {
+ /* a cast does not yield an lvalue */
+ error(163);
+ }
+ /* %soperand of %s must be lvalue */
+ error(114, "left ", mp->m_name);
+ return (0);
+ } else if (ltp->t_const || ((lt == STRUCT || lt == UNION) &&
+ conmemb(ltp))) {
+ /* %soperand of %s must be modifiable lvalue */
+ if (!tflag)
+ warning(115, "left ", mp->m_name);
+ }
+ break;
+ case COMMA:
+ if (!modtab[ln->tn_op].m_sideeff)
+ nulleff(ln);
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ if (mp->m_badeop &&
+ (ltp->t_isenum || (mp->m_binary && rtp->t_isenum))) {
+ chkbeop(op, ln, rn);
+ } else if (mp->m_enumop && (ltp->t_isenum && rtp->t_isenum)) {
+ chkeop2(op, arg, ln, rn);
+ } else if (mp->m_enumop && (ltp->t_isenum || rtp->t_isenum)) {
+ chkeop1(op, arg, ln, rn);
+ }
+
+ return (1);
+}
+
+static void
+ptrcmpok(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ type_t *ltp, *rtp;
+ tspec_t lt, rt;
+ const char *lts, *rts;
+
+ lt = (ltp = ln->tn_type)->t_subt->t_tspec;
+ rt = (rtp = rn->tn_type)->t_subt->t_tspec;
+
+ if (lt == VOID || rt == VOID) {
+ if (sflag && (lt == FUNC || rt == FUNC)) {
+ /* (void *)0 already handled in typeok() */
+ *(lt == FUNC ? &lts : &rts) = "function pointer";
+ *(lt == VOID ? &lts : &rts) = "'void *'";
+ /* ANSI C forbids comparision of %s with %s */
+ warning(274, lts, rts);
+ }
+ return;
+ }
+
+ if (!eqtype(ltp->t_subt, rtp->t_subt, 1, 0, NULL)) {
+ illptrc(&modtab[op], ltp, rtp);
+ return;
+ }
+
+ if (lt == FUNC && rt == FUNC) {
+ if (sflag && op != EQ && op != NE)
+ /* ANSI C forbids ordered comp. of func ptr */
+ warning(125);
+ }
+}
+
+/*
+ * Checks type compatibility for ASSIGN, INIT, FARG and RETURN
+ * and prints warnings/errors if necessary.
+ * If the types are (almost) compatible, 1 is returned, otherwise 0.
+ */
+static int
+asgntypok(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt, lst, rst;
+ type_t *ltp, *rtp, *lstp, *rstp;
+ mod_t *mp;
+ const char *lts, *rts;
+
+ if ((lt = (ltp = ln->tn_type)->t_tspec) == PTR)
+ lst = (lstp = ltp->t_subt)->t_tspec;
+ if ((rt = (rtp = rn->tn_type)->t_tspec) == PTR)
+ rst = (rstp = rtp->t_subt)->t_tspec;
+ mp = &modtab[op];
+
+ if (isatyp(lt) && isatyp(rt))
+ return (1);
+
+ if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION))
+ /* both are struct or union */
+ return (ltp->t_str == rtp->t_str);
+
+ /* 0, 0L and (void *)0 may be assigned to any pointer */
+ if (lt == PTR && ((rt == PTR && rst == VOID) || isityp(rt))) {
+ if (rn->tn_op == CON && rn->tn_val->v_quad == 0)
+ return (1);
+ }
+
+ if (lt == PTR && rt == PTR && (lst == VOID || rst == VOID)) {
+ /* two pointers, at least one pointer to void */
+ if (sflag && (lst == FUNC || rst == FUNC)) {
+ /* comb. of ptr to func and ptr to void */
+ *(lst == FUNC ? &lts : &rts) = "function pointer";
+ *(lst == VOID ? &lts : &rts) = "'void *'";
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* ANSI C forbids conversion of %s to %s */
+ warning(303, rts, lts);
+ break;
+ case FARG:
+ /* ANSI C forbids conv. of %s to %s, arg #%d */
+ warning(304, rts, lts, arg);
+ break;
+ default:
+ /* ANSI C forbids conv. of %s to %s, op %s */
+ warning(305, rts, lts, mp->m_name);
+ break;
+ }
+ }
+ }
+
+ if (lt == PTR && rt == PTR && (lst == VOID || rst == VOID ||
+ eqtype(lstp, rstp, 1, 0, NULL))) {
+ /* compatible pointer types (qualifiers ignored) */
+ if (!tflag &&
+ ((!lstp->t_const && rstp->t_const) ||
+ (!lstp->t_volatile && rstp->t_volatile))) {
+ /* left side has not all qualifiers of right */
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* incompatible pointer types */
+ warning(182);
+ break;
+ case FARG:
+ /* argument has incompat. ptr. type, arg #%d */
+ warning(153, arg);
+ break;
+ default:
+ /* operands have incompat. ptr. types, op %s */
+ warning(128, mp->m_name);
+ break;
+ }
+ }
+ return (1);
+ }
+
+ if ((lt == PTR && isityp(rt)) || (isityp(lt) && rt == PTR)) {
+ switch (op) {
+ case INIT:
+ case RETURN:
+ /* illegal combination of pointer and integer */
+ warning(183);
+ break;
+ case FARG:
+ /* illegal comb. of ptr. and int., arg #%d */
+ warning(154, arg);
+ break;
+ default:
+ /* illegal comb. of ptr. and int., op %s */
+ warning(123, mp->m_name);
+ break;
+ }
+ return (1);
+ }
+
+ if (lt == PTR && rt == PTR) {
+ switch (op) {
+ case INIT:
+ case RETURN:
+ illptrc(NULL, ltp, rtp);
+ break;
+ case FARG:
+ /* argument has incompatible pointer type, arg #%d */
+ warning(153, arg);
+ break;
+ default:
+ illptrc(mp, ltp, rtp);
+ break;
+ }
+ return (1);
+ }
+
+ switch (op) {
+ case INIT:
+ /* initialisation type mismatch */
+ error(185);
+ break;
+ case RETURN:
+ /* return value type mismatch */
+ error(211);
+ break;
+ case FARG:
+ /* argument is incompatible with prototype, arg #%d */
+ warning(155, arg);
+ break;
+ default:
+ incompat(op, lt, rt);
+ break;
+ }
+
+ return (0);
+}
+
+/*
+ * Prints a warning if an operator, which should be senseless for an
+ * enum type, is applied to an enum type.
+ */
+static void
+chkbeop(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+
+ if (!eflag)
+ return;
+
+ mp = &modtab[op];
+
+ if (!(ln->tn_type->t_isenum ||
+ (mp->m_binary && rn->tn_type->t_isenum))) {
+ return;
+ }
+
+ /*
+ * Enum as offset to a pointer is an exception (otherwise enums
+ * could not be used as array indizes).
+ */
+ if (op == PLUS &&
+ ((ln->tn_type->t_isenum && rn->tn_type->t_tspec == PTR) ||
+ (rn->tn_type->t_isenum && ln->tn_type->t_tspec == PTR))) {
+ return;
+ }
+
+ /* dubious operation on enum, op %s */
+ warning(241, mp->m_name);
+
+}
+
+/*
+ * Prints a warning if an operator is applied to two different enum types.
+ */
+static void
+chkeop2(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ mod_t *mp;
+
+ mp = &modtab[op];
+
+ if (ln->tn_type->t_enum != rn->tn_type->t_enum) {
+ switch (op) {
+ case INIT:
+ /* enum type mismatch in initialisation */
+ warning(210);
+ break;
+ case FARG:
+ /* enum type mismatch, arg #%d */
+ warning(156, arg);
+ break;
+ case RETURN:
+ /* return value type mismatch */
+ warning(211);
+ break;
+ default:
+ /* enum type mismatch, op %s */
+ warning(130, mp->m_name);
+ break;
+ }
+#if 0
+ } else if (mp->m_comp && op != EQ && op != NE) {
+ if (eflag)
+ /* dubious comparisions of enums */
+ warning(243, mp->m_name);
+#endif
+ }
+}
+
+/*
+ * Prints a warning if an operator has both enum end other integer
+ * types.
+ */
+static void
+chkeop1(op, arg, ln, rn)
+ op_t op;
+ int arg;
+ tnode_t *ln, *rn;
+{
+ if (!eflag)
+ return;
+
+ switch (op) {
+ case INIT:
+ /*
+ * Initializations with 0 should be allowed. Otherwise,
+ * we should complain about all uninitialized enums,
+ * consequently.
+ */
+ if (!rn->tn_type->t_isenum && rn->tn_op == CON &&
+ isityp(rn->tn_type->t_tspec) && rn->tn_val->v_quad == 0) {
+ return;
+ }
+ /* initialisation of '%s' with '%s' */
+ warning(277, tyname(ln->tn_type), tyname(rn->tn_type));
+ break;
+ case FARG:
+ /* combination of '%s' and '%s', arg #%d */
+ warning(278, tyname(ln->tn_type), tyname(rn->tn_type), arg);
+ break;
+ case RETURN:
+ /* combination of '%s' and '%s' in return */
+ warning(279, tyname(ln->tn_type), tyname(rn->tn_type));
+ break;
+ default:
+ /* combination of '%s' and %s, op %s */
+ warning(242, tyname(ln->tn_type), tyname(rn->tn_type),
+ modtab[op].m_name);
+ break;
+ }
+}
+
+/*
+ * Build and initialize a new node.
+ */
+static tnode_t *
+mktnode(op, type, ln, rn)
+ op_t op;
+ type_t *type;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn;
+ tspec_t t;
+
+ ntn = getnode();
+
+ ntn->tn_op = op;
+ ntn->tn_type = type;
+ ntn->tn_left = ln;
+ ntn->tn_right = rn;
+
+ if (op == STAR || op == FSEL) {
+ if (ln->tn_type->t_tspec == PTR) {
+ t = ln->tn_type->t_subt->t_tspec;
+ if (t != FUNC && t != VOID)
+ ntn->tn_lvalue = 1;
+ } else {
+ lerror("mktnode() 2");
+ }
+ }
+
+ return (ntn);
+}
+
+/*
+ * Performs usual conversion of operands to (unsigned) int.
+ *
+ * If tflag is set or the operand is a function argument with no
+ * type information (no prototype or variable # of args), convert
+ * float to double.
+ */
+tnode_t *
+promote(op, farg, tn)
+ op_t op;
+ int farg;
+ tnode_t *tn;
+{
+ tspec_t t;
+ type_t *ntp;
+ int len;
+
+ t = tn->tn_type->t_tspec;
+
+ if (!isatyp(t))
+ return (tn);
+
+ if (!tflag) {
+ /*
+ * ANSI C requires that the result is always of type INT
+ * if INT can represent all possible values of the previous
+ * type.
+ */
+ if (tn->tn_type->t_isfield) {
+ len = tn->tn_type->t_flen;
+ if (size(INT) > len) {
+ t = INT;
+ } else {
+ if (size(INT) != len)
+ lerror("promote() 1");
+ if (isutyp(t)) {
+ t = UINT;
+ } else {
+ t = INT;
+ }
+ }
+ } else if (t == CHAR || t == UCHAR || t == SCHAR) {
+ t = (size(CHAR) < size(INT) || t != UCHAR) ?
+ INT : UINT;
+ } else if (t == SHORT || t == USHORT) {
+ t = (size(SHORT) < size(INT) || t == SHORT) ?
+ INT : UINT;
+ } else if (t == ENUM) {
+ t = INT;
+ } else if (farg && t == FLOAT) {
+ t = DOUBLE;
+ }
+ } else {
+ /*
+ * In traditional C, keep unsigned and promote FLOAT
+ * to DOUBLE.
+ */
+ if (t == UCHAR || t == USHORT) {
+ t = UINT;
+ } else if (t == CHAR || t == SCHAR || t == SHORT) {
+ t = INT;
+ } else if (t == FLOAT) {
+ t = DOUBLE;
+ } else if (t == ENUM) {
+ t = INT;
+ }
+ }
+
+ if (t != tn->tn_type->t_tspec) {
+ ntp = tduptyp(tn->tn_type);
+ ntp->t_tspec = t;
+ /*
+ * Keep t_isenum so we are later able to check compatibility
+ * of enum types.
+ */
+ tn = convert(op, 0, ntp, tn);
+ }
+
+ return (tn);
+}
+
+/*
+ * Insert conversions which are necessary to give both operands the same
+ * type. This is done in different ways for traditional C and ANIS C.
+ */
+static void
+balance(op, lnp, rnp)
+ op_t op;
+ tnode_t **lnp, **rnp;
+{
+ tspec_t lt, rt, t;
+ int i, u;
+ type_t *ntp;
+ static tspec_t tl[] = {
+ LDOUBLE, DOUBLE, FLOAT, UQUAD, QUAD, ULONG, LONG, UINT, INT,
+ };
+
+ lt = (*lnp)->tn_type->t_tspec;
+ rt = (*rnp)->tn_type->t_tspec;
+
+ if (!isatyp(lt) || !isatyp(rt))
+ return;
+
+ if (!tflag) {
+ if (lt == rt) {
+ t = lt;
+ } else if (lt == LDOUBLE || rt == LDOUBLE) {
+ t = LDOUBLE;
+ } else if (lt == DOUBLE || rt == DOUBLE) {
+ t = DOUBLE;
+ } else if (lt == FLOAT || rt == FLOAT) {
+ t = FLOAT;
+ } else {
+ /*
+ * If type A has more bits than type B it should
+ * be able to hold all possible values of type B.
+ */
+ if (size(lt) > size(rt)) {
+ t = lt;
+ } else if (size(lt) < size(rt)) {
+ t = rt;
+ } else {
+ for (i = 3; tl[i] != INT; i++) {
+ if (tl[i] == lt || tl[i] == rt)
+ break;
+ }
+ if ((isutyp(lt) || isutyp(rt)) &&
+ !isutyp(tl[i])) {
+ i--;
+ }
+ t = tl[i];
+ }
+ }
+ } else {
+ /* Keep unsigned in traditional C */
+ u = isutyp(lt) || isutyp(rt);
+ for (i = 0; tl[i] != INT; i++) {
+ if (lt == tl[i] || rt == tl[i])
+ break;
+ }
+ t = tl[i];
+ if (u && isityp(t) && !isutyp(t))
+ t = utyp(t);
+ }
+
+ if (t != lt) {
+ ntp = tduptyp((*lnp)->tn_type);
+ ntp->t_tspec = t;
+ *lnp = convert(op, 0, ntp, *lnp);
+ }
+ if (t != rt) {
+ ntp = tduptyp((*rnp)->tn_type);
+ ntp->t_tspec = t;
+ *rnp = convert(op, 0, ntp, *rnp);
+ }
+}
+
+/*
+ * Insert a conversion operator, which converts the type of the node
+ * to another given type.
+ * If op is FARG, arg is the number of the argument (used for warnings).
+ */
+tnode_t *
+convert(op, arg, tp, tn)
+ op_t op;
+ int arg;
+ type_t *tp;
+ tnode_t *tn;
+{
+ tnode_t *ntn;
+ tspec_t nt, ot, ost;
+
+ if (tn->tn_lvalue)
+ lerror("convert() 1");
+
+ nt = tp->t_tspec;
+ if ((ot = tn->tn_type->t_tspec) == PTR)
+ ost = tn->tn_type->t_subt->t_tspec;
+
+ if (!tflag && !sflag && op == FARG)
+ ptconv(arg, nt, ot, tp, tn);
+ if (isityp(nt) && isityp(ot)) {
+ iiconv(op, arg, nt, ot, tp, tn);
+ } else if (nt == PTR && ((ot == PTR && ost == VOID) || isityp(ot)) &&
+ tn->tn_op == CON && tn->tn_val->v_quad == 0) {
+ /* 0, 0L and (void *)0 may be assigned to any pointer. */
+ } else if (isityp(nt) && ot == PTR) {
+ piconv(op, nt, tp, tn);
+ } else if (nt == PTR && ot == PTR) {
+ ppconv(op, tn, tp);
+ }
+
+ ntn = getnode();
+ ntn->tn_op = CVT;
+ ntn->tn_type = tp;
+ ntn->tn_cast = op == CVT;
+ if (tn->tn_op != CON || nt == VOID) {
+ ntn->tn_left = tn;
+ } else {
+ ntn->tn_op = CON;
+ ntn->tn_val = tgetblk(sizeof (val_t));
+ cvtcon(op, arg, ntn->tn_type, ntn->tn_val, tn->tn_val);
+ }
+
+ return (ntn);
+}
+
+/*
+ * Print a warning if a prototype causes a type conversion that is
+ * different from what would happen to the same argument in the
+ * absence of a prototype.
+ *
+ * Errors/Warnings about illegal type combinations are already printed
+ * in asgntypok().
+ */
+static void
+ptconv(arg, nt, ot, tp, tn)
+ int arg;
+ tspec_t nt, ot;
+ type_t *tp;
+ tnode_t *tn;
+{
+ tnode_t *ptn;
+
+ if (!isatyp(nt) || !isatyp(ot))
+ return;
+
+ /*
+ * If the type of the formal parameter is char/short, a warning
+ * would be useless, because functions declared the old style
+ * can't expect char/short arguments.
+ */
+ if (nt == CHAR || nt == UCHAR || nt == SHORT || nt == USHORT)
+ return;
+
+ /* get default promotion */
+ ptn = promote(NOOP, 1, tn);
+ ot = ptn->tn_type->t_tspec;
+
+ /* return if types are the same with and without prototype */
+ if (nt == ot || (nt == ENUM && ot == INT))
+ return;
+
+ if (isftyp(nt) != isftyp(ot) || psize(nt) != psize(ot)) {
+ /* representation and/or width change */
+ if (styp(nt) != SHORT || !isityp(ot) || psize(ot) > psize(INT))
+ /* conversion to '%s' due to prototype, arg #%d */
+ warning(259, tyname(tp), arg);
+ } else if (hflag) {
+ /*
+ * they differ in sign or base type (char, short, int,
+ * long, long long, float, double, long double)
+ *
+ * if they differ only in sign and the argument is a constant
+ * and the msb of the argument is not set, print no warning
+ */
+ if (ptn->tn_op == CON && isityp(nt) && styp(nt) == styp(ot) &&
+ msb(ptn->tn_val->v_quad, ot, -1) == 0) {
+ /* ok */
+ } else {
+ /* conversion to '%s' due to prototype, arg #%d */
+ warning(259, tyname(tp), arg);
+ }
+ }
+}
+
+/*
+ * Print warnings for conversions of integer types which my cause
+ * problems.
+ */
+/* ARGSUSED */
+static void
+iiconv(op, arg, nt, ot, tp, tn)
+ op_t op;
+ int arg;
+ tspec_t nt, ot;
+ type_t *tp;
+ tnode_t *tn;
+{
+ if (tn->tn_op == CON)
+ return;
+
+ if (op == CVT)
+ return;
+
+#if 0
+ if (psize(nt) > psize(ot) && isutyp(nt) != isutyp(ot)) {
+ /* conversion to %s may sign-extend incorrectly (, arg #%d) */
+ if (aflag && pflag) {
+ if (op == FARG) {
+ warning(297, tyname(tp), arg);
+ } else {
+ warning(131, tyname(tp));
+ }
+ }
+ }
+#endif
+
+ if (psize(nt) < psize(ot) &&
+ (ot == LONG || ot == ULONG || ot == QUAD || ot == UQUAD ||
+ aflag > 1)) {
+ /* conversion from '%s' may lose accuracy */
+ if (aflag) {
+ if (op == FARG) {
+ warning(298, tyname(tn->tn_type), arg);
+ } else {
+ warning(132, tyname(tn->tn_type));
+ }
+ }
+ }
+}
+
+/*
+ * Print warnings for dubious conversions of pointer to integer.
+ */
+static void
+piconv(op, nt, tp, tn)
+ op_t op;
+ tspec_t nt;
+ type_t *tp;
+ tnode_t *tn;
+{
+ if (tn->tn_op == CON)
+ return;
+
+ if (op != CVT) {
+ /* We got already an error. */
+ return;
+ }
+
+ if (psize(nt) < psize(PTR)) {
+ if (pflag && size(nt) >= size(PTR)) {
+ /* conv. of pointer to %s may lose bits */
+ warning(134, tyname(tp));
+ } else {
+ /* conv. of pointer to %s loses bits */
+ warning(133, tyname(tp));
+ }
+ }
+}
+
+/*
+ * Print warnings for questionable pointer conversions.
+ */
+static void
+ppconv(op, tn, tp)
+ op_t op;
+ tnode_t *tn;
+ type_t *tp;
+{
+ tspec_t nt, ot;
+ const char *nts, *ots;
+
+ /*
+ * We got already an error (pointers of different types
+ * without a cast) or we will not get a warning.
+ */
+ if (op != CVT)
+ return;
+
+ nt = tp->t_subt->t_tspec;
+ ot = tn->tn_type->t_subt->t_tspec;
+
+ if (nt == VOID || ot == VOID) {
+ if (sflag && (nt == FUNC || ot == FUNC)) {
+ /* (void *)0 already handled in convert() */
+ *(nt == FUNC ? &nts : &ots) = "function pointer";
+ *(nt == VOID ? &nts : &ots) = "'void *'";
+ /* ANSI C forbids conversion of %s to %s */
+ warning(303, ots, nts);
+ }
+ return;
+ } else if (nt == FUNC && ot == FUNC) {
+ return;
+ } else if (nt == FUNC || ot == FUNC) {
+ /* questionable conversion of function pointer */
+ warning(229);
+ return;
+ }
+
+ if (getbound(tp->t_subt) > getbound(tn->tn_type->t_subt)) {
+ if (hflag)
+ /* possible pointer alignment problem */
+ warning(135);
+ }
+ if (((nt == STRUCT || nt == UNION) &&
+ tp->t_subt->t_str != tn->tn_type->t_subt->t_str) ||
+ psize(nt) != psize(ot)) {
+ if (cflag) {
+ /* pointer casts may be troublesome */
+ warning(247);
+ }
+ }
+}
+
+/*
+ * Converts a typed constant in a constant of another type.
+ *
+ * op operator which requires conversion
+ * arg if op is FARG, # of argument
+ * tp type in which to convert the constant
+ * nv new constant
+ * v old constant
+ */
+void
+cvtcon(op, arg, tp, nv, v)
+ op_t op;
+ int arg;
+ type_t *tp;
+ val_t *nv, *v;
+{
+ tspec_t ot, nt;
+ ldbl_t max, min;
+ int sz, rchk;
+ quad_t xmask, xmsk1;
+ int osz, nsz;
+
+ ot = v->v_tspec;
+ nt = nv->v_tspec = tp->t_tspec;
+ rchk = 0;
+
+ if (ot == FLOAT || ot == DOUBLE || ot == LDOUBLE) {
+ switch (nt) {
+ case CHAR:
+ max = CHAR_MAX; min = CHAR_MIN; break;
+ case UCHAR:
+ max = UCHAR_MAX; min = 0; break;
+ case SCHAR:
+ max = SCHAR_MAX; min = SCHAR_MIN; break;
+ case SHORT:
+ max = SHRT_MAX; min = SHRT_MIN; break;
+ case USHORT:
+ max = USHRT_MAX; min = 0; break;
+ case ENUM:
+ case INT:
+ max = INT_MAX; min = INT_MIN; break;
+ case UINT:
+ max = (u_int)UINT_MAX; min = 0; break;
+ case LONG:
+ max = LONG_MAX; min = LONG_MIN; break;
+ case ULONG:
+ max = (u_long)ULONG_MAX; min = 0; break;
+ case QUAD:
+ max = QUAD_MAX; min = QUAD_MIN; break;
+ case UQUAD:
+ max = (u_quad_t)UQUAD_MAX; min = 0; break;
+ case FLOAT:
+ max = FLT_MAX; min = -FLT_MAX; break;
+ case DOUBLE:
+ max = DBL_MAX; min = -DBL_MAX; break;
+ case PTR:
+ /* Got already an error because of float --> ptr */
+ case LDOUBLE:
+ max = LDBL_MAX; min = -LDBL_MAX; break;
+ default:
+ lerror("cvtcon() 1");
+ }
+ if (v->v_ldbl > max || v->v_ldbl < min) {
+ if (nt == LDOUBLE)
+ lerror("cvtcon() 2");
+ if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ v->v_ldbl = v->v_ldbl > 0 ? max : min;
+ }
+ if (nt == FLOAT) {
+ nv->v_ldbl = (float)v->v_ldbl;
+ } else if (nt == DOUBLE) {
+ nv->v_ldbl = (double)v->v_ldbl;
+ } else if (nt == LDOUBLE) {
+ nv->v_ldbl = v->v_ldbl;
+ } else {
+ nv->v_quad = (nt == PTR || isutyp(nt)) ?
+ (u_quad_t)v->v_ldbl : (quad_t)v->v_ldbl;
+ }
+ } else {
+ if (nt == FLOAT) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (float)(u_quad_t)v->v_quad : (float)v->v_quad;
+ } else if (nt == DOUBLE) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (double)(u_quad_t)v->v_quad : (double)v->v_quad;
+ } else if (nt == LDOUBLE) {
+ nv->v_ldbl = (ot == PTR || isutyp(ot)) ?
+ (ldbl_t)(u_quad_t)v->v_quad : (ldbl_t)v->v_quad;
+ } else {
+ rchk = 1; /* Check for lost precision. */
+ nv->v_quad = v->v_quad;
+ }
+ }
+
+ if (v->v_ansiu && isftyp(nt)) {
+ /* ANSI C treats constant as unsigned */
+ warning(157);
+ v->v_ansiu = 0;
+ } else if (v->v_ansiu && (isityp(nt) && !isutyp(nt) &&
+ psize(nt) > psize(ot))) {
+ /* ANSI C treats constant as unsigned */
+ warning(157);
+ v->v_ansiu = 0;
+ }
+
+ if (nt != FLOAT && nt != DOUBLE && nt != LDOUBLE) {
+ sz = tp->t_isfield ? tp->t_flen : size(nt);
+ nv->v_quad = xsign(nv->v_quad, nt, sz);
+ }
+
+ if (rchk && op != CVT) {
+ osz = size(ot);
+ nsz = tp->t_isfield ? tp->t_flen : size(nt);
+ xmask = qlmasks[nsz] ^ qlmasks[osz];
+ xmsk1 = qlmasks[nsz] ^ qlmasks[osz - 1];
+ /*
+ * For bitwise operations we are not interested in the
+ * value, but in the bits itself.
+ */
+ if (op == ORASS || op == OR || op == XOR) {
+ /*
+ * Print a warning if bits which were set are
+ * lost due to the conversion.
+ * This can happen with operator ORASS only.
+ */
+ if (nsz < osz && (v->v_quad & xmask) != 0) {
+ /* constant truncated by conv., op %s */
+ warning(306, modtab[op].m_name);
+ }
+ } else if (op == ANDASS || op == AND) {
+ /*
+ * Print a warning if additional bits are not all 1
+ * and the most significant bit of the old value is 1,
+ * or if at least one (but not all) removed bit was 0.
+ */
+ if (nsz > osz &&
+ (nv->v_quad & qbmasks[osz - 1]) != 0 &&
+ (nv->v_quad & xmask) != xmask) {
+ /*
+ * extra bits set to 0 in conversion
+ * of '%s' to '%s', op %s
+ */
+ warning(309, tyname(gettyp(ot)),
+ tyname(tp), modtab[op].m_name);
+ } else if (nsz < osz &&
+ (v->v_quad & xmask) != xmask &&
+ (v->v_quad & xmask) != 0) {
+ /* const. truncated by conv., op %s */
+ warning(306, modtab[op].m_name);
+ }
+ } else if ((nt != PTR && isutyp(nt)) &&
+ (ot != PTR && !isutyp(ot)) && v->v_quad < 0) {
+ if (op == ASSIGN) {
+ /* assignment of negative constant to ... */
+ warning(164);
+ } else if (op == INIT) {
+ /* initialisation of unsigned with neg. ... */
+ warning(221);
+ } else if (op == FARG) {
+ /* conversion of neg. const. to ..., arg #%d */
+ warning(296, arg);
+ } else if (modtab[op].m_comp) {
+ /* we get this warning already in chkcomp() */
+ } else {
+ /* conversion of negative constant to ... */
+ warning(222);
+ }
+ } else if (nv->v_quad != v->v_quad && nsz <= osz &&
+ (v->v_quad & xmask) != 0 &&
+ (isutyp(ot) || (v->v_quad & xmsk1) != xmsk1)) {
+ /*
+ * Loss of significant bit(s). All truncated bits
+ * of unsigned types or all truncated bits plus the
+ * msb of the target for signed types are considered
+ * to be significant bits. Loss of significant bits
+ * means that at least on of the bits was set in an
+ * unsigned type or that at least one, but not all of
+ * the bits was set in an signed type.
+ * Loss of significant bits means that it is not
+ * possible, also not with necessary casts, to convert
+ * back to the original type. A example for a
+ * necessary cast is:
+ * char c; int i; c = 128;
+ * i = c; ** yields -128 **
+ * i = (unsigned char)c; ** yields 128 **
+ */
+ if (op == ASSIGN && tp->t_isfield) {
+ /* precision lost in bit-field assignment */
+ warning(166);
+ } else if (op == ASSIGN) {
+ /* constant truncated by assignment */
+ warning(165);
+ } else if (op == INIT && tp->t_isfield) {
+ /* bit-field initializer does not fit */
+ warning(180);
+ } else if (op == INIT) {
+ /* initializer does not fit */
+ warning(178);
+ } else if (op == CASE) {
+ /* case label affected by conversion */
+ warning(196);
+ } else if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ } else if (nv->v_quad != v->v_quad) {
+ if (op == ASSIGN && tp->t_isfield) {
+ /* precision lost in bit-field assignment */
+ warning(166);
+ } else if (op == INIT && tp->t_isfield) {
+ /* bit-field initializer out of range */
+ warning(11);
+ } else if (op == CASE) {
+ /* case label affected by conversion */
+ warning(196);
+ } else if (op == FARG) {
+ /* conv. of %s to %s is out of rng., arg #%d */
+ warning(295, tyname(gettyp(ot)), tyname(tp),
+ arg);
+ } else {
+ /* conversion of %s to %s is out of range */
+ warning(119, tyname(gettyp(ot)), tyname(tp));
+ }
+ }
+ }
+}
+
+/*
+ * Called if incompatible types were detected.
+ * Prints a appropriate warning.
+ */
+static void
+incompat(op, lt, rt)
+ op_t op;
+ tspec_t lt, rt;
+{
+ mod_t *mp;
+
+ mp = &modtab[op];
+
+ if (lt == VOID || (mp->m_binary && rt == VOID)) {
+ /* void type illegal in expression */
+ error(109);
+ } else if (op == ASSIGN) {
+ if ((lt == STRUCT || lt == UNION) &&
+ (rt == STRUCT || rt == UNION)) {
+ /* assignment of different structures */
+ error(240);
+ } else {
+ /* assignment type mismatch */
+ error(171);
+ }
+ } else if (mp->m_binary) {
+ /* operands of %s have incompatible types */
+ error(107, mp->m_name);
+ } else {
+ /* operand of %s has incompatible type */
+ error(108, mp->m_name);
+ }
+}
+
+/*
+ * Called if incompatible pointer types are detected.
+ * Print an appropriate warning.
+ */
+static void
+illptrc(mp, ltp, rtp)
+ mod_t *mp;
+ type_t *ltp, *rtp;
+{
+ tspec_t lt, rt;
+
+ if (ltp->t_tspec != PTR || rtp->t_tspec != PTR)
+ lerror("illptrc() 1");
+
+ lt = ltp->t_subt->t_tspec;
+ rt = rtp->t_subt->t_tspec;
+
+ if ((lt == STRUCT || lt == UNION) && (rt == STRUCT || rt == UNION)) {
+ if (mp == NULL) {
+ /* illegal structure pointer combination */
+ warning(244);
+ } else {
+ /* illegal structure pointer combination, op %s */
+ warning(245, mp->m_name);
+ }
+ } else {
+ if (mp == NULL) {
+ /* illegal pointer combination */
+ warning(184);
+ } else {
+ /* illegal pointer combination, op %s */
+ warning(124, mp->m_name);
+ }
+ }
+}
+
+/*
+ * Make sure type (*tpp)->t_subt has at least the qualifiers
+ * of tp1->t_subt and tp2->t_subt.
+ */
+static void
+mrgqual(tpp, tp1, tp2)
+ type_t **tpp, *tp1, *tp2;
+{
+ if ((*tpp)->t_tspec != PTR ||
+ tp1->t_tspec != PTR || tp2->t_tspec != PTR) {
+ lerror("mrgqual()");
+ }
+
+ if ((*tpp)->t_subt->t_const ==
+ (tp1->t_subt->t_const | tp2->t_subt->t_const) &&
+ (*tpp)->t_subt->t_volatile ==
+ (tp1->t_subt->t_volatile | tp2->t_subt->t_volatile)) {
+ return;
+ }
+
+ *tpp = tduptyp(*tpp);
+ (*tpp)->t_subt = tduptyp((*tpp)->t_subt);
+ (*tpp)->t_subt->t_const =
+ tp1->t_subt->t_const | tp2->t_subt->t_const;
+ (*tpp)->t_subt->t_volatile =
+ tp1->t_subt->t_volatile | tp2->t_subt->t_volatile;
+}
+
+/*
+ * Returns 1 if the given structure or union has a constant member
+ * (maybe recursively).
+ */
+static int
+conmemb(tp)
+ type_t *tp;
+{
+ sym_t *m;
+ tspec_t t;
+
+ if ((t = tp->t_tspec) != STRUCT && t != UNION)
+ lerror("conmemb()");
+ for (m = tp->t_str->memb; m != NULL; m = m->s_nxt) {
+ tp = m->s_type;
+ if (tp->t_const)
+ return (1);
+ if ((t = tp->t_tspec) == STRUCT || t == UNION) {
+ if (conmemb(m->s_type))
+ return (1);
+ }
+ }
+ return (0);
+}
+
+const char *
+tyname(tp)
+ type_t *tp;
+{
+ tspec_t t;
+ const char *s;
+
+ if ((t = tp->t_tspec) == INT && tp->t_isenum)
+ t = ENUM;
+
+ switch (t) {
+ case CHAR: s = "char"; break;
+ case UCHAR: s = "unsigned char"; break;
+ case SCHAR: s = "signed char"; break;
+ case SHORT: s = "short"; break;
+ case USHORT: s = "unsigned short"; break;
+ case INT: s = "int"; break;
+ case UINT: s = "unsigned int"; break;
+ case LONG: s = "long"; break;
+ case ULONG: s = "unsigned long"; break;
+ case QUAD: s = "long long"; break;
+ case UQUAD: s = "unsigned long long"; break;
+ case FLOAT: s = "float"; break;
+ case DOUBLE: s = "double"; break;
+ case LDOUBLE: s = "long double"; break;
+ case PTR: s = "pointer"; break;
+ case ENUM: s = "enum"; break;
+ case STRUCT: s = "struct"; break;
+ case UNION: s = "union"; break;
+ case FUNC: s = "function"; break;
+ case ARRAY: s = "array"; break;
+ default:
+ lerror("tyname()");
+ }
+ return (s);
+}
+
+/*
+ * Create a new node for one of the operators POINT and ARROW.
+ */
+static tnode_t *
+bldstr(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn, *ctn;
+ int nolval;
+
+ if (rn->tn_op != NAME)
+ lerror("bldstr() 1");
+ if (rn->tn_sym->s_value.v_tspec != INT)
+ lerror("bldstr() 2");
+ if (rn->tn_sym->s_scl != MOS && rn->tn_sym->s_scl != MOU)
+ lerror("bldstr() 3");
+
+ /*
+ * Remember if the left operand is an lvalue (structure members
+ * are lvalues if and only if the structure itself is an lvalue).
+ */
+ nolval = op == POINT && !ln->tn_lvalue;
+
+ if (op == POINT) {
+ ln = bldamper(ln, 1);
+ } else if (ln->tn_type->t_tspec != PTR) {
+ if (!tflag || !isityp(ln->tn_type->t_tspec))
+ lerror("bldstr() 4");
+ ln = convert(NOOP, 0, tincref(gettyp(VOID), PTR), ln);
+ }
+
+#if PTRDIFF_IS_LONG
+ ctn = getinode(LONG, rn->tn_sym->s_value.v_quad / CHAR_BIT);
+#else
+ ctn = getinode(INT, rn->tn_sym->s_value.v_quad / CHAR_BIT);
+#endif
+
+ ntn = mktnode(PLUS, tincref(rn->tn_type, PTR), ln, ctn);
+ if (ln->tn_op == CON)
+ ntn = fold(ntn);
+
+ if (rn->tn_type->t_isfield) {
+ ntn = mktnode(FSEL, ntn->tn_type->t_subt, ntn, NULL);
+ } else {
+ ntn = mktnode(STAR, ntn->tn_type->t_subt, ntn, NULL);
+ }
+
+ if (nolval)
+ ntn->tn_lvalue = 0;
+
+ return (ntn);
+}
+
+/*
+ * Create a node for INCAFT, INCBEF, DECAFT and DECBEF.
+ */
+static tnode_t *
+bldincdec(op, ln)
+ op_t op;
+ tnode_t *ln;
+{
+ tnode_t *cn, *ntn;
+
+ if (ln == NULL)
+ lerror("bldincdec() 1");
+
+ if (ln->tn_type->t_tspec == PTR) {
+ cn = plength(ln->tn_type);
+ } else {
+ cn = getinode(INT, (quad_t)1);
+ }
+ ntn = mktnode(op, ln->tn_type, ln, cn);
+
+ return (ntn);
+}
+
+/*
+ * Create a tree node for the & operator
+ */
+static tnode_t *
+bldamper(tn, noign)
+ tnode_t *tn;
+ int noign;
+{
+ tnode_t *ntn;
+ tspec_t t;
+
+ if (!noign && ((t = tn->tn_type->t_tspec) == ARRAY || t == FUNC)) {
+ /* & before array or function: ignored */
+ if (tflag)
+ warning(127);
+ return (tn);
+ }
+
+ /* eliminate &* */
+ if (tn->tn_op == STAR &&
+ tn->tn_left->tn_type->t_tspec == PTR &&
+ tn->tn_left->tn_type->t_subt == tn->tn_type) {
+ return (tn->tn_left);
+ }
+
+ ntn = mktnode(AMPER, tincref(tn->tn_type, PTR), tn, NULL);
+
+ return (ntn);
+}
+
+/*
+ * Create a node for operators PLUS and MINUS.
+ */
+static tnode_t *
+bldplmi(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tnode_t *ntn, *ctn;
+ type_t *tp;
+
+ /* If pointer and integer, then pointer to the lhs. */
+ if (rn->tn_type->t_tspec == PTR && isityp(ln->tn_type->t_tspec)) {
+ ntn = ln;
+ ln = rn;
+ rn = ntn;
+ }
+
+ if (ln->tn_type->t_tspec == PTR && rn->tn_type->t_tspec != PTR) {
+
+ if (!isityp(rn->tn_type->t_tspec))
+ lerror("bldplmi() 1");
+
+ ctn = plength(ln->tn_type);
+ if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec)
+ rn = convert(NOOP, 0, ctn->tn_type, rn);
+ rn = mktnode(MULT, rn->tn_type, rn, ctn);
+ if (rn->tn_left->tn_op == CON)
+ rn = fold(rn);
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ } else if (rn->tn_type->t_tspec == PTR) {
+
+ if (ln->tn_type->t_tspec != PTR || op != MINUS)
+ lerror("bldplmi() 2");
+#if PTRDIFF_IS_LONG
+ tp = gettyp(LONG);
+#else
+ tp = gettyp(INT);
+#endif
+ ntn = mktnode(op, tp, ln, rn);
+ if (ln->tn_op == CON && rn->tn_op == CON)
+ ntn = fold(ntn);
+ ctn = plength(ln->tn_type);
+ balance(NOOP, &ntn, &ctn);
+ ntn = mktnode(DIV, tp, ntn, ctn);
+
+ } else {
+
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ }
+ return (ntn);
+}
+
+/*
+ * Create a node for operators SHL and SHR.
+ */
+static tnode_t *
+bldshft(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t t;
+ tnode_t *ntn;
+
+ if ((t = rn->tn_type->t_tspec) != INT && t != UINT)
+ rn = convert(CVT, 0, gettyp(INT), rn);
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+ return (ntn);
+}
+
+/*
+ * Create a node for COLON.
+ */
+static tnode_t *
+bldcol(ln, rn)
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt, pdt;
+ type_t *rtp;
+ tnode_t *ntn;
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+#if PTRDIFF_IS_LONG
+ pdt = LONG;
+#else
+ pdt = INT;
+#endif
+
+ /*
+ * Arithmetic types are balanced, all other type combinations
+ * still need to be handled.
+ */
+ if (isatyp(lt) && isatyp(rt)) {
+ rtp = ln->tn_type;
+ } else if (lt == VOID || rt == VOID) {
+ rtp = gettyp(VOID);
+ } else if (lt == STRUCT || lt == UNION) {
+ /* Both types must be identical. */
+ if (rt != STRUCT && rt != UNION)
+ lerror("bldcol() 1");
+ if (ln->tn_type->t_str != rn->tn_type->t_str)
+ lerror("bldcol() 2");
+ if (incompl(ln->tn_type)) {
+ /* unknown operand size, op %s */
+ error(138, modtab[COLON].m_name);
+ return (NULL);
+ }
+ rtp = ln->tn_type;
+ } else if (lt == PTR && isityp(rt)) {
+ if (rt != pdt) {
+ rn = convert(NOOP, 0, gettyp(pdt), rn);
+ rt = pdt;
+ }
+ rtp = ln->tn_type;
+ } else if (rt == PTR && isityp(lt)) {
+ if (lt != pdt) {
+ ln = convert(NOOP, 0, gettyp(pdt), ln);
+ lt = pdt;
+ }
+ rtp = rn->tn_type;
+ } else if (lt == PTR && ln->tn_type->t_subt->t_tspec == VOID) {
+ if (rt != PTR)
+ lerror("bldcol() 4");
+ rtp = ln->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ } else if (rt == PTR && rn->tn_type->t_subt->t_tspec == VOID) {
+ if (lt != PTR)
+ lerror("bldcol() 5");
+ rtp = rn->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ } else {
+ if (lt != PTR || rt != PTR)
+ lerror("bldcol() 6");
+ /*
+ * XXX For now we simply take the left type. This is
+ * probably wrong, if one type contains a functionprototype
+ * and the other one, at the same place, only an old style
+ * declaration.
+ */
+ rtp = ln->tn_type;
+ mrgqual(&rtp, ln->tn_type, rn->tn_type);
+ }
+
+ ntn = mktnode(COLON, rtp, ln, rn);
+
+ return (ntn);
+}
+
+/*
+ * Create a node for an assignment operator (both = and op= ).
+ */
+static tnode_t *
+bldasgn(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt;
+ tnode_t *ntn, *ctn;
+
+ if (ln == NULL || rn == NULL)
+ lerror("bldasgn() 1");
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+
+ if ((op == ADDASS || op == SUBASS) && lt == PTR) {
+ if (!isityp(rt))
+ lerror("bldasgn() 2");
+ ctn = plength(ln->tn_type);
+ if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec)
+ rn = convert(NOOP, 0, ctn->tn_type, rn);
+ rn = mktnode(MULT, rn->tn_type, rn, ctn);
+ if (rn->tn_left->tn_op == CON)
+ rn = fold(rn);
+ }
+
+ if ((op == ASSIGN || op == RETURN) && (lt == STRUCT || rt == STRUCT)) {
+ if (rt != lt || ln->tn_type->t_str != rn->tn_type->t_str)
+ lerror("bldasgn() 3");
+ if (incompl(ln->tn_type)) {
+ if (op == RETURN) {
+ /* cannot return incomplete type */
+ error(212);
+ } else {
+ /* unknown operand size, op %s */
+ error(138, modtab[op].m_name);
+ }
+ return (NULL);
+ }
+ }
+
+ if (op == SHLASS || op == SHRASS) {
+ if (rt != INT) {
+ rn = convert(NOOP, 0, gettyp(INT), rn);
+ rt = INT;
+ }
+ } else {
+ if (op == ASSIGN || lt != PTR) {
+ if (lt != rt ||
+ (ln->tn_type->t_isfield && rn->tn_op == CON)) {
+ rn = convert(op, 0, ln->tn_type, rn);
+ rt = lt;
+ }
+ }
+ }
+
+ ntn = mktnode(op, ln->tn_type, ln, rn);
+
+ return (ntn);
+}
+
+/*
+ * Get length of type tp->t_subt.
+ */
+static tnode_t *
+plength(tp)
+ type_t *tp;
+{
+ int elem, elsz;
+ tspec_t st;
+
+ if (tp->t_tspec != PTR)
+ lerror("plength() 1");
+ tp = tp->t_subt;
+
+ elem = 1;
+ elsz = 0;
+
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* pointer to function is not allowed here */
+ error(110);
+ break;
+ case VOID:
+ /* cannot do pointer arithmetic on operand of ... */
+ (void)gnuism(136);
+ break;
+ case STRUCT:
+ case UNION:
+ if ((elsz = tp->t_str->size) == 0)
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ break;
+ case ENUM:
+ if (incompl(tp)) {
+ /* cannot do pointer arithmetic on operand of ... */
+ warning(136);
+ }
+ /* FALLTHROUGH */
+ default:
+ if ((elsz = size(tp->t_tspec)) == 0) {
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ } else if (elsz == -1) {
+ lerror("plength() 2");
+ }
+ break;
+ }
+
+ if (elem == 0 && elsz != 0) {
+ /* cannot do pointer arithmetic on operand of ... */
+ error(136);
+ }
+
+ if (elsz == 0)
+ elsz = CHAR_BIT;
+
+#if PTRDIFF_IS_LONG
+ st = LONG;
+#else
+ st = INT;
+#endif
+
+ return (getinode(st, (quad_t)(elem * elsz / CHAR_BIT)));
+}
+
+#ifdef XXX_BROKEN_GCC
+static int
+quad_t_eq(x, y)
+ quad_t x, y;
+{
+ return (x == y);
+}
+
+static int
+u_quad_t_eq(x, y)
+ u_quad_t x, y;
+{
+ return (x == y);
+}
+#endif
+
+/*
+ * Do only as much as necessary to compute constant expressions.
+ * Called only if the operator allows folding and (both) operands
+ * are constants.
+ */
+static tnode_t *
+fold(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+ tspec_t t;
+ int utyp, ovfl;
+ quad_t sl, sr, q, mask;
+ u_quad_t ul, ur;
+ tnode_t *cn;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = t = tn->tn_type->t_tspec;
+
+ utyp = t == PTR || isutyp(t);
+ ul = sl = tn->tn_left->tn_val->v_quad;
+ if (modtab[tn->tn_op].m_binary)
+ ur = sr = tn->tn_right->tn_val->v_quad;
+
+ ovfl = 0;
+
+ switch (tn->tn_op) {
+ case UPLUS:
+ q = sl;
+ break;
+ case UMINUS:
+ q = -sl;
+ if (msb(q, t, -1) == msb(sl, t, -1))
+ ovfl = 1;
+ break;
+ case COMPL:
+ q = ~sl;
+ break;
+ case MULT:
+ q = utyp ? ul * ur : sl * sr;
+ if (msb(q, t, -1) != (msb(sl, t, -1) ^ msb(sr, t, -1)))
+ ovfl = 1;
+ break;
+ case DIV:
+ if (sr == 0) {
+ /* division by 0 */
+ error(139);
+ q = utyp ? UQUAD_MAX : QUAD_MAX;
+ } else {
+ q = utyp ? ul / ur : sl / sr;
+ }
+ break;
+ case MOD:
+ if (sr == 0) {
+ /* modulus by 0 */
+ error(140);
+ q = 0;
+ } else {
+ q = utyp ? ul % ur : sl % sr;
+ }
+ break;
+ case PLUS:
+ q = utyp ? ul + ur : sl + sr;
+ if (msb(sl, t, -1) != 0 && msb(sr, t, -1) != 0) {
+ if (msb(q, t, -1) == 0)
+ ovfl = 1;
+ } else if (msb(sl, t, -1) == 0 && msb(sr, t, -1) == 0) {
+ if (msb(q, t, -1) != 0)
+ ovfl = 1;
+ }
+ break;
+ case MINUS:
+ q = utyp ? ul - ur : sl - sr;
+ if (msb(sl, t, -1) != 0 && msb(sr, t, -1) == 0) {
+ if (msb(q, t, -1) == 0)
+ ovfl = 1;
+ } else if (msb(sl, t, -1) == 0 && msb(sr, t, -1) != 0) {
+ if (msb(q, t, -1) != 0)
+ ovfl = 1;
+ }
+ break;
+ case SHL:
+ q = utyp ? ul << sr : sl << sr;
+ break;
+ case SHR:
+ /*
+ * The sign must be explizitly extended because
+ * shifts of signed values are implementation dependent.
+ */
+ q = ul >> sr;
+ q = xsign(q, t, size(t) - (int)sr);
+ break;
+ case LT:
+ q = utyp ? ul < ur : sl < sr;
+ break;
+ case LE:
+ q = utyp ? ul <= ur : sl <= sr;
+ break;
+ case GE:
+ q = utyp ? ul >= ur : sl >= sr;
+ break;
+ case GT:
+ q = utyp ? ul > ur : sl > sr;
+ break;
+ case EQ:
+#ifdef XXX_BROKEN_GCC
+ q = utyp ? u_quad_t_eq(ul, ur) : quad_t_eq(sl, sr);
+#else
+ q = utyp ? ul == ur : sl == sr;
+#endif
+ break;
+ case NE:
+ q = utyp ? ul != ur : sl != sr;
+ break;
+ case AND:
+ q = utyp ? ul & ur : sl & sr;
+ break;
+ case XOR:
+ q = utyp ? ul ^ ur : sl ^ sr;
+ break;
+ case OR:
+ q = utyp ? ul | ur : sl | sr;
+ break;
+ default:
+ lerror("fold() 5");
+ }
+
+ mask = qlmasks[size(t)];
+
+ /* XXX does not work for quads. */
+ if (ovfl || ((q | mask) != ~(u_quad_t)0 && (q & ~mask) != 0)) {
+ if (hflag)
+ /* integer overflow detected, op %s */
+ warning(141, modtab[tn->tn_op].m_name);
+ }
+
+ v->v_quad = xsign(q, t, -1);
+
+ cn = getcnode(tn->tn_type, v);
+
+ return (cn);
+}
+
+#ifdef XXX_BROKEN_GCC
+int
+ldbl_t_neq(x, y)
+ ldbl_t x, y;
+{
+ return (x != y);
+}
+#endif
+
+/*
+ * Same for operators whose operands are compared with 0 (test context).
+ */
+static tnode_t *
+foldtst(tn)
+ tnode_t *tn;
+{
+ int l, r;
+ val_t *v;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = tn->tn_type->t_tspec;
+ if (tn->tn_type->t_tspec != INT)
+ lerror("foldtst() 1");
+
+ if (isftyp(tn->tn_left->tn_type->t_tspec)) {
+#ifdef XXX_BROKEN_GCC
+ l = ldbl_t_neq(tn->tn_left->tn_val->v_ldbl, 0.0);
+#else
+ l = tn->tn_left->tn_val->v_ldbl != 0.0;
+#endif
+ } else {
+ l = tn->tn_left->tn_val->v_quad != 0;
+ }
+
+ if (modtab[tn->tn_op].m_binary) {
+ if (isftyp(tn->tn_right->tn_type->t_tspec)) {
+#ifdef XXX_BROKEN_GCC
+ r = ldbl_t_neq(tn->tn_right->tn_val->v_ldbl, 0.0);
+#else
+ r = tn->tn_right->tn_val->v_ldbl != 0.0;
+#endif
+ } else {
+ r = tn->tn_right->tn_val->v_quad != 0;
+ }
+ }
+
+ switch (tn->tn_op) {
+ case NOT:
+ if (hflag)
+ /* constant argument to NOT */
+ warning(239);
+ v->v_quad = !l;
+ break;
+ case LOGAND:
+ v->v_quad = l && r;
+ break;
+ case LOGOR:
+ v->v_quad = l || r;
+ break;
+ default:
+ lerror("foldtst() 1");
+ }
+
+ return (getcnode(tn->tn_type, v));
+}
+
+/*
+ * Same for operands with floating point type.
+ */
+static tnode_t *
+foldflt(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+ tspec_t t;
+ ldbl_t l, r;
+
+ v = xcalloc(1, sizeof (val_t));
+ v->v_tspec = t = tn->tn_type->t_tspec;
+
+ if (!isftyp(t))
+ lerror("foldflt() 1");
+
+ if (t != tn->tn_left->tn_type->t_tspec)
+ lerror("foldflt() 2");
+ if (modtab[tn->tn_op].m_binary && t != tn->tn_right->tn_type->t_tspec)
+ lerror("foldflt() 3");
+
+ l = tn->tn_left->tn_val->v_ldbl;
+ if (modtab[tn->tn_op].m_binary)
+ r = tn->tn_right->tn_val->v_ldbl;
+
+ switch (tn->tn_op) {
+ case UPLUS:
+ v->v_ldbl = l;
+ break;
+ case UMINUS:
+ v->v_ldbl = -l;
+ break;
+ case MULT:
+ v->v_ldbl = l * r;
+ break;
+ case DIV:
+ if (r == 0.0) {
+ /* division by 0 */
+ error(139);
+ if (t == FLOAT) {
+ v->v_ldbl = l < 0 ? -FLT_MAX : FLT_MAX;
+ } else if (t == DOUBLE) {
+ v->v_ldbl = l < 0 ? -DBL_MAX : DBL_MAX;
+ } else {
+ v->v_ldbl = l < 0 ? -LDBL_MAX : LDBL_MAX;
+ }
+ } else {
+ v->v_ldbl = l / r;
+ }
+ break;
+ case PLUS:
+ v->v_ldbl = l + r;
+ break;
+ case MINUS:
+ v->v_ldbl = l - r;
+ break;
+ case LT:
+ v->v_quad = l < r;
+ break;
+ case LE:
+ v->v_quad = l <= r;
+ break;
+ case GE:
+ v->v_quad = l >= r;
+ break;
+ case GT:
+ v->v_quad = l > r;
+ break;
+ case EQ:
+ v->v_quad = l == r;
+ break;
+ case NE:
+ v->v_quad = l != r;
+ break;
+ default:
+ lerror("foldflt() 4");
+ }
+
+ if (isnan((double)v->v_ldbl))
+ lerror("foldflt() 5");
+ if (isinf((double)v->v_ldbl) ||
+ (t == FLOAT &&
+ (v->v_ldbl > FLT_MAX || v->v_ldbl < -FLT_MAX)) ||
+ (t == DOUBLE &&
+ (v->v_ldbl > DBL_MAX || v->v_ldbl < -DBL_MAX))) {
+ /* floating point overflow detected, op %s */
+ warning(142, modtab[tn->tn_op].m_name);
+ if (t == FLOAT) {
+ v->v_ldbl = v->v_ldbl < 0 ? -FLT_MAX : FLT_MAX;
+ } else if (t == DOUBLE) {
+ v->v_ldbl = v->v_ldbl < 0 ? -DBL_MAX : DBL_MAX;
+ } else {
+ v->v_ldbl = v->v_ldbl < 0 ? -LDBL_MAX: LDBL_MAX;
+ }
+ }
+
+ return (getcnode(tn->tn_type, v));
+}
+
+/*
+ * Create a constant node for sizeof.
+ */
+tnode_t *
+bldszof(tp)
+ type_t *tp;
+{
+ int elem, elsz;
+ tspec_t st;
+
+ elem = 1;
+ while (tp->t_tspec == ARRAY) {
+ elem *= tp->t_dim;
+ tp = tp->t_subt;
+ }
+ if (elem == 0) {
+ /* cannot take size of incomplete type */
+ error(143);
+ elem = 1;
+ }
+ switch (tp->t_tspec) {
+ case FUNC:
+ /* cannot take size of function */
+ error(144);
+ elsz = 1;
+ break;
+ case STRUCT:
+ case UNION:
+ if (incompl(tp)) {
+ /* cannot take size of incomplete type */
+ error(143);
+ elsz = 1;
+ } else {
+ elsz = tp->t_str->size;
+ }
+ break;
+ case ENUM:
+ if (incompl(tp)) {
+ /* cannot take size of incomplete type */
+ warning(143);
+ }
+ /* FALLTHROUGH */
+ default:
+ if (tp->t_isfield) {
+ /* cannot take size of bit-field */
+ error(145);
+ }
+ if (tp->t_tspec == VOID) {
+ /* cannot take size of void */
+ error(146);
+ elsz = 1;
+ } else {
+ elsz = size(tp->t_tspec);
+ if (elsz <= 0)
+ lerror("bldszof() 1");
+ }
+ break;
+ }
+
+#if SIZEOF_IS_ULONG
+ st = ULONG;
+#else
+ st = UINT;
+#endif
+
+ return (getinode(st, (quad_t)(elem * elsz / CHAR_BIT)));
+}
+
+/*
+ * Type casts.
+ */
+tnode_t *
+cast(tn, tp)
+ tnode_t *tn;
+ type_t *tp;
+{
+ tspec_t nt, ot;
+
+ if (tn == NULL)
+ return (NULL);
+
+ tn = cconv(tn);
+
+ nt = tp->t_tspec;
+ ot = tn->tn_type->t_tspec;
+
+ if (nt == VOID) {
+ /*
+ * XXX ANSI C requires scalar types or void (Plauger&Brodie).
+ * But this seams really questionable.
+ */
+ } else if (nt == STRUCT || nt == UNION || nt == ARRAY || nt == FUNC) {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ } else if (ot == STRUCT || ot == UNION) {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ } else if (ot == VOID) {
+ /* improper cast of void expression */
+ error(148);
+ return (NULL);
+ } else if (isityp(nt) && issclt(ot)) {
+ /* ok */
+ } else if (isftyp(nt) && isatyp(ot)) {
+ /* ok */
+ } else if (nt == PTR && isityp(ot)) {
+ /* ok */
+ } else if (nt == PTR && ot == PTR) {
+ if (!tp->t_subt->t_const && tn->tn_type->t_subt->t_const) {
+ if (hflag)
+ /* cast discards 'const' from ... */
+ warning(275);
+ }
+ } else {
+ /* invalid cast expression */
+ error(147);
+ return (NULL);
+ }
+
+ tn = convert(CVT, 0, tp, tn);
+ tn->tn_cast = 1;
+
+ return (tn);
+}
+
+/*
+ * Create the node for a function argument.
+ * All necessary conversions and type checks are done in funccall(), because
+ * in funcarg() we have no information about expected argument types.
+ */
+tnode_t *
+funcarg(args, arg)
+ tnode_t *args, *arg;
+{
+ tnode_t *ntn;
+
+ /*
+ * If there was a serious error in the expression for the argument,
+ * create a dummy argument so the positions of the remaining arguments
+ * will not change.
+ */
+ if (arg == NULL)
+ arg = getinode(INT, (quad_t)0);
+
+ ntn = mktnode(PUSH, arg->tn_type, arg, args);
+
+ return (ntn);
+}
+
+/*
+ * Create the node for a function call. Also check types of
+ * function arguments and insert conversions, if necessary.
+ */
+tnode_t *
+funccall(func, args)
+ tnode_t *func, *args;
+{
+ tnode_t *ntn;
+ op_t fcop;
+
+ if (func == NULL)
+ return (NULL);
+
+ if (func->tn_op == NAME && func->tn_type->t_tspec == FUNC) {
+ fcop = CALL;
+ } else {
+ fcop = ICALL;
+ }
+
+ /*
+ * after cconv() func will always be a pointer to a function
+ * if it is a valid function designator.
+ */
+ func = cconv(func);
+
+ if (func->tn_type->t_tspec != PTR ||
+ func->tn_type->t_subt->t_tspec != FUNC) {
+ /* illegal function */
+ error(149);
+ return (NULL);
+ }
+
+ args = chkfarg(func->tn_type->t_subt, args);
+
+ ntn = mktnode(fcop, func->tn_type->t_subt->t_subt, func, args);
+
+ return (ntn);
+}
+
+/*
+ * Check types of all function arguments and insert conversions,
+ * if necessary.
+ */
+static tnode_t *
+chkfarg(ftp, args)
+ type_t *ftp; /* type of called function */
+ tnode_t *args; /* arguments */
+{
+ tnode_t *arg;
+ sym_t *asym;
+ tspec_t at;
+ int narg, npar, n, i;
+
+ /* get # of args in the prototype */
+ npar = 0;
+ for (asym = ftp->t_args; asym != NULL; asym = asym->s_nxt)
+ npar++;
+
+ /* get # of args in function call */
+ narg = 0;
+ for (arg = args; arg != NULL; arg = arg->tn_right)
+ narg++;
+
+ asym = ftp->t_args;
+ if (ftp->t_proto && npar != narg && !(ftp->t_vararg && npar < narg)) {
+ /* argument mismatch: %d arg%s passed, %d expected */
+ error(150, narg, narg > 1 ? "s" : "", npar);
+ asym = NULL;
+ }
+
+ for (n = 1; n <= narg; n++) {
+
+ /*
+ * The rightmost argument is at the top of the argument
+ * subtree.
+ */
+ for (i = narg, arg = args; i > n; i--, arg = arg->tn_right) ;
+
+ /* some things which are always not allowd */
+ if ((at = arg->tn_left->tn_type->t_tspec) == VOID) {
+ /* void expressions may not be arguments, arg #%d */
+ error(151, n);
+ return (NULL);
+ } else if ((at == STRUCT || at == UNION) &&
+ incompl(arg->tn_left->tn_type)) {
+ /* argument cannot have unknown size, arg #%d */
+ error(152, n);
+ return (NULL);
+ } else if (isityp(at) && arg->tn_left->tn_type->t_isenum &&
+ incompl(arg->tn_left->tn_type)) {
+ /* argument cannot have unknown size, arg #%d */
+ warning(152, n);
+ }
+
+ /* class conversions (arg in value context) */
+ arg->tn_left = cconv(arg->tn_left);
+
+ if (asym != NULL) {
+ arg->tn_left = parg(n, asym->s_type, arg->tn_left);
+ } else {
+ arg->tn_left = promote(NOOP, 1, arg->tn_left);
+ }
+ arg->tn_type = arg->tn_left->tn_type;
+
+ if (asym != NULL)
+ asym = asym->s_nxt;
+ }
+
+ return (args);
+}
+
+/*
+ * Compare the type of an argument with the corresponding type of a
+ * prototype parameter. If it is a valid combination, but both types
+ * are not the same, insert a conversion to convert the argument into
+ * the type of the parameter.
+ */
+static tnode_t *
+parg(n, tp, tn)
+ int n; /* pos of arg */
+ type_t *tp; /* expected type (from prototype) */
+ tnode_t *tn; /* argument */
+{
+ tnode_t *ln;
+ int warn;
+
+ ln = xcalloc(1, sizeof (tnode_t));
+ ln->tn_type = tduptyp(tp);
+ ln->tn_type->t_const = 0;
+ ln->tn_lvalue = 1;
+ if (typeok(FARG, n, ln, tn)) {
+ if (!eqtype(tp, tn->tn_type, 1, 0, (warn = 0, &warn)) || warn)
+ tn = convert(FARG, n, tp, tn);
+ }
+ free(ln);
+ return (tn);
+}
+
+/*
+ * Return the value of an integral constant expression.
+ * If the expression is not constant or its type is not an integer
+ * type, an error message is printed.
+ */
+val_t *
+constant(tn)
+ tnode_t *tn;
+{
+ val_t *v;
+
+ if (tn != NULL)
+ tn = cconv(tn);
+ if (tn != NULL)
+ tn = promote(NOOP, 0, tn);
+
+ v = xcalloc(1, sizeof (val_t));
+
+ if (tn == NULL) {
+ if (nerr == 0)
+ lerror("constant() 1");
+ v->v_tspec = INT;
+ v->v_quad = 1;
+ return (v);
+ }
+
+ v->v_tspec = tn->tn_type->t_tspec;
+
+ if (tn->tn_op == CON) {
+ if (tn->tn_type->t_tspec != tn->tn_val->v_tspec)
+ lerror("constant() 2");
+ if (isityp(tn->tn_val->v_tspec)) {
+ v->v_ansiu = tn->tn_val->v_ansiu;
+ v->v_quad = tn->tn_val->v_quad;
+ return (v);
+ }
+ v->v_quad = tn->tn_val->v_ldbl;
+ } else {
+ v->v_quad = 1;
+ }
+
+ /* integral constant expression expected */
+ error(55);
+
+ if (!isityp(v->v_tspec))
+ v->v_tspec = INT;
+
+ return (v);
+}
+
+/*
+ * Perform some tests on expressions which can't be done in build() and
+ * functions called by build(). These tests must be done here because
+ * we need some information about the context in which the operations
+ * are performed.
+ * After all tests are performed, expr() frees the memory which is used
+ * for the expression.
+ */
+void
+expr(tn, vctx, tctx)
+ tnode_t *tn;
+ int vctx, tctx;
+{
+ if (tn == NULL && nerr == 0)
+ lerror("expr() 1");
+
+ if (tn == NULL) {
+ tfreeblk();
+ return;
+ }
+
+ /* expr() is also called in global initialisations */
+ if (dcs->d_ctx != EXTERN)
+ chkreach();
+
+ chkmisc(tn, vctx, tctx, !tctx, 0, 0, 0);
+ if (tn->tn_op == ASSIGN) {
+ if (hflag && tctx)
+ /* assignment in conditional context */
+ warning(159);
+ } else if (tn->tn_op == CON) {
+ if (hflag && tctx && !ccflg)
+ /* constant in conditional context */
+ warning(161);
+ }
+ if (!modtab[tn->tn_op].m_sideeff) {
+ /*
+ * for left operands of COMMA this warning is already
+ * printed
+ */
+ if (tn->tn_op != COMMA && !vctx && !tctx)
+ nulleff(tn);
+ }
+ if (dflag)
+ displexpr(tn, 0);
+
+ /* free the tree memory */
+ tfreeblk();
+}
+
+static void
+nulleff(tn)
+ tnode_t *tn;
+{
+ if (!hflag)
+ return;
+
+ while (!modtab[tn->tn_op].m_sideeff) {
+ if (tn->tn_op == CVT && tn->tn_type->t_tspec == VOID) {
+ tn = tn->tn_left;
+ } else if (tn->tn_op == LOGAND || tn->tn_op == LOGOR) {
+ /*
+ * && and || have a side effect if the right operand
+ * has a side effect.
+ */
+ tn = tn->tn_right;
+ } else if (tn->tn_op == QUEST) {
+ /*
+ * ? has a side effect if at least one of its right
+ * operands has a side effect
+ */
+ tn = tn->tn_right;
+ } else if (tn->tn_op == COLON) {
+ /*
+ * : has a side effect if at least one of its operands
+ * has a side effect
+ */
+ if (modtab[tn->tn_left->tn_op].m_sideeff) {
+ tn = tn->tn_left;
+ } else if (modtab[tn->tn_right->tn_op].m_sideeff) {
+ tn = tn->tn_right;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if (!modtab[tn->tn_op].m_sideeff)
+ /* expression has null effect */
+ warning(129);
+}
+
+/*
+ * Dump an expression to stdout
+ * only used for debugging
+ */
+static void
+displexpr(tn, offs)
+ tnode_t *tn;
+ int offs;
+{
+ u_quad_t uq;
+
+ if (tn == NULL) {
+ (void)printf("%*s%s\n", offs, "", "NULL");
+ return;
+ }
+ (void)printf("%*sop %s ", offs, "", modtab[tn->tn_op].m_name);
+
+ if (tn->tn_op == NAME) {
+ (void)printf("%s: %s ",
+ tn->tn_sym->s_name, scltoa(tn->tn_sym->s_scl));
+ } else if (tn->tn_op == CON && isftyp(tn->tn_type->t_tspec)) {
+ (void)printf("%#g ", (double)tn->tn_val->v_ldbl);
+ } else if (tn->tn_op == CON && isityp(tn->tn_type->t_tspec)) {
+ uq = tn->tn_val->v_quad;
+ (void)printf("0x %08lx %08lx ", (long)(uq >> 32) & 0xffffffffl,
+ (long)uq & 0xffffffffl);
+ } else if (tn->tn_op == CON) {
+ if (tn->tn_type->t_tspec != PTR)
+ lerror("displexpr() 1");
+ (void)printf("0x%0*lx ", (int)(sizeof (void *) * CHAR_BIT / 4),
+ (u_long)tn->tn_val->v_quad);
+ } else if (tn->tn_op == STRING) {
+ if (tn->tn_strg->st_tspec == CHAR) {
+ (void)printf("\"%s\"", tn->tn_strg->st_cp);
+ } else {
+ char *s;
+ size_t n;
+ n = MB_CUR_MAX * (tn->tn_strg->st_len + 1);
+ s = xmalloc(n);
+ (void)wcstombs(s, tn->tn_strg->st_wcp, n);
+ (void)printf("L\"%s\"", s);
+ free(s);
+ }
+ (void)printf(" ");
+ } else if (tn->tn_op == FSEL) {
+ (void)printf("o=%d, l=%d ", tn->tn_type->t_foffs,
+ tn->tn_type->t_flen);
+ }
+ (void)printf("%s\n", ttos(tn->tn_type));
+ if (tn->tn_op == NAME || tn->tn_op == CON || tn->tn_op == STRING)
+ return;
+ displexpr(tn->tn_left, offs + 2);
+ if (modtab[tn->tn_op].m_binary ||
+ (tn->tn_op == PUSH && tn->tn_right != NULL)) {
+ displexpr(tn->tn_right, offs + 2);
+ }
+}
+
+/*
+ * Called by expr() to recursively perform some tests.
+ */
+/* ARGSUSED */
+void
+chkmisc(tn, vctx, tctx, eqwarn, fcall, rvdisc, szof)
+ tnode_t *tn;
+ int vctx, tctx, eqwarn, fcall, rvdisc, szof;
+{
+ tnode_t *ln, *rn;
+ mod_t *mp;
+ int nrvdisc, cvctx, ctctx;
+ op_t op;
+ scl_t sc;
+ dinfo_t *di;
+
+ if (tn == NULL)
+ return;
+
+ ln = tn->tn_left;
+ rn = tn->tn_right;
+ mp = &modtab[op = tn->tn_op];
+
+ switch (op) {
+ case AMPER:
+ if (ln->tn_op == NAME && (reached || rchflg)) {
+ if (!szof)
+ setsflg(ln->tn_sym);
+ setuflg(ln->tn_sym, fcall, szof);
+ }
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 1);
+ break;
+ case LOAD:
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 0);
+ /* FALLTHROUGH */
+ case PUSH:
+ case INCBEF:
+ case DECBEF:
+ case INCAFT:
+ case DECAFT:
+ case ADDASS:
+ case SUBASS:
+ case MULASS:
+ case DIVASS:
+ case MODASS:
+ case ANDASS:
+ case ORASS:
+ case XORASS:
+ case SHLASS:
+ case SHRASS:
+ if (ln->tn_op == NAME && (reached || rchflg)) {
+ sc = ln->tn_sym->s_scl;
+ /*
+ * Look if there was a asm statement in one of the
+ * compound statements we are in. If not, we don't
+ * print a warning.
+ */
+ for (di = dcs; di != NULL; di = di->d_nxt) {
+ if (di->d_asm)
+ break;
+ }
+ if (sc != EXTERN && sc != STATIC &&
+ !ln->tn_sym->s_set && !szof && di == NULL) {
+ /* %s may be used before set */
+ warning(158, ln->tn_sym->s_name);
+ setsflg(ln->tn_sym);
+ }
+ setuflg(ln->tn_sym, 0, 0);
+ }
+ break;
+ case ASSIGN:
+ if (ln->tn_op == NAME && !szof && (reached || rchflg)) {
+ setsflg(ln->tn_sym);
+ if (ln->tn_sym->s_scl == EXTERN)
+ outusg(ln->tn_sym);
+ }
+ if (ln->tn_op == STAR && ln->tn_left->tn_op == PLUS)
+ /* check the range of array indices */
+ chkaidx(ln->tn_left, 0);
+ break;
+ case CALL:
+ if (ln->tn_op != AMPER || ln->tn_left->tn_op != NAME)
+ lerror("chkmisc() 1");
+ if (!szof)
+ outcall(tn, vctx || tctx, rvdisc);
+ break;
+ case EQ:
+ /* equality operator "==" found where "=" was exp. */
+ if (hflag && eqwarn)
+ warning(160);
+ break;
+ case CON:
+ case NAME:
+ case STRING:
+ return;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ cvctx = mp->m_vctx;
+ ctctx = mp->m_tctx;
+ /*
+ * values of operands of ':' are not used if the type of at least
+ * one of the operands (for gcc compatibility) is void
+ * XXX test/value context of QUEST should probably be used as
+ * context for both operands of COLON
+ */
+ if (op == COLON && tn->tn_type->t_tspec == VOID)
+ cvctx = ctctx = 0;
+ nrvdisc = op == CVT && tn->tn_type->t_tspec == VOID;
+ chkmisc(ln, cvctx, ctctx, mp->m_eqwarn, op == CALL, nrvdisc, szof);
+
+ switch (op) {
+ case PUSH:
+ if (rn != NULL)
+ chkmisc(rn, 0, 0, mp->m_eqwarn, 0, 0, szof);
+ break;
+ case LOGAND:
+ case LOGOR:
+ chkmisc(rn, 0, 1, mp->m_eqwarn, 0, 0, szof);
+ break;
+ case COLON:
+ chkmisc(rn, cvctx, ctctx, mp->m_eqwarn, 0, 0, szof);
+ break;
+ default:
+ if (mp->m_binary)
+ chkmisc(rn, 1, 0, mp->m_eqwarn, 0, 0, szof);
+ break;
+ }
+
+}
+
+/*
+ * Checks the range of array indices, if possible.
+ * amper is set if only the address of the element is used. This
+ * means that the index is allowd to refere to the first element
+ * after the array.
+ */
+static void
+chkaidx(tn, amper)
+ tnode_t *tn;
+ int amper;
+{
+ int dim;
+ tnode_t *ln, *rn;
+ int elsz;
+ quad_t con;
+
+ ln = tn->tn_left;
+ rn = tn->tn_right;
+
+ /* We can only check constant indices. */
+ if (rn->tn_op != CON)
+ return;
+
+ /* Return if the left node does not stem from an array. */
+ if (ln->tn_op != AMPER)
+ return;
+ if (ln->tn_left->tn_op != STRING && ln->tn_left->tn_op != NAME)
+ return;
+ if (ln->tn_left->tn_type->t_tspec != ARRAY)
+ return;
+
+ /*
+ * For incomplete array types, we can print a warning only if
+ * the index is negative.
+ */
+ if (incompl(ln->tn_left->tn_type) && rn->tn_val->v_quad >= 0)
+ return;
+
+ /* Get the size of one array element */
+ if ((elsz = length(ln->tn_type->t_subt, NULL)) == 0)
+ return;
+ elsz /= CHAR_BIT;
+
+ /* Change the unit of the index from bytes to element size. */
+ if (isutyp(rn->tn_type->t_tspec)) {
+ con = (u_quad_t)rn->tn_val->v_quad / elsz;
+ } else {
+ con = rn->tn_val->v_quad / elsz;
+ }
+
+ dim = ln->tn_left->tn_type->t_dim + (amper ? 1 : 0);
+
+ if (!isutyp(rn->tn_type->t_tspec) && con < 0) {
+ /* array subscript cannot be negative: %ld */
+ warning(167, (long)con);
+ } else if (dim > 0 && (u_quad_t)con >= dim) {
+ /* array subscript cannot be > %d: %ld */
+ warning(168, dim - 1, (long)con);
+ }
+}
+
+/*
+ * Check for ordered comparisions of unsigned values with 0.
+ */
+static void
+chkcomp(op, ln, rn)
+ op_t op;
+ tnode_t *ln, *rn;
+{
+ tspec_t lt, rt;
+ mod_t *mp;
+
+ lt = ln->tn_type->t_tspec;
+ rt = rn->tn_type->t_tspec;
+ mp = &modtab[op];
+
+ if (ln->tn_op != CON && rn->tn_op != CON)
+ return;
+
+ if (!isityp(lt) || !isityp(rt))
+ return;
+
+ if ((hflag || pflag) && lt == CHAR && rn->tn_op == CON &&
+ (rn->tn_val->v_quad < 0 ||
+ rn->tn_val->v_quad > ~(~0 << (CHAR_BIT - 1)))) {
+ /* nonportable character comparision, op %s */
+ warning(230, mp->m_name);
+ return;
+ }
+ if ((hflag || pflag) && rt == CHAR && ln->tn_op == CON &&
+ (ln->tn_val->v_quad < 0 ||
+ ln->tn_val->v_quad > ~(~0 << (CHAR_BIT - 1)))) {
+ /* nonportable character comparision, op %s */
+ warning(230, mp->m_name);
+ return;
+ }
+ if (isutyp(lt) && !isutyp(rt) &&
+ rn->tn_op == CON && rn->tn_val->v_quad <= 0) {
+ if (rn->tn_val->v_quad < 0) {
+ /* comparision of %s with %s, op %s */
+ warning(162, tyname(ln->tn_type), "negative constant",
+ mp->m_name);
+ } else if (op == LT || op == GE || (hflag && op == LE)) {
+ /* comparision of %s with %s, op %s */
+ warning(162, tyname(ln->tn_type), "0", mp->m_name);
+ }
+ return;
+ }
+ if (isutyp(rt) && !isutyp(lt) &&
+ ln->tn_op == CON && ln->tn_val->v_quad <= 0) {
+ if (ln->tn_val->v_quad < 0) {
+ /* comparision of %s with %s, op %s */
+ warning(162, "negative constant", tyname(rn->tn_type),
+ mp->m_name);
+ } else if (op == GT || op == LE || (hflag && op == GE)) {
+ /* comparision of %s with %s, op %s */
+ warning(162, "0", tyname(rn->tn_type), mp->m_name);
+ }
+ return;
+ }
+}
+
+/*
+ * Takes an expression an returns 0 if this expression can be used
+ * for static initialisation, otherwise -1.
+ *
+ * Constant initialisation expressions must be costant or an address
+ * of a static object with an optional offset. In the first case,
+ * the result is returned in *offsp. In the second case, the static
+ * object is returned in *symp and the offset in *offsp.
+ *
+ * The expression can consist of PLUS, MINUS, AMPER, NAME, STRING and
+ * CON. Type conversions are allowed if they do not change binary
+ * representation (including width).
+ */
+int
+conaddr(tn, symp, offsp)
+ tnode_t *tn;
+ sym_t **symp;
+ ptrdiff_t *offsp;
+{
+ sym_t *sym;
+ ptrdiff_t offs1, offs2;
+ tspec_t t, ot;
+
+ switch (tn->tn_op) {
+ case MINUS:
+ if (tn->tn_right->tn_op != CON)
+ return (-1);
+ /* FALLTHROUGH */
+ case PLUS:
+ offs1 = offs2 = 0;
+ if (tn->tn_left->tn_op == CON) {
+ offs1 = (ptrdiff_t)tn->tn_left->tn_val->v_quad;
+ if (conaddr(tn->tn_right, &sym, &offs2) == -1)
+ return (-1);
+ } else if (tn->tn_right->tn_op == CON) {
+ offs2 = (ptrdiff_t)tn->tn_right->tn_val->v_quad;
+ if (tn->tn_op == MINUS)
+ offs2 = -offs2;
+ if (conaddr(tn->tn_left, &sym, &offs1) == -1)
+ return (-1);
+ } else {
+ return (-1);
+ }
+ *symp = sym;
+ *offsp = offs1 + offs2;
+ break;
+ case AMPER:
+ if (tn->tn_left->tn_op == NAME) {
+ *symp = tn->tn_left->tn_sym;
+ *offsp = 0;
+ } else if (tn->tn_left->tn_op == STRING) {
+ /*
+ * If this would be the front end of a compiler we
+ * would return a label instead of 0.
+ */
+ *offsp = 0;
+ }
+ break;
+ case CVT:
+ t = tn->tn_type->t_tspec;
+ ot = tn->tn_left->tn_type->t_tspec;
+ if ((!isityp(t) && t != PTR) || (!isityp(ot) && ot != PTR)) {
+ return (-1);
+ } else if (psize(t) != psize(ot)) {
+ return (-1);
+ }
+ if (conaddr(tn->tn_left, symp, offsp) == -1)
+ return (-1);
+ break;
+ default:
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Concatenate two string constants.
+ */
+strg_t *
+catstrg(strg1, strg2)
+ strg_t *strg1, *strg2;
+{
+ size_t len1, len2, len;
+
+ if (strg1->st_tspec != strg2->st_tspec) {
+ /* cannot concatenate wide and regular string literals */
+ error(292);
+ return (strg1);
+ }
+
+ len = (len1 = strg1->st_len) + (len2 = strg2->st_len);
+
+ if (strg1->st_tspec == CHAR) {
+ strg1->st_cp = xrealloc(strg1->st_cp, len + 1);
+ (void)memcpy(strg1->st_cp + len1, strg2->st_cp, len2 + 1);
+ free(strg2->st_cp);
+ } else {
+ strg1->st_wcp = xrealloc(strg1->st_wcp,
+ (len + 1) * sizeof (wchar_t));
+ (void)memcpy(strg1->st_wcp + len1, strg2->st_wcp,
+ (len2 + 1) * sizeof (wchar_t));
+ free(strg2->st_wcp);
+ }
+ free(strg2);
+
+ return (strg1);
+}
+
+/*
+ * Print a warning if the given node has operands which should be
+ * parenthesized.
+ *
+ * XXX Does not work if an operand is a constant expression. Constant
+ * expressions are already folded.
+ */
+static void
+precconf(tn)
+ tnode_t *tn;
+{
+ tnode_t *ln, *rn;
+ op_t lop, rop;
+ int lparn, rparn;
+ mod_t *mp;
+ int warn;
+
+ if (!hflag)
+ return;
+
+ mp = &modtab[tn->tn_op];
+
+ lparn = 0;
+ for (ln = tn->tn_left; ln->tn_op == CVT; ln = ln->tn_left)
+ lparn |= ln->tn_parn;
+ lparn |= ln->tn_parn;
+ lop = ln->tn_op;
+
+ if (mp->m_binary) {
+ rparn = 0;
+ for (rn = tn->tn_right; tn->tn_op == CVT; rn = rn->tn_left)
+ rparn |= rn->tn_parn;
+ rparn |= rn->tn_parn;
+ rop = rn->tn_op;
+ }
+
+ warn = 0;
+
+ switch (tn->tn_op) {
+ case SHL:
+ case SHR:
+ if (!lparn && (lop == PLUS || lop == MINUS)) {
+ warn = 1;
+ } else if (!rparn && (rop == PLUS || rop == MINUS)) {
+ warn = 1;
+ }
+ break;
+ case LOGOR:
+ if (!lparn && lop == LOGAND) {
+ warn = 1;
+ } else if (!rparn && rop == LOGAND) {
+ warn = 1;
+ }
+ break;
+ case AND:
+ case XOR:
+ case OR:
+ if (!lparn && lop != tn->tn_op) {
+ if (lop == PLUS || lop == MINUS) {
+ warn = 1;
+ } else if (lop == AND || lop == XOR) {
+ warn = 1;
+ }
+ }
+ if (!warn && !rparn && rop != tn->tn_op) {
+ if (rop == PLUS || rop == MINUS) {
+ warn = 1;
+ } else if (rop == AND || rop == XOR) {
+ warn = 1;
+ }
+ }
+ break;
+ /* LINTED (enumeration values not handled in switch) */
+ }
+
+ if (warn) {
+ /* precedence confusion possible: parenthesize! */
+ warning(169);
+ }
+
+}
diff --git a/usr.bin/xlint/lint2/Makefile b/usr.bin/xlint/lint2/Makefile
new file mode 100644
index 0000000..0e7d405
--- /dev/null
+++ b/usr.bin/xlint/lint2/Makefile
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.2 1995/07/03 21:24:39 cgd Exp $
+
+.PATH: ${.CURDIR}/../lint1
+
+PROG= lint2
+SRCS= main2.c hash.c read.c mem.c mem2.c chk.c msg.c emit.c emit2.c
+NOMAN=
+CFLAGS+=-I${.CURDIR}/../lint1
+LINTFLAGS=-abehrz
+
+BINDIR= /usr/libexec
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/lint2/chk.c b/usr.bin/xlint/lint2/chk.c
new file mode 100644
index 0000000..0aac852
--- /dev/null
+++ b/usr.bin/xlint/lint2/chk.c
@@ -0,0 +1,1462 @@
+/* $NetBSD: chk.c,v 1.2 1995/07/03 21:24:42 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: chk.c,v 1.2 1995/07/03 21:24:42 cgd Exp $";
+#endif
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include <err.h>
+
+#include "lint2.h"
+
+/* various type information */
+ttab_t ttab[NTSPEC];
+
+
+static void chkund __P((hte_t *));
+static void chkdnu __P((hte_t *));
+static void chkdnud __P((hte_t *));
+static void chkmd __P((hte_t *));
+static void chkvtui __P((hte_t *, sym_t *, sym_t *));
+static void chkvtdi __P((hte_t *, sym_t *, sym_t *));
+static void chkfaui __P((hte_t *, sym_t *, sym_t *));
+static void chkau __P((hte_t *, int, sym_t *, sym_t *, pos_t *,
+ fcall_t *, fcall_t *, type_t *, type_t *));
+static void chkrvu __P((hte_t *, sym_t *));
+static void chkadecl __P((hte_t *, sym_t *, sym_t *));
+static void printflike __P((hte_t *,fcall_t *, int,
+ const char *, type_t **));
+static void scanflike __P((hte_t *, fcall_t *, int,
+ const char *, type_t **));
+static void badfmt __P((hte_t *, fcall_t *));
+static void inconarg __P((hte_t *, fcall_t *, int));
+static void tofewarg __P((hte_t *, fcall_t *));
+static void tomanyarg __P((hte_t *, fcall_t *));
+static int eqtype __P((type_t *, type_t *, int, int, int, int *));
+static int eqargs __P((type_t *, type_t *, int *));
+static int mnoarg __P((type_t *, int *));
+
+
+void
+inittyp()
+{
+ int i;
+ static struct {
+ tspec_t it_tspec;
+ ttab_t it_ttab;
+ } ittab[] = {
+ { SIGNED, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "signed" } },
+ { UNSIGN, { 0, 0,
+ SIGNED, UNSIGN,
+ 0, 0, 0, 0, 0, "unsigned" } },
+ { CHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "char" } },
+ { SCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 0, 0, 1, 1, "signed char" } },
+ { UCHAR, { CHAR_BIT, CHAR_BIT,
+ SCHAR, UCHAR,
+ 1, 1, 0, 1, 1, "unsigned char" } },
+ { SHORT, { sizeof (short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 0, 0, 1, 1, "short" } },
+ { USHORT, { sizeof (u_short) * CHAR_BIT, 2 * CHAR_BIT,
+ SHORT, USHORT,
+ 1, 1, 0, 1, 1, "unsigned short" } },
+ { INT, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 0, 0, 1, 1, "int" } },
+ { UINT, { sizeof (u_int) * CHAR_BIT, 3 * CHAR_BIT,
+ INT, UINT,
+ 1, 1, 0, 1, 1, "unsigned int" } },
+ { LONG, { sizeof (long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 0, 0, 1, 1, "long" } },
+ { ULONG, { sizeof (u_long) * CHAR_BIT, 4 * CHAR_BIT,
+ LONG, ULONG,
+ 1, 1, 0, 1, 1, "unsigned long" } },
+ { QUAD, { sizeof (quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 0, 0, 1, 1, "long long" } },
+ { UQUAD, { sizeof (u_quad_t) * CHAR_BIT, 8 * CHAR_BIT,
+ QUAD, UQUAD,
+ 1, 1, 0, 1, 1, "unsigned long long" } },
+ { FLOAT, { sizeof (float) * CHAR_BIT, 4 * CHAR_BIT,
+ FLOAT, FLOAT,
+ 0, 0, 1, 1, 1, "float" } },
+ { DOUBLE, { sizeof (double) * CHAR_BIT, 8 * CHAR_BIT,
+ DOUBLE, DOUBLE,
+ 0, 0, 1, 1, 1, "double" } },
+ { LDOUBLE, { sizeof (ldbl_t) * CHAR_BIT, 10 * CHAR_BIT,
+ LDOUBLE, LDOUBLE,
+ 0, 0, 1, 1, 1, "long double" } },
+ { VOID, { -1, -1,
+ VOID, VOID,
+ 0, 0, 0, 0, 0, "void" } },
+ { STRUCT, { -1, -1,
+ STRUCT, STRUCT,
+ 0, 0, 0, 0, 0, "struct" } },
+ { UNION, { -1, -1,
+ UNION, UNION,
+ 0, 0, 0, 0, 0, "union" } },
+ { ENUM, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
+ ENUM, ENUM,
+ 1, 0, 0, 1, 1, "enum" } },
+ { PTR, { sizeof (void *) * CHAR_BIT, 4 * CHAR_BIT,
+ PTR, PTR,
+ 0, 1, 0, 0, 1, "pointer" } },
+ { ARRAY, { -1, -1,
+ ARRAY, ARRAY,
+ 0, 0, 0, 0, 0, "array" } },
+ { FUNC, { -1, -1,
+ FUNC, FUNC,
+ 0, 0, 0, 0, 0, "function" } },
+ };
+
+ for (i = 0; i < sizeof (ittab) / sizeof (ittab[0]); i++)
+ STRUCT_ASSIGN(ttab[ittab[i].it_tspec], ittab[i].it_ttab);
+ if (!pflag) {
+ for (i = 0; i < NTSPEC; i++)
+ ttab[i].tt_psz = ttab[i].tt_sz;
+ }
+}
+
+
+/*
+ * If there is a symbol named "main", mark it as used.
+ */
+void
+mainused()
+{
+ hte_t *hte;
+
+ if ((hte = hsearch("main", 0)) != NULL)
+ hte->h_used = 1;
+}
+
+/*
+ * Performs all tests for a single name
+ */
+void
+chkname(hte)
+ hte_t *hte;
+{
+ sym_t *sym, *def, *pdecl, *decl;
+
+ if (uflag) {
+ chkund(hte);
+ chkdnu(hte);
+ if (xflag)
+ chkdnud(hte);
+ }
+ chkmd(hte);
+
+ /* Get definition, prototype declaration and declaration */
+ def = pdecl = decl = NULL;
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (def == NULL && (sym->s_def == DEF || sym->s_def == TDEF))
+ def = sym;
+ if (pdecl == NULL && sym->s_def == DECL &&
+ TP(sym->s_type)->t_tspec == FUNC &&
+ TP(sym->s_type)->t_proto) {
+ pdecl = sym;
+ }
+ if (decl == NULL && sym->s_def == DECL)
+ decl = sym;
+ }
+
+ /* A prototype is better than an old style declaration. */
+ if (pdecl != NULL)
+ decl = pdecl;
+
+ chkvtui(hte, def, decl);
+
+ chkvtdi(hte, def, decl);
+
+ chkfaui(hte, def, decl);
+
+ chkrvu(hte, def);
+
+ chkadecl(hte, def, decl);
+}
+
+/*
+ * Print a warning if the name has been used, but not defined.
+ */
+static void
+chkund(hte)
+ hte_t *hte;
+{
+ fcall_t *fcall;
+ usym_t *usym;
+
+ if (!hte->h_used || hte->h_def)
+ return;
+
+ if ((fcall = hte->h_calls) != NULL) {
+ /* %s used( %s ), but not defined */
+ msg(0, hte->h_name, mkpos(&fcall->f_pos));
+ } else if ((usym = hte->h_usyms) != NULL) {
+ /* %s used( %s ), but not defined */
+ msg(0, hte->h_name, mkpos(&usym->u_pos));
+ }
+}
+
+/*
+ * Print a warning if the name has been defined, but never used.
+ */
+static void
+chkdnu(hte)
+ hte_t *hte;
+{
+ sym_t *sym;
+
+ if (!hte->h_def || hte->h_used)
+ return;
+
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym->s_def == DEF || sym->s_def == TDEF) {
+ /* %s defined( %s ), but never used */
+ msg(1, hte->h_name, mkpos(&sym->s_pos));
+ break;
+ }
+ }
+}
+
+/*
+ * Print a warning if the name has been declared, but is not used
+ * or defined.
+ */
+static void
+chkdnud(hte)
+ hte_t *hte;
+{
+ sym_t *sym;
+
+ if (hte->h_syms == NULL || hte->h_used || hte->h_def)
+ return;
+
+ if ((sym = hte->h_syms) != NULL) {
+ if (sym->s_def != DECL)
+ errx(1, "internal error: chkdnud() 1");
+ /* %s declared( %s ), but never used or defined */
+ msg(2, hte->h_name, mkpos(&sym->s_pos));
+ }
+}
+
+/*
+ * Print a warning if there is more then one definition for
+ * this name.
+ */
+static void
+chkmd(hte)
+ hte_t *hte;
+{
+ sym_t *sym, *def1;
+ char *pos1;
+
+ if (!hte->h_def)
+ return;
+
+ def1 = NULL;
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ /*
+ * ANSI C allows tentative definitions of the same name in
+ * only one compilation unit.
+ */
+ if (sym->s_def != DEF && (!sflag || sym->s_def != TDEF))
+ continue;
+ if (def1 == NULL) {
+ def1 = sym;
+ continue;
+ }
+ pos1 = xstrdup(mkpos(&def1->s_pos));
+ /* %s multiply defined\t%s :: %s */
+ msg(3, hte->h_name, pos1, mkpos(&sym->s_pos));
+ free(pos1);
+ }
+}
+
+/*
+ * Print a warning if the return value assumed for a function call
+ * differs from the return value of the function definition or
+ * function declaration.
+ *
+ * If no definition/declaration can be found, the assumed return values
+ * are always int. So there is no need to compare with another function
+ * call as it's done for function arguments.
+ */
+static void
+chkvtui(hte, def, decl)
+ hte_t *hte;
+ sym_t *def, *decl;
+{
+ fcall_t *call;
+ char *pos1;
+ type_t *tp1, *tp2;
+ /* LINTED (automatic hides external declaration: warn) */
+ int warn, eq;
+ tspec_t t1;
+
+ if (hte->h_calls == NULL)
+ return;
+
+ if (def == NULL)
+ def = decl;
+ if (def == NULL)
+ return;
+
+ t1 = (tp1 = TP(def->s_type)->t_subt)->t_tspec;
+ for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
+ tp2 = TP(call->f_type)->t_subt;
+ eq = eqtype(tp1, tp2, 1, 0, 0, (warn = 0, &warn));
+ if (!call->f_rused) {
+ /* no return value used */
+ if ((t1 == STRUCT || t1 == UNION) && !eq) {
+ /*
+ * If a function returns a struct or union it
+ * must be declared to return a struct or
+ * union, also if the return value is ignored.
+ * This is necessary because the caller must
+ * allocate stack space for the return value.
+ * If it does not, the return value would over-
+ * write other data.
+ * XXX Following massage may be confusing
+ * because it appears also if the return value
+ * was declared inconsistently. But this
+ * behaviour matches pcc based lint, so it is
+ * accepted for now.
+ */
+ pos1 = xstrdup(mkpos(&def->s_pos));
+ /* %s value must be decl. before use %s :: %s */
+ msg(17, hte->h_name,
+ pos1, mkpos(&call->f_pos));
+ free(pos1);
+ }
+ continue;
+ }
+ if (!eq || (sflag && warn)) {
+ pos1 = xstrdup(mkpos(&def->s_pos));
+ /* %s value used inconsistenty\t%s :: %s */
+ msg(4, hte->h_name, pos1, mkpos(&call->f_pos));
+ free(pos1);
+ }
+ }
+}
+
+/*
+ * Print a warning if a definition/declaration does not match another
+ * definition/declaration of the same name. For functions, only the
+ * types of return values are tested.
+ */
+static void
+chkvtdi(hte, def, decl)
+ hte_t *hte;
+ sym_t *def, *decl;
+{
+ sym_t *sym;
+ type_t *tp1, *tp2;
+ /* LINTED (automatic hides external declaration: warn) */
+ int eq, warn;
+ char *pos1;
+
+ if (def == NULL)
+ def = decl;
+ if (def == NULL)
+ return;
+
+ tp1 = TP(def->s_type);
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym == def)
+ continue;
+ tp2 = TP(sym->s_type);
+ warn = 0;
+ if (tp1->t_tspec == FUNC && tp2->t_tspec == FUNC) {
+ eq = eqtype(tp1->t_subt, tp2->t_subt, 1, 0, 0, &warn);
+ } else {
+ eq = eqtype(tp1, tp2, 0, 0, 0, &warn);
+ }
+ if (!eq || (sflag && warn)) {
+ pos1 = xstrdup(mkpos(&def->s_pos));
+ /* %s value declared inconsistently\t%s :: %s */
+ msg(5, hte->h_name, pos1, mkpos(&sym->s_pos));
+ free(pos1);
+ }
+ }
+}
+
+/*
+ * Print a warning if a function is called with arguments which does
+ * not match the function definition, declaration or another call
+ * of the same function.
+ */
+static void
+chkfaui(hte, def, decl)
+ hte_t *hte;
+ sym_t *def, *decl;
+{
+ type_t *tp1, *tp2, **ap1, **ap2;
+ pos_t *pos1p;
+ fcall_t *calls, *call, *call1;
+ int n, as;
+ char *pos1;
+ arginf_t *ai;
+
+ if ((calls = hte->h_calls) == NULL)
+ return;
+
+ /*
+ * If we find a function definition, we use this for comparision,
+ * otherwise the first prototype we can find. If there is no
+ * definition or prototype declaration, the first function call
+ * is used.
+ */
+ tp1 = NULL;
+ call1 = NULL;
+ if (def != NULL) {
+ if ((tp1 = TP(def->s_type))->t_tspec != FUNC)
+ return;
+ pos1p = &def->s_pos;
+ } else if (decl != NULL && TP(decl->s_type)->t_proto) {
+ if ((tp1 = TP(decl->s_type))->t_tspec != FUNC)
+ return;
+ pos1p = &decl->s_pos;
+ }
+ if (tp1 == NULL) {
+ call1 = calls;
+ calls = calls->f_nxt;
+ if ((tp1 = TP(call1->f_type))->t_tspec != FUNC)
+ return;
+ pos1p = &call1->f_pos;
+ }
+
+ n = 1;
+ for (call = calls; call != NULL; call = call->f_nxt) {
+ if ((tp2 = TP(call->f_type))->t_tspec != FUNC)
+ continue;
+ ap1 = tp1->t_args;
+ ap2 = tp2->t_args;
+ n = 0;
+ while (*ap1 != NULL && *ap2 != NULL) {
+ if (def != NULL && def->s_va && n >= def->s_nva)
+ break;
+ n++;
+ chkau(hte, n, def, decl, pos1p, call1, call,
+ *ap1, *ap2);
+ ap1++;
+ ap2++;
+ }
+ if (*ap1 == *ap2) {
+ /* equal # of arguments */
+ } else if (def != NULL && def->s_va && n >= def->s_nva) {
+ /*
+ * function definition with VARARGS; The # of
+ * arguments of the call must be at least as large
+ * as the parameter of VARARGS.
+ */
+ } else if (*ap2 != NULL && tp1->t_proto && tp1->t_vararg) {
+ /*
+ * prototype with ... and function call with
+ * at least the same # of arguments as declared
+ * in the prototype.
+ */
+ } else {
+ pos1 = xstrdup(mkpos(pos1p));
+ /* %s: variable # of args\t%s :: %s */
+ msg(7, hte->h_name, pos1, mkpos(&call->f_pos));
+ free(pos1);
+ continue;
+ }
+
+ /* perform SCANFLIKE/PRINTFLIKE tests */
+ if (def == NULL || (!def->s_prfl && !def->s_scfl))
+ continue;
+ as = def->s_prfl ? def->s_nprfl : def->s_nscfl;
+ for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
+ if (ai->a_num == as)
+ break;
+ }
+ if (ai == NULL || !ai->a_fmt)
+ continue;
+ if (def->s_prfl) {
+ printflike(hte, call, n, ai->a_fstrg, ap2);
+ } else {
+ scanflike(hte, call, n, ai->a_fstrg, ap2);
+ }
+ }
+}
+
+/*
+ * Check a single argument in a function call.
+ *
+ * hte a pointer to the hash table entry of the function
+ * n the number of the argument (1..)
+ * def the function definition or NULL
+ * decl prototype declaration, old style declaration or NULL
+ * pos1p position of definition, declaration of first call
+ * call1 first call, if both def and decl are old style def/decl
+ * call checked call
+ * arg1 currently checked argument of def/decl/call1
+ * arg2 currently checked argument of call
+ *
+ */
+static void
+chkau(hte, n, def, decl, pos1p, call1, call, arg1, arg2)
+ hte_t *hte;
+ int n;
+ sym_t *def, *decl;
+ pos_t *pos1p;
+ fcall_t *call1, *call;
+ type_t *arg1, *arg2;
+{
+ /* LINTED (automatic hides external declaration: warn) */
+ int promote, asgn, warn;
+ tspec_t t1, t2;
+ arginf_t *ai, *ai1;
+ char *pos1;
+
+ /*
+ * If a function definition is available (def != NULL), we compair the
+ * function call (call) with the definition. Otherwise, if a function
+ * definition is available and it is not an old style definition
+ * (decl != NULL && TP(decl->s_type)->t_proto), we compair the call
+ * with this declaration. Otherwise we compair it with the first
+ * call we have found (call1).
+ */
+
+ /* arg1 must be promoted if it stems from an old style definition */
+ promote = def != NULL && def->s_osdef;
+
+ /*
+ * If we compair with a definition or declaration, we must perform
+ * the same checks for qualifiers in indirected types as in
+ * assignments.
+ */
+ asgn = def != NULL || (decl != NULL && TP(decl->s_type)->t_proto);
+
+ warn = 0;
+ if (eqtype(arg1, arg2, 1, promote, asgn, &warn) && (!sflag || !warn))
+ return;
+
+ /*
+ * Other lint implementations print warnings as soon as the type
+ * of an argument does not match exactly the expected type. The
+ * result are lots of warnings which are really not neccessary.
+ * We print a warning only if
+ * (0) at least one type is not an interger type and types differ
+ * (1) hflag is set and types differ
+ * (2) types differ, except in signedness
+ * If the argument is an integer constant whose msb is not set,
+ * signedness is ignored (e.g. 0 matches both signed and unsigned
+ * int). This is with and without hflag.
+ * If the argument is an integer constant with value 0 and the
+ * expected argument is of type pointer and the width of the
+ * interger constant is the same as the width of the pointer,
+ * no warning is printed.
+ */
+ t1 = arg1->t_tspec;
+ t2 = arg2->t_tspec;
+ if (isityp(t1) && isityp(t2) && !arg1->t_isenum && !arg2->t_isenum) {
+ if (promote) {
+ /*
+ * XXX Here is a problem: Althrough it is possible to
+ * pass an int where a char/short it expected, there
+ * may be loss in significant digits. We should first
+ * check for const arguments if they can be converted
+ * into the original parameter type.
+ */
+ if (t1 == FLOAT) {
+ t1 = DOUBLE;
+ } else if (t1 == CHAR || t1 == SCHAR) {
+ t1 = INT;
+ } else if (t1 == UCHAR) {
+ t1 = tflag ? UINT : INT;
+ } else if (t1 == SHORT) {
+ t1 = INT;
+ } else if (t1 == USHORT) {
+ /* CONSTCOND */
+ t1 = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
+ }
+ }
+
+ if (styp(t1) == styp(t2)) {
+
+ /*
+ * types differ only in signedness; get information
+ * about arguments
+ */
+
+ /*
+ * treat a definition like a call with variable
+ * arguments
+ */
+ ai1 = call1 != NULL ? call1->f_args : NULL;
+
+ /*
+ * if two calls are compared, ai1 is set to the
+ * information for the n-th argument, if this was
+ * a constant, otherwise to NULL
+ */
+ for ( ; ai1 != NULL; ai1 = ai1->a_nxt) {
+ if (ai1->a_num == n)
+ break;
+ }
+ /*
+ * ai is set to the information of the n-th arg
+ * of the (second) call, if this was a constant,
+ * otherwise to NULL
+ */
+ for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
+ if (ai->a_num == n)
+ break;
+ }
+
+ if (ai1 == NULL && ai == NULL) {
+ /* no constant at all */
+ if (!hflag)
+ return;
+ } else if (ai1 == NULL || ai == NULL) {
+ /* one constant */
+ if (ai == NULL)
+ ai = ai1;
+ if (ai->a_zero || ai->a_pcon)
+ /* same value in signed and unsigned */
+ return;
+ /* value (not representation) differently */
+ } else {
+ /*
+ * two constants, one signed, one unsigned;
+ * if the msb of one of the constants is set,
+ * the argument is used inconsistently.
+ */
+ if (!ai1->a_ncon && !ai->a_ncon)
+ return;
+ }
+ }
+
+ } else if (t1 == PTR && isityp(t2) && psize(t1) == psize(t2)) {
+ for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
+ if (ai->a_num == n)
+ break;
+ }
+ if (ai != NULL && ai->a_zero)
+ return;
+ }
+
+ pos1 = xstrdup(mkpos(pos1p));
+ /* %s, arg %d used inconsistently\t%s :: %s */
+ msg(6, hte->h_name, n, pos1, mkpos(&call->f_pos));
+ free(pos1);
+}
+
+/*
+ * Compare the types in the NULL-terminated array ap with the format
+ * string fmt.
+ */
+static void
+printflike(hte, call, n, fmt, ap)
+ hte_t *hte;
+ fcall_t *call;
+ int n;
+ const char *fmt;
+ type_t **ap;
+{
+ const char *fp;
+ int fc;
+ int fwidth, prec, left, sign, space, alt, zero;
+ tspec_t sz, t1, t2;
+ type_t *tp;
+
+ fp = fmt;
+ fc = *fp++;
+
+ for ( ; ; ) {
+ if (fc == '\0') {
+ if (*ap != NULL)
+ tomanyarg(hte, call);
+ break;
+ }
+ if (fc != '%') {
+ badfmt(hte, call);
+ break;
+ }
+ fc = *fp++;
+ fwidth = prec = left = sign = space = alt = zero = 0;
+ sz = NOTSPEC;
+
+ /* Flags */
+ for ( ; ; ) {
+ if (fc == '-') {
+ if (left)
+ break;
+ left = 1;
+ } else if (fc == '+') {
+ if (sign)
+ break;
+ sign = 1;
+ } else if (fc == ' ') {
+ if (space)
+ break;
+ space = 1;
+ } else if (fc == '#') {
+ if (alt)
+ break;
+ alt = 1;
+ } else if (fc == '0') {
+ if (zero)
+ break;
+ zero = 1;
+ } else {
+ break;
+ }
+ fc = *fp++;
+ }
+
+ /* field width */
+ if (isdigit(fc)) {
+ fwidth = 1;
+ do { fc = *fp++; } while (isdigit(fc)) ;
+ } else if (fc == '*') {
+ fwidth = 1;
+ fc = *fp++;
+ if ((tp = *ap++) == NULL) {
+ tofewarg(hte, call);
+ break;
+ }
+ n++;
+ if ((t1 = tp->t_tspec) != INT && (hflag || t1 != UINT))
+ inconarg(hte, call, n);
+ }
+
+ /* precision */
+ if (fc == '.') {
+ fc = *fp++;
+ prec = 1;
+ if (isdigit(fc)) {
+ do { fc = *fp++; } while (isdigit(fc));
+ } else if (fc == '*') {
+ fc = *fp++;
+ if ((tp = *ap++) == NULL) {
+ tofewarg(hte, call);
+ break;
+ }
+ n++;
+ if (tp->t_tspec != INT)
+ inconarg(hte, call, n);
+ } else {
+ badfmt(hte, call);
+ break;
+ }
+ }
+
+ if (fc == 'h') {
+ sz = SHORT;
+ } else if (fc == 'l') {
+ sz = LONG;
+ } else if (fc == 'q') {
+ sz = QUAD;
+ } else if (fc == 'L') {
+ sz = LDOUBLE;
+ }
+ if (sz != NOTSPEC)
+ fc = *fp++;
+
+ if (fc == '%') {
+ if (sz != NOTSPEC || left || sign || space ||
+ alt || zero || prec || fwidth) {
+ badfmt(hte, call);
+ }
+ fc = *fp++;
+ continue;
+ }
+
+ if (fc == '\0') {
+ badfmt(hte, call);
+ break;
+ }
+
+ if ((tp = *ap++) == NULL) {
+ tofewarg(hte, call);
+ break;
+ }
+ n++;
+ if ((t1 = tp->t_tspec) == PTR)
+ t2 = tp->t_subt->t_tspec;
+
+ if (fc == 'd' || fc == 'i') {
+ if (alt || sz == LDOUBLE) {
+ badfmt(hte, call);
+ break;
+ }
+ int_conv:
+ if (sz == LONG) {
+ if (t1 != LONG && (hflag || t1 != ULONG))
+ inconarg(hte, call, n);
+ } else if (sz == QUAD) {
+ if (t1 != QUAD && (hflag || t1 != UQUAD))
+ inconarg(hte, call, n);
+ } else {
+ /*
+ * SHORT is always promoted to INT, USHORT
+ * to INT or UINT.
+ */
+ if (t1 != INT && (hflag || t1 != UINT))
+ inconarg(hte, call, n);
+ }
+ } else if (fc == 'o' || fc == 'u' || fc == 'x' || fc == 'X') {
+ if ((alt && fc == 'u') || sz == LDOUBLE)
+ badfmt(hte, call);
+ uint_conv:
+ if (sz == LONG) {
+ if (t1 != ULONG && (hflag || t1 != LONG))
+ inconarg(hte, call, n);
+ } else if (sz == QUAD) {
+ if (t1 != UQUAD && (hflag || t1 != QUAD))
+ inconarg(hte, call, n);
+ } else if (sz == SHORT) {
+ /* USHORT was promoted to INT or UINT */
+ if (t1 != UINT && t1 != INT)
+ inconarg(hte, call, n);
+ } else {
+ if (t1 != UINT && (hflag || t1 != INT))
+ inconarg(hte, call, n);
+ }
+ } else if (fc == 'D' || fc == 'O' || fc == 'U') {
+ if ((alt && fc != 'O') || sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = LONG;
+ if (fc == 'D') {
+ goto int_conv;
+ } else {
+ goto uint_conv;
+ }
+ } else if (fc == 'f' || fc == 'e' || fc == 'E' ||
+ fc == 'g' || fc == 'G') {
+ if (sz == NOTSPEC)
+ sz = DOUBLE;
+ if (sz != DOUBLE && sz != LDOUBLE)
+ badfmt(hte, call);
+ if (t1 != sz)
+ inconarg(hte, call, n);
+ } else if (fc == 'c') {
+ if (sz != NOTSPEC || alt || zero)
+ badfmt(hte, call);
+ if (t1 != INT)
+ inconarg(hte, call, n);
+ } else if (fc == 's') {
+ if (sz != NOTSPEC || alt || zero)
+ badfmt(hte, call);
+ if (t1 != PTR ||
+ (t2 != CHAR && t2 != UCHAR && t2 != SCHAR)) {
+ inconarg(hte, call, n);
+ }
+ } else if (fc == 'p') {
+ if (fwidth || prec || sz != NOTSPEC || alt || zero)
+ badfmt(hte, call);
+ if (t1 != PTR || (hflag && t2 != VOID))
+ inconarg(hte, call, n);
+ } else if (fc == 'n') {
+ if (fwidth || prec || alt || zero || sz == LDOUBLE)
+ badfmt(hte, call);
+ if (t1 != PTR) {
+ inconarg(hte, call, n);
+ } else if (sz == LONG) {
+ if (t2 != LONG && t2 != ULONG)
+ inconarg(hte, call, n);
+ } else if (sz == SHORT) {
+ if (t2 != SHORT && t2 != USHORT)
+ inconarg(hte, call, n);
+ } else {
+ if (t2 != INT && t2 != UINT)
+ inconarg(hte, call, n);
+ }
+ } else {
+ badfmt(hte, call);
+ break;
+ }
+
+ fc = *fp++;
+ }
+}
+
+/*
+ * Compare the types in the NULL-terminated array ap with the format
+ * string fmt.
+ */
+static void
+scanflike(hte, call, n, fmt, ap)
+ hte_t *hte;
+ fcall_t *call;
+ int n;
+ const char *fmt;
+ type_t **ap;
+{
+ const char *fp;
+ int fc;
+ int noasgn, fwidth;
+ tspec_t sz, t1, t2;
+ type_t *tp;
+
+ fp = fmt;
+ fc = *fp++;
+
+ for ( ; ; ) {
+ if (fc == '\0') {
+ if (*ap != NULL)
+ tomanyarg(hte, call);
+ break;
+ }
+ if (fc != '%') {
+ badfmt(hte, call);
+ break;
+ }
+ fc = *fp++;
+
+ noasgn = fwidth = 0;
+ sz = NOTSPEC;
+
+ if (fc == '*') {
+ noasgn = 1;
+ fc = *fp++;
+ }
+
+ if (isdigit(fc)) {
+ fwidth = 1;
+ do { fc = *fp++; } while (isdigit(fc));
+ }
+
+ if (fc == 'h') {
+ sz = SHORT;
+ } else if (fc == 'l') {
+ sz = LONG;
+ } else if (fc == 'q') {
+ sz = QUAD;
+ } else if (fc == 'L') {
+ sz = LDOUBLE;
+ }
+ if (sz != NOTSPEC)
+ fc = *fp++;
+
+ if (fc == '%') {
+ if (sz != NOTSPEC || noasgn || fwidth)
+ badfmt(hte, call);
+ fc = *fp++;
+ continue;
+ }
+
+ if (!noasgn) {
+ if ((tp = *ap++) == NULL) {
+ tofewarg(hte, call);
+ break;
+ }
+ n++;
+ if ((t1 = tp->t_tspec) == PTR)
+ t2 = tp->t_subt->t_tspec;
+ }
+
+ if (fc == 'd' || fc == 'i' || fc == 'n') {
+ if (sz == LDOUBLE)
+ badfmt(hte, call);
+ if (sz != SHORT && sz != LONG && sz != QUAD)
+ sz = INT;
+ conv:
+ if (!noasgn) {
+ if (t1 != PTR) {
+ inconarg(hte, call, n);
+ } else if (t2 != styp(sz)) {
+ inconarg(hte, call, n);
+ } else if (hflag && t2 != sz) {
+ inconarg(hte, call, n);
+ } else if (tp->t_subt->t_const) {
+ inconarg(hte, call, n);
+ }
+ }
+ } else if (fc == 'o' || fc == 'u' || fc == 'x') {
+ if (sz == LDOUBLE)
+ badfmt(hte, call);
+ if (sz == SHORT) {
+ sz = USHORT;
+ } else if (sz == LONG) {
+ sz = ULONG;
+ } else if (sz == QUAD) {
+ sz = UQUAD;
+ } else {
+ sz = UINT;
+ }
+ goto conv;
+ } else if (fc == 'D') {
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = LONG;
+ goto conv;
+ } else if (fc == 'O') {
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = ULONG;
+ goto conv;
+ } else if (fc == 'X') {
+ /*
+ * XXX valid in ANSI C, but in NetBSD's libc imple-
+ * mented as "lx". Thats why it should be avoided.
+ */
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = ULONG;
+ goto conv;
+ } else if (fc == 'E') {
+ /*
+ * XXX valid in ANSI C, but in NetBSD's libc imple-
+ * mented as "lf". Thats why it should be avoided.
+ */
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = DOUBLE;
+ goto conv;
+ } else if (fc == 'F') {
+ /* XXX only for backward compatibility */
+ if (sz != NOTSPEC || !tflag)
+ badfmt(hte, call);
+ sz = DOUBLE;
+ goto conv;
+ } else if (fc == 'G') {
+ /*
+ * XXX valid in ANSI C, but in NetBSD's libc not
+ * implemented
+ */
+ if (sz != NOTSPEC && sz != LONG && sz != LDOUBLE)
+ badfmt(hte, call);
+ goto fconv;
+ } else if (fc == 'e' || fc == 'f' || fc == 'g') {
+ fconv:
+ if (sz == NOTSPEC) {
+ sz = FLOAT;
+ } else if (sz == LONG) {
+ sz = DOUBLE;
+ } else if (sz != LDOUBLE) {
+ badfmt(hte, call);
+ sz = FLOAT;
+ }
+ goto conv;
+ } else if (fc == 's' || fc == '[' || fc == 'c') {
+ if (sz != NOTSPEC)
+ badfmt(hte, call);
+ if (fc == '[') {
+ if ((fc = *fp++) == '-') {
+ badfmt(hte, call);
+ fc = *fp++;
+ }
+ if (fc != ']') {
+ badfmt(hte, call);
+ if (fc == '\0')
+ break;
+ }
+ }
+ if (!noasgn) {
+ if (t1 != PTR) {
+ inconarg(hte, call, n);
+ } else if (t2 != CHAR && t2 != UCHAR &&
+ t2 != SCHAR) {
+ inconarg(hte, call, n);
+ }
+ }
+ } else if (fc == 'p') {
+ if (sz != NOTSPEC)
+ badfmt(hte, call);
+ if (!noasgn) {
+ if (t1 != PTR || t2 != PTR) {
+ inconarg(hte, call, n);
+ } else if (tp->t_subt->t_subt->t_tspec!=VOID) {
+ if (hflag)
+ inconarg(hte, call, n);
+ }
+ }
+ } else {
+ badfmt(hte, call);
+ break;
+ }
+
+ fc = *fp++;
+ }
+}
+
+static void
+badfmt(hte, call)
+ hte_t *hte;
+ fcall_t *call;
+{
+ /* %s: malformed format string\t%s */
+ msg(13, hte->h_name, mkpos(&call->f_pos));
+}
+
+static void
+inconarg(hte, call, n)
+ hte_t *hte;
+ fcall_t *call;
+ int n;
+{
+ /* %s, arg %d inconsistent with format\t%s(%d) */
+ msg(14, hte->h_name, n, mkpos(&call->f_pos));
+}
+
+static void
+tofewarg(hte, call)
+ hte_t *hte;
+ fcall_t *call;
+{
+ /* %s: too few args for format \t%s */
+ msg(15, hte->h_name, mkpos(&call->f_pos));
+}
+
+static void
+tomanyarg(hte, call)
+ hte_t *hte;
+ fcall_t *call;
+{
+ /* %s: too many args for format \t%s */
+ msg(16, hte->h_name, mkpos(&call->f_pos));
+}
+
+
+/*
+ * Print warnings for return values which are used, but not returned,
+ * or return values which are always or sometimes ignored.
+ */
+static void
+chkrvu(hte, def)
+ hte_t *hte;
+ sym_t *def;
+{
+ fcall_t *call;
+ int used, ignored;
+
+ if (def == NULL)
+ /* don't know wheter or not the functions returns a value */
+ return;
+
+ if (hte->h_calls == NULL)
+ return;
+
+ if (def->s_rval) {
+ /* function has return value */
+ used = ignored = 0;
+ for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
+ used |= call->f_rused;
+ ignored |= !call->f_rused && !call->f_rdisc;
+ }
+ /*
+ * XXX as soon as we are able to disable single warnings
+ * the following dependencies from hflag should be removed.
+ * but for now I do'nt want to be botherd by this warnings
+ * which are almost always useless.
+ */
+ if (!used && ignored) {
+ if (hflag)
+ /* %s returns value which is always ignored */
+ msg(8, hte->h_name);
+ } else if (used && ignored) {
+ if (hflag)
+ /* %s returns value which is sometimes ign. */
+ msg(9, hte->h_name);
+ }
+ } else {
+ /* function has no return value */
+ for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
+ if (call->f_rused)
+ /* %s value is used( %s ), but none ret. */
+ msg(10, hte->h_name, mkpos(&call->f_pos));
+ }
+ }
+}
+
+/*
+ * Print warnings for inconsistent argument declarations.
+ */
+static void
+chkadecl(hte, def, decl)
+ hte_t *hte;
+ sym_t *def, *decl;
+{
+ /* LINTED (automatic hides external declaration: warn) */
+ int osdef, eq, warn, n;
+ sym_t *sym1, *sym;
+ type_t **ap1, **ap2, *tp1, *tp2;
+ char *pos1;
+ const char *pos2;
+
+ osdef = 0;
+ if (def != NULL) {
+ osdef = def->s_osdef;
+ sym1 = def;
+ } else if (decl != NULL && TP(decl->s_type)->t_proto) {
+ sym1 = decl;
+ } else {
+ return;
+ }
+ if (TP(sym1->s_type)->t_tspec != FUNC)
+ return;
+
+ /*
+ * XXX Prototypes should also be compared with old style function
+ * declarations.
+ */
+
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym == sym1 || !TP(sym->s_type)->t_proto)
+ continue;
+ ap1 = TP(sym1->s_type)->t_args;
+ ap2 = TP(sym->s_type)->t_args;
+ n = 0;
+ while (*ap1 != NULL && *ap2 != NULL) {
+ warn = 0;
+ eq = eqtype(*ap1, *ap2, 1, osdef, 0, &warn);
+ if (!eq || warn) {
+ pos1 = xstrdup(mkpos(&sym1->s_pos));
+ pos2 = mkpos(&sym->s_pos);
+ /* %s, arg %d declared inconsistently ... */
+ msg(11, hte->h_name, n + 1, pos1, pos2);
+ free(pos1);
+ }
+ n++;
+ ap1++;
+ ap2++;
+ }
+ if (*ap1 == *ap2) {
+ tp1 = TP(sym1->s_type);
+ tp2 = TP(sym->s_type);
+ if (tp1->t_vararg == tp2->t_vararg)
+ continue;
+ if (tp2->t_vararg &&
+ sym1->s_va && sym1->s_nva == n && !sflag) {
+ continue;
+ }
+ }
+ /* %s: variable # of args declared\t%s :: %s */
+ pos1 = xstrdup(mkpos(&sym1->s_pos));
+ msg(12, hte->h_name, pos1, mkpos(&sym->s_pos));
+ free(pos1);
+ }
+}
+
+
+/*
+ * Check compatibility of two types. Returns 1 if types are compatible,
+ * otherwise 0.
+ *
+ * ignqual if set, ignore qualifiers of outhermost type; used for
+ * function arguments
+ * promote if set, promote left type before comparision; used for
+ * comparisions of arguments with parameters of old style
+ * definitions
+ * asgn left indirected type must have at least the same qualifiers
+ * like right indirected type (for assignments and function
+ * arguments)
+ * *warn set to 1 if an old style declaration was compared with
+ * an incompatible prototype declaration
+ */
+static int
+eqtype(tp1, tp2, ignqual, promot, asgn, warn)
+ type_t *tp1, *tp2;
+ int ignqual, promot, asgn, *warn;
+{
+ tspec_t t, to;
+ int indir;
+
+ to = NOTSPEC;
+ indir = 0;
+
+ while (tp1 != NULL && tp2 != NULL) {
+
+ t = tp1->t_tspec;
+ if (promot) {
+ if (t == FLOAT) {
+ t = DOUBLE;
+ } else if (t == CHAR || t == SCHAR) {
+ t = INT;
+ } else if (t == UCHAR) {
+ t = tflag ? UINT : INT;
+ } else if (t == SHORT) {
+ t = INT;
+ } else if (t == USHORT) {
+ /* CONSTCOND */
+ t = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
+ }
+ }
+
+ if (asgn && to == PTR) {
+ if (indir == 1 && (t == VOID || tp2->t_tspec == VOID))
+ return (1);
+ }
+
+ if (t != tp2->t_tspec) {
+ /*
+ * Give pointer to types which differ only in
+ * signedness a chance if not sflag and not hflag.
+ */
+ if (sflag || hflag || to != PTR)
+ return (0);
+ if (styp(t) != styp(tp2->t_tspec))
+ return (0);
+ }
+
+ if (tp1->t_isenum && tp2->t_isenum) {
+ if (tp1->t_istag && tp2->t_istag) {
+ return (tp1->t_tag == tp2->t_tag);
+ } else if (tp1->t_istynam && tp2->t_istynam) {
+ return (tp1->t_tynam == tp2->t_tynam);
+ } else {
+ return (0);
+ }
+ }
+
+ /*
+ * XXX Handle combinations of enum and int if eflag is set.
+ * But note: enum and 0 should be allowed.
+ */
+
+ if (asgn && indir == 1) {
+ if (!tp1->t_const && tp2->t_const)
+ return (0);
+ if (!tp1->t_volatile && tp2->t_volatile)
+ return (0);
+ } else if (!ignqual && !tflag) {
+ if (tp1->t_const != tp2->t_const)
+ return (0);
+ if (tp1->t_const != tp2->t_const)
+ return (0);
+ }
+
+ if (t == STRUCT || t == UNION) {
+ if (tp1->t_istag && tp2->t_istag) {
+ return (tp1->t_tag == tp2->t_tag);
+ } else if (tp1->t_istynam && tp2->t_istynam) {
+ return (tp1->t_tynam == tp2->t_tynam);
+ } else {
+ return (0);
+ }
+ }
+
+ if (t == ARRAY && tp1->t_dim != tp2->t_dim) {
+ if (tp1->t_dim != 0 && tp2->t_dim != 0)
+ return (0);
+ }
+
+ if (t == FUNC) {
+ if (tp1->t_proto && tp2->t_proto) {
+ if (!eqargs(tp1, tp2, warn))
+ return (0);
+ } else if (tp1->t_proto) {
+ if (!mnoarg(tp1, warn))
+ return (0);
+ } else if (tp2->t_proto) {
+ if (!mnoarg(tp2, warn))
+ return (0);
+ }
+ }
+
+ tp1 = tp1->t_subt;
+ tp2 = tp2->t_subt;
+ ignqual = promot = 0;
+ to = t;
+ indir++;
+
+ }
+
+ return (tp1 == tp2);
+}
+
+/*
+ * Compares arguments of two prototypes
+ */
+static int
+eqargs(tp1, tp2, warn)
+ type_t *tp1, *tp2;
+ int *warn;
+{
+ type_t **a1, **a2;
+
+ if (tp1->t_vararg != tp2->t_vararg)
+ return (0);
+
+ a1 = tp1->t_args;
+ a2 = tp2->t_args;
+
+ while (*a1 != NULL && *a2 != NULL) {
+
+ if (eqtype(*a1, *a2, 1, 0, 0, warn) == 0)
+ return (0);
+
+ a1++;
+ a2++;
+
+ }
+
+ return (*a1 == *a2);
+}
+
+/*
+ * mnoarg() (matches functions with no argument type information)
+ * returns 1 if all parameters of a prototype are compatible with
+ * and old style function declaration.
+ * This is the case if following conditions are met:
+ * 1. the prototype must have a fixed number of parameters
+ * 2. no parameter is of type float
+ * 3. no parameter is converted to another type if integer promotion
+ * is applied on it
+ */
+static int
+mnoarg(tp, warn)
+ type_t *tp;
+ int *warn;
+{
+ type_t **arg;
+ tspec_t t;
+
+ if (tp->t_vararg && warn != NULL)
+ *warn = 1;
+ for (arg = tp->t_args; *arg != NULL; arg++) {
+ if ((t = (*arg)->t_tspec) == FLOAT)
+ return (0);
+ if (t == CHAR || t == SCHAR || t == UCHAR)
+ return (0);
+ if (t == SHORT || t == USHORT)
+ return (0);
+ }
+ return (1);
+}
+
diff --git a/usr.bin/xlint/lint2/emit2.c b/usr.bin/xlint/lint2/emit2.c
new file mode 100644
index 0000000..82527b5
--- /dev/null
+++ b/usr.bin/xlint/lint2/emit2.c
@@ -0,0 +1,236 @@
+/* $NetBSD: emit2.c,v 1.2 1995/07/03 21:24:44 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: emit2.c,v 1.2 1995/07/03 21:24:44 cgd Exp $";
+#endif
+
+#include <err.h>
+
+#include "lint2.h"
+
+static void outtype __P((type_t *));
+static void outdef __P((hte_t *, sym_t *));
+static void dumpname __P((hte_t *));
+
+/*
+ * Write type into the output buffer.
+ */
+static void
+outtype(tp)
+ type_t *tp;
+{
+ int t, s, na;
+ tspec_t ts;
+ type_t **ap;
+
+ while (tp != NULL) {
+ if ((ts = tp->t_tspec) == INT && tp->t_isenum)
+ ts = ENUM;
+ switch (ts) {
+ case CHAR: t = 'C'; s = '\0'; break;
+ case SCHAR: t = 'C'; s = 's'; break;
+ case UCHAR: t = 'C'; s = 'u'; break;
+ case SHORT: t = 'S'; s = '\0'; break;
+ case USHORT: t = 'S'; s = 'u'; break;
+ case INT: t = 'I'; s = '\0'; break;
+ case UINT: t = 'I'; s = 'u'; break;
+ case LONG: t = 'L'; s = '\0'; break;
+ case ULONG: t = 'L'; s = 'u'; break;
+ case QUAD: t = 'Q'; s = '\0'; break;
+ case UQUAD: t = 'Q'; s = 'u'; break;
+ case FLOAT: t = 'D'; s = 's'; break;
+ case DOUBLE: t = 'D'; s = '\0'; break;
+ case LDOUBLE: t = 'D'; s = 'l'; break;
+ case VOID: t = 'V'; s = '\0'; break;
+ case PTR: t = 'P'; s = '\0'; break;
+ case ARRAY: t = 'A'; s = '\0'; break;
+ case ENUM: t = 'T'; s = 'e'; break;
+ case STRUCT: t = 'T'; s = 's'; break;
+ case UNION: t = 'T'; s = 'u'; break;
+ case FUNC:
+ if (tp->t_args != NULL && !tp->t_proto) {
+ t = 'f';
+ } else {
+ t = 'F';
+ }
+ s = '\0';
+ break;
+ default:
+ errx(1, "internal error: outtype() 1");
+ }
+ if (tp->t_const)
+ outchar('c');
+ if (tp->t_volatile)
+ outchar('v');
+ if (s != '\0')
+ outchar(s);
+ outchar(t);
+ if (ts == ARRAY) {
+ outint(tp->t_dim);
+ } else if (ts == ENUM || ts == STRUCT || ts == UNION) {
+ if (tp->t_istag) {
+ outint(1);
+ outname(tp->t_tag->h_name);
+ } else if (tp->t_istynam) {
+ outint(2);
+ outname(tp->t_tynam->h_name);
+ } else {
+ outint(0);
+ }
+ } else if (ts == FUNC && tp->t_args != NULL) {
+ na = 0;
+ for (ap = tp->t_args; *ap != NULL; ap++)
+ na++;
+ if (tp->t_vararg)
+ na++;
+ outint(na);
+ for (ap = tp->t_args; *ap != NULL; ap++)
+ outtype(*ap);
+ if (tp->t_vararg)
+ outchar('E');
+ }
+ tp = tp->t_subt;
+ }
+}
+
+/*
+ * Write a definition.
+ */
+static void
+outdef(hte, sym)
+ hte_t *hte;
+ sym_t *sym;
+{
+ /* reset output buffer */
+ outclr();
+
+ /* line number in C source file */
+ outint(0);
+
+ /* this is a definition */
+ outchar('d');
+
+ /* index of file where symbol was defined and line number of def. */
+ outint(0);
+ outchar('.');
+ outint(0);
+
+ /* flags */
+ if (sym->s_va) {
+ outchar('v'); /* varargs */
+ outint(sym->s_nva);
+ }
+ if (sym->s_scfl) {
+ outchar('S'); /* scanflike */
+ outint(sym->s_nscfl);
+ }
+ if (sym->s_prfl) {
+ outchar('P'); /* printflike */
+ outint(sym->s_nprfl);
+ }
+ /* definition or tentative definition */
+ outchar(sym->s_def == DEF ? 'd' : 't');
+ if (TP(sym->s_type)->t_tspec == FUNC) {
+ if (sym->s_rval)
+ outchar('r'); /* fkt. has return value */
+ if (sym->s_osdef)
+ outchar('o'); /* old style definition */
+ }
+ outchar('u'); /* used (no warning if not used) */
+
+ /* name */
+ outname(hte->h_name);
+
+ /* type */
+ outtype(TP(sym->s_type));
+}
+
+/*
+ * Write the first definition of a name into the lint library.
+ */
+static void
+dumpname(hte)
+ hte_t *hte;
+{
+ sym_t *sym, *def;
+
+ /* static and undefined symbols are not written */
+ if (hte->h_static || !hte->h_def)
+ return;
+
+ /*
+ * If there is a definition, write it. Otherwise write a tentative
+ * definition. This is neccessary because more than one tentative
+ * definition is allowed (except with sflag).
+ */
+ def = NULL;
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym->s_def == DEF) {
+ def = sym;
+ break;
+ }
+ if (sym->s_def == TDEF && def == NULL)
+ def = sym;
+ }
+ if (def == NULL)
+ errx(1, "internal error: dumpname() %s", hte->h_name);
+
+ outdef(hte, def);
+}
+
+/*
+ * Write a new lint library.
+ */
+void
+outlib(name)
+ const char *name;
+{
+ /* Open of output file and initialisation of the output buffer */
+ outopen(name);
+
+ /* write name of lint library */
+ outsrc(name);
+
+ /* name of lint lib has index 0 */
+ outclr();
+ outint(0);
+ outchar('s');
+ outstrg(name);
+
+ /* write all definitions with external linkage */
+ forall(dumpname);
+
+ /* close the output */
+ outclose();
+}
diff --git a/usr.bin/xlint/lint2/externs2.h b/usr.bin/xlint/lint2/externs2.h
new file mode 100644
index 0000000..2e65e53
--- /dev/null
+++ b/usr.bin/xlint/lint2/externs2.h
@@ -0,0 +1,87 @@
+/* $NetBSD: externs2.h,v 1.2 1995/07/03 21:24:46 cgd 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.
+ */
+
+/*
+ * main.c
+ */
+extern int xflag;
+extern int uflag;
+extern int Cflag;
+extern const char *libname;
+extern int pflag;
+extern int sflag;
+extern int tflag;
+extern int Hflag;
+extern int hflag;
+extern int Fflag;
+
+
+/*
+ * hash.c
+ */
+extern void inithash __P((void));
+extern hte_t *hsearch __P((const char *, int));
+extern void forall __P((void (*)(hte_t *)));
+
+/*
+ * read.c
+ */
+extern const char **fnames;
+extern type_t **tlst;
+
+extern void readfile __P((const char *));
+extern void mkstatic __P((hte_t *));
+
+/*
+ * mem2.c
+ */
+extern void initmem __P((void));
+extern void *xalloc __P((size_t));
+
+/*
+ * chk.c
+ */
+extern void inittyp __P((void));
+extern void mainused __P((void));
+extern void chkname __P((hte_t *));
+
+/*
+ * msg.c
+ */
+extern void msg __P((int, ...));
+extern const char *mkpos __P((pos_t *));
+
+/*
+ * emit2.c
+ */
+extern void outlib __P((const char *));
diff --git a/usr.bin/xlint/lint2/hash.c b/usr.bin/xlint/lint2/hash.c
new file mode 100644
index 0000000..7901802
--- /dev/null
+++ b/usr.bin/xlint/lint2/hash.c
@@ -0,0 +1,123 @@
+/* $NetBSD: hash.c,v 1.2 1995/07/03 21:24:47 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: hash.c,v 1.2 1995/07/03 21:24:47 cgd Exp $";
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <limits.h>
+
+#include "lint2.h"
+
+/* pointer to hash table, initialized in inithash() */
+static hte_t **htab;
+
+static int hash __P((const char *));
+
+/*
+ * Initialize hash table.
+ */
+void
+inithash()
+{
+ htab = xcalloc(HSHSIZ2, sizeof (hte_t *));
+}
+
+/*
+ * Compute hash value from a string.
+ */
+static int
+hash(s)
+ const char *s;
+{
+ u_int v;
+ const u_char *us;
+
+ v = 0;
+ for (us = (const u_char *)s; *us != '\0'; us++) {
+ v = (v << sizeof (v)) + *us;
+ v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
+ }
+ return (v % HSHSIZ2);
+}
+
+/*
+ * Look for a hash table entry. If no hash table entry for the
+ * given name exists and mknew is set, create a new one.
+ */
+hte_t *
+hsearch(s, mknew)
+ const char *s;
+ int mknew;
+{
+ int h;
+ hte_t *hte;
+
+ h = hash(s);
+ for (hte = htab[h]; hte != NULL; hte = hte->h_link) {
+ if (strcmp(hte->h_name, s) == 0)
+ break;
+ }
+
+ if (hte != NULL || !mknew)
+ return (hte);
+
+ /* create a new hte */
+ hte = xalloc(sizeof (hte_t));
+ hte->h_name = xstrdup(s);
+ hte->h_lsym = &hte->h_syms;
+ hte->h_lcall = &hte->h_calls;
+ hte->h_lusym = &hte->h_usyms;
+ hte->h_link = htab[h];
+ htab[h] = hte;
+
+ return (hte);
+}
+
+/*
+ * Call function f for each name in the hash table.
+ */
+void
+forall(f)
+ void (*f) __P((hte_t *));
+{
+ int i;
+ hte_t *hte;
+
+ for (i = 0; i < HSHSIZ2; i++) {
+ for (hte = htab[i]; hte != NULL; hte = hte->h_link)
+ (*f)(hte);
+ }
+}
diff --git a/usr.bin/xlint/lint2/lint2.h b/usr.bin/xlint/lint2/lint2.h
new file mode 100644
index 0000000..0ade110
--- /dev/null
+++ b/usr.bin/xlint/lint2/lint2.h
@@ -0,0 +1,177 @@
+/* $NetBSD: lint2.h,v 1.2 1995/07/03 21:24:49 cgd 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.
+ */
+
+#include "lint.h"
+
+/*
+ * Types are described by structures of type type_t.
+ */
+typedef struct type {
+ tspec_t t_tspec; /* type specifier */
+ u_int t_const : 1; /* constant */
+ u_int t_volatile : 1; /* volatile */
+ u_int t_vararg : 1; /* function has variable number of arguments */
+ u_int t_isenum : 1; /* enum type */
+ u_int t_proto : 1; /* this is a prototype */
+ u_int t_istag : 1; /* tag with _t_tag valid */
+ u_int t_istynam : 1; /* tag with _t_tynam valid */
+ union {
+ int _t_dim; /* if the type is an ARRAY than this
+ is the dimension of the array. */
+ struct hte *_t_tag; /* hash table entry of tag if
+ t_isenum, STRUCT or UNION */
+ struct hte *_t_tynam; /* hash table entry of typename if
+ t_isenum, STRUCT or UNION */
+ struct type **_t_args; /* list of argument types if this
+ is a prototype */
+ } t_u;
+ struct type *t_subt; /* indirected type (array element, pointed to
+ type, type of return value) */
+} type_t;
+
+#define t_dim t_u._t_dim
+#define t_tag t_u._t_tag
+#define t_tynam t_u._t_tynam
+#define t_args t_u._t_args
+
+/*
+ * argument information
+ *
+ * Such a structure is created for each argument of a function call
+ * which is an integer constant or a constant string.
+ */
+typedef struct arginf {
+ int a_num; /* # of argument (1..) */
+ u_int a_zero : 1; /* argument is 0 */
+ u_int a_pcon : 1; /* msb of argument is not set */
+ u_int a_ncon : 1; /* msb of argument is set */
+ u_int a_fmt : 1; /* a_fstrg points to format string */
+ char *a_fstrg; /* format string */
+ struct arginf *a_nxt; /* information for next const. argument */
+} arginf_t;
+
+/*
+ * Keeps information about position in source file.
+ */
+typedef struct {
+ u_short p_src; /* index of name of translation unit
+ (the name which was specified at the
+ command line) */
+ u_short p_line; /* line number in p_src */
+ u_short p_isrc; /* index of (included) file */
+ u_short p_iline; /* line number in p_iline */
+} pos_t;
+
+/*
+ * Used for definitions and declarations
+ *
+ * To save memory, variable sized structures are used. If
+ * all s_va, s_prfl and s_scfl are not set, the memory allocated
+ * for a symbol is only large enough to keep the first member of
+ * struct sym, s_s.
+ */
+typedef struct sym {
+ struct {
+ pos_t s_pos; /* pos of def./decl. */
+#ifndef lint
+ u_int s_def : 3; /* DECL, TDEF or DEF */
+#else
+ def_t s_def;
+#endif
+ u_int s_rval : 1; /* function has return value */
+ u_int s_osdef : 1; /* old style function definition */
+ u_int s_static : 1; /* symbol is static */
+ u_int s_va : 1; /* check only first s_nva arguments */
+ u_int s_prfl : 1; /* printflike */
+ u_int s_scfl : 1; /* scanflike */
+ u_short s_type; /* type */
+ struct sym *s_nxt; /* next symbol with same name */
+ } s_s;
+ short s_nva;
+ short s_nprfl;
+ short s_nscfl;
+} sym_t;
+
+#define s_pos s_s.s_pos
+#define s_rval s_s.s_rval
+#define s_osdef s_s.s_osdef
+#define s_static s_s.s_static
+#define s_def s_s.s_def
+#define s_va s_s.s_va
+#define s_prfl s_s.s_prfl
+#define s_scfl s_s.s_scfl
+#define s_type s_s.s_type
+#define s_nxt s_s.s_nxt
+
+/*
+ * Used to store informations about function calls.
+ */
+typedef struct fcall {
+ pos_t f_pos; /* position of call */
+ u_int f_rused : 1; /* return value used */
+ u_int f_rdisc : 1; /* return value discarded (casted to void) */
+ u_short f_type; /* types of expected return value and args */
+ arginf_t *f_args; /* information about constant arguments */
+ struct fcall *f_nxt; /* next call of same function */
+} fcall_t;
+
+/*
+ * Used to store information about usage of symbols other
+ * than for function calls.
+ */
+typedef struct usym {
+ pos_t u_pos; /* position */
+ struct usym *u_nxt; /* next usage */
+} usym_t;
+
+/*
+ * hash table entry
+ */
+typedef struct hte {
+ const char *h_name; /* name */
+ u_int h_used : 1; /* symbol is used */
+ u_int h_def : 1; /* symbol is defined */
+ u_int h_static : 1; /* static symbol */
+ sym_t *h_syms; /* declarations and definitions */
+ sym_t **h_lsym; /* points to s_nxt of last decl./def. */
+ fcall_t *h_calls; /* function calls */
+ fcall_t **h_lcall; /* points to f_nxt of last call */
+ usym_t *h_usyms; /* usage info */
+ usym_t **h_lusym; /* points to u_nxt of last usage info */
+ struct hte *h_link; /* next hte with same hash function */
+} hte_t;
+
+/* maps type indices into pointers to type structs */
+#define TP(idx) (tlst[idx])
+
+#include "externs2.h"
diff --git a/usr.bin/xlint/lint2/main2.c b/usr.bin/xlint/lint2/main2.c
new file mode 100644
index 0000000..171344a
--- /dev/null
+++ b/usr.bin/xlint/lint2/main2.c
@@ -0,0 +1,190 @@
+/* $NetBSD: main2.c,v 1.2 1995/07/03 21:24:53 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: main2.c,v 1.2 1995/07/03 21:24:53 cgd Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "lint2.h"
+
+/* warnings for symbols which are declared but not defined or used */
+int xflag;
+
+/*
+ * warnings for symbols which are used and not defined or defined
+ * and not used
+ */
+int uflag = 1;
+
+/* Create a lint library in the current directory with name libname. */
+int Cflag;
+const char *libname;
+
+int pflag;
+
+/*
+ * warnings for (tentative) definitions of the same name in more then
+ * one translation unit
+ */
+int sflag;
+
+int tflag;
+
+/*
+ * If a complaint stems from a included file, print the name of the included
+ * file instead of the name spezified at the command line followed by '?'
+ */
+int Hflag;
+
+int hflag;
+
+/* Print full path names, not only the last component */
+int Fflag;
+
+/*
+ * List of libraries (from -l flag). These libraries are read after all
+ * other input files has been read and, for Cflag, after the new lint library
+ * has been written.
+ */
+const char **libs;
+
+static void usage __P((void));
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, i;
+ size_t len;
+ char *lname;
+
+ libs = xcalloc(1, sizeof (char *));
+
+ opterr = 0;
+ while ((c = getopt(argc, argv, "hpstxuC:HFl:")) != -1) {
+ switch (c) {
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'u':
+ uflag = 0;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'C':
+ len = strlen(optarg);
+ lname = xmalloc(len + 10);
+ (void)sprintf(lname, "llib-l%s.ln", optarg);
+ libname = lname;
+ Cflag = 1;
+ uflag = 0;
+ break;
+ case 'H':
+ Hflag = 1;
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'l':
+ for (i = 0; libs[i] != NULL; i++) ;
+ libs = xrealloc(libs, (i + 2) * sizeof (char *));
+ libs[i] = xstrdup(optarg);
+ libs[i + 1] = NULL;
+ break;
+ case '?':
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ initmem();
+
+ /* initialize hash table */
+ inithash();
+
+ inittyp();
+
+ for (i = 0; i < argc; i++)
+ readfile(argv[i]);
+
+ /* write the lint library */
+ if (Cflag) {
+ forall(mkstatic);
+ outlib(libname);
+ }
+
+ /* read additional libraries */
+ for (i = 0; libs[i] != NULL; i++)
+ readfile(libs[i]);
+
+ forall(mkstatic);
+
+ mainused();
+
+ /* perform all tests */
+ forall(chkname);
+
+ exit(0);
+ /* NOTREACHED */
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: lint2 -hpstxuHF -Clib -l lib ... src1 ...\n");
+ exit(1);
+}
+
diff --git a/usr.bin/xlint/lint2/mem2.c b/usr.bin/xlint/lint2/mem2.c
new file mode 100644
index 0000000..06d7491
--- /dev/null
+++ b/usr.bin/xlint/lint2/mem2.c
@@ -0,0 +1,97 @@
+/* $NetBSD: mem2.c,v 1.3 1995/10/02 17:27:11 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: mem2.c,v 1.3 1995/10/02 17:27:11 jpo Exp $";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+
+#include "lint2.h"
+
+/* length of new allocated memory blocks */
+static size_t mblklen;
+
+/* offset of next free byte in mbuf */
+static size_t nxtfree;
+
+/* current buffer to server memory requests from */
+static void *mbuf;
+
+void
+initmem()
+{
+ int pgsz;
+
+ pgsz = getpagesize();
+ mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
+
+ nxtfree = mblklen;
+}
+
+/*
+ * Allocate memory in large chunks to avoid space and time overhead of
+ * malloc(). This is possible because memory allocated by xalloc()
+ * need never to be freed.
+ */
+void *
+xalloc(sz)
+ size_t sz;
+{
+ void *ptr;
+ int prot, flags;
+
+ sz = ALIGN(sz);
+ if (nxtfree + sz > mblklen) {
+ /* use mmap() instead of malloc() to avoid malloc overhead. */
+ prot = PROT_READ | PROT_WRITE;
+ flags = MAP_ANON | MAP_PRIVATE;
+ mbuf = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
+ if (mbuf == (void *)-1)
+ err(1, "can't map memory");
+ if (ALIGN((u_long)mbuf) != (u_long)mbuf)
+ errx(1, "mapped address is not aligned");
+ (void)memset(mbuf, 0, mblklen);
+ nxtfree = 0;
+ }
+
+ ptr = (char *)mbuf + nxtfree;
+ nxtfree += sz;
+
+ return (ptr);
+}
diff --git a/usr.bin/xlint/lint2/msg.c b/usr.bin/xlint/lint2/msg.c
new file mode 100644
index 0000000..c55ba96
--- /dev/null
+++ b/usr.bin/xlint/lint2/msg.c
@@ -0,0 +1,157 @@
+/* $NetBSD: msg.c,v 1.2 1995/07/03 21:24:56 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: msg.c,v 1.2 1995/07/03 21:24:56 cgd Exp $";
+#endif
+
+#include <string.h>
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include "lint2.h"
+
+
+static const char *msgs[] = {
+ "%s used( %s ), but not defined", /* 0 */
+ "%s defined( %s ), but never used", /* 1 */
+ "%s declared( %s ), but never used or defined", /* 2 */
+ "%s multiply defined \t%s :: %s", /* 3 */
+ "%s value used inconsistently \t%s :: %s", /* 4 */
+ "%s value declared inconsistently \t%s :: %s", /* 5 */
+ "%s, arg %d used inconsistently \t%s :: %s", /* 6 */
+ "%s: variable # of args \t%s :: %s", /* 7 */
+ "%s returns value which is always ignored", /* 8 */
+ "%s returns value which is sometimes ignored", /* 9 */
+ "%s value is used( %s ), but none returned", /* 10 */
+ "%s, arg %d declared inconsistently \t%s :: %s", /* 11 */
+ "%s: variable # of args declared \t%s :: %s", /* 12 */
+ "%s: malformed format string \t%s", /* 13 */
+ "%s, arg %d inconsistent with format \t%s", /* 14 */
+ "%s: too few args for format \t%s", /* 15 */
+ "%s: too many args for format \t%s", /* 16 */
+ "%s function value must be declared before use \t%s :: %s",/* 17 */
+};
+
+static const char *basename __P((const char *));
+
+#ifdef __STDC__
+void
+msg(int n, ...)
+{
+#else
+void
+msg(va_alist)
+ va_dcl
+ int n;
+{
+#endif
+ va_list ap;
+
+#ifdef __STDC__
+ va_start(ap, n);
+#else
+ va_start(ap);
+ n = va_arg(ap, int);
+#endif
+
+ (void)vprintf(msgs[n], ap);
+ (void)printf("\n");
+
+ va_end(ap);
+}
+
+/*
+ * Return a pointer to the last component of a path.
+ */
+static const char *
+basename(path)
+ const char *path;
+{
+ const char *cp, *cp1, *cp2;
+
+ if (Fflag)
+ return (path);
+
+ cp = cp1 = cp2 = path;
+ while (*cp != '\0') {
+ if (*cp++ == '/') {
+ cp2 = cp1;
+ cp1 = cp;
+ }
+ }
+ return (*cp1 == '\0' ? cp2 : cp1);
+}
+
+/*
+ * Create a string which describes a position in a source file.
+ */
+const char *
+mkpos(posp)
+ pos_t *posp;
+{
+ size_t len;
+ const char *fn;
+ static char *buf;
+ static size_t blen = 0;
+ int qm, src, line;
+
+ if (Hflag && posp->p_src != posp->p_isrc) {
+ src = posp->p_isrc;
+ line = posp->p_iline;
+ } else {
+ src = posp->p_src;
+ line = posp->p_line;
+ }
+ qm = !Hflag && posp->p_src != posp->p_isrc;
+
+ len = strlen(fn = basename(fnames[src]));
+ len += 3 * sizeof (u_short) + 4;
+
+ if (len > blen)
+ buf = xrealloc(buf, blen = len);
+ if (line != 0) {
+ (void)sprintf(buf, "%s%s(%hu)",
+ fn, qm ? "?" : "", line);
+ } else {
+ (void)sprintf(buf, "%s", fn);
+ }
+
+ return (buf);
+}
+
diff --git a/usr.bin/xlint/lint2/read.c b/usr.bin/xlint/lint2/read.c
new file mode 100644
index 0000000..daffe1e
--- /dev/null
+++ b/usr.bin/xlint/lint2/read.c
@@ -0,0 +1,1133 @@
+/* $NetBSD: read.c,v 1.2 1995/07/03 21:24:59 cgd 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: read.c,v 1.2 1995/07/03 21:24:59 cgd Exp $";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <err.h>
+
+#include "lint2.h"
+
+
+/* index of current (included) source file */
+static int srcfile;
+
+/*
+ * The array pointed to by inpfns maps the file name indices of input files
+ * to the file name indices used in lint2
+ */
+static short *inpfns;
+static size_t ninpfns;
+
+/*
+ * The array pointed to by *fnames maps file name indizes to file names.
+ * Indices of type short are used instead of pointers to save memory.
+ */
+const char **fnames;
+static size_t nfnames;
+
+/*
+ * Types are shared (to save memory for the types itself) and accessed
+ * via indices (to save memory for references to types (indices are short)).
+ * To share types, a equal type must be located fast. This is done by a
+ * hash table. Access by indices is done via an array of pointers to the
+ * types.
+ */
+typedef struct thtab {
+ const char *th_name;
+ u_short th_idx;
+ struct thtab *th_nxt;
+} thtab_t;
+static thtab_t **thtab; /* hash table */
+type_t **tlst; /* array for indexed access */
+static size_t tlstlen; /* length of tlst */
+
+/* index of current C source file (as spezified at the command line) */
+static int csrcfile;
+
+
+static void inperr __P((void));
+static void setsrc __P((const char *));
+static void setfnid __P((int, const char *));
+static void funccall __P((pos_t *, const char *));
+static void decldef __P((pos_t *, const char *));
+static void usedsym __P((pos_t *, const char *));
+static u_short inptype __P((const char *, const char **));
+static int gettlen __P((const char *, const char **));
+static u_short findtype __P((const char *, size_t, int));
+static u_short storetyp __P((type_t *, const char *, size_t, int));
+static int thash __P((const char *, size_t));
+static char *inpqstrg __P((const char *, const char **));
+static const char *inpname __P((const char *, const char **));
+static int getfnidx __P((const char *));
+
+void
+readfile(name)
+ const char *name;
+{
+ FILE *inp;
+ size_t len;
+ const char *cp;
+ char *line, *eptr, rt;
+ int cline, isrc, iline;
+ pos_t pos;
+
+ if (inpfns == NULL)
+ inpfns = xcalloc(ninpfns = 128, sizeof (short));
+ if (fnames == NULL)
+ fnames = xcalloc(nfnames = 256, sizeof (char *));
+ if (tlstlen == 0)
+ tlst = xcalloc(tlstlen = 256, sizeof (type_t *));
+ if (thtab == NULL)
+ thtab = xcalloc(THSHSIZ2, sizeof (thtab_t));
+
+ srcfile = getfnidx(name);
+
+ if ((inp = fopen(name, "r")) == NULL)
+ err(1, "cannot open %s", name);
+
+ while ((line = fgetln(inp, &len)) != NULL) {
+
+ if (len == 0 || line[len - 1] != '\n')
+ inperr();
+ line[len - 1] = '\0';
+ cp = line;
+
+ /* line number in csrcfile */
+ cline = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr) {
+ cline = -1;
+ } else {
+ cp = eptr;
+ }
+
+ /* record type */
+ if (*cp != '\0') {
+ rt = *cp++;
+ } else {
+ inperr();
+ }
+
+ if (rt == 'S') {
+ setsrc(cp);
+ continue;
+ } else if (rt == 's') {
+ setfnid(cline, cp);
+ continue;
+ }
+
+ /*
+ * Index of (included) source file. If this index is
+ * different from csrcfile, it refers to an included
+ * file.
+ */
+ isrc = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+ isrc = inpfns[isrc];
+
+ /* line number in isrc */
+ if (*cp++ != '.')
+ inperr();
+ iline = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+
+ pos.p_src = (u_short)csrcfile;
+ pos.p_line = (u_short)cline;
+ pos.p_isrc = (u_short)isrc;
+ pos.p_iline = (u_short)iline;
+
+ /* process rest of this record */
+ switch (rt) {
+ case 'c':
+ funccall(&pos, cp);
+ break;
+ case 'd':
+ decldef(&pos, cp);
+ break;
+ case 'u':
+ usedsym(&pos, cp);
+ break;
+ default:
+ inperr();
+ }
+
+ }
+
+ if (ferror(inp))
+ err(1, "read error on %s", name);
+
+ (void)fclose(inp);
+}
+
+
+static void
+inperr()
+{
+ errx(1, "input file error: %s", fnames[srcfile]);
+}
+
+/*
+ * Set the name of the C source file of the .ln file which is
+ * currently read.
+ */
+static void
+setsrc(cp)
+ const char *cp;
+{
+ csrcfile = getfnidx(cp);
+}
+
+/*
+ * setfnid() gets as input an index as used in an input file and the
+ * associated file name. If neccessary, it creates a new lint2 file
+ * name index for this file name and creates the mapping of the index
+ * as used in the input file to the index used in lint2.
+ */
+static void
+setfnid(fid, cp)
+ int fid;
+ const char *cp;
+{
+ if (fid == -1)
+ inperr();
+
+ if (fid >= ninpfns) {
+ inpfns = xrealloc(inpfns, (ninpfns * 2) * sizeof (short));
+ (void)memset(inpfns + ninpfns, 0, ninpfns * sizeof (short));
+ ninpfns *= 2;
+ }
+ /*
+ * Should always be true because indices written in the output
+ * file by lint1 are always the previous index + 1.
+ */
+ if (fid >= ninpfns)
+ errx(1, "internal error: setfnid()");
+ inpfns[fid] = (u_short)getfnidx(cp);
+}
+
+/*
+ * Process a function call record (c-record).
+ */
+static void
+funccall(posp, cp)
+ pos_t *posp;
+ const char *cp;
+{
+ arginf_t *ai, **lai;
+ char c, *eptr;
+ int rused, rdisc;
+ hte_t *hte;
+ fcall_t *fcall;
+
+ fcall = xalloc(sizeof (fcall_t));
+ STRUCT_ASSIGN(fcall->f_pos, *posp);
+
+ /* read flags */
+ rused = rdisc = 0;
+ lai = &fcall->f_args;
+ while ((c = *cp) == 'u' || c == 'i' || c == 'd' ||
+ c == 'z' || c == 'p' || c == 'n' || c == 's') {
+ cp++;
+ switch (c) {
+ case 'u':
+ if (rused || rdisc)
+ inperr();
+ rused = 1;
+ break;
+ case 'i':
+ if (rused || rdisc)
+ inperr();
+ break;
+ case 'd':
+ if (rused || rdisc)
+ inperr();
+ rdisc = 1;
+ break;
+ case 'z':
+ case 'p':
+ case 'n':
+ case 's':
+ ai = xalloc(sizeof (arginf_t));
+ ai->a_num = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+ if (c == 'z') {
+ ai->a_pcon = ai->a_zero = 1;
+ } else if (c == 'p') {
+ ai->a_pcon = 1;
+ } else if (c == 'n') {
+ ai->a_ncon = 1;
+ } else {
+ ai->a_fmt = 1;
+ ai->a_fstrg = inpqstrg(cp, &cp);
+ }
+ *lai = ai;
+ lai = &ai->a_nxt;
+ break;
+ }
+ }
+ fcall->f_rused = rused;
+ fcall->f_rdisc = rdisc;
+
+ /* read name of function */
+ hte = hsearch(inpname(cp, &cp), 1);
+ hte->h_used = 1;
+
+ fcall->f_type = inptype(cp, &cp);
+
+ *hte->h_lcall = fcall;
+ hte->h_lcall = &fcall->f_nxt;
+
+ if (*cp != '\0')
+ inperr();
+}
+
+/*
+ * Process a declaration or definition (d-record).
+ */
+static void
+decldef(posp, cp)
+ pos_t *posp;
+ const char *cp;
+{
+ sym_t *symp, sym;
+ char c, *ep;
+ int used;
+ hte_t *hte;
+
+ (void)memset(&sym, 0, sizeof (sym));
+ STRUCT_ASSIGN(sym.s_pos, *posp);
+ sym.s_def = NODECL;
+
+ used = 0;
+
+ while ((c = *cp) == 't' || c == 'd' || c == 'e' || c == 'u' ||
+ c == 'r' || c == 'o' || c == 's' || c == 'v' ||
+ c == 'P' || c == 'S') {
+ cp++;
+ switch (c) {
+ case 't':
+ if (sym.s_def != NODECL)
+ inperr();
+ sym.s_def = TDEF;
+ break;
+ case 'd':
+ if (sym.s_def != NODECL)
+ inperr();
+ sym.s_def = DEF;
+ break;
+ case 'e':
+ if (sym.s_def != NODECL)
+ inperr();
+ sym.s_def = DECL;
+ break;
+ case 'u':
+ if (used)
+ inperr();
+ used = 1;
+ break;
+ case 'r':
+ if (sym.s_rval)
+ inperr();
+ sym.s_rval = 1;
+ break;
+ case 'o':
+ if (sym.s_osdef)
+ inperr();
+ sym.s_osdef = 1;
+ break;
+ case 's':
+ if (sym.s_static)
+ inperr();
+ sym.s_static = 1;
+ break;
+ case 'v':
+ if (sym.s_va)
+ inperr();
+ sym.s_va = 1;
+ sym.s_nva = (short)strtol(cp, &ep, 10);
+ if (cp == ep)
+ inperr();
+ cp = ep;
+ break;
+ case 'P':
+ if (sym.s_prfl)
+ inperr();
+ sym.s_prfl = 1;
+ sym.s_nprfl = (short)strtol(cp, &ep, 10);
+ if (cp == ep)
+ inperr();
+ cp = ep;
+ break;
+ case 'S':
+ if (sym.s_scfl)
+ inperr();
+ sym.s_scfl = 1;
+ sym.s_nscfl = (short)strtol(cp, &ep, 10);
+ if (cp == ep)
+ inperr();
+ cp = ep;
+ break;
+ }
+ }
+
+ /* read symbol name */
+ hte = hsearch(inpname(cp, &cp), 1);
+ hte->h_used |= used;
+ if (sym.s_def == DEF || sym.s_def == TDEF)
+ hte->h_def = 1;
+
+ sym.s_type = inptype(cp, &cp);
+
+ /*
+ * Allocate memory for this symbol only if it was not already
+ * declared or tentatively defined at the same location with
+ * the same type. Works only for symbols with external linkage,
+ * because static symbols, tentatively defined at the same location
+ * but in different translation units are really different symbols.
+ */
+ for (symp = hte->h_syms; symp != NULL; symp = symp->s_nxt) {
+ if (symp->s_pos.p_isrc == sym.s_pos.p_isrc &&
+ symp->s_pos.p_iline == sym.s_pos.p_iline &&
+ symp->s_type == sym.s_type &&
+ ((symp->s_def == DECL && sym.s_def == DECL) ||
+ (!sflag && symp->s_def == TDEF && sym.s_def == TDEF)) &&
+ !symp->s_static && !sym.s_static) {
+ break;
+ }
+ }
+
+ if (symp == NULL) {
+ /* allocsym reserviert keinen Platz fuer s_nva */
+ if (sym.s_va || sym.s_prfl || sym.s_scfl) {
+ symp = xalloc(sizeof (sym_t));
+ STRUCT_ASSIGN(*symp, sym);
+ } else {
+ symp = xalloc(sizeof (symp->s_s));
+ STRUCT_ASSIGN(symp->s_s, sym.s_s);
+ }
+ *hte->h_lsym = symp;
+ hte->h_lsym = &symp->s_nxt;
+ }
+
+ if (*cp != '\0')
+ inperr();
+}
+
+/*
+ * Read an u-record (emited by lint1 if a symbol was used).
+ */
+static void
+usedsym(posp, cp)
+ pos_t *posp;
+ const char *cp;
+{
+ usym_t *usym;
+ hte_t *hte;
+
+ usym = xalloc(sizeof (usym_t));
+ STRUCT_ASSIGN(usym->u_pos, *posp);
+
+ /* needed as delimiter between two numbers */
+ if (*cp++ != 'x')
+ inperr();
+
+ hte = hsearch(inpname(cp, &cp), 1);
+ hte->h_used = 1;
+
+ *hte->h_lusym = usym;
+ hte->h_lusym = &usym->u_nxt;
+}
+
+/*
+ * Read a type and return the index of this type.
+ */
+static u_short
+inptype(cp, epp)
+ const char *cp, **epp;
+{
+ char c, s, *eptr;
+ const char *ep;
+ type_t *tp;
+ int narg, i, osdef;
+ size_t tlen;
+ u_short tidx;
+ int h;
+
+ /* If we have this type already, return it's index. */
+ tlen = gettlen(cp, &ep);
+ h = thash(cp, tlen);
+ if ((tidx = findtype(cp, tlen, h)) != 0) {
+ *epp = ep;
+ return (tidx);
+ }
+
+ /* No, we must create a new type. */
+ tp = xalloc(sizeof (type_t));
+
+ tidx = storetyp(tp, cp, tlen, h);
+
+ c = *cp++;
+
+ while (c == 'c' || c == 'v') {
+ if (c == 'c') {
+ tp->t_const = 1;
+ } else {
+ tp->t_volatile = 1;
+ }
+ c = *cp++;
+ }
+
+ if (c == 's' || c == 'u' || c == 'l' || c == 'e') {
+ s = c;
+ c = *cp++;
+ } else {
+ s = '\0';
+ }
+
+ switch (c) {
+ case 'C':
+ tp->t_tspec = s == 's' ? SCHAR : (s == 'u' ? UCHAR : CHAR);
+ break;
+ case 'S':
+ tp->t_tspec = s == 'u' ? USHORT : SHORT;
+ break;
+ case 'I':
+ tp->t_tspec = s == 'u' ? UINT : INT;
+ break;
+ case 'L':
+ tp->t_tspec = s == 'u' ? ULONG : LONG;
+ break;
+ case 'Q':
+ tp->t_tspec = s == 'u' ? UQUAD : QUAD;
+ break;
+ case 'D':
+ tp->t_tspec = s == 's' ? FLOAT : (s == 'l' ? LDOUBLE : DOUBLE);
+ break;
+ case 'V':
+ tp->t_tspec = VOID;
+ break;
+ case 'P':
+ tp->t_tspec = PTR;
+ break;
+ case 'A':
+ tp->t_tspec = ARRAY;
+ break;
+ case 'F':
+ case 'f':
+ osdef = c == 'f';
+ tp->t_tspec = FUNC;
+ break;
+ case 'T':
+ tp->t_tspec = s == 'e' ? ENUM : (s == 's' ? STRUCT : UNION);
+ break;
+ }
+
+ switch (tp->t_tspec) {
+ case ARRAY:
+ tp->t_dim = (int)strtol(cp, &eptr, 10);
+ cp = eptr;
+ tp->t_subt = TP(inptype(cp, &cp));
+ break;
+ case PTR:
+ tp->t_subt = TP(inptype(cp, &cp));
+ break;
+ case FUNC:
+ c = *cp;
+ if (isdigit((u_char)c)) {
+ if (!osdef)
+ tp->t_proto = 1;
+ narg = (int)strtol(cp, &eptr, 10);
+ cp = eptr;
+ tp->t_args = xcalloc((size_t)(narg + 1),
+ sizeof (type_t *));
+ for (i = 0; i < narg; i++) {
+ if (i == narg - 1 && *cp == 'E') {
+ tp->t_vararg = 1;
+ cp++;
+ } else {
+ tp->t_args[i] = TP(inptype(cp, &cp));
+ }
+ }
+ }
+ tp->t_subt = TP(inptype(cp, &cp));
+ break;
+ case ENUM:
+ tp->t_tspec = INT;
+ tp->t_isenum = 1;
+ /* FALLTHROUGH */
+ case STRUCT:
+ case UNION:
+ switch (*cp++) {
+ case '0':
+ break;
+ case '1':
+ tp->t_istag = 1;
+ tp->t_tag = hsearch(inpname(cp, &cp), 1);
+ break;
+ case '2':
+ tp->t_istynam = 1;
+ tp->t_tynam = hsearch(inpname(cp, &cp), 1);
+ break;
+ }
+ break;
+ /* LINTED (enumeration value(s) not handled in switch) */
+ }
+
+ *epp = cp;
+ return (tidx);
+}
+
+/*
+ * Get the length of a type string.
+ */
+static int
+gettlen(cp, epp)
+ const char *cp, **epp;
+{
+ const char *cp1;
+ char c, s, *eptr;
+ tspec_t t;
+ int narg, i, cm, vm;
+
+ cp1 = cp;
+
+ c = *cp++;
+
+ cm = vm = 0;
+
+ while (c == 'c' || c == 'v') {
+ if (c == 'c') {
+ if (cm)
+ inperr();
+ cm = 1;
+ } else {
+ if (vm)
+ inperr();
+ vm = 1;
+ }
+ c = *cp++;
+ }
+
+ if (c == 's' || c == 'u' || c == 'l' || c == 'e') {
+ s = c;
+ c = *cp++;
+ } else {
+ s = '\0';
+ }
+
+ t = NOTSPEC;
+
+ switch (c) {
+ case 'C':
+ if (s == 's') {
+ t = SCHAR;
+ } else if (s == 'u') {
+ t = UCHAR;
+ } else if (s == '\0') {
+ t = CHAR;
+ }
+ break;
+ case 'S':
+ if (s == 'u') {
+ t = USHORT;
+ } else if (s == '\0') {
+ t = SHORT;
+ }
+ break;
+ case 'I':
+ if (s == 'u') {
+ t = UINT;
+ } else if (s == '\0') {
+ t = INT;
+ }
+ break;
+ case 'L':
+ if (s == 'u') {
+ t = ULONG;
+ } else if (s == '\0') {
+ t = LONG;
+ }
+ break;
+ case 'Q':
+ if (s == 'u') {
+ t = UQUAD;
+ } else if (s == '\0') {
+ t = QUAD;
+ }
+ break;
+ case 'D':
+ if (s == 's') {
+ t = FLOAT;
+ } else if (s == 'l') {
+ t = LDOUBLE;
+ } else if (s == '\0') {
+ t = DOUBLE;
+ }
+ break;
+ case 'V':
+ if (s == '\0')
+ t = VOID;
+ break;
+ case 'P':
+ if (s == '\0')
+ t = PTR;
+ break;
+ case 'A':
+ if (s == '\0')
+ t = ARRAY;
+ break;
+ case 'F':
+ case 'f':
+ if (s == '\0')
+ t = FUNC;
+ break;
+ case 'T':
+ if (s == 'e') {
+ t = ENUM;
+ } else if (s == 's') {
+ t = STRUCT;
+ } else if (s == 'u') {
+ t = UNION;
+ }
+ break;
+ default:
+ inperr();
+ }
+
+ if (t == NOTSPEC)
+ inperr();
+
+ switch (t) {
+ case ARRAY:
+ (void)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+ (void)gettlen(cp, &cp);
+ break;
+ case PTR:
+ (void)gettlen(cp, &cp);
+ break;
+ case FUNC:
+ c = *cp;
+ if (isdigit((u_char)c)) {
+ narg = (int)strtol(cp, &eptr, 10);
+ cp = eptr;
+ for (i = 0; i < narg; i++) {
+ if (i == narg - 1 && *cp == 'E') {
+ cp++;
+ } else {
+ (void)gettlen(cp, &cp);
+ }
+ }
+ }
+ (void)gettlen(cp, &cp);
+ break;
+ case ENUM:
+ case STRUCT:
+ case UNION:
+ switch (*cp++) {
+ case '0':
+ break;
+ case '1':
+ (void)inpname(cp, &cp);
+ break;
+ case '2':
+ (void)inpname(cp, &cp);
+ break;
+ default:
+ inperr();
+ }
+ break;
+ /* LINTED (enumeration value(s) not handled in switch) */
+ }
+
+ *epp = cp;
+ return (cp - cp1);
+}
+
+/*
+ * Search a type by it's type string.
+ */
+static u_short
+findtype(cp, len, h)
+ const char *cp;
+ size_t len;
+ int h;
+{
+ thtab_t *thte;
+
+ for (thte = thtab[h]; thte != NULL; thte = thte->th_nxt) {
+ if (strncmp(thte->th_name, cp, len) != 0)
+ continue;
+ if (thte->th_name[len] == '\0')
+ return (thte->th_idx);
+ }
+
+ return (0);
+}
+
+/*
+ * Store a type and it's type string so we can later share this type
+ * if we read the same type string from the input file.
+ */
+static u_short
+storetyp(tp, cp, len, h)
+ type_t *tp;
+ const char *cp;
+ size_t len;
+ int h;
+{
+ /* 0 ist reserved */
+ static u_int tidx = 1;
+ thtab_t *thte;
+ char *name;
+
+ if (tidx >= USHRT_MAX)
+ errx(1, "sorry, too many types");
+
+ if (tidx == tlstlen - 1) {
+ tlst = xrealloc(tlst, (tlstlen * 2) * sizeof (type_t *));
+ (void)memset(tlst + tlstlen, 0, tlstlen * sizeof (type_t *));
+ tlstlen *= 2;
+ }
+
+ tlst[tidx] = tp;
+
+ /* create a hash table entry */
+ name = xalloc(len + 1);
+ (void)memcpy(name, cp, len);
+ name[len] = '\0';
+
+ thte = xalloc(sizeof (thtab_t));
+ thte->th_name = name;
+ thte->th_idx = tidx;
+ thte->th_nxt = thtab[h];
+ thtab[h] = thte;
+
+ return ((u_short)tidx++);
+}
+
+/*
+ * Hash function for types
+ */
+static int
+thash(s, len)
+ const char *s;
+ size_t len;
+{
+ u_int v;
+
+ v = 0;
+ while (len-- != 0) {
+ v = (v << sizeof (v)) + (u_char)*s++;
+ v ^= v >> (sizeof (v) * CHAR_BIT - sizeof (v));
+ }
+ return (v % THSHSIZ2);
+}
+
+/*
+ * Read a string enclosed by "". This string may contain quoted chars.
+ */
+static char *
+inpqstrg(src, epp)
+ const char *src, **epp;
+{
+ char *strg, *dst;
+ size_t slen;
+ int c;
+ int v;
+
+ dst = strg = xmalloc(slen = 32);
+
+ if ((c = *src++) != '"')
+ inperr();
+ if ((c = *src++) == '\0')
+ inperr();
+
+ while (c != '"') {
+ if (c == '\\') {
+ if ((c = *src++) == '\0')
+ inperr();
+ switch (c) {
+ case 'n':
+ c = '\n';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+#ifdef __STDC__
+ c = '\v';
+#else
+ c = '\013';
+#endif
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'a':
+#ifdef __STDC__
+ c = '\a';
+#else
+ c = '\007';
+#endif
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '"':
+ c = '"';
+ break;
+ case '\'':
+ c = '\'';
+ break;
+ case '0': case '1': case '2': case '3':
+ v = (c - '0') << 6;
+ if ((c = *src++) < '0' || c > '7')
+ inperr();
+ v |= (c - '0') << 3;
+ if ((c = *src++) < '0' || c > '7')
+ inperr();
+ v |= c - '0';
+ c = (u_char)v;
+ break;
+ default:
+ inperr();
+ }
+ }
+ /* keep space for trailing '\0' */
+ if (dst - strg == slen - 1) {
+ strg = xrealloc(strg, slen * 2);
+ dst = strg + (slen - 1);
+ slen *= 2;
+ }
+ *dst++ = (char)c;
+ if ((c = *src++) == '\0')
+ inperr();
+ }
+ *dst = '\0';
+
+ *epp = src;
+ return (strg);
+}
+
+/*
+ * Read the name of a symbol in static memory.
+ */
+static const char *
+inpname(cp, epp)
+ const char *cp, **epp;
+{
+ static char *buf;
+ static size_t blen = 0;
+ size_t len, i;
+ char *eptr, c;
+
+ len = (int)strtol(cp, &eptr, 10);
+ if (cp == eptr)
+ inperr();
+ cp = eptr;
+ if (len + 1 > blen)
+ buf = xrealloc(buf, blen = len + 1);
+ for (i = 0; i < len; i++) {
+ c = *cp++;
+ if (!isalnum(c) && c != '_')
+ inperr();
+ buf[i] = c;
+ }
+ buf[i] = '\0';
+
+ *epp = cp;
+ return (buf);
+}
+
+/*
+ * Return the index of a file name. If the name cannot be found, create
+ * a new entry and return the index of the newly created entry.
+ */
+static int
+getfnidx(fn)
+ const char *fn;
+{
+ int i;
+
+ /* 0 ist reserved */
+ for (i = 1; fnames[i] != NULL; i++) {
+ if (strcmp(fnames[i], fn) == 0)
+ break;
+ }
+ if (fnames[i] != NULL)
+ return (i);
+
+ if (i == nfnames - 1) {
+ fnames = xrealloc(fnames, (nfnames * 2) * sizeof (char *));
+ (void)memset(fnames + nfnames, 0, nfnames * sizeof (char *));
+ nfnames *= 2;
+ }
+
+ fnames[i] = xstrdup(fn);
+ return (i);
+}
+
+/*
+ * Separate symbols with static and external linkage.
+ */
+void
+mkstatic(hte)
+ hte_t *hte;
+{
+ sym_t *sym1, **symp, *sym;
+ fcall_t **callp, *call;
+ usym_t **usymp, *usym;
+ hte_t *nhte;
+ int ofnd;
+
+ /* Look for first static definition */
+ for (sym1 = hte->h_syms; sym1 != NULL; sym1 = sym1->s_nxt) {
+ if (sym1->s_static)
+ break;
+ }
+ if (sym1 == NULL)
+ return;
+
+ /* Do nothing if this name is used only in one translation unit. */
+ ofnd = 0;
+ for (sym = hte->h_syms; sym != NULL && !ofnd; sym = sym->s_nxt) {
+ if (sym->s_pos.p_src != sym1->s_pos.p_src)
+ ofnd = 1;
+ }
+ for (call = hte->h_calls; call != NULL && !ofnd; call = call->f_nxt) {
+ if (call->f_pos.p_src != sym1->s_pos.p_src)
+ ofnd = 1;
+ }
+ for (usym = hte->h_usyms; usym != NULL && !ofnd; usym = usym->u_nxt) {
+ if (usym->u_pos.p_src != sym1->s_pos.p_src)
+ ofnd = 1;
+ }
+ if (!ofnd) {
+ hte->h_used = 1;
+ /* errors about undef. static symbols are printed in lint1 */
+ hte->h_def = 1;
+ hte->h_static = 1;
+ return;
+ }
+
+ /*
+ * Create a new hash table entry
+ *
+ * XXX this entry should be put at the beginning of the list to
+ * avoid to process the same symbol twice.
+ */
+ for (nhte = hte; nhte->h_link != NULL; nhte = nhte->h_link) ;
+ nhte->h_link = xalloc(sizeof (hte_t));
+ nhte = nhte->h_link;
+ nhte->h_name = hte->h_name;
+ nhte->h_static = 1;
+ nhte->h_used = 1;
+ nhte->h_def = 1; /* error in lint1 */
+ nhte->h_lsym = &nhte->h_syms;
+ nhte->h_lcall = &nhte->h_calls;
+ nhte->h_lusym = &nhte->h_usyms;
+
+ /*
+ * move all symbols used in this translation unit into the new
+ * hash table entry.
+ */
+ for (symp = &hte->h_syms; (sym = *symp) != NULL; ) {
+ if (sym->s_pos.p_src == sym1->s_pos.p_src) {
+ sym->s_static = 1;
+ (*symp) = sym->s_nxt;
+ if (hte->h_lsym == &sym->s_nxt)
+ hte->h_lsym = symp;
+ sym->s_nxt = NULL;
+ *nhte->h_lsym = sym;
+ nhte->h_lsym = &sym->s_nxt;
+ } else {
+ symp = &sym->s_nxt;
+ }
+ }
+ for (callp = &hte->h_calls; (call = *callp) != NULL; ) {
+ if (call->f_pos.p_src == sym1->s_pos.p_src) {
+ (*callp) = call->f_nxt;
+ if (hte->h_lcall == &call->f_nxt)
+ hte->h_lcall = callp;
+ call->f_nxt = NULL;
+ *nhte->h_lcall = call;
+ nhte->h_lcall = &call->f_nxt;
+ } else {
+ callp = &call->f_nxt;
+ }
+ }
+ for (usymp = &hte->h_usyms; (usym = *usymp) != NULL; ) {
+ if (usym->u_pos.p_src == sym1->s_pos.p_src) {
+ (*usymp) = usym->u_nxt;
+ if (hte->h_lusym == &usym->u_nxt)
+ hte->h_lusym = usymp;
+ usym->u_nxt = NULL;
+ *nhte->h_lusym = usym;
+ nhte->h_lusym = &usym->u_nxt;
+ } else {
+ usymp = &usym->u_nxt;
+ }
+ }
+
+ /* h_def must be recalculated for old hte */
+ hte->h_def = nhte->h_def = 0;
+ for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
+ if (sym->s_def == DEF || sym->s_def == TDEF) {
+ hte->h_def = 1;
+ break;
+ }
+ }
+
+ mkstatic(hte);
+}
diff --git a/usr.bin/xlint/llib/Makefile b/usr.bin/xlint/llib/Makefile
new file mode 100644
index 0000000..2e24c31
--- /dev/null
+++ b/usr.bin/xlint/llib/Makefile
@@ -0,0 +1,20 @@
+# $NetBSD: Makefile,v 1.2 1995/07/03 21:25:05 cgd Exp $
+
+LIBS= llib-lposix.ln llib-lstdc.ln
+
+all: ${LIBS}
+
+install:
+ install ${COPY} -o ${BINOWN} -g ${BINGRP} -m ${NONBINMODE} \
+ ${LIBS} ${DESTDIR}${LINTLIBDIR}
+
+clean cleanall:
+ rm -f ${LIBS}
+
+llib-lposix.ln: llib-lposix
+ lint -Cposix ${.ALLSRC}
+
+llib-lstdc.ln: llib-lstdc
+ lint -Cstdc ${.ALLSRC}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/llib/llib-lposix b/usr.bin/xlint/llib/llib-lposix
new file mode 100644
index 0000000..db1b3cf
--- /dev/null
+++ b/usr.bin/xlint/llib/llib-lposix
@@ -0,0 +1,311 @@
+/* $NetBSD: llib-lposix,v 1.2 1995/07/03 21:25:09 cgd 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.
+ */
+
+/* LINTLIBRARY */
+
+#define _POSIX_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/times.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+#include <assert.h>
+#include <termios.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <signal.h>
+#include <locale.h>
+#include <setjmp.h>
+#include <string.h>
+#include <utime.h>
+
+
+/* PROTOLIB1 */
+
+
+void (abort)(void);
+int (abs)(int j);
+int (access)(const char *path, int amode);
+double (acos)(double x);
+unsigned (alarm)(unsigned seconds);
+char *(asctime)(const struct tm *timeptr);
+double (asin)(double x);
+void (__assert)(const char *expression, int line, const char *file);
+double (atan)(double x);
+double (atan2)(double y, double x);
+int (atexit)(void (*func)(void));
+double (atof)(const char *nptr);
+int (atoi)(const char *nptr);
+long (atol)(const char *nptr);
+void *(bsearch)(const void *key, const void *base, size_t nmemb,
+ size_t size, int (*compar)(const void *, const void *));
+void *(calloc)(size_t nmemb, size_t size);
+double (ceil)(double x);
+speed_t (cfgetispeed)(const struct termios *p);
+speed_t (cfgetospeed)(const struct termios *p);
+int (cfsetispeed)(struct termios *p, speed_t speed);
+int (cfsetospeed)(struct termios *p, speed_t speed);
+int (chdir)(const char *path);
+int (chmod)(const char *path, mode_t mode);
+int (chown)(const char *path, uid_t owner, gid_t group);
+void (clearerr)(FILE *stream);
+clock_t (clock)(void);
+int (close)(int fildes);
+int (closedir)(DIR *dirp);
+double (cos)(double x);
+double (cosh)(double x);
+int (creat)(const char *path, mode_t mode);
+char *(ctermid)(char *s);
+char *(ctime)(const time_t *timer);
+char *(cuserid)(char *s);
+double (difftime)(time_t time1, time_t time0);
+div_t (div)(int numer, int denom);
+int (dup)(int fildes);
+int (dup2)(int fildes, int fildes2);
+int (errno);
+int (execl)(const char *path, const char *arg, ...);
+int (execle)(const char *path, const char *arg, ...);
+int (execlp)(const char *file, const char *arg, ...);
+int (execv)(const char *path, char *const argv[]);
+int (execve)(const char *path, char *const argv[], char *const *envp);
+int (execvp)(const char *file, char *const argv[]);
+void (exit)(int status);
+void (_exit)(int status);
+double (exp)(double x);
+double (fabs)(double x);
+int (fclose)(FILE *stream);
+int (fcntl)(int fildes, int cmd, ...);
+FILE *(fdopen)(int fildes, const char *type);
+int (feof)(FILE *stream);
+int (ferror)(FILE *stream);
+int (fflush)(FILE *stream);
+int (fgetc)(FILE *stream);
+int (fgetpos)(FILE *stream, fpos_t *pos);
+char *(fgets)(char *s, int n, FILE *stream);
+int (fileno)(FILE *stream);
+double (floor)(double x);
+double (fmod)(double x, double y);
+FILE *(fopen)(const char *filename, const char *mode);
+pid_t (fork)(void);
+long (fpathconf)(int fildes, int name);
+/* PRINTFLIKE2 */
+int (fprintf)(FILE *stream, const char *format, ...);
+int (fputc)(int c, FILE *stream);
+int (fputs)(const char *s, FILE *stream);
+size_t (fread)(void *ptr, size_t size, size_t nmemb, FILE *stream);
+void (free)(void *ptr);
+FILE *(freopen)(const char *filename, const char *mode, FILE *stream);
+double (frepx)(double value, int *exp);
+/* SCANFLIKE2 */
+int (fscanf)(FILE *stream, const char *format, ...);
+int (fseek)(FILE *stream, long int offset, int whence);
+int (fsetpos)(FILE *stream, const fpos_t *pos);
+int (fstat)(int fildes, struct stat *buf);
+long (ftell)(FILE *stream);
+size_t (fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream);
+int (getc)(FILE *stream);
+int (getchar)(void);
+char *(getcwd)(char *buf, size_t size);
+gid_t (getegid)(void);
+char *(getenv)(const char *name);
+uid_t (geteuid)(void);
+gid_t (getgid)(void);
+struct group *(getgrgid)(gid_t gid);
+struct group *(getgrnam)(const char *name);
+int (getgroups)(int gidsetsize, gid_t grouplist[]);
+char *(getlogin)(void);
+pid_t (getpgrp)(void);
+pid_t (getpid)(void);
+pid_t (getppid)(void);
+struct passwd *(getpwnam)(const char *name);
+struct passwd *(getpwuid)(uid_t uid);
+char *(gets)(char *s);
+uid_t (getuid)(void);
+struct tm *(gmtime)(const time_t *timer);
+int (isalnum)(int c);
+int (isalpha)(int c);
+int (isatty)(int fildes);
+int (iscntrl)(int c);
+int (isdigit)(int c);
+int (isgraph)(int c);
+int (islower)(int c);
+int (isprint)(int c);
+int (ispunct)(int c);
+int (isspace)(int c);
+int (isupper)(int c);
+int (isxdigit)(int c);
+int (kill)(pid_t pid, int sig);
+long (labs)(long j);
+double (ldexp)(double x, int exp);
+ldiv_t (ldiv)(long numer, long denom);
+int (link)(const char *existing, const char *new);
+struct lconv *(localeconv)(void);
+struct tm *(localtime)(const time_t *timer);
+double (log)(double x);
+double (log10)(double x);
+void (longjmp)(jmp_buf env, int val);
+off_t (lseek)(int fildes, off_t offset, int whence);
+void *(malloc)(size_t size);
+int (mblen)(const char *s, size_t n);
+size_t (mbstowcs)(wchar_t *pwcs, const char *s, size_t n);
+int (mbtowc)(wchar_t *pwc, const char *s, size_t n);
+void *(memchr)(const void *s, int c, size_t n);
+int (memcmp)(const void *s1, const void *s2, size_t n);
+void *(memcpy)(void *s1, const void *s2, size_t n);
+void *(memmove)(void *s1, const void *s2, size_t n);
+void *(memset)(void *s, int c, size_t n);
+int (mkdir)(const char *path, mode_t mode);
+int (mkfifo)(const char *path, mode_t mode);
+time_t (mktime)(struct tm *timeptr);
+double (modf)(double value, double *iptr);
+int (open)(const char *path, int oflag, ...);
+DIR *(opendir)(const char *dirname);
+long (pathconf)(const char *path, int name);
+int (pause)(void);
+void (perror)(const char *s);
+int (pipe)(int fildes[2]);
+double (pow)(double x, double y);
+/* PRINTFLIKE1 */
+int (printf)(const char *format, ...);
+int (putc)(int c, FILE *stream);
+int (putchar)(int c);
+int (puts)(const char *s);
+void (qsort)(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *));
+int (raise)(int sig);
+int (rand)(void);
+ssize_t (read)(int fildes, void *buf, size_t nbyte);
+struct dirent *(readdir)(DIR *dirp);
+void *(realloc)(void *ptr, size_t size);
+int (remove)(const char *filename);
+int (rename)(const char *old, const char *new);
+void (rewind)(FILE *stream);
+void (rewinddir)(DIR *dirp);
+int (rmdir)(const char *path);
+/* SCANFLIKE1 */
+int (scanf)(const char *format, ...);
+void (setbuf)(FILE *stream, char *buf);
+int (setgid)(gid_t gid);
+int (setjmp)(jmp_buf env);
+char *(setlocale)(int category, const char *locale);
+int (setpgid)(pid_t pid, pid_t pgid);
+pid_t (setsid)(void);
+int (setuid)(uid_t uid);
+int (setvbuf)(FILE *stream, char *buf, int mode, size_t size);
+int (sigaction)(int sig, const struct sigaction *act,
+ struct sigaction *oact);
+int (sigaddset)(sigset_t *set, int signo);
+int (sigdelset)(sigset_t *set, int signo);
+int (sigemptyset)(sigset_t *set);
+int (sigfillset)(sigset_t *set);
+int (sigismember)(const sigset_t *set, int signo);
+void (siglongjmp)(sigjmp_buf env, int val);
+void (*(signal)(int sig, void (*func)(int)))(int);
+int (sigpending)(sigset_t *set);
+int (sigprocmask)(int how, const sigset_t *set, sigset_t *oset);
+int (sigsetjmp)(sigjmp_buf env, int savemask);
+int (sigsuspend)(const sigset_t *sigmask);
+double (sin)(double x);
+double (sinh)(double x);
+unsigned (sleep)(unsigned seconds);
+/* PRINTFLIKE2 */
+int (sprintf)(char *s, const char *format, ...);
+double (sqrt)(double x);
+void (srand)(unsigned seed);
+/* SCANFLIKE2 */
+int (sscanf)(const char *s, const char *format, ...);
+int (stat)(const char *path, struct stat *buf);
+char *(strcat)(char *s1, const char *s2);
+char *(strchr)(const char *s, int c);
+int (strcmp)(const char *s1, const char *s2);
+int (strcoll)(const char *s1, const char *s2);
+char *(strcpy)(char *s1, const char *s2);
+size_t (strcspn)(const char *s1, const char *s2);
+char *(strerror)(int errnum);
+size_t (strftime)(char *s, size_t maxsize, const char *format,
+ const struct tm *timeptr);
+size_t (strlen)(const char *s);
+char *(strncat)(char *s1, const char *s2, size_t n);
+int (strncmp)(const char *s1, const char *s2, size_t n);
+char *(strncpy)(char *s1, const char *s2, size_t n);
+char *(strpbrk)(const char *s1, const char *s2);
+char *(strrchr)(const char *s, int c);
+size_t (strspn)(const char *s1, const char *s2);
+char *(strstr)(const char *s1, const char *s2);
+double (strtod)(const char *nptr, char **endptr);
+char *(strtok)(char *s1, const char *s2);
+long (strtol)(const char *nptr, char **endptr, int base);
+unsigned long (strtoul)(const char *nptr, char **endptr, int base);
+size_t (strxfrm)(char *s1, const char *s2, size_t n);
+long (sysconf)(int name);
+int (system)(const char *string);
+double (tan)(double x);
+double (tanh)(double x);
+int (tcdrain)(int fildes);
+int (tcflow)(int fildes, int action);
+int (tcflush)(int fildes, int queue_selector);
+int (tcgetattr)(int fildes, struct termios *tp);
+pid_t (tcgetpgrp)(int fildes);
+int (tcsendbreak)(int fildes, int duration);
+int (tcsetattr)(int fildes, int options, const struct termios *tp);
+int (tcsetpgrp)(int fildes, pid_t pgrpid);
+time_t (time)(time_t *timer);
+clock_t (times)(struct tms *buffer);
+FILE *(tmpfile)(void);
+char *(tmpnam)(char *s);
+int (tolower)(int c);
+int (toupper)(int c);
+char *(ttyname)(int filedes);
+void (tzset)(void);
+mode_t (umask)(mode_t cmask);
+int (uname)(struct utsname *name);
+int (ungetc)(int c, FILE *stream);
+int (unlink)(const char *path);
+int (utime)(const char *path, const struct utimbuf *times);
+int (vfprintf)(FILE *stream, const char *format, va_list arg);
+int (vprintf)(const char *format, va_list arg);
+int (vsprintf)(char *s, const char *format, va_list arg);
+pid_t (wait)(int *statloc);
+pid_t (waitpid)(pid_t pid, int *stat_loc, int options);
+size_t (wcstombs)(char *s, const wchar_t *pwcs, size_t n);
+int (wctomb)(char *s, wchar_t wchar);
+ssize_t (write)(int fildes, const void *buf, size_t nbyte);
diff --git a/usr.bin/xlint/llib/llib-lstdc b/usr.bin/xlint/llib/llib-lstdc
new file mode 100644
index 0000000..f2b33da
--- /dev/null
+++ b/usr.bin/xlint/llib/llib-lstdc
@@ -0,0 +1,252 @@
+/* $NetBSD: llib-lstdc,v 1.3 1995/07/03 21:39:28 cgd 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.
+ */
+
+/* LINTLIBRARY */
+
+#define _ANSI_SOURCE
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+#include <math.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/* PROTOLIB1 */
+
+/*
+ * assert.h
+ */
+#ifdef __NetBSD__
+void (__assert)(const char *expression, int line, const char *file);
+#else
+void (assert)(int expression);
+#endif
+
+/*
+ * ctype.h
+ */
+int (isalnum)(int c);
+int (isalpha)(int c);
+int (iscntrl)(int c);
+int (isdigit)(int c);
+int (isgraph)(int c);
+int (islower)(int c);
+int (isprint)(int c);
+int (ispunct)(int c);
+int (isspace)(int c);
+int (isupper)(int c);
+int (isxdigit)(int c);
+int (tolower)(int c);
+int (toupper)(int c);
+
+/*
+ * errno.h
+ */
+int (errno);
+
+/*
+ * locale.h
+ */
+char *(setlocale)(int category, const char *locale);
+struct lconv *(localeconv)(void);
+
+/*
+ * math.h
+ */
+double (acos)(double x);
+double (asin)(double x);
+double (atan)(double x);
+double (atan2)(double y, double x);
+double (cos)(double x);
+double (sin)(double x);
+double (tan)(double x);
+double (cosh)(double x);
+double (sinh)(double x);
+double (tanh)(double x);
+double (exp)(double x);
+double (frexp)(double value, int *exp);
+double (ldexp)(double x, int exp);
+double (log)(double x);
+double (log10)(double x);
+double (modf)(double value, double *iptr);
+double (pow)(double x, double y);
+double (sqrt)(double x);
+double (ceil)(double x);
+double (fabs)(double x);
+double (floor)(double x);
+double (fmod)(double x, double y);
+
+/*
+ * setjmp.h
+ */
+int (setjmp)(jmp_buf env);
+void (longjmp)(jmp_buf env, int val);
+
+/*
+ * signal.h
+ */
+void (*(signal)(int sig, void (*func)(int)))(int);
+int (raise)(int sig);
+
+/*
+ * stdio.h
+ */
+int (remove)(const char *filename);
+int (rename)(const char *old, const char *new);
+FILE *(tmpfile)(void);
+char *(tmpnam)(char *s);
+int (fclose)(FILE *stream);
+int (fflush)(FILE *stream);
+FILE *(fopen)(const char *filename, const char *mode);
+FILE *(freopen)(const char *filename, const char *mode, FILE *stream);
+void (setbuf)(FILE *stream, char *buf);
+int (setvbuf)(FILE *stream, char *buf, int mode, size_t size);
+/* PRINTFLIKE2 */
+int (fprintf)(FILE *stream, const char *format, ...);
+/* SCANFLIKE2 */
+int (fscanf)(FILE *stream, const char *format, ...);
+/* PRINTFLIKE1 */
+int (printf)(const char *format, ...);
+/* SCANFLIKE1 */
+int (scanf)(const char *format, ...);
+/* PRINTFLIKE2 */
+int (sprintf)(char *s, const char *format, ...);
+/* SCANFLIKE2 */
+int (sscanf)(const char *s, const char *format, ...);
+int (vfprintf)(FILE *stream, const char *format, va_list arg);
+int (vprintf)(const char *format, va_list arg);
+int (vsprintf)(char *s, const char *format, va_list arg);
+int (fgetc)(FILE *stream);
+char *(fgets)(char *s, int n, FILE *stream);
+int (fputc)(int c, FILE *stream);
+int (fputs)(const char *s, FILE *stream);
+int (getc)(FILE *stream);
+int (getchar)(void);
+char *(gets)(char *s);
+int (putc)(int c, FILE *stream);
+int (putchar)(int c);
+int (puts)(const char *s);
+int (ungetc)(int c, FILE *stream);
+size_t (fread)(void *ptr, size_t size, size_t nmemb, FILE *stream);
+size_t (fwrite)(const void *ptr, size_t size, size_t nmemb, FILE *stream);
+int (fgetpos)(FILE *stream, fpos_t *pos);
+int (fseek)(FILE *stream, long offset, int whence);
+int (fsetpos)(FILE *stream, const fpos_t *pos);
+long (ftell)(FILE *stream);
+void (rewind)(FILE *stream);
+void (clearerr)(FILE *stream);
+int (feof)(FILE *stream);
+int (ferror)(FILE *stream);
+void (perror)(const char *s);
+
+/*
+ * stdlib.h
+ */
+double (atof)(const char *nptr);
+int (atoi)(const char *nptr);
+long (atol)(const char *nptr);
+double (strtod)(const char *nptr, char **endptr);
+long (strtol)(const char *nptr, char **endptr, int base);
+unsigned long (strtoul)(const char *nptr, char **endptr, int base);
+int (rand)(void);
+void (srand)(unsigned seed);
+void *(calloc)(size_t nmemb, size_t size);
+void (free)(void *ptr);
+void *(malloc)(size_t size);
+void *(realloc)(void *ptr, size_t size);
+void (abort)(void);
+int (atexit)(void (*func)(void));
+void (exit)(int status);
+char *(getenv)(const char *name);
+int (system)(const char *string);
+void *(bsearch)(const void *key, const void *base, size_t nmemb,
+ size_t size, int (*compar)(const void *, const void *));
+void (qsort)(void *base, size_t nmemb, size_t size,
+ int (*compar)(const void *, const void *));
+int (abs)(int j);
+div_t (div)(int numer, int denom);
+long (labs)(long j);
+ldiv_t (ldiv)(long numer, long denom);
+int (mblen)(const char *s, size_t n);
+int (mbtowc)(wchar_t *PWC, const char *s, size_t n);
+int (wctomb)(char *s, wchar_t wchar);
+size_t (mbstowcs)(wchar_t *pwcs, const char *s, size_t n);
+size_t (wcstombs)(char *s, const wchar_t *pwcs, size_t n);
+
+/*
+ * string.h
+ */
+void *(memcpy)(void *s1, const void *s2, size_t n);
+void *(memmove)(void *s1, const void *s2, size_t n);
+char *(strcpy)(char *s1, const char *s2);
+char *(strncpy)(char *s1, const char *s2, size_t n);
+char *(strcat)(char *s1, const char *s2);
+char *(strncat)(char *s1, const char *s2, size_t n);
+int (memcmp)(const void *s1, const void *s2, size_t n);
+int (strcmp)(const char *s1, const char *s2);
+int (strcoll)(const char *s1, const char *s2);
+int (strncmp)(const char *s1, const char *s2, size_t n);
+size_t (strxfrm)(char *s1, const char *s2, size_t n);
+void *(memchr)(const void *s, int c, size_t n);
+char *(strchr)(const char *s, int c);
+size_t (strcspn)(const char *s1, const char *s2);
+char *(strpbrk)(const char *s1, const char *s2);
+char *(strrchr)(const char *s1, int c);
+size_t (strspn)(const char *s1, const char *s2);
+char *(strstr)(const char *s1, const char *s2);
+char *(strtok)(char *s1, const char *s2);
+void *(memset)(void *s, int c, size_t n);
+char *(strerror)(int errnom);
+size_t (strlen)(const char *s);
+
+/*
+ * time.h
+ */
+clock_t (clock)(void);
+double (difftime)(time_t time1, time_t time2);
+time_t (mktime)(struct tm *timeptr);
+time_t (time)(time_t *timer);
+char *(asctime)(const struct tm *timeptr);
+char *(ctime)(const time_t *timer);
+struct tm *(gmtime)(const time_t *timer);
+struct tm *(localtime)(const time_t *timer);
+size_t (strftime)(char *s, size_t maxsize, const char *format,
+ const struct tm *timeptr);
diff --git a/usr.bin/xlint/xlint/Makefile b/usr.bin/xlint/xlint/Makefile
new file mode 100644
index 0000000..41c833c
--- /dev/null
+++ b/usr.bin/xlint/xlint/Makefile
@@ -0,0 +1,17 @@
+# $NetBSD: Makefile,v 1.2 1995/07/03 21:25:14 cgd Exp $
+
+.PATH: ${.CURDIR}/../lint1
+
+PROG= xlint
+SRCS= xlint.c mem.c
+MAN= lint.1
+
+CFLAGS+=-I${.CURDIR}/../lint1
+
+realinstall:
+ install ${COPY} ${STRIP} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${PROG} ${DESTDIR}${BINDIR}/lint
+
+
+.include "${.CURDIR}/../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.bin/xlint/xlint/lint.1 b/usr.bin/xlint/xlint/lint.1
new file mode 100644
index 0000000..99d459c
--- /dev/null
+++ b/usr.bin/xlint/xlint/lint.1
@@ -0,0 +1,509 @@
+.\" $NetBSD: lint.1,v 1.3 1995/10/23 13:45:31 jpo 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.
+.\"
+.Dd August 28, 1994
+.Dt LINT 1
+.Os NetBSD
+.Sh NAME
+.Nm lint
+.Nd a C program verifier.
+.Sh SYNOPSIS
+.Nm lint
+.Op Fl abceghprvxzHFV
+.Op Fl s Ns | Ns Fl t
+.Op Fl i Ns | Ns Fl nu
+.Op Fl D Ns Ar name Ns Op =def
+.Op Fl U Ns Ar name
+.Op Fl I Ns Ar directory
+.Op Fl L Ns Ar directory
+.Op Fl l Ns Ar library
+.Op Fl o Ns Ar outputfile
+.Ar
+.Nm lint
+.Op Fl abceghprvzHFV
+.Op Fl s Ns | Ns Fl t
+.Fl C Ns Ar library
+.Op Fl D Ns Ar name Ns Op =def
+.Op Fl I Ns Ar directory
+.Op Fl U Ns Ar name
+.Ar
+.Sh DESCRIPTION
+.Nm
+attempts to detect features of the named C program files
+that are likely to be bugs, to be non-portable, or to be
+wasteful. It also performs stricter type checking then does
+the C compiler.
+.Nm
+runs the C preprocessor as its first phase, with the
+preprocessor symbol
+.Sy lint
+defined to allow certain questionable code to be altered
+or skipped by
+.Nm lint .
+Therefore, this symbol should be thought of as a reserved
+word for all code that is to be checked by
+.Nm lint .
+.Pp
+Among the possible problems that are currently noted are
+unreachable statements, loops not entered at the top,
+variables declared and not used, and logical expressions
+with constant values. Function calls are checked for
+inconsistencies, such as calls to functions that return
+values in some places and not in others, functions called
+with varying numbers of arguments, function calls that
+pass arguments of a type other than the type the function
+expects to receive, functions whose values are not used,
+and calls to functions not returning values that use
+the non-existent return value of the function.
+.Pp
+Filename arguments ending with
+.Pa \&.c
+are taken to be C source files. Filename arguments with
+names ending with
+.Pa \&.ln
+are taken to be the result of an earlier invocation of
+.Nm lint ,
+with either the
+.Fl i ,
+.Fl o
+or
+.Fl C
+option in effect. The
+.Pa \&.ln
+files are analogous to the
+.Pa \&.o
+(object) files produced by
+.Xr cc 1
+from
+.Pa \&.c
+files.
+.Nm
+also accepts special libraries specified with the
+.Fl l
+option, which contain definitions of library routines and
+variables.
+.Pp
+.Nm
+takes all the
+.Pa \&.c , \&.ln ,
+and
+.Pa llib-l Ns Ar library Ns Pa \&.ln
+(lint library) files and processes them in command-line order.
+By default,
+.Nm
+appends the standard C lint library
+.Pq Pa llib-lc.ln
+to the end of the list of files. When the
+.Fl i
+option is used, the
+.Pa \&.ln
+files are ignored.
+Also, when the
+.Fl o
+or
+.Fl i
+options are used, the
+.Pa llib-l Ns Ar library Ns Pa \&.ln
+files are ignored. When the
+.Fl i
+option is
+.Em omitted
+the second pass of
+.Nm
+checks this list of files for mutual compatibility. At this point,
+if a complaint stems not from a given source file, but from one of
+its included files, the source filename will be printed followed by
+a question mark.
+.Pp
+.Sy Options
+.Bl -tag -width Fl
+.It Fl a
+Report assignments of
+.Sy long
+values to variables that are not
+.Sy long .
+.It Fl aa
+Additional to
+.Fl a ,
+report
+.Em all
+assignments of integer values to other integer values which
+cause implicit narrowing conversion.
+.It Fl b
+Report
+.Sy break
+statements that cannot be reached. This is not the default
+because, unfortunately, most
+.Xr lex 1
+and many
+.Xr yacc 1
+outputs produce many such complaints.
+.It Fl c
+Complain about casts which have questionable portability.
+.It Fl e
+Complain about unusual operations on
+.Sy enum Ns -Types
+and combinations of
+.Sy enum Ns -
+and
+.Sy integer Ns -Types.
+.It Fl g
+Don't print warnings for some extensions of
+.Xr gcc 1
+to the C language. Currently these are nonconstant initializers in
+automatic aggregate initializations, arithmetic on pointer to void,
+zero sized structures, subscripting of non-lvalue arrays, prototypes
+overriding old style function declarations and long long
+integer types. The
+.Fl g
+flag also turns on the keywords
+.Sy asm
+and
+.Sy inline
+(alternate keywords with leading underscores for both
+.Sy asm
+and
+.Sy inline
+are always available).
+.It Fl h
+Apply a number of heuristic tests to attempt to intuit
+bugs, improve style, and reduce waste.
+.It Fl i
+Produce a
+.Pa \&.ln
+file for every
+.Pa \&.c
+file on the command line. These
+.Pa \&.ln
+files are the product of
+.Nm lint Ns 's
+first pass only, and are not checked for compatibility
+between functions.
+.It Fl n
+Do not check compatibility against the standard library.
+.It Fl p
+Attempt to check portability of code to other dialects of C.
+.It Fl r
+In case of redeclarations report the position of the
+previous declaration.
+.It Fl s
+Strict ANSI C mode. Issue warnings and errors required by ANSI C.
+Also do not produce warnings for constructs which behave
+differently in traditional C and ANSI C. With the
+.Fl s
+flag,
+.Li __STRICT_ANSI__
+is a predefined preprocessor macro.
+.It Fl t
+Traditional C mode.
+.Li __STDC__
+is not predefined in this mode. Warnings are printed for constructs
+not allowed in traditional C. Warnings for constructs which behave
+differently in traditional C and ANSI C are suppressed. Preprocessor
+macros describing the machine type (e.g.
+.Li sun3 Ns )
+and machine architecture (e.g.
+.Li m68k Ns )
+are defined without leading and trailing underscores. The keywords
+.Sy const Ns ,
+.Sy volatile
+and
+.Sy signed
+are not available in traditional C mode (although the alternate
+keywords with leading underscores still are).
+.It Fl u
+Do not complain about functions and external variables used
+and not defined, or defined and not used (this is suitable
+for running
+.Nm
+on a subset of files comprising part of a larger program).
+.It Fl v
+Suppress complaints about unused arguments in functions.
+.It Fl x
+Report variables refferd to by
+.Sy extern
+declarations, but never used.
+.It Fl z
+Do not complain about structures that are never defined
+(for example, using a structure pointer without knowing
+its contents).
+.It Fl C Ns Ar library
+Create a
+.Nm
+library with the name
+.Pa llib-l Ns Ar library Ns Pa .ln .
+This library is built from all
+.Pa \&.c
+and
+.Pa \&.ln
+input files. After all global definitions of functions and
+variables in these files are written to the newly created library,
+.Nm
+checks all input files, including libraries specified with the
+.Fl l
+option, for mutual compatibility.
+.It Fl D Ns Ar name Ns Op =def
+Define
+.Ar name
+for
+.Xr cpp 1 ,
+as if by a
+.Li #define
+directive. If no definition is given,
+.Ar name
+is defined as 1.
+.It Fl I Ns Ar directory
+Add
+.Ar directory
+to the list of directories in which to search for include files.
+.It Fl l Ns Ar library
+Include the lint library
+.Pa llib-l Ns Ar library Ns Pa \&.ln .
+.It Fl L Ns Ar directory
+Search for lint libraries in
+.Ar directory
+and
+.Ar directory Ns Pa /lint
+before searching the standard place.
+.It Fl F
+Print pathnames of files.
+.Nm
+normally prints the filename without the path.
+.It Fl H
+If a complaint stems from an included file
+.Nm
+prints the name of the included file instead of the source file name
+followed by a question mark.
+.It Fl o Ns Ar outputfile
+Name the output file
+.Ar outputfile .
+The output file produced is the input that is given to
+.Nm lint Ns 's
+second pass. The
+.Fl o
+option simply saves this file in the named output file. If the
+.Fl i
+option is also used the files are not checked for compatibility.
+To produce a
+.Pa llib-l Ns Ar library Ns Pa \&.ln
+without extraneous messages, use of the
+.Fl u
+option is suggested. The
+.Fl v
+option is useful if the source file(s) for the lint library
+are just external interfaces.
+.It Fl U Ns Ar name
+Remove any initial definition of
+.Ar name
+for the preprocessor.
+.It Fl V
+Print the command lines constructed by the controller program to
+run the C preprocessor and
+.Nm lint Ns 's
+first and second pass.
+.El
+.Pp
+.Sy Input Grammar
+.Pp
+.Nm lint Ns 's
+first pass reads standard C source files.
+.Nm
+recognizes the following C comments as commands.
+.Bl -tag -width Fl
+.It Li /* ARGSUSED Ns Ar n Li */
+makes
+.Nm
+check only the first
+.Ar n
+arguments for usage; a missing
+.Ar n
+is taken to be 0 (this option acts like the
+.Fl v
+option for the next function).
+.It Li /* CONSTCOND */ No or Xo
+.Li /* CONSTANTCOND */ No or
+.Li /* CONSTANTCONDITION */
+.Xc
+suppress complaints about constant operands for the next expression.
+.It Li /*\ FALLTHRU\ */ No or Xo
+.Li /* FALLTHROUGH */
+.Xc
+suppress complaints about fall through to a
+.Sy case
+or
+.Sy default
+labelled statement. This directive should be placed immediately
+preceding the label.
+.It Li /* LINTLIBRARY */
+At the beginning of a file, mark all functions and variables defined
+in this file as
+.Em used .
+Also shut off complaints about unused function arguments.
+.It Li /* LINTED Xo
+.Op Ar comment
+.Li */ No or
+.Li /* NOSTRICT
+.Op Ar comment
+.Li */
+.Xc
+Suppresses any intra-file warning except those dealing with
+unused variables or functions. This directive should be placed
+on the line immediately preceding where the lint warning occured.
+.It Li /* LONGLONG */
+Suppress complaints about use of long long integer types.
+.It Li /* NOTREACHED */
+At appropriate points, inhibit complaints about unreachable code.
+(This comment is typically placed just after calls to functions
+like
+.Xr exit 2 ).
+.It Li /* PRINTFLIKE Ns Ar n Li */
+makes
+.Nm
+check the first
+.Pq Ar n Ns No -1
+arguments as usual. The
+.Ar n Ns No -th
+argument is interpreted as a
+.Sy printf
+format string that is used to check the remaining arguments.
+.It Li /* PROTOLIB Ns Ar n Li */
+causes
+.Nm
+to treat function declaration prototypes as function definitions
+if
+.Ar n
+is non-zero. This directive can only be used in conjunction with
+the
+.Li /* LINTLIBRARY */
+directive. If
+.Ar n
+is zero, function prototypes will be treated normally.
+.It Li /* SCANFLIKE Ns Ar n Li */
+makes
+.Nm
+check the first
+.Pq Ar n Ns No -1
+arguments as usual. The
+.Ar n Ns No -th
+argument is interpreted as a
+.Sy scanf
+format string that is used to check the remaining arguments.
+.It Li /* VARARGS Ns Ar n Li */
+Suppress the usual checking for variable numbers of arguments in
+the following function declaration. The data types of the first
+.Ar n
+arguments are checked; a missing
+.Ar n
+is taken to be 0.
+.El
+.Pp
+The behavior of the
+.Fl i
+and the
+.Fl o
+options allows for incremental use of
+.Nm
+on a set of C source files. Generally, one invokes
+.Nm
+once for each source file with the
+.Fl i
+option. Each of these invocations produces a
+.Pa \&.ln
+file that corresponds to the
+.Pa \&.c
+file, and prints all messages that are about just that
+source file. After all the source files have been separetely
+run through
+.Nm lint ,
+it is invoked once more (without the
+.Fl i
+option), listing all the
+.Pa \&.ln
+files with the needed
+.Fl l Ns Ar library
+options. this will print all the inter-file inconsistencies. This
+scheme works well with
+.Xr make 1 ;
+it allows
+.Xr make 1
+to be used to
+.Nm
+only the source files that have been modified since the last
+time the set of source files were
+.Nm lint Ns No ed .
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev LIBDIR
+the directory where the lint libraries specified by the
+.Fl l Ns Ar library
+option must exist. If this environment variable is undefined,
+then the default path
+.Pa /usr/libdata/lint
+will be used to search for the libraries.
+.It Ev TMPDIR
+usually the path for temporary files can be redefined by setting
+this environment variable.
+.El
+.Sh FILES
+.Bl -tag -width /usr/libdata/lint/llib-lc.ln -compact
+.It Pa /usr/libexec/lint Ns Bq 12
+programs
+.It Pa /usr/libdata/lint/llib-l*.ln
+various prebuilt lint libraries
+.It Pa /tmp/lint*
+temporaries
+.Sh SEE ALSO
+.Xr cc 1 ,
+.Xr cpp 1 ,
+.Xr make 1
+.Sh AUTHORS
+Jochen Pohl
+.Sh BUGS
+The routines
+.Xr exit 2 ,
+.Xr longjmp 3
+and other functions that do not return are not understood; this
+causes various incorrect diagnostics.
+.Pp
+Static functions which are used only before their first
+extern declaration are reported as unused.
+.Pp
+Libraries created by the
+.Fl o
+option will, when used in later
+.Nm
+runs, cause certain errors that were reported when the libraries
+were created to be reported again, and cause line numbers and file
+names from the original source used to create those libraries
+to be reported in error messages. For these reasons, it is recommended
+to use the
+.Fl C
+option to create lint libraries.
diff --git a/usr.bin/xlint/xlint/pathnames.h b/usr.bin/xlint/xlint/pathnames.h
new file mode 100644
index 0000000..d03845d
--- /dev/null
+++ b/usr.bin/xlint/xlint/pathnames.h
@@ -0,0 +1,38 @@
+/* $NetBSD: pathnames.h,v 1.2 1995/07/03 21:25:20 cgd 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.
+ */
+
+/* directory where lint1 and lint2 reside */
+#define PATH_LIBEXEC "/usr/libexec"
+
+/* default library search path */
+#define PATH_LINTLIB "/usr/libdata/lint"
diff --git a/usr.bin/xlint/xlint/xlint.c b/usr.bin/xlint/xlint/xlint.c
new file mode 100644
index 0000000..3e57797
--- /dev/null
+++ b/usr.bin/xlint/xlint/xlint.c
@@ -0,0 +1,761 @@
+/* $NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo 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.
+ */
+
+#ifndef lint
+static char rcsid[] = "$NetBSD: xlint.c,v 1.3 1995/10/23 14:29:30 jpo Exp $";
+#endif
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+
+#include "lint.h"
+#include "pathnames.h"
+
+/* directory for temporary files */
+static const char *tmpdir;
+
+/* path name for cpp output */
+static char *cppout;
+
+/* files created by 1st pass */
+static char **p1out;
+
+/* input files for 2nd pass (without libraries) */
+static char **p2in;
+
+/* library which will be created by 2nd pass */
+static char *p2out;
+
+/* flags always passed to cpp */
+static char **cppflags;
+
+/* flags for cpp, controled by sflag/tflag */
+static char **lcppflgs;
+
+/* flags for lint1 */
+static char **l1flags;
+
+/* flags for lint2 */
+static char **l2flags;
+
+/* libraries for lint2 */
+static char **l2libs;
+
+/* default libraries */
+static char **deflibs;
+
+/* additional libraries */
+static char **libs;
+
+/* search path for libraries */
+static char **libsrchpath;
+
+/* flags */
+static int iflag, oflag, Cflag, sflag, tflag, Fflag;
+
+/* print the commands executed to run the stages of compilation */
+static int Vflag;
+
+/* filename for oflag */
+static char *outputfn;
+
+/* reset after first .c source has been processed */
+static int first = 1;
+
+/*
+ * name of a file which is currently written by a child and should
+ * be removed after abnormal termination of the child
+ */
+static const char *currfn;
+
+
+static void appstrg __P((char ***, char *));
+static void appcstrg __P((char ***, const char *));
+static void applst __P((char ***, char *const *));
+static void freelst __P((char ***));
+static char *concat2 __P((const char *, const char *));
+static char *concat3 __P((const char *, const char *, const char *));
+static void terminate __P((int));
+static const char *basename __P((const char *, int));
+static void appdef __P((char ***, const char *));
+static void usage __P((void));
+static void fname __P((const char *, int));
+static void runchild __P((const char *, char *const *, const char *));
+static void findlibs __P((char *const *));
+static int rdok __P((const char *));
+static void lint2 __P((void));
+static void cat __P((char *const *, const char *));
+
+/*
+ * Some functions to deal with lists of strings.
+ * Take care that we get no surprises in case of asyncron signals.
+ */
+static void
+appstrg(lstp, s)
+ char ***lstp, *s;
+{
+ char **lst, **olst;
+ int i;
+
+ olst = *lstp;
+ for (i = 0; olst[i] != NULL; i++) ;
+ lst = xmalloc((i + 2) * sizeof (char *));
+ (void)memcpy(lst, olst, i * sizeof (char *));
+ lst[i] = s;
+ lst[i + 1] = NULL;
+ *lstp = lst;
+}
+
+static void
+appcstrg(lstp, s)
+ char ***lstp;
+ const char *s;
+{
+ appstrg(lstp, xstrdup(s));
+}
+
+static void
+applst(destp, src)
+ char ***destp;
+ char *const *src;
+{
+ int i, k;
+ char **dest, **odest;
+
+ odest = *destp;
+ for (i = 0; odest[i] != NULL; i++) ;
+ for (k = 0; src[k] != NULL; k++) ;
+ dest = xmalloc((i + k + 1) * sizeof (char *));
+ (void)memcpy(dest, odest, i * sizeof (char *));
+ for (k = 0; src[k] != NULL; k++)
+ dest[i + k] = xstrdup(src[k]);
+ dest[i + k] = NULL;
+ *destp = dest;
+ free(odest);
+}
+
+static void
+freelst(lstp)
+ char ***lstp;
+{
+ char *s;
+ int i;
+
+ for (i = 0; (*lstp)[i] != NULL; i++) ;
+ while (i-- > 0) {
+ s = (*lstp)[i];
+ (*lstp)[i] = NULL;
+ free(s);
+ }
+}
+
+static char *
+concat2(s1, s2)
+ const char *s1, *s2;
+{
+ char *s;
+
+ s = xmalloc(strlen(s1) + strlen(s2) + 1);
+ (void)strcpy(s, s1);
+ (void)strcat(s, s2);
+
+ return (s);
+}
+
+static char *
+concat3(s1, s2, s3)
+ const char *s1, *s2, *s3;
+{
+ char *s;
+
+ s = xmalloc(strlen(s1) + strlen(s2) + strlen(s3) + 1);
+ (void)strcpy(s, s1);
+ (void)strcat(s, s2);
+ (void)strcat(s, s3);
+
+ return (s);
+}
+
+/*
+ * Clean up after a signal.
+ */
+static void
+terminate(signo)
+ int signo;
+{
+ int i;
+
+ if (cppout != NULL)
+ (void)remove(cppout);
+
+ if (p1out != NULL) {
+ for (i = 0; p1out[i] != NULL; i++)
+ (void)remove(p1out[i]);
+ }
+
+ if (p2out != NULL)
+ (void)remove(p2out);
+
+ if (currfn != NULL)
+ (void)remove(currfn);
+
+ exit(signo != 0 ? 1 : 0);
+}
+
+/*
+ * Returns a pointer to the last component of strg after delim.
+ * Returns strg if the string does not contain delim.
+ */
+static const char *
+basename(strg, delim)
+ const char *strg;
+ int delim;
+{
+ const char *cp, *cp1, *cp2;
+
+ cp = cp1 = cp2 = strg;
+ while (*cp != '\0') {
+ if (*cp++ == delim) {
+ cp2 = cp1;
+ cp1 = cp;
+ }
+ }
+ return (*cp1 == '\0' ? cp2 : cp1);
+}
+
+static void
+appdef(lstp, def)
+ char ***lstp;
+ const char *def;
+{
+ appstrg(lstp, concat2("-D__", def));
+ appstrg(lstp, concat3("-D__", def, "__"));
+}
+
+static void
+usage()
+{
+ (void)printf("lint [-abceghprvxzHF] [-s|-t] [-i|-nu] [-Dname[=def]] [-Uname]\n");
+ (void)printf(" [-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile] file ...\n");
+ (void)printf("\n");
+ (void)printf("lint [-abceghprvzHF] [-s|-t] -Clibrary [-Dname[=def]]\n");
+ (void)printf(" [-Idirectory] [-Uname] file ...\n");
+ terminate(-1);
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ char flgbuf[3], *tmp, *s;
+ size_t len;
+ struct utsname un;
+
+ if ((tmp = getenv("TMPDIR")) == NULL || (len = strlen(tmp)) == 0) {
+ tmpdir = xstrdup(_PATH_TMP);
+ } else {
+ s = xmalloc(len + 2);
+ (void)sprintf(s, "%s%s", tmp, tmp[len - 1] == '/' ? "" : "/");
+ tmpdir = s;
+ }
+
+ cppout = xmalloc(strlen(tmpdir) + sizeof ("lint0.XXXXXX"));
+ (void)sprintf(cppout, "%slint0.XXXXXX", tmpdir);
+ if (mktemp(cppout) == NULL) {
+ warn("can't make temp");
+ terminate(-1);
+ }
+
+ p1out = xcalloc(1, sizeof (char *));
+ p2in = xcalloc(1, sizeof (char *));
+ cppflags = xcalloc(1, sizeof (char *));
+ lcppflgs = xcalloc(1, sizeof (char *));
+ l1flags = xcalloc(1, sizeof (char *));
+ l2flags = xcalloc(1, sizeof (char *));
+ l2libs = xcalloc(1, sizeof (char *));
+ deflibs = xcalloc(1, sizeof (char *));
+ libs = xcalloc(1, sizeof (char *));
+ libsrchpath = xcalloc(1, sizeof (char *));
+
+ appcstrg(&cppflags, "-lang-c");
+ appcstrg(&cppflags, "-undef");
+ appcstrg(&cppflags, "-$");
+ appcstrg(&cppflags, "-C");
+ appcstrg(&cppflags, "-Wcomment");
+ appcstrg(&cppflags, "-D__NetBSD__");
+ appcstrg(&cppflags, "-Dlint"); /* XXX don't def. with -s */
+ appdef(&cppflags, "lint");
+ appdef(&cppflags, "unix");
+
+ appcstrg(&lcppflgs, "-Wtraditional");
+
+ if (uname(&un) == -1)
+ err(1, "uname");
+ appdef(&cppflags, un.machine);
+ appstrg(&lcppflgs, concat2("-D", un.machine));
+
+#ifdef MACHINE_ARCH
+ if (strcmp(un.machine, MACHINE_ARCH) != 0) {
+ appdef(&cppflags, MACHINE_ARCH);
+ appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
+ }
+#endif
+
+ appcstrg(&deflibs, "c");
+
+ if (signal(SIGHUP, terminate) == SIG_IGN)
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, terminate);
+ (void)signal(SIGQUIT, terminate);
+ (void)signal(SIGTERM, terminate);
+
+ while (argc > optind) {
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ c = getopt(argc, argv, "abceghil:no:prstuvxzC:D:FHI:L:U:V");
+
+ switch (c) {
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'e':
+ case 'g':
+ case 'r':
+ case 'v':
+ case 'z':
+ (void)sprintf(flgbuf, "-%c", c);
+ appcstrg(&l1flags, flgbuf);
+ break;
+
+ case 'F':
+ Fflag = 1;
+ /* FALLTHROUGH */
+ case 'u':
+ case 'h':
+ (void)sprintf(flgbuf, "-%c", c);
+ appcstrg(&l1flags, flgbuf);
+ appcstrg(&l2flags, flgbuf);
+ break;
+
+ case 'i':
+ if (Cflag)
+ usage();
+ iflag = 1;
+ break;
+
+ case 'n':
+ freelst(&deflibs);
+ break;
+
+ case 'p':
+ appcstrg(&l1flags, "-p");
+ appcstrg(&l2flags, "-p");
+ if (*deflibs != NULL) {
+ freelst(&deflibs);
+ appcstrg(&deflibs, "c");
+ }
+ break;
+
+ case 's':
+ if (tflag)
+ usage();
+ freelst(&lcppflgs);
+ appcstrg(&lcppflgs, "-trigraphs");
+ appcstrg(&lcppflgs, "-Wtrigraphs");
+ appcstrg(&lcppflgs, "-pedantic");
+ appcstrg(&lcppflgs, "-D__STRICT_ANSI__");
+ appcstrg(&l1flags, "-s");
+ appcstrg(&l2flags, "-s");
+ sflag = 1;
+ break;
+
+ case 't':
+ if (sflag)
+ usage();
+ freelst(&lcppflgs);
+ appcstrg(&lcppflgs, "-traditional");
+ appstrg(&lcppflgs, concat2("-D", MACHINE));
+ appstrg(&lcppflgs, concat2("-D", MACHINE_ARCH));
+ appcstrg(&l1flags, "-t");
+ appcstrg(&l2flags, "-t");
+ tflag = 1;
+ break;
+
+ case 'x':
+ appcstrg(&l2flags, "-x");
+ break;
+
+ case 'C':
+ if (Cflag || oflag || iflag)
+ usage();
+ Cflag = 1;
+ appstrg(&l2flags, concat2("-C", optarg));
+ p2out = xmalloc(sizeof ("llib-l.ln") + strlen(optarg));
+ (void)sprintf(p2out, "llib-l%s.ln", optarg);
+ freelst(&deflibs);
+ break;
+
+ case 'D':
+ case 'I':
+ case 'U':
+ (void)sprintf(flgbuf, "-%c", c);
+ appstrg(&cppflags, concat2(flgbuf, optarg));
+ break;
+
+ case 'l':
+ appcstrg(&libs, optarg);
+ break;
+
+ case 'o':
+ if (Cflag || oflag)
+ usage();
+ oflag = 1;
+ outputfn = xstrdup(optarg);
+ break;
+
+ case 'L':
+ appcstrg(&libsrchpath, optarg);
+ break;
+
+ case 'H':
+ appcstrg(&l2flags, "-H");
+ break;
+
+ case 'V':
+ Vflag = 1;
+ break;
+
+ case '?':
+ usage();
+ /* NOTREACHED */
+
+ case -1:
+ /* filename */
+ fname(argv[0], argc == 1);
+ first = 0;
+ optind = 1;
+ }
+
+ }
+
+ if (first)
+ usage();
+
+ if (iflag)
+ terminate(0);
+
+ if (!oflag) {
+ if ((s = getenv("LIBDIR")) == NULL || strlen(s) == 0)
+ s = PATH_LINTLIB;
+ appcstrg(&libsrchpath, s);
+ findlibs(libs);
+ findlibs(deflibs);
+ }
+
+ (void)printf("Lint pass2:\n");
+ lint2();
+
+ if (oflag)
+ cat(p2in, outputfn);
+
+ if (Cflag)
+ p2out = NULL;
+
+ terminate(0);
+ /* NOTREACHED */
+}
+
+/*
+ * Read a file name from the command line
+ * and pass it through lint1 if it is a C source.
+ */
+static void
+fname(name, last)
+ const char *name;
+ int last;
+{
+ const char *bn, *suff;
+ char **args, *ofn, *path;
+ size_t len;
+
+ bn = basename(name, '/');
+ suff = basename(bn, '.');
+
+ if (strcmp(suff, "ln") == 0) {
+ /* only for lint2 */
+ if (!iflag)
+ appcstrg(&p2in, name);
+ return;
+ }
+
+ if (strcmp(suff, "c") != 0 &&
+ (strncmp(bn, "llib-l", 6) != 0 || bn != suff)) {
+ warnx("unknown file type: %s\n", name);
+ return;
+ }
+
+ if (!iflag || !first || !last)
+ (void)printf("%s:\n", Fflag ? name : bn);
+
+ /* build the name of the output file of lint1 */
+ if (oflag) {
+ ofn = outputfn;
+ outputfn = NULL;
+ oflag = 0;
+ } else if (iflag) {
+ ofn = xmalloc(strlen(bn) + (bn == suff ? 4 : 2));
+ len = bn == suff ? strlen(bn) : (suff - 1) - bn;
+ (void)sprintf(ofn, "%.*s", (int)len, bn);
+ (void)strcat(ofn, ".ln");
+ } else {
+ ofn = xmalloc(strlen(tmpdir) + sizeof ("lint1.XXXXXX"));
+ (void)sprintf(ofn, "%slint1.XXXXXX", tmpdir);
+ if (mktemp(ofn) == NULL) {
+ warn("can't make temp");
+ terminate(-1);
+ }
+ }
+ if (!iflag)
+ appcstrg(&p1out, ofn);
+
+ args = xcalloc(1, sizeof (char *));
+
+ /* run cpp */
+
+ path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/cpp"));
+ (void)sprintf(path, "%s/cpp", PATH_LIBEXEC);
+
+ appcstrg(&args, path);
+ applst(&args, cppflags);
+ applst(&args, lcppflgs);
+ appcstrg(&args, name);
+ appcstrg(&args, cppout);
+
+ runchild(path, args, cppout);
+ free(path);
+ freelst(&args);
+
+ /* run lint1 */
+
+ path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint1"));
+ (void)sprintf(path, "%s/lint1", PATH_LIBEXEC);
+
+ appcstrg(&args, path);
+ applst(&args, l1flags);
+ appcstrg(&args, cppout);
+ appcstrg(&args, ofn);
+
+ runchild(path, args, ofn);
+ free(path);
+ freelst(&args);
+
+ appcstrg(&p2in, ofn);
+ free(ofn);
+
+ free(args);
+}
+
+static void
+runchild(path, args, crfn)
+ const char *path, *crfn;
+ char *const *args;
+{
+ int status, rv, signo, i;
+
+ if (Vflag) {
+ for (i = 0; args[i] != NULL; i++)
+ (void)printf("%s ", args[i]);
+ (void)printf("\n");
+ }
+
+ currfn = crfn;
+
+ (void)fflush(stdout);
+
+ switch (fork()) {
+ case -1:
+ warn("cannot fork");
+ terminate(-1);
+ /* NOTREACHED */
+ default:
+ /* parent */
+ break;
+ case 0:
+ /* child */
+ (void)execv(path, args);
+ warn("cannot exec %s", path);
+ exit(1);
+ /* NOTREACHED */
+ }
+
+ while ((rv = wait(&status)) == -1 && errno == EINTR) ;
+ if (rv == -1) {
+ warn("wait");
+ terminate(-1);
+ }
+ if (WIFSIGNALED(status)) {
+ signo = WTERMSIG(status);
+ warnx("%s got SIG%s", path, sys_signame[signo]);
+ terminate(-1);
+ }
+ if (WEXITSTATUS(status) != 0)
+ terminate(-1);
+ currfn = NULL;
+}
+
+static void
+findlibs(liblst)
+ char *const *liblst;
+{
+ int i, k;
+ const char *lib, *path;
+ char *lfn;
+ size_t len;
+
+ lfn = NULL;
+
+ for (i = 0; (lib = liblst[i]) != NULL; i++) {
+ for (k = 0; (path = libsrchpath[k]) != NULL; k++) {
+ len = strlen(path) + strlen(lib);
+ lfn = xrealloc(lfn, len + sizeof ("/llib-l.ln"));
+ (void)sprintf(lfn, "%s/llib-l%s.ln", path, lib);
+ if (rdok(lfn))
+ break;
+ lfn = xrealloc(lfn, len + sizeof ("/lint/llib-l.ln"));
+ (void)sprintf(lfn, "%s/lint/llib-l%s.ln", path, lib);
+ if (rdok(lfn))
+ break;
+ }
+ if (path != NULL) {
+ appstrg(&l2libs, concat2("-l", lfn));
+ } else {
+ warnx("cannot find llib-l%s.ln", lib);
+ }
+ }
+
+ free(lfn);
+}
+
+static int
+rdok(path)
+ const char *path;
+{
+ struct stat sbuf;
+
+ if (stat(path, &sbuf) == -1)
+ return (0);
+ if ((sbuf.st_mode & S_IFMT) != S_IFREG)
+ return (0);
+ if (access(path, R_OK) == -1)
+ return (0);
+ return (1);
+}
+
+static void
+lint2()
+{
+ char *path, **args;
+
+ args = xcalloc(1, sizeof (char *));
+
+ path = xmalloc(strlen(PATH_LIBEXEC) + sizeof ("/lint2"));
+ (void)sprintf(path, "%s/lint2", PATH_LIBEXEC);
+
+ appcstrg(&args, path);
+ applst(&args, l2flags);
+ applst(&args, l2libs);
+ applst(&args, p2in);
+
+ runchild(path, args, p2out);
+ free(path);
+ freelst(&args);
+ free(args);
+}
+
+static void
+cat(srcs, dest)
+ char *const *srcs;
+ const char *dest;
+{
+ int ifd, ofd, i;
+ char *src, *buf;
+ ssize_t rlen;
+
+ if ((ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC, 0666)) == -1) {
+ warn("cannot open %s", dest);
+ terminate(-1);
+ }
+
+ buf = xmalloc(MBLKSIZ);
+
+ for (i = 0; (src = srcs[i]) != NULL; i++) {
+ if ((ifd = open(src, O_RDONLY)) == -1) {
+ free(buf);
+ warn("cannot open %s", src);
+ terminate(-1);
+ }
+ do {
+ if ((rlen = read(ifd, buf, MBLKSIZ)) == -1) {
+ free(buf);
+ warn("read error on %s", src);
+ terminate(-1);
+ }
+ if (write(ofd, buf, (size_t)rlen) == -1) {
+ free(buf);
+ warn("write error on %s", dest);
+ terminate(-1);
+ }
+ } while (rlen == MBLKSIZ);
+ (void)close(ifd);
+ }
+ (void)close(ofd);
+ free(buf);
+}
+
OpenPOWER on IntegriCloud