1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #include <ctype.h> 8 #include <stdio.h> 9 #include <sys/types.h> 10 #include <sys/stat.h> 11 #include <locale.h> 12 #include <euc.h> 13 #include <stdlib.h> 14 15 #define boolean int 16 #define TRUE 1 17 #define FALSE 0 18 #define NIL 0 19 #define STANDARD 0 20 #define ALTERNATE 1 21 22 /* 23 * Vfontedpr. 24 * 25 * Dave Presotto 1/12/81 (adapted from an earlier version by Bill Joy) 26 * 27 */ 28 29 #define STRLEN 10 /* length of strings introducing things */ 30 #define PNAMELEN 40 /* length of a function/procedure name */ 31 #define PSMAX 20 /* size of procedure name stacking */ 32 33 /* regular expression routines */ 34 35 char *expmatch(); /* match a string to an expression */ 36 char *STRNCMP(); /* a different kind of strncmp */ 37 char *convexp(); /* convert expression to internal form */ 38 39 char *tgetstr(); /* extract a string-valued capability */ 40 boolean isproc(); 41 char *ctime(); 42 char *strchr(); 43 44 /* 45 * The state variables 46 */ 47 48 boolean incomm; /* in a comment of the primary type */ 49 boolean instr; /* in a string constant */ 50 boolean inchr; /* in a string constant */ 51 boolean nokeyw = FALSE; /* no keywords being flagged */ 52 boolean doindex = FALSE; /* form an index */ 53 boolean twocol = FALSE; /* in two-column mode */ 54 boolean filter = FALSE; /* act as a filter (like eqn) */ 55 boolean pass = FALSE; /* when acting as a filter, pass indicates 56 * whether we are currently processing 57 * input. 58 */ 59 boolean prccont; /* continue last procedure */ 60 int comtype; /* type of comment */ 61 int margin; 62 int psptr; /* the stack index of the current procedure */ 63 char pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */ 64 int plstack[PSMAX]; /* the procedure nesting level stack */ 65 int blklevel; /* current nesting level */ 66 int prclevel; /* nesting level at which procedure definitions 67 may be found, -1 if none currently valid 68 (meaningful only if l_prclevel is true) */ 69 char *defsfile = "/usr/lib/vgrindefs"; /* name of language definitions file */ 70 char pname[BUFSIZ+1]; 71 72 /* 73 * The language specific globals 74 */ 75 76 char *language = "c"; /* the language indicator */ 77 char *l_keywds[BUFSIZ/2]; /* keyword table address */ 78 char *l_prcbeg; /* regular expr for procedure begin */ 79 char *l_combeg; /* string introducing a comment */ 80 char *l_comend; /* string ending a comment */ 81 char *l_acmbeg; /* string introducing a comment */ 82 char *l_acmend; /* string ending a comment */ 83 char *l_blkbeg; /* string begining of a block */ 84 char *l_blkend; /* string ending a block */ 85 char *l_strbeg; /* delimiter for string constant */ 86 char *l_strend; /* delimiter for string constant */ 87 char *l_chrbeg; /* delimiter for character constant */ 88 char *l_chrend; /* delimiter for character constant */ 89 char *l_prcenable; /* re indicating that procedure definitions 90 can be found in the next lexical level -- 91 kludge for lisp-like languages that use 92 something like 93 (defun (proc ...) 94 (proc ...) 95 ) 96 to define procedures */ 97 char l_escape; /* character used to escape characters */ 98 boolean l_toplex; /* procedures only defined at top lex level */ 99 boolean l_prclevel; /* procedure definitions valid only within 100 the nesting level indicated by the px 101 (l_prcenable) capability */ 102 103 /* 104 * for the benefit of die-hards who aren't convinced that tabs 105 * occur every eight columns 106 */ 107 short tabsize = 8; 108 109 /* 110 * global variables also used by expmatch 111 */ 112 boolean _escaped; /* if last character was an escape */ 113 char *Start; /* start of the current string */ 114 boolean l_onecase; /* upper and lower case are equivalent */ 115 char *l_idchars; /* characters legal in identifiers in addition 116 to letters and digits (default "_") */ 117 118 static void putcp(int c); 119 static int width(char *s, char *os); 120 static int tabs(char *s, char *os); 121 static void putKcp(char *start, char *end, boolean force); 122 static void putScp(char *os); 123 static int iskw(char *s); 124 125 /* 126 * The code below emits troff macros and directives that consume part of the 127 * troff macro and register space. See tmac.vgrind for an enumeration of 128 * these macros and registers. 129 */ 130 131 int 132 main(int argc, char *argv[]) 133 { 134 FILE *in; 135 char *fname; 136 struct stat stbuf; 137 char buf[BUFSIZ]; 138 char idbuf[256]; /* enough for all 8 bit chars */ 139 char strings[2 * BUFSIZ]; 140 char defs[2 * BUFSIZ]; 141 int needbp = 0; 142 int i; 143 char *cp; 144 145 (void) setlocale(LC_ALL, ""); 146 #if !defined(TEXT_DOMAIN) 147 #define TEXT_DOMAIN "SYS_TEST" 148 #endif 149 (void) textdomain(TEXT_DOMAIN); 150 151 /* 152 * Dump the name by which we were invoked. 153 */ 154 argc--, argv++; 155 156 /* 157 * Process arguments. For the sake of compatibility with older versions 158 * of the program, the syntax accepted below is very idiosyncratic. Some 159 * options require space between the option and its argument; others 160 * disallow it. No options may be bundled together. 161 * 162 * Actually, there is one incompatibility. Files and options formerly 163 * could be arbitrarily intermixed, but this is no longer allowed. (This 164 * possiblity was never documented.) 165 */ 166 while (argc > 0 && *argv[0] == '-') { 167 switch (*(cp = argv[0] + 1)) { 168 169 case '\0': /* - */ 170 /* Take input from stdin. */ 171 /* 172 * This option implies the end of the flag arguments. Leave the 173 * "-" in place for the file processing code to see. 174 */ 175 goto flagsdone; 176 177 case '2': /* -2 */ 178 /* Enter two column mode. */ 179 twocol = 1; 180 printf("'nr =2 1\n"); 181 break; 182 183 case 'd': /* -d <defs-file> */ 184 /* Specify the language description file. */ 185 defsfile = argv[1]; 186 argc--, argv++; 187 break; 188 189 case 'f': /* -f */ 190 /* Act as a filter like eqn. */ 191 filter = 1; 192 /* 193 * Slide remaining arguments down one position and postpend "-", 194 * to force reading from stdin. 195 */ 196 for (i = 0; i < argc - 1; i++) 197 argv[i] = argv[i + 1]; 198 argv[argc - 1] = "-"; 199 continue; 200 201 case 'h': /* -h [header] */ 202 /* Specify header string. */ 203 if (argc == 1) { 204 printf("'ds =H\n"); 205 break; 206 } 207 printf("'ds =H %s\n", argv[1]); 208 argc--, argv++; 209 break; 210 211 case 'l': /* -l<language> */ 212 /* Specify the language. */ 213 language = cp + 1; 214 break; 215 216 case 'n': /* -n */ 217 /* Indicate no keywords. */ 218 nokeyw = 1; 219 break; 220 221 case 's': /* -s<size> */ 222 /* Specify the font size. */ 223 i = 0; 224 cp++; 225 while (*cp) 226 i = i * 10 + (*cp++ - '0'); 227 printf("'nr vP %d\n", i); 228 break; 229 230 case 't': /* -t */ 231 /* Specify a nondefault tab size. */ 232 tabsize = 4; 233 break; 234 235 case 'x': /* -x */ 236 /* Build an index. */ 237 doindex = 1; 238 /* This option implies "-n" as well; turn it on. */ 239 argv[0] = "-n"; 240 continue; 241 } 242 243 /* Advance to next argument. */ 244 argc--, argv++; 245 } 246 247 flagsdone: 248 249 /* 250 * Get the language definition from the defs file. 251 */ 252 i = tgetent (defs, language, defsfile); 253 if (i == 0) { 254 fprintf (stderr, gettext("no entry for language %s\n"), language); 255 exit (0); 256 } else if (i < 0) { 257 fprintf (stderr, gettext("cannot find vgrindefs file %s\n"), defsfile); 258 exit (0); 259 } 260 cp = strings; 261 if (tgetstr ("kw", &cp) == NIL) 262 nokeyw = TRUE; 263 else { 264 char **cpp; 265 266 cpp = l_keywds; 267 cp = strings; 268 while (*cp) { 269 while (*cp == ' ' || *cp =='\t') 270 *cp++ = '\0'; 271 if (*cp) 272 *cpp++ = cp; 273 while (*cp != ' ' && *cp != '\t' && *cp) 274 cp++; 275 } 276 *cpp = NIL; 277 } 278 cp = buf; 279 l_prcbeg = convexp (tgetstr ("pb", &cp)); 280 cp = buf; 281 l_combeg = convexp (tgetstr ("cb", &cp)); 282 cp = buf; 283 l_comend = convexp (tgetstr ("ce", &cp)); 284 cp = buf; 285 l_acmbeg = convexp (tgetstr ("ab", &cp)); 286 cp = buf; 287 l_acmend = convexp (tgetstr ("ae", &cp)); 288 cp = buf; 289 l_strbeg = convexp (tgetstr ("sb", &cp)); 290 cp = buf; 291 l_strend = convexp (tgetstr ("se", &cp)); 292 cp = buf; 293 l_blkbeg = convexp (tgetstr ("bb", &cp)); 294 cp = buf; 295 l_blkend = convexp (tgetstr ("be", &cp)); 296 cp = buf; 297 l_chrbeg = convexp (tgetstr ("lb", &cp)); 298 cp = buf; 299 l_chrend = convexp (tgetstr ("le", &cp)); 300 cp = buf; 301 l_prcenable = convexp (tgetstr ("px", &cp)); 302 cp = idbuf; 303 l_idchars = tgetstr ("id", &cp); 304 /* Set default, for compatibility with old version */ 305 if (l_idchars == NIL) 306 l_idchars = "_"; 307 l_escape = '\\'; 308 l_onecase = tgetflag ("oc"); 309 l_toplex = tgetflag ("tl"); 310 l_prclevel = tgetflag ("pl"); 311 312 /* 313 * Emit a call to the initialization macro. If not in filter mode, emit a 314 * call to the vS macro, so that tmac.vgrind can uniformly assume that all 315 * program input is bracketed with vS-vE pairs. 316 */ 317 printf("'vI\n"); 318 if (!filter) 319 printf("'vS\n"); 320 321 if (doindex) { 322 /* 323 * XXX: Hard-wired spacing information. This should probably turn 324 * into the emission of a macro invocation, so that tmac.vgrind 325 * can make up its own mind about what spacing is appropriate. 326 */ 327 if (twocol) 328 printf("'ta 2.5i 2.75i 4.0iR\n'in .25i\n"); 329 else 330 printf("'ta 4i 4.25i 5.5iR\n'in .5i\n"); 331 } 332 333 while (argc > 0) { 334 if (strcmp(argv[0], "-") == 0) { 335 /* Embed an instance of the original stdin. */ 336 in = fdopen(fileno(stdin), "r"); 337 fname = ""; 338 } else { 339 /* Open the file for input. */ 340 if ((in = fopen(argv[0], "r")) == NULL) { 341 perror(argv[0]); 342 exit(1); 343 } 344 fname = argv[0]; 345 } 346 argc--, argv++; 347 348 /* 349 * Reinitialize for the current file. 350 */ 351 incomm = FALSE; 352 instr = FALSE; 353 inchr = FALSE; 354 _escaped = FALSE; 355 blklevel = 0; 356 prclevel = -1; 357 for (psptr=0; psptr<PSMAX; psptr++) { 358 pstack[psptr][0] = '\0'; 359 plstack[psptr] = 0; 360 } 361 psptr = -1; 362 printf("'-F\n"); 363 if (!filter) { 364 char *cp; 365 366 printf(".ds =F %s\n", fname); 367 if (needbp) { 368 needbp = 0; 369 printf(".()\n"); 370 printf(".bp\n"); 371 } 372 fstat(fileno(in), &stbuf); 373 cp = ctime(&stbuf.st_mtime); 374 cp[16] = '\0'; 375 cp[24] = '\0'; 376 printf(".ds =M %s %s\n", cp+4, cp+20); 377 printf("'wh 0 vH\n"); 378 printf("'wh -1i vF\n"); 379 } 380 if (needbp && filter) { 381 needbp = 0; 382 printf(".()\n"); 383 printf(".bp\n"); 384 } 385 386 /* 387 * MAIN LOOP!!! 388 */ 389 while (fgets(buf, sizeof buf, in) != NULL) { 390 if (buf[0] == '\f') { 391 printf(".bp\n"); 392 } 393 if (buf[0] == '.') { 394 printf("%s", buf); 395 if (!strncmp (buf+1, "vS", 2)) 396 pass = TRUE; 397 if (!strncmp (buf+1, "vE", 2)) 398 pass = FALSE; 399 continue; 400 } 401 prccont = FALSE; 402 if (!filter || pass) 403 putScp(buf); 404 else 405 printf("%s", buf); 406 if (prccont && (psptr >= 0)) 407 printf("'FC %s\n", pstack[psptr]); 408 #ifdef DEBUG 409 printf ("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr); 410 #endif 411 margin = 0; 412 } 413 414 needbp = 1; 415 (void) fclose(in); 416 } 417 418 /* Close off the vS-vE pair. */ 419 if (!filter) 420 printf("'vE\n"); 421 422 return (0); 423 } 424 425 #define isidchr(c) (isalnum(c) || ((c) != NIL && strchr(l_idchars, (c)) != NIL)) 426 427 static void 428 putScp(char *os) 429 { 430 char *s = os; /* pointer to unmatched string */ 431 char dummy[BUFSIZ]; /* dummy to be used by expmatch */ 432 char *comptr; /* end of a comment delimiter */ 433 char *acmptr; /* end of a comment delimiter */ 434 char *strptr; /* end of a string delimiter */ 435 char *chrptr; /* end of a character const delimiter */ 436 char *blksptr; /* end of a lexical block start */ 437 char *blkeptr; /* end of a lexical block end */ 438 439 Start = os; /* remember the start for expmatch */ 440 _escaped = FALSE; 441 if (nokeyw || incomm || instr) 442 goto skip; 443 if (isproc(s)) { 444 printf("'FN %s\n", pname); 445 if (psptr < PSMAX-1) { 446 ++psptr; 447 strncpy (pstack[psptr], pname, PNAMELEN); 448 pstack[psptr][PNAMELEN] = '\0'; 449 plstack[psptr] = blklevel; 450 } 451 } 452 /* 453 * if l_prclevel is set, check to see whether this lexical level 454 * is one immediately below which procedure definitions are allowed. 455 */ 456 if (l_prclevel && !incomm && !instr && !inchr) { 457 if (expmatch (s, l_prcenable, dummy) != NIL) 458 prclevel = blklevel + 1; 459 } 460 skip: 461 do { 462 /* check for string, comment, blockstart, etc */ 463 if (!incomm && !instr && !inchr) { 464 465 blkeptr = expmatch (s, l_blkend, dummy); 466 blksptr = expmatch (s, l_blkbeg, dummy); 467 comptr = expmatch (s, l_combeg, dummy); 468 acmptr = expmatch (s, l_acmbeg, dummy); 469 strptr = expmatch (s, l_strbeg, dummy); 470 chrptr = expmatch (s, l_chrbeg, dummy); 471 472 /* start of a comment? */ 473 if (comptr != NIL) 474 if ((comptr < strptr || strptr == NIL) 475 && (comptr < acmptr || acmptr == NIL) 476 && (comptr < chrptr || chrptr == NIL) 477 && (comptr < blksptr || blksptr == NIL) 478 && (comptr < blkeptr || blkeptr == NIL)) { 479 putKcp (s, comptr-1, FALSE); 480 s = comptr; 481 incomm = TRUE; 482 comtype = STANDARD; 483 if (s != os) 484 printf ("\\c"); 485 printf ("\\c\n'+C\n"); 486 continue; 487 } 488 489 /* start of a comment? */ 490 if (acmptr != NIL) 491 if ((acmptr < strptr || strptr == NIL) 492 && (acmptr < chrptr || chrptr == NIL) 493 && (acmptr < blksptr || blksptr == NIL) 494 && (acmptr < blkeptr || blkeptr == NIL)) { 495 putKcp (s, acmptr-1, FALSE); 496 s = acmptr; 497 incomm = TRUE; 498 comtype = ALTERNATE; 499 if (s != os) 500 printf ("\\c"); 501 printf ("\\c\n'+C\n"); 502 continue; 503 } 504 505 /* start of a string? */ 506 if (strptr != NIL) 507 if ((strptr < chrptr || chrptr == NIL) 508 && (strptr < blksptr || blksptr == NIL) 509 && (strptr < blkeptr || blkeptr == NIL)) { 510 putKcp (s, strptr-1, FALSE); 511 s = strptr; 512 instr = TRUE; 513 continue; 514 } 515 516 /* start of a character string? */ 517 if (chrptr != NIL) 518 if ((chrptr < blksptr || blksptr == NIL) 519 && (chrptr < blkeptr || blkeptr == NIL)) { 520 putKcp (s, chrptr-1, FALSE); 521 s = chrptr; 522 inchr = TRUE; 523 continue; 524 } 525 526 /* end of a lexical block */ 527 if (blkeptr != NIL) { 528 if (blkeptr < blksptr || blksptr == NIL) { 529 /* reset prclevel if necessary */ 530 if (l_prclevel && prclevel == blklevel) 531 prclevel = -1; 532 putKcp (s, blkeptr - 1, FALSE); 533 s = blkeptr; 534 blklevel--; 535 if (psptr >= 0 && plstack[psptr] >= blklevel) { 536 537 /* end of current procedure */ 538 if (s != os) 539 printf ("\\c"); 540 printf ("\\c\n'-F\n"); 541 blklevel = plstack[psptr]; 542 543 /* see if we should print the last proc name */ 544 if (--psptr >= 0) 545 prccont = TRUE; 546 else 547 psptr = -1; 548 } 549 continue; 550 } 551 } 552 553 /* start of a lexical block */ 554 if (blksptr != NIL) { 555 putKcp (s, blksptr - 1, FALSE); 556 s = blksptr; 557 blklevel++; 558 continue; 559 } 560 561 /* check for end of comment */ 562 } else if (incomm) { 563 comptr = expmatch (s, l_comend, dummy); 564 acmptr = expmatch (s, l_acmend, dummy); 565 if (((comtype == STANDARD) && (comptr != NIL)) || 566 ((comtype == ALTERNATE) && (acmptr != NIL))) { 567 if (comtype == STANDARD) { 568 putKcp (s, comptr-1, TRUE); 569 s = comptr; 570 } else { 571 putKcp (s, acmptr-1, TRUE); 572 s = acmptr; 573 } 574 incomm = FALSE; 575 printf("\\c\n'-C\n"); 576 continue; 577 } else { 578 putKcp (s, s + strlen(s) -1, TRUE); 579 s = s + strlen(s); 580 continue; 581 } 582 583 /* check for end of string */ 584 } else if (instr) { 585 if ((strptr = expmatch (s, l_strend, dummy)) != NIL) { 586 putKcp (s, strptr-1, TRUE); 587 s = strptr; 588 instr = FALSE; 589 continue; 590 } else { 591 putKcp (s, s+strlen(s)-1, TRUE); 592 s = s + strlen(s); 593 continue; 594 } 595 596 /* check for end of character string */ 597 } else if (inchr) { 598 if ((chrptr = expmatch (s, l_chrend, dummy)) != NIL) { 599 putKcp (s, chrptr-1, TRUE); 600 s = chrptr; 601 inchr = FALSE; 602 continue; 603 } else { 604 putKcp (s, s+strlen(s)-1, TRUE); 605 s = s + strlen(s); 606 continue; 607 } 608 } 609 610 /* print out the line */ 611 putKcp (s, s + strlen(s) -1, FALSE); 612 s = s + strlen(s); 613 } while (*s); 614 } 615 616 static void 617 putKcp(char *start, char *end, boolean force) 618 /* start - start of string to write */ 619 /* end - end of string to write */ 620 /* force - true if we should force nokeyw */ 621 { 622 int i; 623 int xfld = 0; 624 625 while (start <= end) { 626 if (doindex) { 627 if (*start == ' ' || *start == '\t') { 628 if (xfld == 0) 629 printf(""); 630 printf("\t"); 631 xfld = 1; 632 while (*start == ' ' || *start == '\t') 633 start++; 634 continue; 635 } 636 } 637 638 /* take care of nice tab stops */ 639 if (*start == '\t') { 640 while (*start == '\t') 641 start++; 642 i = tabs(Start, start) - margin / tabsize; 643 printf ("\\h'|%dn'", 644 i * (tabsize == 4 ? 5 : 10) + 1 - margin % tabsize); 645 continue; 646 } 647 648 if (!nokeyw && !force) 649 if ( (*start == '#' || isidchr(*start)) 650 && (start == Start || !isidchr(start[-1])) 651 ) { 652 i = iskw(start); 653 if (i > 0) { 654 printf("\\*(+K"); 655 do 656 putcp(*start++); 657 while (--i > 0); 658 printf("\\*(-K"); 659 continue; 660 } 661 } 662 663 putcp (*start++); 664 } 665 } 666 667 668 static int 669 tabs(char *s, char *os) 670 { 671 672 return (width(s, os) / tabsize); 673 } 674 675 static int 676 width(char *s, char *os) 677 { 678 int i = 0; 679 unsigned char c; 680 int n; 681 682 while (s < os) { 683 if (*s == '\t') { 684 i = (i + tabsize) &~ (tabsize-1); 685 s++; 686 continue; 687 } 688 c = *(unsigned char *)s; 689 if (c < ' ') 690 i += 2, s++; 691 else if (c >= 0200) { 692 if ((n = mblen(s, MB_CUR_MAX)) > 0) { 693 i += csetcol(csetno(c)); 694 s += n; 695 } else 696 s++; 697 } else 698 i++, s++; 699 } 700 return (i); 701 } 702 703 static void 704 putcp(int c) 705 { 706 707 switch(c) { 708 709 case 0: 710 break; 711 712 case '\f': 713 break; 714 715 case '{': 716 printf("\\*(+K{\\*(-K"); 717 break; 718 719 case '}': 720 printf("\\*(+K}\\*(-K"); 721 break; 722 723 case '\\': 724 printf("\\e"); 725 break; 726 727 case '_': 728 printf("\\*_"); 729 break; 730 731 case '-': 732 printf("\\*-"); 733 break; 734 735 /* 736 * The following two cases deal with the accent characters. 737 * If they're part of a comment, we assume that they're part 738 * of running text and hand them to troff as regular quote 739 * characters. Otherwise, we assume they're being used as 740 * special characters (e.g., string delimiters) and arrange 741 * for troff to render them as accents. This is an imperfect 742 * heuristic that produces slightly better appearance than the 743 * former behavior of unconditionally rendering the characters 744 * as accents. (See bug 1040343.) 745 */ 746 747 case '`': 748 if (incomm) 749 printf("`"); 750 else 751 printf("\\`"); 752 break; 753 754 case '\'': 755 if (incomm) 756 printf("'"); 757 else 758 printf("\\'"); 759 break; 760 761 case '.': 762 printf("\\&."); 763 break; 764 765 /* 766 * The following two cases contain special hacking 767 * to make C-style comments line up. The tests aren't 768 * really adequate; they lead to grotesqueries such 769 * as italicized multiplication and division operators. 770 * However, the obvious test (!incomm) doesn't work, 771 * because incomm isn't set until after we've put out 772 * the comment-begin characters. The real problem is 773 * that expmatch() doesn't give us enough information. 774 */ 775 776 case '*': 777 if (instr || inchr) 778 printf("*"); 779 else 780 printf("\\f2*\\fP"); 781 break; 782 783 case '/': 784 if (instr || inchr) 785 printf("/"); 786 else 787 printf("\\f2\\h'\\w' 'u-\\w'/'u'/\\fP"); 788 break; 789 790 default: 791 if (c < 040) 792 putchar('^'), c |= '@'; 793 /* FALLTHROUGH */ 794 case '\t': 795 case '\n': 796 putchar(c); 797 } 798 } 799 800 /* 801 * look for a process beginning on this line 802 */ 803 boolean 804 isproc(char *s) 805 { 806 pname[0] = '\0'; 807 if (l_prclevel ? (prclevel == blklevel) : (!l_toplex || blklevel == 0)) 808 if (expmatch (s, l_prcbeg, pname) != NIL) { 809 return (TRUE); 810 } 811 return (FALSE); 812 } 813 814 815 /* 816 * iskw - check to see if the next word is a keyword 817 * Return its length if it is or 0 if it isn't. 818 */ 819 820 static int 821 iskw(char *s) 822 { 823 char **ss = l_keywds; 824 int i = 1; 825 char *cp = s; 826 827 /* Get token length. */ 828 while (++cp, isidchr(*cp)) 829 i++; 830 831 while (cp = *ss++) { 832 if (!STRNCMP(s,cp,i) && !isidchr(cp[i])) 833 return (i); 834 } 835 return (0); 836 } 837