Print this page
10100 Illumos is confused about calloc() arguments
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/checknr/checknr.c
+++ new/usr/src/cmd/checknr/checknr.c
1 1 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
2 2 /* All Rights Reserved */
3 3
4 4
5 5 /*
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
6 6 * Copyright (c) 1980 Regents of the University of California.
7 7 * All rights reserved. The Berkeley software License Agreement
8 8 * specifies the terms and conditions for redistribution.
9 9 */
10 10
11 11 /*
12 12 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
13 13 * Use is subject to license terms.
14 14 */
15 15
16 -#pragma ident "%Z%%M% %I% %E% SMI"
16 +/*
17 + * Copyright (c) 2018, Joyent, Inc.
18 + */
17 19
18 20 /*
19 21 * checknr: check an nroff/troff input file for matching macro calls.
20 22 * we also attempt to match size and font changes, but only the embedded
21 23 * kind. These must end in \s0 and \fP resp. Maybe more sophistication
22 24 * later but for now think of these restrictions as contributions to
23 25 * structured typesetting.
24 26 */
25 27 #include <stdio.h>
26 28 #include <stdlib.h>
27 29 #include <unistd.h>
28 30 #include <string.h>
29 31 #include <ctype.h>
30 32 #include <locale.h>
31 33
32 34 #define MAXSTK 100 /* Stack size */
33 35 static int maxstk;
34 36 #define MAXBR 100 /* Max number of bracket pairs known */
35 37 #define MAXCMDS 500 /* Max number of commands known */
36 38
37 39 /*
38 40 * The stack on which we remember what we've seen so far.
39 41 */
40 42 static struct stkstr {
41 43 int opno; /* number of opening bracket */
42 44 int pl; /* '+', '-', ' ' for \s, 1 for \f, 0 for .ft */
43 45 int parm; /* parm to size, font, etc */
44 46 int lno; /* line number the thing came in in */
45 47 } *stk;
46 48 static int stktop;
47 49
48 50 /*
49 51 * The kinds of opening and closing brackets.
50 52 */
51 53 static struct brstr {
52 54 char *opbr;
53 55 char *clbr;
54 56 } br[MAXBR] = {
55 57 /* A few bare bones troff commands */
56 58 #define SZ 0
57 59 "sz", "sz", /* also \s */
58 60 #define FT 1
59 61 "ft", "ft", /* also \f */
60 62 /* the -mm package */
61 63 "AL", "LE",
62 64 "AS", "AE",
63 65 "BL", "LE",
64 66 "BS", "BE",
65 67 "DF", "DE",
66 68 "DL", "LE",
67 69 "DS", "DE",
68 70 "FS", "FE",
69 71 "ML", "LE",
70 72 "NS", "NE",
71 73 "RL", "LE",
72 74 "VL", "LE",
73 75 /* the -ms package */
74 76 "AB", "AE",
75 77 "BD", "DE",
76 78 "CD", "DE",
77 79 "DS", "DE",
78 80 "FS", "FE",
79 81 "ID", "DE",
80 82 "KF", "KE",
81 83 "KS", "KE",
82 84 "LD", "DE",
83 85 "LG", "NL",
84 86 "QS", "QE",
85 87 "RS", "RE",
86 88 "SM", "NL",
87 89 "XA", "XE",
88 90 "XS", "XE",
89 91 /* The -me package */
90 92 "(b", ")b",
91 93 "(c", ")c",
92 94 "(d", ")d",
93 95 "(f", ")f",
94 96 "(l", ")l",
95 97 "(q", ")q",
96 98 "(x", ")x",
97 99 "(z", ")z",
98 100 /* Things needed by preprocessors */
99 101 "EQ", "EN",
100 102 "TS", "TE",
101 103 /* Refer */
102 104 "[", "]",
103 105 0, 0
104 106 };
105 107
106 108 /*
107 109 * All commands known to nroff, plus macro packages.
108 110 * Used so we can complain about unrecognized commands.
109 111 */
110 112 static char *knowncmds[MAXCMDS] = {
111 113 "$c", "$f", "$h", "$p", "$s", "(b", "(c", "(d", "(f", "(l", "(q", "(t",
112 114 "(x", "(z", ")b", ")c", ")d", ")f", ")l", ")q", ")t", ")x", ")z", "++",
113 115 "+c", "1C", "1c", "2C", "2c", "@(", "@)", "@C", "@D", "@F", "@I", "@M",
114 116 "@c", "@e", "@f", "@h", "@m", "@n", "@o", "@p", "@r", "@t", "@z", "AB",
115 117 "AE", "AF", "AI", "AL", "AM", "AS", "AT", "AU", "AX", "B", "B1", "B2",
116 118 "BD", "BE", "BG", "BL", "BS", "BT", "BX", "C1", "C2", "CD", "CM", "CT",
117 119 "D", "DA", "DE", "DF", "DL", "DS", "DT", "EC", "EF", "EG", "EH", "EM",
118 120 "EN", "EQ", "EX", "FA", "FD", "FE", "FG", "FJ", "FK", "FL", "FN", "FO",
119 121 "FQ", "FS", "FV", "FX", "H", "HC", "HD", "HM", "HO", "HU", "I", "ID",
120 122 "IE", "IH", "IM", "IP", "IX", "IZ", "KD", "KE", "KF", "KQ", "KS", "LB",
121 123 "LC", "LD", "LE", "LG", "LI", "LP", "MC", "ME", "MF", "MH", "ML", "MR",
122 124 "MT", "ND", "NE", "NH", "NL", "NP", "NS", "OF", "OH", "OK", "OP", "P",
123 125 "P1", "PF", "PH", "PP", "PT", "PX", "PY", "QE", "QP", "QS", "R", "RA",
124 126 "RC", "RE", "RL", "RP", "RQ", "RS", "RT", "S", "S0", "S2", "S3", "SA",
125 127 "SG", "SH", "SK", "SM", "SP", "SY", "T&", "TA", "TB", "TC", "TD", "TE",
126 128 "TH", "TL", "TM", "TP", "TQ", "TR", "TS", "TX", "UL", "US", "UX", "VL",
127 129 "WC", "WH", "XA", "XD", "XE", "XF", "XK", "XP", "XS", "[", "[-", "[0",
128 130 "[1", "[2", "[3", "[4", "[5", "[<", "[>", "[]", "]", "]-", "]<", "]>",
129 131 "][", "ab", "ac", "ad", "af", "am", "ar", "as", "b", "ba", "bc", "bd",
130 132 "bi", "bl", "bp", "br", "bx", "c.", "c2", "cc", "ce", "cf", "ch", "cs",
131 133 "ct", "cu", "da", "de", "di", "dl", "dn", "ds", "dt", "dw", "dy", "ec",
132 134 "ef", "eh", "el", "em", "eo", "ep", "ev", "ex", "fc", "fi", "fl", "fo",
133 135 "fp", "ft", "fz", "hc", "he", "hl", "hp", "ht", "hw", "hx", "hy", "i",
134 136 "ie", "if", "ig", "in", "ip", "it", "ix", "lc", "lg", "li", "ll", "ln",
135 137 "lo", "lp", "ls", "lt", "m1", "m2", "m3", "m4", "mc", "mk", "mo", "n1",
136 138 "n2", "na", "ne", "nf", "nh", "nl", "nm", "nn", "np", "nr", "ns", "nx",
137 139 "of", "oh", "os", "pa", "pc", "pi", "pl", "pm", "pn", "po", "pp", "ps",
138 140 "q", "r", "rb", "rd", "re", "rm", "rn", "ro", "rr", "rs", "rt", "sb",
139 141 "sc", "sh", "sk", "so", "sp", "ss", "st", "sv", "sz", "ta", "tc", "th",
140 142 "ti", "tl", "tm", "tp", "tr", "u", "uf", "uh", "ul", "vs", "wh", "xp",
141 143 "yr", 0
142 144 };
143 145
144 146 static int lineno; /* current line number in input file */
145 147 static char line[256]; /* the current line */
146 148 static char *cfilename; /* name of current file */
147 149 static int nfiles; /* number of files to process */
148 150 static int fflag; /* -f: ignore \f */
149 151 static int sflag; /* -s: ignore \s */
150 152 static int ncmds; /* size of knowncmds */
151 153 static int slot; /* slot in knowncmds found by binsrch */
152 154
153 155 static void growstk();
154 156 static void usage();
155 157 static void process(FILE *f);
156 158 static void complain(int i);
157 159 static void prop(int i);
158 160 static void chkcmd(char *line, char *mac);
159 161 static void nomatch(char *mac);
160 162 static int eq(char *s1, char *s2);
161 163 static void pe(int lineno);
162 164 static void checkknown(char *mac);
163 165 static void addcmd(char *line);
164 166 static void addmac(char *mac);
165 167 static int binsrch(char *mac);
166 168
167 169 static void
168 170 growstk()
169 171 {
170 172 stktop++;
171 173 if (stktop >= maxstk) {
172 174 maxstk *= 2;
173 175 stk = (struct stkstr *)realloc(stk,
174 176 sizeof (struct stkstr) * maxstk);
175 177 }
176 178 }
177 179
178 180 int
179 181 main(argc, argv)
180 182 int argc;
181 183 char **argv;
182 184 {
↓ open down ↓ |
156 lines elided |
↑ open up ↑ |
183 185 FILE *f;
184 186 int i;
185 187 char *cp;
186 188 char b1[4];
187 189
188 190 (void) setlocale(LC_ALL, "");
189 191 #if !defined(TEXT_DOMAIN)
190 192 #define TEXT_DOMAIN "SYS_TEST"
191 193 #endif
192 194 (void) textdomain(TEXT_DOMAIN);
193 - stk = (struct stkstr *)calloc(sizeof (struct stkstr), 100);
195 + stk = (struct stkstr *)calloc(100, sizeof (struct stkstr));
194 196 maxstk = 100;
195 197 /* Figure out how many known commands there are */
196 198 while (knowncmds[ncmds])
197 199 ncmds++;
198 200 while (argc > 1 && argv[1][0] == '-') {
199 201 switch (argv[1][1]) {
200 202
201 203 /* -a: add pairs of macros */
202 204 case 'a':
203 205 i = strlen(argv[1]) - 2;
204 206 if (i % 6 != 0)
205 207 usage();
206 208 /* look for empty macro slots */
207 209 for (i = 0; br[i].opbr; i++)
208 210 ;
209 211 for (cp = argv[1]+3; cp[-1]; cp += 6) {
210 212 br[i].opbr = malloc(3);
211 213 (void) strncpy(br[i].opbr, cp, 2);
212 214 br[i].clbr = malloc(3);
213 215 (void) strncpy(br[i].clbr, cp+3, 2);
214 216 /* knows pairs are also known cmds */
215 217 addmac(br[i].opbr);
216 218 addmac(br[i].clbr);
217 219 i++;
218 220 }
219 221 break;
220 222
221 223 /* -c: add known commands */
222 224 case 'c':
223 225 i = strlen(argv[1]) - 2;
224 226 if (i % 3 != 0)
225 227 usage();
226 228 for (cp = argv[1]+3; cp[-1]; cp += 3) {
227 229 if (cp[2] && cp[2] != '.')
228 230 usage();
229 231 (void) strncpy(b1, cp, 2);
230 232 addmac(b1);
231 233 }
232 234 break;
233 235
234 236 /* -f: ignore font changes */
235 237 case 'f':
236 238 fflag = 1;
237 239 break;
238 240
239 241 /* -s: ignore size changes */
240 242 case 's':
241 243 sflag = 1;
242 244 break;
243 245 default:
244 246 usage();
245 247 }
246 248 argc--; argv++;
247 249 }
248 250
249 251 nfiles = argc - 1;
250 252
251 253 if (nfiles > 0) {
252 254 for (i = 1; i < argc; i++) {
253 255 cfilename = argv[i];
254 256 f = fopen(cfilename, "r");
255 257 if (f == NULL) {
256 258 perror(cfilename);
257 259 exit(1);
258 260 }
259 261 else
260 262 process(f);
261 263 }
262 264 } else {
263 265 cfilename = "stdin";
264 266 process(stdin);
265 267 }
266 268 return (0);
267 269 }
268 270
269 271 static void
270 272 usage()
271 273 {
272 274 (void) printf(gettext("Usage: \
273 275 checknr [ -fs ] [ -a.xx.yy.xx.yy...] [-c.xx.xx.xx...] [ filename .. ]\n"));
274 276 exit(1);
275 277 }
276 278
277 279 static void
278 280 process(FILE *f)
279 281 {
280 282 int i, n;
281 283 char mac[5]; /* The current macro or nroff command */
282 284 int pl;
283 285
284 286 stktop = -1;
285 287 for (lineno = 1; fgets(line, sizeof (line), f); lineno++) {
286 288 if (line[0] == '.') {
287 289 /*
288 290 * find and isolate the macro/command name.
289 291 */
290 292 (void) strncpy(mac, line+1, 4);
291 293 if (isspace(mac[0])) {
292 294 pe(lineno);
293 295 (void) printf(gettext("Empty command\n"));
294 296 } else if (isspace(mac[1])) {
295 297 mac[1] = 0;
296 298 } else if (isspace(mac[2])) {
297 299 mac[2] = 0;
298 300 } else if (mac[0] != '\\' || mac[1] != '\"') {
299 301 pe(lineno);
300 302 (void) printf(gettext("Command too long\n"));
301 303 }
302 304
303 305 /*
304 306 * Is it a known command?
305 307 */
306 308 checkknown(mac);
307 309
308 310 /*
309 311 * Should we add it?
310 312 */
311 313 if (eq(mac, "de"))
312 314 addcmd(line);
313 315
314 316 chkcmd(line, mac);
315 317 }
316 318
317 319 /*
318 320 * At this point we process the line looking
319 321 * for \s and \f.
320 322 */
321 323 for (i = 0; line[i]; i++)
322 324 if (line[i] == '\\' && (i == 0 || line[i-1] != '\\')) {
323 325 if (!sflag && line[++i] == 's') {
324 326 pl = line[++i];
325 327 if (isdigit(pl)) {
326 328 n = pl - '0';
327 329 pl = ' ';
328 330 } else
329 331 n = 0;
330 332 while (isdigit(line[++i]))
331 333 n = 10 * n + line[i] - '0';
332 334 i--;
333 335 if (n == 0) {
334 336 if (stk[stktop].opno == SZ) {
335 337 stktop--;
336 338 } else {
337 339 pe(lineno);
338 340 (void) printf(
339 341 gettext("unmatched \\s0\n"));
340 342 }
341 343 } else {
342 344 growstk();
343 345 stk[stktop].opno = SZ;
344 346 stk[stktop].pl = pl;
345 347 stk[stktop].parm = n;
346 348 stk[stktop].lno = lineno;
347 349 }
348 350 } else if (!fflag && line[i] == 'f') {
349 351 n = line[++i];
350 352 if (n == 'P') {
351 353 if (stk[stktop].opno == FT) {
352 354 stktop--;
353 355 } else {
354 356 pe(lineno);
355 357 (void) printf(
356 358 gettext("unmatched \\fP\n"));
357 359 }
358 360 } else {
359 361 growstk();
360 362 stk[stktop].opno = FT;
361 363 stk[stktop].pl = 1;
362 364 stk[stktop].parm = n;
363 365 stk[stktop].lno = lineno;
364 366 }
365 367 }
366 368 }
367 369 }
368 370 /*
369 371 * We've hit the end and look at all this stuff that hasn't been
370 372 * matched yet! Complain, complain.
371 373 */
372 374 for (i = stktop; i >= 0; i--) {
373 375 complain(i);
374 376 }
375 377 }
376 378
377 379 static void
378 380 complain(int i)
379 381 {
380 382 pe(stk[i].lno);
381 383 (void) printf(gettext("Unmatched "));
382 384 prop(i);
383 385 (void) printf("\n");
384 386 }
385 387
386 388 static void
387 389 prop(int i)
388 390 {
389 391 if (stk[i].pl == 0)
390 392 (void) printf(".%s", br[stk[i].opno].opbr);
391 393 else switch (stk[i].opno) {
392 394 case SZ:
393 395 (void) printf("\\s%c%d", stk[i].pl, stk[i].parm);
394 396 break;
395 397 case FT:
396 398 (void) printf("\\f%c", stk[i].parm);
397 399 break;
398 400 default:
399 401 (void) printf(gettext("Bug: stk[%d].opno = %d = .%s, .%s"),
400 402 i, stk[i].opno, br[stk[i].opno].opbr,
401 403 br[stk[i].opno].clbr);
402 404 }
403 405 }
404 406
405 407 /* ARGSUSED */
406 408 static void
407 409 chkcmd(char *line, char *mac)
408 410 {
409 411 int i;
410 412
411 413 /*
412 414 * Check to see if it matches top of stack.
413 415 */
414 416 if (stktop >= 0 && eq(mac, br[stk[stktop].opno].clbr))
415 417 stktop--; /* OK. Pop & forget */
416 418 else {
417 419 /* No. Maybe it's an opener */
418 420 for (i = 0; br[i].opbr; i++) {
419 421 if (eq(mac, br[i].opbr)) {
420 422 /* Found. Push it. */
421 423 growstk();
422 424 stk[stktop].opno = i;
423 425 stk[stktop].pl = 0;
424 426 stk[stktop].parm = 0;
425 427 stk[stktop].lno = lineno;
426 428 break;
427 429 }
428 430 /*
429 431 * Maybe it's an unmatched closer.
430 432 * NOTE: this depends on the fact
431 433 * that none of the closers can be
432 434 * openers too.
433 435 */
434 436 if (eq(mac, br[i].clbr)) {
435 437 nomatch(mac);
436 438 break;
437 439 }
438 440 }
439 441 }
440 442 }
441 443
442 444 static void
443 445 nomatch(char *mac)
444 446 {
445 447 int i, j;
446 448
447 449 /*
448 450 * Look for a match further down on stack
449 451 * If we find one, it suggests that the stuff in
450 452 * between is supposed to match itself.
451 453 */
452 454 for (j = stktop; j >= 0; j--)
453 455 if (eq(mac, br[stk[j].opno].clbr)) {
454 456 /* Found. Make a good diagnostic. */
455 457 if (j == stktop-2) {
456 458 /*
457 459 * Check for special case \fx..\fR and don't
458 460 * complain.
459 461 */
460 462 if (stk[j+1].opno == FT &&
461 463 stk[j+1].parm != 'R' &&
462 464 stk[j+2].opno == FT &&
463 465 stk[j+2].parm == 'R') {
464 466 stktop = j -1;
465 467 return;
466 468 }
467 469 /*
468 470 * We have two unmatched frobs. Chances are
469 471 * they were intended to match, so we mention
470 472 * them together.
471 473 */
472 474 pe(stk[j+1].lno);
473 475 prop(j+1);
474 476 (void) printf(gettext(" does not match %d: "),
475 477 stk[j+2].lno);
476 478 prop(j+2);
477 479 (void) printf("\n");
478 480 } else for (i = j+1; i <= stktop; i++) {
479 481 complain(i);
480 482 }
481 483 stktop = j-1;
482 484 return;
483 485 }
484 486 /* Didn't find one. Throw this away. */
485 487 pe(lineno);
486 488 (void) printf(gettext("Unmatched .%s\n"), mac);
487 489 }
488 490
489 491 /* eq: are two strings equal? */
490 492 static int
491 493 eq(char *s1, char *s2)
492 494 {
493 495 return (strcmp(s1, s2) == 0);
494 496 }
495 497
496 498 /* print the first part of an error message, given the line number */
497 499 static void
498 500 pe(int lineno)
499 501 {
500 502 if (nfiles > 1)
501 503 (void) printf("%s: ", cfilename);
502 504 (void) printf("%d: ", lineno);
503 505 }
504 506
505 507 static void
506 508 checkknown(char *mac)
507 509 {
508 510
509 511 if (eq(mac, "."))
510 512 return;
511 513 if (binsrch(mac) >= 0)
512 514 return;
513 515 if (mac[0] == '\\' && mac[1] == '"') /* comments */
514 516 return;
515 517
516 518 pe(lineno);
517 519 (void) printf(gettext("Unknown command: .%s\n"), mac);
518 520 }
519 521
520 522 /*
521 523 * We have a .de xx line in "line". Add xx to the list of known commands.
522 524 */
523 525 static void
524 526 addcmd(char *line)
525 527 {
526 528 char *mac;
527 529
528 530 /* grab the macro being defined */
529 531 mac = line+4;
530 532 while (isspace(*mac))
531 533 mac++;
532 534 if (*mac == 0) {
533 535 pe(lineno);
534 536 (void) printf(gettext("illegal define: %s\n"), line);
535 537 return;
536 538 }
537 539 mac[2] = 0;
538 540 if (isspace(mac[1]) || mac[1] == '\\')
539 541 mac[1] = 0;
540 542 if (ncmds >= MAXCMDS) {
541 543 (void) printf(gettext("Only %d known commands allowed\n"),
542 544 MAXCMDS);
543 545 exit(1);
544 546 }
545 547 addmac(mac);
546 548 }
547 549
548 550 /*
549 551 * Add mac to the list. We should really have some kind of tree
550 552 * structure here but this is a quick-and-dirty job and I just don't
551 553 * have time to mess with it. (I wonder if this will come back to haunt
552 554 * me someday?) Anyway, I claim that .de is fairly rare in user
553 555 * nroff programs, and the loop below is pretty fast.
554 556 */
555 557 static void
556 558 addmac(char *mac)
557 559 {
558 560 char **src, **dest, **loc;
559 561
560 562 if (binsrch(mac) >= 0) { /* it's OK to redefine something */
561 563 #ifdef DEBUG
562 564 (void) printf("binsrch(%s) -> already in table\n", mac);
563 565 #endif
564 566 return;
565 567 }
566 568 /* binsrch sets slot as a side effect */
567 569 #ifdef DEBUG
568 570 printf("binsrch(%s) -> %d\n", mac, slot);
569 571 #endif
570 572 loc = &knowncmds[slot];
571 573 src = &knowncmds[ncmds-1];
572 574 dest = src+1;
573 575 while (dest > loc)
574 576 *dest-- = *src--;
575 577 *loc = malloc(3);
576 578 (void) strcpy(*loc, mac);
577 579 ncmds++;
578 580 #ifdef DEBUG
579 581 (void) printf("after: %s %s %s %s %s, %d cmds\n",
580 582 knowncmds[slot-2], knowncmds[slot-1], knowncmds[slot],
581 583 knowncmds[slot+1], knowncmds[slot+2], ncmds);
582 584 #endif
583 585 }
584 586
585 587 /*
586 588 * Do a binary search in knowncmds for mac.
587 589 * If found, return the index. If not, return -1.
588 590 */
589 591 static int
590 592 binsrch(char *mac)
591 593 {
592 594 char *p; /* pointer to current cmd in list */
593 595 int d; /* difference if any */
594 596 int mid; /* mid point in binary search */
595 597 int top, bot; /* boundaries of bin search, inclusive */
596 598
597 599 top = ncmds-1;
598 600 bot = 0;
599 601 while (top >= bot) {
600 602 mid = (top+bot)/2;
601 603 p = knowncmds[mid];
602 604 d = p[0] - mac[0];
603 605 if (d == 0)
604 606 d = p[1] - mac[1];
605 607 if (d == 0)
606 608 return (mid);
607 609 if (d < 0)
608 610 bot = mid + 1;
609 611 else
610 612 top = mid - 1;
611 613 }
612 614 slot = bot; /* place it would have gone */
613 615 return (-1);
614 616 }
↓ open down ↓ |
411 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX