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