/* * 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_t *hte, sym_t *def, sym_t *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 there is more than one definition for * this name. */ static void chkmd(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_t *hte, sym_t *def, sym_t *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); } } }
static void tomanyarg(hte_t *hte, fcall_t *call) { /* %s: too many args for format \t%s */ msg(16, hte->h_name, mkpos(&call->f_pos)); }
static void inconarg(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 badfmt(hte_t *hte, fcall_t *call) { /* %s: malformed format string\t%s */ msg(13, hte->h_name, mkpos(&call->f_pos)); }
/* * Print a warning if the name has been used, but not defined. */ static void chkund(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_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 variable has been declared, but is not used * or defined. */ static void chkdnud(hte_t *hte) { sym_t *sym; if (hte->h_syms == NULL || hte->h_used || hte->h_def) return; sym = hte->h_syms; if (TP(sym->s_type)->t_tspec == FUNC) return; 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 warnings for return values which are used, but not returned, * or return values which are always or sometimes ignored. */ static void chkrvu(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 || call->f_rdisc; 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)); } } }
/* * 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_t *hte, int n, sym_t *def, sym_t *decl, pos_t *pos1p, fcall_t *call1, fcall_t *call, type_t *arg1, type_t *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 compare 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 compare the call * with this declaration. Otherwise we compare 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 necessary. * We print a warning only if * (0) at least one type is not an integer 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 * integer 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: Although 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)) { for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) { if (ai->a_num == n) break; } /* * Vendor implementations of lint (e.g. HP-UX, Digital UNIX) * don't care about the size of the integer argument, * only whether or not it is zero. We do the same. */ 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); }
/* * 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_t *hte, sym_t *def, sym_t *decl) { type_t *tp1, *tp2, **ap1, **ap2; pos_t *pos1p = NULL; 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 comparison, * 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); } } }
/* * Print warnings for inconsistent argument declarations. */ static void chkadecl(hte_t *hte, sym_t *def, sym_t *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); } }
void test(bool* result) { SCREEN_Screen scr; scr = screen(80, 25); update(result, tposeq("initial cursor", mkpos(0, 0), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(5, 10)); update(result, tposeq("cursor_address", mkpos(5, 10), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(12, 5)); carriage_return(&scr); update(result, tposeq("carriage_return", mkpos(0, 5), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(12, 5)); newline(&scr); update(result, tposeq("newline", mkpos(0, 6), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(10, 6)); tab(&scr); update(result, tposeq("tab", mkpos(16, 6), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(1, 6)); column_address(&scr, 16); update(result, tposeq("column_address", mkpos(16, 6), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(16, 6)); row_address(&scr, 12); update(result, tposeq("row_address", mkpos(16, 12), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(15, 6)); cursor_down(&scr); update(result, tposeq("cursor_down", mkpos(15, 7), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(15, 6)); cursor_home(&scr); update(result, tposeq("cursor_home", mkpos(0, 0), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(6, 8)); cursor_left(&scr); update(result, tposeq("cursor_left", mkpos(5, 8), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(6, 8)); cursor_right(&scr); update(result, tposeq("cursor_right", mkpos(7, 8), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(6, 8)); cursor_to_ll(&scr); update(result, tposeq("cursor_to_ll", mkpos(0, 24), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(6, 8)); cursor_up(&scr); update(result, tposeq("cursor_up", mkpos(6, 7), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(26, 9)); parm_left_cursor(&scr, 23); update(result, tposeq("parm_left_cursor", mkpos(3, 9), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(3, 9)); parm_right_cursor(&scr, 23); update(result, tposeq("parm_right_cursor", mkpos(26, 9), cursor(&scr))); scr = screen(80, 25); cursor_address(&scr, mkpos(26, 4)); parm_down_cursor(&scr, 11); update(result, tposeq("parm_down_cursor", mkpos(26, 15), cursor(&scr))); scr = screen(6, 4); cursor_address(&scr, mkpos(2, 3)); put_char(&scr, 'a'); SCREEN_Cell want_0 = {'a', SCREEN_COLOR_WHITE, SCREEN_COLOR_BLACK, {false, false}}; update(result, tcelleq("put_char puts", want_0, cellat(&scr, mkpos(2,3)))); scr = screen(6, 4); cursor_address(&scr, mkpos(2, 3)); put_char(&scr, 'a'); update(result, tposeq("put_char moves", mkpos(3, 3), cursor(&scr))); scr = screen(6, 4); cursor_address(&scr, mkpos(5, 1)); put_char(&scr, 'a'); update(result, tposeq("put_char am", mkpos(0, 2), cursor(&scr))); scr = screen(6, 4); put_chars(&scr, "abcdefGHIJKLmno"); SCREEN_Cell want_1 = {'J', SCREEN_COLOR_WHITE, SCREEN_COLOR_BLACK, {false, false}}; update(result, tcelleq("put_char multiple", want_1, cellat(&scr, mkpos(3,1)))); scr = screen(6, 4); put_chars(&scr, "abcdefGHIJKLmno"); clear_screen(&scr); update(result, tposeq("clear_screen homes", mkpos(0, 0), cursor(&scr))); scr = screen(6, 4); put_chars(&scr, "abcdefGHIJKLmno"); clear_screen(&scr); SCREEN_Cell want_2 = {' ', SCREEN_COLOR_WHITE, SCREEN_COLOR_BLACK, {false, false}}; update(result, tcelleq("clear_screen clears", want_2, cellat(&scr, mkpos(3,1)))); scr = screen(6, 4); cursor_address(&scr, mkpos(0, 3)); put_chars(&scr, "abcdefGHIJKLmno"); SCREEN_Cell want_3 = {'J', SCREEN_COLOR_WHITE, SCREEN_COLOR_BLACK, {false, false}}; update(result, tcelleq("put_char scrolls at end", want_3, cellat(&scr, mkpos(3,2)))); scr = screen(6, 3); put_chars(&scr, "abcdefGHIJKLmno"); cursor_home(&scr); clr_eos(&scr); SCREEN_Cell want_4 = {' ', SCREEN_COLOR_WHITE, SCREEN_COLOR_BLACK, {false, false}}; update(result, tcelleq("put_char scrolls at end", want_4, cellat(&scr, mkpos(4,1)))); scr = screen(6, 4); cursor_down(&scr); put_chars(&scr, "abcdefGHIJKLmno"); cursor_address(&scr, mkpos(0, 3)); newline(&scr); SCREEN_Cell want_5 = {'K', SCREEN_COLOR_WHITE, SCREEN_COLOR_BLACK, {false, false}}; update(result, tcelleq("newline at bottom scrolls", want_5, cellat(&scr, mkpos(4,1)))); scr = screen(6, 4); put_chars(&scr, "abcdefGHIJKLmno"); cursor_address(&scr, mkpos(0, 0)); insert_line(&scr); SCREEN_Cell want_6 = {' ', SCREEN_COLOR_WHITE, SCREEN_COLOR_BLACK, {false, false}}; update(result, tcelleq("insert_line clears full line", want_6, cellat(&scr, mkpos(5,0)))); scr = screen(24, 4); cursor_address(&scr, mkpos(20, 1)); tab(&scr); update(result, tposeq("tab at eol", mkpos(0, 2), cursor(&scr))); }
void outputter(SCREEN_Screen* scr, int terminator, GetCharFunction getf) { while (1) { unsigned char c = getf(); if (c == terminator) { return; } switch (c) { case '\a': break; // TODO: alert? case '\t': tab(scr); break; case '\n': cursor_down(scr); break; case '\b': cursor_left(scr); break; case '\r': carriage_return(scr); break; case 0x1b: { c = getf(); switch (c) { case '[': { int x; if (getnum(getf, &x, &c)) { if (x == 1 && c == 'K') { clr_bol(scr); } else { switch (c) { case 'm': mode(scr, x); break; case 'A': parm_up_cursor(scr, x); break; case 'B': parm_down_cursor(scr, x); break; case 'C': parm_right_cursor(scr, x); break; case 'D': parm_left_cursor(scr, x); break; case 'G': column_address(scr, (x-1)); break; case 'L': parm_insert_line(scr, x); break; case 'M': parm_delete_line(scr, x); break; case 'P': parm_dch(scr, x); break; case 'S': parm_index(scr, x); break; case 'T': parm_rindex(scr, x); break; case 'X': erase_chars(scr, x); break; case '@': parm_ich(scr, x); break; case 'd': row_address(scr, (x-1)); break; case ';': { int y; if (getnum(getf, &y, &c)) { switch (c) { case 'm': mode(scr, x); mode(scr, y); break; case 'H': cursor_address(scr, mkpos(y-1, x-1)); break; default: fprintf(stderr, "unhandled: ESC[%i;%i%c\n", x, y, c); break; } } else { fprintf(stderr, "unhandled: ESC[%i;%c\n", x, c); } } break; default: fprintf(stderr, "unahndled: ESC[%i%c\n", x, c); break; } } } else { switch (c) { case '@': insert_character(scr); break; case 'A': cursor_up(scr); break; case 'B': cursor_down(scr); break; case 'C': cursor_right(scr); break; case 'D': cursor_left(scr); break; case 'H': cursor_home(scr); break; case 'I': tab(scr); break; case 'J': clr_eos(scr); break; case 'K': clr_eol(scr); break; case 'L': insert_line(scr); break; case 'M': delete_line(scr); break; case 'P': delete_character(scr); break; case 'm': exit_attribute_mode(scr); break; default: fprintf(stderr, "unhandled: ESC[%c\n", c); break; } } } break; case 'M': scroll_reverse(scr); break; default: fprintf(stderr, "unhandled: ESC%c\n", c); break; } } break; default: { wchar_t wc; if ((c & 0x80) == 0x00) { wc = c; } else if ((c & 0xE0) == 0xC0) { char c1 = 0x1F & c; char c2 = 0x3F & getf(); wc = (c1 << 6) | c2; } else if ((c & 0xF0) == 0xE0) { char c1 = 0x0F & c; char c2 = 0x3F & getf(); char c3 = 0x3F & getf(); wc = (c1 << 12) | (c2 << 6) | c3; } else if ((c & 0xF8) == 0xF0) { char c1 = 0x07 & c; char c2 = 0x3F & getf(); char c3 = 0x3F & getf(); char c4 = 0x3F & getf(); wc = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4; } else if ((c & 0xFC) == 0xF8) { char c1 = 0x03 & c; char c2 = 0x3F & getf(); char c3 = 0x3F & getf(); char c4 = 0x3F & getf(); char c5 = 0x3F & getf(); wc = (c1 << 24) | (c2 << 18) | (c3 << 12) | (c4 << 6) | c5; } else if ((c & 0xFE) == 0xFC) { char c1 = 0x01 & c; char c2 = 0x3F & getf(); char c3 = 0x3F & getf(); char c4 = 0x3F & getf(); char c5 = 0x3F & getf(); char c6 = 0x3F & getf(); wc = (c1 << 30) | (c2 << 24) | (c3 << 18) | (c4 << 12) | (c5 < 6) | c6; } else { fprintf(stderr, "bad utf-8 sequence: c=0x%02x\n", c); wc = '\0'; } put_char(scr, wc); } break; } } }
/* * Process a declaration or definition (d-record). */ static void decldef(pos_t *posp, const char *cp) { sym_t *symp, sym; char c, *ep, *pos1; int used, renamed; hte_t *hte, *renamehte = NULL; const char *name, *rename; (void)memset(&sym, 0, sizeof (sym)); STRUCT_ASSIGN(sym.s_pos, *posp); sym.s_def = NODECL; used = 0; while (strchr("tdeurosvPS", (c = *cp)) != NULL) { 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, doing renaming if necessary */ name = inpname(cp, &cp); renamed = 0; if (*cp == 'r') { cp++; name = xstrdup(name); rename = inpname(cp, &cp); /* enter it and see if it's already been renamed */ renamehte = _hsearch(renametab, name, 1); if (renamehte->h_hte == NULL) { hte = hsearch(rename, 1); renamehte->h_hte = hte; renamed = 1; } else if (strcmp((hte = renamehte->h_hte)->h_name, rename)) { pos1 = xstrdup(mkpos(&renamehte->h_syms->s_pos)); /* %s renamed multiple times\t%s :: %s */ msg(18, name, pos1, mkpos(&sym.s_pos)); free(pos1); } free((char *)name); } else { /* it might be a previously-done rename */ hte = _hsearch(renametab, name, 0); if (hte != NULL) hte = hte->h_hte; else hte = hsearch(name, 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; /* XXX hack so we can remember where a symbol was renamed */ if (renamed) renamehte->h_syms = symp; } if (*cp != '\0') inperr(); }