home *** CD-ROM | disk | FTP | other *** search
/ Dream 45 / Amiga_Dream_45.iso / Amiga / Magazine / Dossier-LaTeX / lgrind-amiga.lha / lgrind / src / lgrind.c next >
C/C++ Source or Header  |  1996-08-04  |  48KB  |  1,641 lines

  1. /* lgrind.c, a %%\LaTeX%% version of tgrind, which is a %%\TeX%% version
  2.  * of vgrind.  Used to `grind nice program listings'.
  3.  */
  4.  
  5. #ifndef lint
  6. static char sccsid[] = "@(#)@(#)tfontedpr.c     1.3 (LBL) 4/12/85";
  7. static char Version[] =
  8.    "$Id: lgrind.c,v 1.4 91/10/01 00:36:11 gvr Exp $";
  9. #endif
  10.  
  11. /* lgrind --- general purpose "pretty printer" for use with %%\LaTeX%%.
  12.  *
  13.  * Copyright %%\copyright%% 1985 by Van Jacobson, Lawrence Berkeley Laboratory
  14.  * This program may be freely used and copied but may not be sold
  15.  * without the author's written permission.  This notice must remain
  16.  * in any copy or derivative.
  17.  *
  18.  * This program is an adaptation of "vfontedpr" v4.2 (12/11/84) from
  19.  * the 4.2bsd Unix distribution.  Vfontedpr was written by Dave
  20.  * Presotto (based on an earlier program of the same name written by
  21.  * Bill Joy).
  22.  *
  23.  * I would welcome comments, enhancements, bug fixes, etc.  Please
  24.  * mail them to:
  25.  *    van@@lbl-rtsg.arpa    (from arpanet, milnet, csnet, etc.)
  26.  *    ..!ucbvax!lbl-csam!van    (from Usenet/UUCP)
  27.  *
  28.  * Modifications.
  29.  * --------------
  30.  * 10 Feb 85    Van        Written.
  31.  * 29 Mar 85    Chris Torek    (chris@@maryland):  Bug fixes for %|~|% and
  32.  *                %|^L|% output.    Most cpu-time eaters recoded
  33.  *                to improve efficiency.
  34.  * 30 Mar 85  Chris & Van Fixed %|\C|% & %|\S|% (comment & string start
  35.  *                indicators to really appear at the start of
  36.  *                comments & strings.  Changes for speeded-up
  37.  *                @expmatch()@.
  38.  *  8 Oct 87    JSL        Modified so as to compile on VMS.  On VMS, we
  39.  *                don't use a surrounding shell script, so the
  40.  *                options are a bit different --- added %|-i|% to
  41.  *                make a file to be %|\input|% in a %%\LaTeX%%
  42.  *                environment.  Changed some of the characters
  43.  *                around --- e.g., we always take %|*|% in math
  44.  *                mode (to make it centered) so we have to
  45.  *                write %|*|% as %|\*|%.    Etc.
  46.  * 14 Jan 88    JSL        %|-e|% option for embedded code.
  47.  * 22 Jan 88    JSL        Bugfix --- program could overrun @pstack@
  48.  *                because of an incorrect limit test.
  49.  *    Sep 91    George V Reilly Reformated and cleaned up code, including
  50.  *                naughtiness with @NULL@.  Added %|@|%,
  51.  *                %|%%|%, %|%$|%, and %%\tt \%|%% features.
  52.  *                Also the %|%<|%, %|%!|%, and %|%#|% features.
  53.  *    Oct94     Matthias Eckermann (%|ud311aa@sunmail.lrz-muenchen.de|%)
  54.  *                fixed a little bug, added: Internal_Help,
  55.  *                command-line-param: %|-?|%
  56.  *    Sep95    Michael Piefel    Modified for %%\LaTeXe%%
  57.  */
  58.  
  59. #include <stdlib.h>
  60. #include <stdio.h>
  61. #include <ctype.h>
  62. #include <string.h>
  63. #include <unistd.h>
  64.  
  65. #include "regexp.h"
  66. #include "lgrindefs.h"
  67. #include "lgrind.h"
  68.  
  69. boolean    (*isproc)(unsigned char *s);
  70.  
  71. /* The state variables */
  72.  
  73. boolean incomm;         /* in a comment of the primary type */
  74. boolean instr;            /* in a string constant */
  75. boolean inchr;            /* in a character constant */
  76. int    incode;         /* in program text within a comment */
  77. int    latexcode;        /* in program text within %%\LaTeX%% */
  78. int    latex_tt;        /* in %|\texttt|% text within %%\LaTeX%% */
  79. boolean use_tt;         /* use %|\texttt|% everywhere */
  80. boolean do_at;            /* pay attention to %|@|%s in %%\LaTeX%% */
  81. boolean do_tt;            /* pay attention to %|||%s in %%\LaTeX%% */
  82. boolean nokeyw = FALSE;     /* no keywords being flagged */
  83. boolean prccont;        /* continue last procedure */
  84. boolean code_cmnts = TRUE;    /* Treat %|@|%, etc specially in comments */
  85. boolean code_latex = TRUE;    /* Treat %|@|%, etc specially in %%\LaTeX%% */
  86. #if nospaceincomment
  87. boolean linehead;        /* at beginning of line or after whitespace */
  88. #endif
  89. int    lastout;        /* (extended) last character to outchar */
  90. int    comtype;        /* type of comment */
  91. int    psptr;            /* the stack index of the current procedure */
  92. unsigned char    pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */
  93. int    plstack[PSMAX];     /* the procedure nesting level stack */
  94. int    blklevel;        /* current nesting level */
  95. int    reclevel;        /* current @record@ nesting level */
  96. unsigned char    *fname = "";        /* File being read */
  97. int    lineno;         /* Line number in that file */
  98. unsigned char    pname[BUFFERSIZE+1];    /* Current procedure name */
  99.  
  100.  
  101. /* The language specific globals */
  102.  
  103. unsigned char    *defsfile = DEFSFILE;  /* name of language definitions file */
  104. unsigned char    language[PNAMELEN]="c"; /* the language indicator */
  105. unsigned char    the_buf[BUFFERSIZE+1];    /* general purpose buffer */
  106. unsigned char    *buf = the_buf + 1;    /* @buf-1@ must be valid */
  107. unsigned char    strings[2*BUFFERSIZE];    /* store the keywords */
  108. unsigned char    defs[2 * BUFFERSIZE];    /* language definitions from lgrindefs */
  109. unsigned char    preamble[BUFFERSIZE/4];    /* first preamble */
  110. unsigned char    preambl2[BUFFERSIZE/4];    /* file preamble */
  111. unsigned char    config[BUFFERSIZE/4];    /* redefinitions within lgrind-environment */
  112. unsigned char    chartab[BUFFERSIZE/4];    /* buffer for chartab modifications */
  113. unsigned char    *l_keywds[BUFFERSIZE/2];/* keyword table address */
  114. unsigned char    *l_prcbeg;        /* regular expr for procedure begin */
  115. unsigned char    *l_noproc;        /* regexp for lines with NO procedure begin */
  116. unsigned char    *l_combeg;        /* regexp introducing a comment */
  117. unsigned char    *l_comend;        /* regexp ending a comment */
  118. unsigned char    *l_acmbeg;        /* regexp introducing a comment */
  119. unsigned char    *l_acmend;        /* regexp ending a comment */
  120. unsigned char    *l_blkbeg;        /* regexp beginning of a block */
  121. unsigned char    *l_blkend;        /* regexp ending a block */
  122. unsigned char    *l_strbeg;        /* regexp starting string constant */
  123. unsigned char    *l_strend;        /* regexp ending string constant */
  124. unsigned char    *l_chrbeg;        /* regexp starting character constant */
  125. unsigned char    *l_chrend;        /* regexp ending character constant */
  126. unsigned char    *l_cdebeg;        /* regexp starting prog text within comment */
  127. unsigned char     s_cdebeg[PNAMELEN+1];    /* actual string corresponding to @l_cdebeg@ */
  128. unsigned char    *l_cdeend;        /* regexp ending prog text within comment */
  129. unsigned char    *l_texbeg;        /* regexp starting %%\TeX%% text in comment */
  130. unsigned char    *l_texend;        /* regexp ending %%\TeX%% text in comment */
  131. unsigned char    *l_txmbeg;        /* regexp starting %%\TeX%% math in comment */
  132. unsigned char    *l_txmend;        /* regexp ending %%\TeX%% math in comment */
  133. unsigned char    *l_tt_beg;        /* regexp starting verbatim text in comment */
  134. unsigned char    *l_tt_end;        /* regexp ending typewriter text in comment */
  135. unsigned char    *l_at;            /* regexp for %|@|% in %%\LaTeX%% text */
  136. unsigned char    *l_tt;            /* regexp for %|||% in %%\LaTeX%% text */
  137. unsigned char    *l_pc;            /* regexp for %|%|% in %%\LaTeX%% text */
  138. unsigned char    *l_id;            /* string containing valid identifier chars */
  139. unsigned char    *l_record;        /* start of lexical block outside functions */
  140. unsigned char    l_escape;        /* character used to escape characters */
  141. boolean l_toplex;        /* procedures only defined at top lex level */
  142. boolean l_onecase;        /* upper & lower case equivalent */
  143. boolean embed = FALSE;        /* -e seen --- do embedded code */
  144. boolean code = TRUE;        /* Looking at code */
  145.  
  146.  
  147. int    main(int argc, char *argv[])
  148. {
  149.    struct stat  stbuf;
  150. /*   unsigned char     *p;*/
  151.    boolean    hseen = FALSE;        /* -h seen        */
  152.    unsigned char     *hstring;        /* header string to use */
  153.    boolean    iseen = FALSE;        /* -i seen        */
  154.    int        files_done = 0;
  155.  
  156.    argc = getredirection(argc, argv);
  157.  
  158.    argc--, argv++;
  159.    do {
  160.       register unsigned char *cp;
  161. /*      register int i;*/
  162.  
  163.       if (argc > 0) {
  164.          /* Help-facility */
  165.      if (!strcmp(argv[0], "-?") || !strcmp(argv[0], "-help")) {
  166.             Internal_Help();
  167.         return OKEXIT;
  168.          }
  169.  
  170.      if (!strcmp(argv[0], "-h")) {
  171.         hseen = TRUE;
  172.         if (argc == 1) {
  173.            hstring = "";
  174.            argc = 0;
  175.            goto rest;
  176.         }
  177.         hstring = argv[0];
  178.         argc--, argv++;
  179.         argc--, argv++;
  180.         if (argc > 0)
  181.            continue;
  182.         goto rest;
  183.      }
  184.  
  185.      /* take input from the standard place */
  186.      if (!strcmp(argv[0], "-")) {
  187.         argc = 0;
  188.         goto rest;
  189.      }
  190.  
  191.      /* Process embedded text */
  192.      if (!strcmp(argv[0], "-e")) {
  193.         embed = TRUE;
  194.         argc--, argv++;
  195.         continue;
  196.      }
  197.  
  198.      /* format for inclusion */
  199.      if (!strcmp(argv[0], "-i")) {
  200.         iseen = TRUE;
  201.         argc--, argv++;
  202.         continue;
  203.      }
  204.  
  205.      /* indicate no keywords */
  206.      if (!strcmp(argv[0], "-n")) {
  207.         nokeyw++;
  208.         argc--, argv++;
  209.         continue;
  210.      }
  211.  
  212.      /* Don't treat %|@|%, etc. specially in comments */
  213.      if (!strcmp(argv[0], "-c")) {
  214.         code_cmnts = FALSE;
  215.         argc--, argv++;
  216.         continue;
  217.      }
  218.  
  219.      /* Do treat %|@|%, etc. specially in comments */
  220.      if (!strcmp(argv[0], "+c")) {
  221.         code_cmnts = TRUE;
  222.         argc--, argv++;
  223.         continue;
  224.      }
  225.  
  226.      /* Don't treat %|@|%, etc. specially in
  227.       * %%\LaTeX%% text (@embed@ only) */
  228.      if (!strcmp(argv[0], "-a")) {
  229.         code_latex = FALSE;
  230.         argc--, argv++;
  231.         continue;
  232.      }
  233.  
  234.      /* Do treat %|@|%, etc. specially in
  235.       * %%\LaTeX%% text (@embed@ only) */
  236.      if (!strcmp(argv[0], "+a")) {
  237.         code_latex = TRUE;
  238.         argc--, argv++;
  239.         continue;
  240.      }
  241.  
  242.      /* Use %|\texttt|% for all fonts */
  243.      if (!strcmp(argv[0], "-t")) {
  244.         use_tt = TRUE;
  245.         argc--, argv++;
  246.         continue;
  247.      }
  248.  
  249.      /* specify the language */
  250.      if (!strncmp(argv[0], "-l", 2)) {
  251.         strcpy(language, argv[0]+2);
  252.         argc--, argv++;
  253.         continue;
  254.      }
  255.  
  256.      /* specify the language description file */
  257.      if (!strncmp(argv[0], "-d", 2)) {
  258.         defsfile = argv[1];
  259.         argc--, argv++;
  260.         argc--, argv++;
  261.         continue;
  262.      }
  263.  
  264.      /* open the file for input */
  265.      if (freopen(argv[0], "r", stdin) == NULL) {
  266.         perror(argv[0]);
  267.         exit(BADEXIT);
  268.      }
  269.  
  270.      fname = argv[0];
  271.      lineno = 0;
  272.      argc--, argv++;
  273.       }
  274.    rest:
  275.  
  276.       setpreambles();
  277.  
  278.       /* get config data from %|lgrindefs|% */
  279.       if (tgetent(buf, "firstpreamble", defsfile)>0)
  280.          parsepreamble(preamble);
  281.  
  282.       if (tgetent(buf, "filepreamble", defsfile)>0)
  283.          parsepreamble(preambl2);
  284.  
  285.       if (tgetent(buf, "configuration", defsfile)>0)
  286.          parsepreamble(config);
  287.  
  288.       if (tgetent(buf, "chartab", defsfile)>0)
  289.          parsechartab();
  290.  
  291.       if (iseen && embed) {
  292.      fprintf(stderr, "-i makes no sense with -e; -e ignored\n");
  293.      embed = FALSE;
  294.       }
  295.  
  296.       if (!iseen && !embed) {
  297.      if (files_done == 0) printpreamble(preamble);
  298.      printpreamble(preambl2);
  299.      if (files_done == 0) {
  300.         printf("\\begin{document}\n");
  301.      }
  302.      printf("\\begin{lgrind}\n");
  303.       }
  304.  
  305.       printpreamble(config);
  306.  
  307.       if (embed)
  308.      printf("%% This document was generated automagically by lgrind.  DO NOT EDIT.\n\n");
  309.       if (iseen)
  310.      printf("%% Remember to use the lgrind style\n\n");
  311.  
  312.       if (hseen) {
  313.      printf("\\Head{");
  314.      putstr(hstring);
  315.      printf("}\n");
  316.       }
  317.  
  318.       setlang();
  319.  
  320.       /* initialize the program */
  321.  
  322.       incomm = instr = inchr = _escaped = FALSE;
  323.       incode = latexcode = latex_tt = NOTCODE;
  324.       do_at = do_tt = TRUE;
  325.       blklevel = 0;
  326.       reclevel = 0;
  327.       for (psptr = 0; psptr < PSMAX; psptr++) {
  328.      pstack[psptr][0] = '\0';
  329.      plstack[psptr] = 0;
  330.       }
  331.       psptr = -1;
  332.       fstat(fileno(stdin), &stbuf);
  333.       cp = ctime(&stbuf.st_mtime);
  334.       cp[10] = cp[16] = cp[24] = '\0';
  335.  
  336.       if (!embed) {
  337.      printf("\\File{");
  338.      putstr(fname);
  339.  
  340.      printf("},{%s},{%s %s}\n", cp+11, cp+4, cp+20);
  341.       }
  342.  
  343.       code = FALSE;
  344.       readfile(stdin);
  345.       files_done++;
  346.  
  347.       if (!iseen && !embed) {
  348.      printf("\\end{lgrind}\n");
  349.       }
  350.  
  351.       if (code)
  352.      fprintf(stderr, "Reached EOF within code in file %s\n", fname);
  353.    } while (argc > 0);
  354.  
  355.    if (!iseen && !embed) {
  356.       printf("\\end{document}\n");
  357.    }
  358.    return OKEXIT;
  359. }
  360.  
  361. /*
  362.  * Internal_Help() --- show help
  363.  */
  364.  
  365. void    Internal_Help(void) {
  366.    printf("lgrind -- general purpose \"pretty printer\" for use with LaTeX.\n"
  367.       "usage:  lgrind  [-?] [options] <name> ...\n"
  368.     "-e     process embedded text in a LaTeX file\n"
  369.     "-i     format source code for inclusion in a LaTeX document.\n"
  370.     "-      take input from standard input.\n"
  371.     "-n     don't boldface keywords.\n"
  372.     "-h<header>   specifies text in header (default: none).\n"
  373.     "-d<deffile>  use another language definitions file, default:\n\t '%s'\n"
  374.     "-l<language> choose the language to us. Currently known are\n"
  375.     "    C (-lc) (default),      C++ (-lc++ or -lCC),    Pascal (-lp),\n"
  376.     "    Modula-2 (-lm2),        Fortran (-lf),          RATFOR (-lr),\n"
  377.     "    Prolog (-lprolog),      ISP (-lisp),            LDL (-lldl),\n"
  378.      "    Linda (-llinda),        Russell (-lrussell),    MODEL (-lm),\n"
  379.        "    Perl (-lperl),          MLisp (-lml),           Icon (-lI),\n"
  380.        "    PostScript (-lps),      TeX (-ltex),            IDL (-lidl),\n"
  381.        "    Yacc (-ly),             Bourne Shell(-lsh),     CSH (-lcsh),\n"
  382.       "    assembler (-lasm),      68000 assembler (-la68),\n"
  383.     "    asm68 (-lasm68),        VMS assembler (-lvmsasm).\n"
  384.     "    ada (-lada),            Java (-ljava).\n"
  385.     "    agda (-lagda ).\n"
  386.     "If neither -e nor -i are specified, a complete LaTeX-file is produced.\n",DEFSFILE);
  387. }
  388.  
  389. /*
  390.  * @readfile()@ --- read and process a file
  391.  */
  392.    void
  393. readfile(FILE *fp)
  394. {
  395.    register unsigned char *cp;
  396.    boolean    LGinline=FALSE;    /* Doing %( -- %)    */
  397.    unsigned char     term;        /* ']' or ')'           */
  398.    unsigned char     *atptr;     /* start of %|@|% within %%\LaTeX%% text */
  399.    unsigned char     *atendptr;    /* end of %|@|% within %%\LaTeX%% text */
  400.    unsigned char     *ttptr;     /* start of %|||% within %%\LaTeX%% text */
  401.    unsigned char     *ttendptr;    /* end of %|||% within %%\LaTeX%% text */
  402.    unsigned char     *pcptr;     /* start of %|%|% within %%\LaTeX%% text */
  403.    unsigned char     *pcendptr;    /* end of %|%|% within %%\LaTeX%% text */
  404.    unsigned char     temp[BUFFERSIZE];
  405.    unsigned char        fnamebak[100];
  406.    int        linenobak;
  407.  
  408.    while (fgets(buf, BUFFERSIZE, fp) != NULL) {
  409.       cp = &buf[strlen(buf)-1];
  410.       if (*cp != '\n') {*(++cp) = '\n'; *(++cp) = '\0'; }
  411.       lineno++;
  412.       cp = buf;
  413. #if nospaceincomment
  414.       linehead = TRUE;
  415. #endif
  416.       lastout = '\0';
  417.       if (embed) {
  418.      if (!code) {
  419.         if (buf[0] == '%' &&
  420.         (buf[1] == '[' || buf[1] == '('
  421.          || buf[1] == '#' || buf[1] == '<' || buf[1] == '!'
  422.          || buf[1] == '@' || buf[1] == '|')) {
  423.  
  424.            for (cp = buf + 2; *cp == ' ' || *cp == '\t'; cp++)
  425.           ;
  426.  
  427.            /* Change the language */
  428.            if (buf[1] == '#') {
  429.           if (*cp == '\n')
  430.              fprintf(stderr, "no language seen after %%# in file\
  431.  %s at line %d\n", fname, lineno);
  432.           else {
  433.              cp[strlen(cp) - 1] = '\0'; /* nuke the @'\n'@ */
  434.              strcpy(language, cp);
  435.              printf("%% switching to %s\n", language);
  436.              setlang();
  437.           }
  438.           continue;
  439.            }
  440.  
  441.            /* Turn %|@|% or %|||% processing within %%\LaTeX%%
  442.         * text on or off. */
  443.  
  444.            if (buf[1] == '@' || buf[1] == '|') {
  445.           if (*cp == '\n')
  446.              fprintf(stderr, "no setting seen after %%%c in file\
  447.  %s at line %d\n", buf[1], fname, lineno);
  448.           else {
  449.              int flag = (*cp == '1' || *cp == '+');
  450.              if (buf[1] == '@')
  451.             do_at = flag;
  452.              else
  453.             do_tt = flag;
  454.           }
  455.           continue;
  456.            }
  457.  
  458.            code = TRUE;
  459.  
  460.            /* take input from another file or from a shell command */
  461.            if (buf[1] == '<' || buf[1] == '!') {
  462.           FILE *fp;
  463.           unsigned char source = buf[1];
  464.  
  465.           cp[strlen(cp) - 1] = '\0';    /* nuke the @'\n'@ */
  466.           if (source == '<')
  467.              fp = fopen(cp, "r");
  468.           else /* @source == '!'@ */
  469.              fp = popen(cp, "r");
  470.  
  471.           if (fp == NULL) {
  472.              sprintf(temp, "%%%c on `%s' failed", source, cp);
  473.              perror(temp);
  474.           } else {
  475.              strcpy(temp, cp);
  476.              printf("%% start of `%s'\n", temp);
  477.              /* printf("\\LGinlinefalse\\LGbegin\\lgrinde\n"); */
  478.              printf("\\begin{lgrind}\n");
  479.              embed = FALSE;
  480.              linenobak=lineno; strcpy(fnamebak, fname);
  481.              lineno=0; strcpy(fname, temp);
  482.              readfile(fp);
  483.              lineno=linenobak; strcpy(fname, fnamebak);
  484.              embed = TRUE;
  485.              /* printf("\\endlgrinde\\LGend\n"); */
  486.              printf("\\end{lgrind}\n");
  487.              printf("%% end of `%s'\n", temp);
  488.              if (source == '<')
  489.             fclose(fp);
  490.              else
  491.             pclose(fp);
  492.           }
  493.           code = FALSE;
  494.           continue;
  495.            }
  496.  
  497.            /* embedded inline or displayed code */
  498.            if (buf[1] == '(') {
  499.           LGinline = TRUE;
  500.           term = ')';
  501.           printf("\\LGinlinetrue");
  502.            } else { /* @buf[1] == '['@ */
  503.           LGinline = FALSE;
  504.           term = ']';
  505.           printf("\\LGinlinefalse");
  506.            }
  507.            if (buf[2] == '\n') {
  508.           printf("\\LGbegin\\lgrinde\n");
  509.            } else {
  510.           buf[strlen(buf)-1] = '\0';
  511.           printf("%s\\lgrinde\n", &buf[2]);
  512.            }
  513.            continue;
  514.  
  515.         } else if (do_at &&
  516.                (atendptr = expmatch(buf, l_at, &atptr,
  517.                         (unsigned char *) NULL)) != NULL) {
  518.            /* This is a gross hack.  Fix it, dammit */
  519.         restart_at:
  520.            pcendptr = expmatch(cp, l_pc, &pcptr, (unsigned char *) NULL);
  521.  
  522.            if (pcptr == NULL || atptr < pcptr) {
  523.           putVcp(cp, atptr-1);
  524.           printf("\\LGinlinetrue\\LGbegin\\lgrinde");
  525.           cp = atendptr;
  526.           atendptr = expmatch(cp, l_at, &atptr, (unsigned char *) NULL);
  527.           if (atptr != NULL && (pcptr == NULL || atptr < pcptr)) {
  528.              strncpy(temp, cp, atptr-cp);
  529.              temp[atptr-cp] = '\0';
  530.              cp = atendptr;
  531.              printf("\\L{\\LB{");
  532.              putScp(temp);
  533.              printf("}}\\endlgrinde\\LGend{}");
  534.              atendptr = expmatch(cp, l_at, &atptr, (unsigned char *) NULL);
  535.              if (atptr != NULL)
  536.             goto restart_at;
  537.              else {
  538.             fputs(cp, stdout); continue;
  539.              }
  540.           } else {
  541.              /* multiline */
  542.           }
  543.            } else {
  544.           fputs(buf, stdout);
  545.           continue;
  546.            }
  547.         } else if (do_tt &&
  548.                (ttendptr = expmatch(buf, l_tt, &ttptr,
  549.                         (unsigned char *) NULL)) != NULL) {
  550.            pcendptr = expmatch(buf, l_pc, &pcptr, (unsigned char *) NULL);
  551.  
  552.            if (pcptr == NULL || ttptr < pcptr) {
  553.           putVcp(buf, ttptr-1);
  554.            } else {
  555.           fputs(buf, stdout); continue;
  556.            }
  557.         } else {
  558.            fputs(buf, stdout);
  559.            continue;
  560.         }
  561.      } /* @if (!code)@ */
  562.  
  563.      /*
  564.       * We're in embedded code.
  565.       */
  566.      if (buf[0] == '%') {
  567.         if (buf[1] == '*') {
  568.            if (term != ']')
  569.           fprintf(stderr, "%%* only makes sense in display mode\
  570.  in file %s at line %d\n", fname, lineno);
  571.            else {
  572.           printf("\\endlgrinde\\LGend\n");
  573.           printf("\\LGinlinefalse\\LGbegin\\lgrinde\n");
  574.            }
  575.            continue;
  576.         } else if (buf[1] == term) {
  577.            if (buf[2] == '\n')
  578.           printf("\\endlgrinde\\LGend\n");
  579.            else
  580.           printf("\\endlgrinde%s", &buf[2]);
  581.            code = FALSE;
  582.            continue;
  583.         } else if (buf[1] == '=') { /* Send literal */
  584.            fputs(&buf[2], stdout);
  585.            continue;
  586.         } else if (buf[1] == '[' || buf[1] == '('
  587.                || buf[1] == ']' || buf[1] == ')') {
  588.            fprintf(stderr,
  589.                "Possible nested embedded code in file %s at line %d\n",
  590.                fname, lineno);
  591.         }
  592.      }
  593.  
  594.      /*
  595.       * Inline code --- suppress leading whitespace
  596.       */
  597.      if (LGinline) {
  598.         while (isspace(*cp))
  599.            cp++;
  600.      }
  601.       } /* @if (embed)@ */
  602.  
  603.       if (*cp == '\f') {
  604.      printf("\\NewPage\n");
  605.      cp++;
  606.      if (*cp == '\n')  /* some people like ^Ls on their own line */
  607.         continue;
  608.       }
  609.       prccont = FALSE;
  610.       printf("\\L{\\LB{");
  611.       putScp(cp);
  612.       if (!embed && prccont && (psptr >= 0)) {
  613.      printf("\\ProcCont{");
  614.      putstr(pstack[psptr]);
  615.      printf("}");
  616.       }
  617. #ifdef DEBUG
  618.       printf("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr);
  619. #endif
  620.    } /* @while fgets()@ */
  621. }
  622.  
  623.  
  624.  
  625. /*
  626.  * Set all of the language-dependent variables
  627.  */
  628.    void
  629. setlang(void)
  630. {
  631.    unsigned char *p, *cp;
  632.    int i;
  633.  
  634.    /*
  635.     *  get the language definition from the defs file
  636.     */
  637.    i = tgetent(defs, language, defsfile);
  638.    if (i == 0) {
  639.       fprintf(stderr, "no entry for language %s\n", language);
  640.       exit(BADEXIT);
  641.    } else if (i < 0) {
  642.       fprintf(stderr,  "cannot find lgrindefs file `%s'\n", defsfile);
  643.       exit(BADEXIT);
  644.    }
  645.  
  646.    p = strings;
  647.    if (tgetstr("kw", &p) == NULL)
  648.       nokeyw = TRUE;
  649.    else  {
  650.       unsigned char **cpp;
  651.  
  652.       cpp = l_keywds;
  653.       cp = strings;
  654.       while (*cp) {
  655.      while (*cp == ' ' || *cp =='\t')
  656.         *cp++ = '\0';
  657.      if (*cp)
  658.         *cpp++ = cp;
  659.      while (*cp != ' ' && *cp  != '\t' && *cp)
  660.         cp++;
  661.       }
  662.       *cpp = NULL;
  663.    }
  664.  
  665.    p = buf;  l_prcbeg = convexp(tgetstr("pb", &p));
  666.    p = buf;  l_noproc = convexp(tgetstr("np", &p));
  667.    p = buf;  l_combeg = convexp(tgetstr("cb", &p));
  668.    p = buf;  l_comend = convexp(tgetstr("ce", &p));
  669.    p = buf;  l_acmbeg = convexp(tgetstr("ab", &p));
  670.    p = buf;  l_acmend = convexp(tgetstr("ae", &p));
  671.    p = buf;  l_strbeg = convexp(tgetstr("sb", &p));
  672.    p = buf;  l_strend = convexp(tgetstr("se", &p));
  673.    p = buf;  l_blkbeg = convexp(tgetstr("bb", &p));
  674.    p = buf;  l_blkend = convexp(tgetstr("be", &p));
  675.    p = buf;  l_chrbeg = convexp(tgetstr("lb", &p));
  676.    p = buf;  l_chrend = convexp(tgetstr("le", &p));
  677.    p = s_cdebeg;  l_cdebeg = convexp(tgetstr("zb", &p));
  678.    p = buf;  l_cdeend = convexp(tgetstr("ze", &p));
  679.    p = buf;  l_texbeg = convexp(tgetstr("tb", &p));
  680.    p = buf;  l_texend = convexp(tgetstr("te", &p));
  681.    p = buf;  l_txmbeg = convexp(tgetstr("mb", &p));
  682.    p = buf;  l_txmend = convexp(tgetstr("me", &p));
  683.    p = buf;  l_tt_beg = convexp(tgetstr("vb", &p));
  684.    p = buf;  l_tt_end = convexp(tgetstr("ve", &p));
  685.    p = buf;  l_record = convexp(tgetstr("rb", &p));
  686.    p = buf;  cp       =         tgetstr("id", &p) ;
  687.    if (cp)
  688.    {
  689.      l_id = (unsigned char*)malloc(strlen(cp));
  690.      strcpy(l_id, cp);
  691.    }
  692.    else    l_id = "_";
  693.  
  694.    l_tt = convexp("\\|");
  695.    l_at = convexp("@");
  696.    l_pc = convexp("%");
  697.  
  698.    l_escape = '\\';
  699.    /* abuse of l_onecase */
  700.    l_onecase = tgetflag("cf");
  701.    isproc = l_onecase ? isprocC : isprocNorm;
  702.  
  703.    l_onecase = tgetflag("oc");
  704.  
  705.     if(l_onecase) re_strncmp = lc_strncmp;
  706.     else re_strncmp = strncmp;
  707.  
  708. /*   re_strncmp = (l_onecase ? lc_strncmp : strncmp);*/
  709.    l_toplex = tgetflag("tl");
  710. }
  711.  
  712. /*
  713. extern int    (*re_strncmp)();
  714. int    l_onecase;
  715. int lc_strncmp(const char *s1, const char *s2, int len)
  716. int strncmp(const char *s1, const char *s2, size_t n);
  717.  
  718. */
  719.  
  720.  
  721. /*
  722.  * Write out a formatted line of program text
  723.  */
  724.    void
  725. putScp(unsigned char *os)
  726. {
  727.    register unsigned char *s = os; /* pointer to unmatched string */
  728. /*   register unsigned char *s1;    /* temp. string */
  729.    unsigned char *comptr;    /* start of a comment delimiter */
  730.    unsigned char *comendptr;    /* end of a comment delimiter */
  731.    unsigned char *acmptr;    /* start of an alt. comment delimiter */
  732.    unsigned char *acmendptr;    /* end of an alt. comment delimiter */
  733.    unsigned char *strptr;    /* start of a string delimiter */
  734.    unsigned char *strendptr;    /* end of a string delimiter */
  735.    unsigned char *chrptr;    /* start of a char. const delimiter */
  736.    unsigned char *chrendptr;    /* end of a unsigned char. const delimiter */
  737.    unsigned char *cdeptr;    /* start of prog text delim within a comment */
  738.    unsigned char *cdeendptr;    /* end of prog text delim within a comment */
  739.    unsigned char *cdbptr;    /* start of prog text delim within a comment */
  740.    unsigned char *cdbendptr;    /* end of prog text delim within a comment */
  741.    unsigned char *texptr;    /* start of %%\TeX%% text delim within a comment */
  742.    unsigned char *texendptr;    /* end of %%\TeX%% text delim within a comment */
  743.    unsigned char *txmptr;    /* start of %%\TeX%% math delim within a comment */
  744.    unsigned char *txmendptr;    /* end of %%\TeX%% math delim within a comment */
  745.    unsigned char *tt_ptr;    /* start of typewriter delim within a comment */
  746.    unsigned char *tt_endptr;    /* end of typewriter delim within a comment */
  747.    unsigned char *blksptr;    /* start of a lexical block start */
  748.    unsigned char *blksendptr;    /* end of a lexical block start */
  749.    unsigned char *recsptr;    /* start of a lexical block outside functions start */
  750.    unsigned char *recsendptr;    /* end of a lexical block outside functions start */
  751.    unsigned char *blkeptr;    /* start of a lexical block end */
  752.    unsigned char *blkeendptr;    /* end of a lexical block end */
  753.  
  754.    _sstart = os;     /* remember the start for @expmatch()@ */
  755.    _escaped = FALSE;
  756.    if (nokeyw || incomm || instr)
  757.       goto skip;
  758.    if ((*isproc)(s) && reclevel == 0) {
  759.       printf("\\Proc{");
  760.       putstr(pname);
  761.       printf("}");
  762.       if (!embed && psptr < PSMAX-1) {
  763.      ++psptr;
  764.      strncpy(pstack[psptr], pname, PNAMELEN);
  765.      pstack[psptr][PNAMELEN] = '\0';
  766.      plstack[psptr] = blklevel;
  767.       }
  768.    }
  769.  skip:
  770.    do {
  771.       /* check for string, comment, blockstart, etc */
  772.       if (!incomm && !instr && !inchr) {
  773.  
  774.      blkeendptr = expmatch(s, l_blkend, &blkeptr, (unsigned char *) NULL);
  775.      blksendptr = expmatch(s, l_blkbeg, &blksptr, (unsigned char *) NULL);
  776.      recsendptr = expmatch(s, l_record, &recsptr, (unsigned char *) NULL);
  777.      comendptr =  expmatch(s, l_combeg, &comptr,  (unsigned char *) NULL);
  778.      acmendptr =  expmatch(s, l_acmbeg, &acmptr,  (unsigned char *) NULL);
  779.      strendptr =  expmatch(s, l_strbeg, &strptr,  (unsigned char *) NULL);
  780.      chrendptr =  expmatch(s, l_chrbeg, &chrptr,  (unsigned char *) NULL);
  781.  
  782.      /* check for end of program text in comment */
  783.      if (incode != NOTCODE) {
  784.         cdeendptr = expmatch(s, l_cdeend, &cdeptr, (unsigned char *) NULL);
  785.  
  786.         if ((cdeptr == NULL && (comptr != NULL || acmptr != NULL))
  787.         || (cdeptr != NULL
  788.             && ((comptr != NULL && comptr < cdeptr)
  789.             || ((acmptr != NULL && acmptr < cdeptr))))) {
  790.            fprintf(stderr, "Comments may not be nested within\
  791.  program text within comments in file %s at\
  792.  line %d\n", fname, lineno);
  793.            s = (comptr != NULL) ? comptr : acmptr;
  794.            incode = NOTCODE;
  795.            continue;
  796.         }
  797.  
  798.         /* look to see if there's a \<zb> in the program text */
  799.         cdbendptr = expmatch(s, l_cdebeg, &cdbptr, (unsigned char *) NULL);
  800.         if (cdeptr != NULL
  801.         && (strptr  == NULL || cdbptr < strptr)
  802.         && (chrptr  == NULL || cdbptr < chrptr)
  803.         && (blksptr == NULL || cdbptr < blksptr)
  804.         && (recsptr == NULL || cdbptr < recsptr)
  805.         && (blkeptr == NULL || cdbptr < blkeptr)) {
  806.            if (cdbptr > s && cdbptr[-1] == l_escape) {
  807.           putKcp(s, cdbptr-2, FALSE);
  808.           printf("\\C{}");
  809.           putKcp(s_cdebeg, s_cdebeg + strlen(s_cdebeg) - 1, TRUE);
  810.           printf("\\CE{}");
  811.           s = cdbendptr;
  812.           incode = OTHERCODE;
  813.           continue;
  814.            }
  815.         }
  816.  
  817.         comendptr =
  818.            expmatch(s, (comtype == STANDARD) ? l_comend : l_acmend,
  819.             &comptr, (unsigned char *) NULL);
  820.  
  821.         if ((cdeptr == NULL && comptr != NULL)
  822.         || (cdeptr != NULL && (comptr != NULL && comptr < cdeptr))) {
  823.            fprintf(stderr, "Unterminated program text within comment\
  824.  in file %s at line %d\n", fname, lineno);
  825.            printf("\\C{}");
  826.            s = comptr;
  827.            incode = NOTCODE; incomm = TRUE;
  828.            continue;
  829.         }
  830.  
  831.  
  832.         if (cdeendptr != NULL) {
  833.            if ((strptr  == NULL || cdeptr < strptr)
  834.            && (chrptr  == NULL || cdeptr < chrptr)
  835.            && (blksptr == NULL || cdeptr < blksptr)
  836.            && (recsptr == NULL || cdeptr < recsptr)
  837.            && (blkeptr == NULL || cdeptr < blkeptr)) {
  838.           if (incode == INITCODE && cdeptr == s) {
  839.              printf("\\C{}");
  840.              putKcp(s_cdebeg, s_cdebeg + strlen(s_cdebeg) - 1, TRUE);
  841.           } else {
  842.              putKcp(s, cdeptr-1, FALSE);
  843.              printf("\\C{}");
  844.           }
  845.           s = cdeendptr;
  846.           incode = NOTCODE; incomm = TRUE;
  847.           continue;
  848.            }
  849.         } else if (strptr == NULL && chrptr == NULL
  850.                && blksptr == NULL && recsptr == NULL 
  851.                && blkeptr == NULL) {
  852.            cdeptr = s;
  853.            s += strlen(s);
  854.            putKcp(cdeptr, s-1, FALSE);
  855.            incode = OTHERCODE;
  856.            continue;
  857.         } /* else there is a string/char/block on this line */
  858.  
  859.         incode = OTHERCODE;
  860.      } /* @if (incode)@ */
  861.  
  862.  
  863.      /* start of a comment? */
  864.      if (comptr != NULL
  865.          && (strptr  == NULL || comptr < strptr)
  866.          && (acmptr  == NULL || comptr < acmptr)
  867.          && (chrptr  == NULL || comptr < chrptr)
  868.          && (blksptr == NULL || comptr < blksptr)
  869.          && (recsptr == NULL || comptr < recsptr)
  870.          && (blkeptr == NULL || comptr < blkeptr)) {
  871.         putKcp(s, comptr-1, FALSE);
  872.         printf("\\C{}");
  873.         s = comendptr;
  874.         putKcp(comptr, comendptr-1, FALSE);
  875.         incomm = TRUE;
  876.         comtype = STANDARD;
  877.         continue;
  878.      }
  879.  
  880.      /* start of an alternate-form comment? */
  881.      if (acmptr != NULL
  882.          && (strptr  == NULL || acmptr < strptr)
  883.          && (chrptr  == NULL || acmptr < chrptr)
  884.          && (blksptr == NULL || acmptr < blksptr)
  885.          && (recsptr == NULL || acmptr < recsptr)
  886.          && (blkeptr == NULL || acmptr < blkeptr)) {
  887.         putKcp(s, acmptr-1, FALSE);
  888.         printf("\\C{}");
  889.         s = acmendptr;
  890.         putKcp(acmptr, acmendptr-1, FALSE);
  891.         incomm = TRUE;
  892.         comtype = ALTERNATE;
  893.         continue;
  894.      }
  895.  
  896.      /* start of a string? */
  897.      if (strptr != NULL
  898.          && (chrptr  == NULL || strptr < chrptr)
  899.          && (blksptr == NULL || strptr < blksptr)
  900.          && (recsptr == NULL || strptr < recsptr)
  901.          && (blkeptr == NULL || strptr < blkeptr)) {
  902.         putKcp(s, strptr-1, FALSE);
  903.         printf("\\S{}");
  904.         s = strendptr;
  905.         putKcp(strptr, strendptr-1, FALSE);
  906.         instr = TRUE;
  907.         continue;
  908.      }
  909.  
  910.      /* start of a character string? */
  911.      if (chrptr != NULL
  912.          && (blksptr == NULL || chrptr < blksptr)
  913.          && (recsptr == NULL || chrptr < recsptr)
  914.          && (blkeptr == NULL || chrptr < blkeptr)) {
  915.         putKcp(s, chrptr-1, FALSE);
  916.         printf("\\S{}");
  917.         s = chrendptr;
  918.         putKcp(chrptr, chrendptr-1, FALSE);
  919.         inchr = TRUE;
  920.         continue;
  921.      }
  922.  
  923.      /* end of a lexical block */
  924.      if (blkeptr != NULL) {
  925.         if ((blksptr == NULL || blkeptr < blksptr) &&
  926.             (recsptr == NULL || blkeptr < recsptr)) {
  927.            putKcp(s, blkeendptr - 1, FALSE);
  928.            s = blkeendptr;
  929.            blklevel--;
  930.            if (reclevel) reclevel--;
  931.            else if (psptr >= 0 && plstack[psptr] >= blklevel) {
  932.  
  933.           /* end of current procedure */
  934.           blklevel = plstack[psptr];
  935.  
  936.           /* see if we should print the last proc name */
  937.           if (--psptr >= 0)
  938.              prccont = TRUE;
  939.           else
  940.              psptr = -1;
  941.            }
  942.            continue;
  943.         }
  944.      }
  945.  
  946.      /* start of a lexical block */
  947.      if (blksptr != NULL) {
  948.         putKcp(s, blksendptr - 1, FALSE);
  949.         s = blksendptr;
  950.         blklevel++;
  951.         continue;
  952.      }
  953.  
  954.      /* start of a lexical block outside functions */
  955.      if (recsptr != NULL) {
  956.         putKcp(s, recsendptr - 1, FALSE);
  957.         s = recsendptr;
  958.         blklevel++;
  959.         reclevel++;
  960.         continue;
  961.      }
  962.  
  963.      /* check for end of comment */
  964.       } else if (incomm) {
  965.  
  966.      cdeendptr = expmatch(s, l_cdebeg, &cdeptr, (unsigned char *) NULL);
  967.      texendptr = expmatch(s, l_texbeg, &texptr, (unsigned char *) NULL);
  968.      txmendptr = expmatch(s, l_txmbeg, &txmptr, (unsigned char *) NULL);
  969.      tt_endptr = expmatch(s, l_tt_beg, &tt_ptr, (unsigned char *) NULL);
  970.  
  971.      if (code_cmnts) {
  972.  
  973.         /* Check for program text within comment */
  974.         if (cdeptr != NULL
  975.         && (texptr == NULL || cdeptr < texptr)
  976.         && (tt_ptr == NULL || cdeptr < tt_ptr)
  977.         && (txmptr == NULL || cdeptr < txmptr)) {
  978.            putKcp(s, cdeptr-1, TRUE);
  979.            printf("\\CE{}");
  980.            s = cdeendptr;
  981.            incode = INITCODE; incomm = FALSE;
  982.            continue;
  983.         }
  984.  
  985.         /* Check for %%\TeX%% text within comment */
  986.         if (texptr != NULL
  987.         && (tt_ptr == NULL || texptr < tt_ptr)
  988.         && (txmptr == NULL || texptr < txmptr)) {
  989.            putKcp(s, texptr-1, TRUE);
  990.            s = texendptr;
  991.            if ((texendptr =
  992.             expmatch(s, l_texend, &texptr, (unsigned char *) NULL)) != NULL) {
  993.           putchar('{'); putVcp(s, texptr-1); putchar('}');
  994.           s = texendptr;
  995.            } else {
  996.           fprintf(stderr, "LaTeX text within a comment must all be\
  997.  on one line (file %s at line %d)\n", fname, lineno);
  998.           s += strlen(s);
  999.            }
  1000.            continue;
  1001.         }
  1002.  
  1003.         /* Check for typewriter text within comment */
  1004.         if (tt_ptr != NULL
  1005.         && (txmptr == NULL || tt_ptr < txmptr)) {
  1006.            putKcp(s, tt_ptr-1, TRUE);
  1007.            s = tt_endptr;
  1008.            if ((tt_endptr =
  1009.             expmatch(s, l_tt_end, &tt_ptr, (unsigned char *) NULL)) != NULL) {
  1010.           printf("\\texttt{");
  1011.           putKcp(s, tt_ptr-1, TRUE);
  1012.           printf("}");
  1013.           s = tt_endptr;
  1014.            } else {
  1015.           fprintf(stderr, "typewriter text within a comment must all\
  1016.  be on one line (file %s at line %d)\n\t%s",
  1017.                 fname, lineno, s);
  1018.           s += strlen(s);
  1019.            }
  1020.            continue;
  1021.         }
  1022.  
  1023.         /* Check for %%\TeX%% math within comment */
  1024.         if (txmptr != NULL) {
  1025.            putKcp(s, txmptr-1, TRUE);
  1026.            s = txmendptr;
  1027.            if ((txmendptr =
  1028.             expmatch(s, l_txmend, &txmptr, (unsigned char *) NULL)) != NULL) {
  1029.           putchar('$'); putVcp(s, txmptr-1); putchar('$');
  1030.           s = txmendptr;
  1031.            } else {
  1032.           fprintf(stderr, "TeX math within a comment must all be\
  1033.  on one line (file %s at line %d)\n", fname, lineno);
  1034.           s += strlen(s);
  1035.            }
  1036.            continue;
  1037.         }
  1038.      } /* @if (code_cmnts)@ */
  1039.  
  1040.      if ((comendptr =
  1041.         expmatch(s, (comtype == STANDARD) ? l_comend : l_acmend,
  1042.              (unsigned char **) NULL, (unsigned char *) NULL)) != NULL) {
  1043.         putKcp(s, comendptr-1, TRUE);
  1044.         s = comendptr;
  1045.         incomm = FALSE;
  1046.         printf("\\CE{}");
  1047.      } else {
  1048.         comptr = s;
  1049.         s += strlen(s);
  1050.         putKcp(comptr, s-1, TRUE);
  1051.      }
  1052.      continue;
  1053.  
  1054.      /* check for end of string */
  1055.       } else if (instr) {
  1056.      if ((strendptr =
  1057.           expmatch(s, l_strend, (unsigned char **) NULL, (unsigned char *) NULL)) != NULL) {
  1058.         putKcp(s, strendptr-1, TRUE);
  1059.         s = strendptr;
  1060.         instr = FALSE;
  1061.         printf("\\SE{}");
  1062.      } else {
  1063.         strptr = s;
  1064.         s += strlen(s);
  1065.         putKcp(strptr, s-1, TRUE);
  1066.      }
  1067.      continue;
  1068.  
  1069.      /* check for end of character string */
  1070.       } else if (inchr) {
  1071.      if ((chrendptr =
  1072.           expmatch(s, l_chrend, (unsigned char **) NULL, (unsigned char *) NULL)) != NULL) {
  1073.         putKcp(s, chrendptr-1, TRUE);
  1074.         s = chrendptr;
  1075.         inchr = FALSE;
  1076.         printf("\\SE{}");
  1077.      } else {
  1078.         chrptr = s;
  1079.         s += strlen(s);
  1080.         putKcp(chrptr, s-1, TRUE);
  1081.      }
  1082.      continue;
  1083.       }
  1084.  
  1085.       /* print out the line */
  1086.       chrptr = s;
  1087.       s += strlen(s);
  1088.       putKcp(chrptr, s-1, FALSE);
  1089.  
  1090.    } while (*s);
  1091. }
  1092.  
  1093.  
  1094.  
  1095. /*
  1096.  * Output a %%\LaTeX%% command to tab to column "col" (see lgrind.doc
  1097.  * for a partial explanation of the bizarre brace arrangement).
  1098.  */
  1099. #define tabto(col) printf("}\\Tab{%d}{", col);
  1100.  
  1101.  
  1102.  
  1103. /*
  1104.  * @islidchr()@ is @TRUE@ for things that can begin identifiers;
  1105.  * @isidchr@ is @TRUE@ of identifier constituents.
  1106.  */
  1107. #define islidchr(c) (((isalpha(c) || (strchr(l_id, c))) && c!=0))
  1108. #define isidchr(c)  (((isalnum(c) || (strchr(l_id, c))) && c!=0)) 
  1109.  
  1110.  
  1111. /*
  1112.  * Write out a portion of the line
  1113.  */
  1114.    void
  1115. putKcp(unsigned char *start, unsigned char *end, boolean nix)
  1116.    /*unsigned char *start;     Start of string to write    */
  1117.    /*unsigned char *end;    End of string to write        */
  1118.    /*boolean    nix;        Don't look for identifiers, numbers */
  1119. {
  1120.    int i, c;
  1121.  
  1122.    while (start <= end) {
  1123.       c = *start++;
  1124.       /*
  1125.        * take care of nice tab stops
  1126.        */
  1127.       if (c == '\t') {
  1128.      while (start <= end && *start == '\t')
  1129.         start++;
  1130.      tabto(width(_sstart, start));
  1131.      continue;
  1132.       }
  1133.  
  1134.       /*
  1135.        * First split off numbers.  We have a rather ad hoc
  1136.        * definition:  A number is a digit followed by any number
  1137.        * of digits or letters, and periods.
  1138.        * (Additionally a number can start with %|$|% (e.g. hex numbers).)
  1139.        * This produces meaningless parses --- %$.2$% is parsed as %|.|%
  1140.        * followed by the number %|2|% --- but should produce decent
  1141.        * results for most languages (outside of maybe FORTRAN and DCL).
  1142.        */
  1143.       if (!nix) {
  1144.      if (isdigit(c) || c == '$') {
  1145.         printf("\\N{");
  1146.         do {
  1147.            if (c == 'l')
  1148.           printf("$\\ell$");
  1149.            else
  1150.           outchar(c);
  1151.            c = *start++;
  1152.         } while (isalnum(c) || c == '.');
  1153.         putchar('}');
  1154.         start--;
  1155.         continue;
  1156.      } else if (c == '#' || islidchr(c)) {
  1157.         i = getid(--start);
  1158.         if (i > 0)
  1159.            printf("\\K{");
  1160.         else {
  1161.            printf("\\V{");
  1162.            i = -i;
  1163.         }
  1164.         while (--i >= 0) {
  1165.            c = *start++;
  1166.            outchar(c);
  1167.         }
  1168.         putchar('}');
  1169.         continue;
  1170.      }
  1171.       }
  1172.       outchar(c);
  1173.    }
  1174. }
  1175.  
  1176.  
  1177.  
  1178. /*
  1179.  * Write out a portion of the line verbatim
  1180.  */
  1181.    void
  1182. putVcp(unsigned char *start, unsigned char *end)
  1183.    /*unsigned char     *start;     /* Start of string to write    */
  1184.    /*unsigned char     *end;        /* End of string to write    */
  1185. {
  1186.    for ( ; start <= end; start++) {
  1187.       putchar(*start);
  1188.    }
  1189. }
  1190.  
  1191.  
  1192.  
  1193. /*
  1194.  * Calculate the width of a string, including tabs
  1195.  */
  1196.    int
  1197. width(register unsigned char *s, register unsigned char *os)
  1198. {
  1199.    register int i = 0, c;
  1200.  
  1201.    while (s < os) {
  1202.       c = *s++;
  1203.       if (c == '\t') {
  1204.      i = (i + 8) &~ 7;
  1205.      continue;
  1206.       }
  1207.       if (c < ' ')
  1208.      i += 2;
  1209.       else
  1210.      i++;
  1211.    }
  1212.    return i;
  1213. }
  1214.  
  1215.  
  1216.  
  1217. /*
  1218.  * Output a string, escaping special characters
  1219.  */
  1220.    void
  1221. putstr(register unsigned char *cp)
  1222. {
  1223.    register int c;
  1224.  
  1225.    if (cp == NULL)
  1226.       return;
  1227.    while ((c = *cp++) != '\0')
  1228.       outchar(c);
  1229. }
  1230.  
  1231.  
  1232.  
  1233. /*
  1234.  * The following table converts ASCII characters to a printed
  1235.  * representation, taking care of all the %%\LaTeX%% quoting.  N.B.: all
  1236.  * single-character strings are assumed to be equivalent to the
  1237.  * character for that index (i.e., @printtab['c']@ can't be @"f"@).
  1238.  * (This is purely for efficiency hacking.)
  1239.  *
  1240.  * Notes:
  1241.  *  Some pairs of characters are handled specially within @outchar()@;
  1242.  *  this table contains no indication when that happens.
  1243.  *  %|`|% is output as %|{`}|% to avoid various ligatures, such as %|!`|%.
  1244.  *  The %|''|% and %|--|% (and %|---|%) ligatures are not a problem
  1245.  *  because those characters are output as macros anyway.  Using %|{`}|%
  1246.  *  is sufficient since nothing we put out will ever be given to the
  1247.  *  hyphenation algorithms anyway.
  1248.  */
  1249.  
  1250. unsigned char *printtab[256] = {
  1251.    "\0x",   "\\^A",  "\\^B",  "\\^C",  "\\^D",  "\\^E",  "\\^F",  "\\^G",
  1252.    "\\^H",  "\t",    "}}\n",  "\\^K",  "\0x",   "\\^M",  "\\^N",  "\\^O",
  1253.    "\\^P",  "\\^Q",  "\\^R",  "\\^S",  "\\^T",  "\\^U",  "\\^V",  "\\^W",
  1254.    "\\^X",  "\\^Y",  "\\^Z",  "\\^[",  "\\^\\!","\\^]",  "\\^\\^","\\^\\_",
  1255.    " ",     "!",     "\\3",   "\\#",   "\\$",   "\\%",   "\\&",   
  1256. "$\\hspace{1pt}\\acute{\\null}\\hspace{2pt}$",
  1257. /* "\\4",    major update :) */
  1258.    "(",     ")",     "\\*",   "+",     ",",     "\\-",   ".",     "\\1",
  1259.    "0",     "1",     "2",     "3",     "4",     "5",     "6",     "7",
  1260.    "8",     "9",     ":",     ";",     "\\<",   "=",     "\\>",   "?",
  1261.    "@",     "A",     "B",     "C",     "D",     "E",     "F",     "G",
  1262.    "H",     "I",     "J",     "K",     "L",     "M",     "N",     "O",
  1263.    "P",     "Q",     "R",     "S",     "T",     "U",     "V",     "W",
  1264.    "X",     "Y",     "Z",     "[",     "\\2",   "]",     "\\5",   "\\_",
  1265.    "{`}",   "a",     "b",     "c",     "d",     "e",     "f",     "g",
  1266.    "h",     "i",     "j",     "k",     "l",     "m",     "n",     "o",
  1267.    "p",     "q",     "r",     "s",     "t",     "u",     "v",     "w",
  1268.    "x",     "y",     "z",     "\\{",   "\\|",   "\\}",   "\\~",   "\\^?",
  1269.    "\200",  "\201",  "\202",  "\203",  "\204",  "\205",  "\206",  "\207",
  1270.    "\210",  "\211",  "\212",  "\213",  "\214",  "\215",  "\216",  "\217",
  1271.    "\220",  "\221",  "\222",  "\223",  "\224",  "\225",  "\226",  "\227",
  1272.    "\230",  "\231",  "\232",  "\233",  "\234",  "\235",  "\236",  "\237",
  1273.    "\240",  "\241",  "\242",  "\243",  "\244",  "\245",  "\246",  "\247",
  1274.    "\250",  "\251",  "\252",  "\253",  "\254",  "\255",  "\256",  "\257",
  1275.    "\260",  "\261",  "\262",  "\263",  "\264",  "\265",  "\266",  "\267",
  1276.    "\270",  "\271",  "\272",  "\273",  "\274",  "\275",  "\276",  "\277",
  1277.    "\300",  "\301",  "\302",  "\303",  "\\\"A",  "\\AA ",  "\306",  "\307",
  1278.    "\310",  "\311",  "\312",  "\313",  "\314",  "\315",  "\316",  "\317",
  1279.    "\320",  "\321",  "\322",  "\323",  "\324",  "\325",  "\\\"O",  "\327",
  1280.    "\330",  "\331",  "\332",  "\333",  "\334",  "\335",  "\336",  "\337",
  1281.    "\340",  "\341",  "\342",  "\343",  "\\\"a",  "\\aa ",  "\346",  "\347",
  1282.    "\350",  "\351",  "\352",  "\353",  "\354",  "\355",  "\356",  "\357",
  1283.    "\360",  "\361",  "\362",  "\363",  "\364",  "\365",  "\\\"o",  "\367",
  1284.    "\370",  "\371",  "\372",  "\373",  "\374",  "\375",  "\376",  "\377",
  1285. };
  1286.  
  1287.  
  1288.  
  1289. #define EMDASH (-1)
  1290. /*
  1291.  * Output one character, fixed up as required.    Since there is no call-back
  1292.  * to tell @outchar()@ to flush what it has stored, it must always produce
  1293.  * some output --- it can't simply retain state.  This makes certain
  1294.  * translations impossible, but we can live without them for now....
  1295.  */
  1296.    void
  1297. outchar(int c)
  1298. {
  1299. #if nospaceincomment
  1300.    if ((linehead || !incomm) && c == ' ') {
  1301.       putchar('_');
  1302.       goto fin;
  1303.    }
  1304.    linehead = FALSE;
  1305. #else
  1306.    if (c == ' ') {
  1307.       putchar('_');
  1308.       goto fin;
  1309.    }
  1310. #endif
  1311.    switch (lastout) {
  1312.    case '.':
  1313.    case '|':
  1314.       if (c == lastout)
  1315.      printf("\\,");
  1316.       break;
  1317.    case ' ':
  1318. #if 0    /* gvr hates this trick */
  1319.       if (incomm && c == '-') {
  1320.      printf("---");
  1321.      c = EMDASH;    /* For future cleverness...    */
  1322.      goto fin;
  1323.       }
  1324. #endif
  1325.       break;
  1326.    case '[':
  1327.       if (c == ']')
  1328.      printf("\\,");
  1329.       break;
  1330.    case '-':
  1331.       if (c == '>')
  1332.      printf("\\!");
  1333.       break;
  1334.    case '<':
  1335.       if (c == '-')
  1336.      printf("\\!");
  1337.       break;
  1338.    }
  1339.    if (incomm && c == '-') {
  1340.       putchar('-');
  1341.       goto fin;
  1342.    }
  1343.    printtab[(unsigned char)c][1] ? 
  1344.        printf("%s", printtab[(unsigned char)c]) : putchar(c);
  1345.  fin:
  1346.    lastout = c;
  1347. }
  1348.  
  1349.  
  1350.  
  1351. /*
  1352.  *   Redefine Chartab from lgrindefs file
  1353.  */
  1354.    void
  1355. parsechartab(void)
  1356. {
  1357.     unsigned char *i=buf, *j=chartab, c;
  1358.     int  charnum=0;
  1359.  
  1360.     while (*i++!=':') {}
  1361.     while (c=*i++) {
  1362.       if (c==':') continue;
  1363.       charnum=(c>='0' && c<='9') ? (int)c-48 : tolower(c)-87;
  1364.       charnum=charnum << 4; c=*i++;
  1365.       charnum+=(c>='0' && c<='9') ? (int)c-48 : tolower(c)-87;
  1366.       i++;
  1367.  
  1368.       printtab[charnum]=j;
  1369.       while (*i!=':')
  1370.     if (*i=='\\') {
  1371.       switch (*++i) {
  1372.         case ':':  *j++=':'; break;
  1373.         case '\\': *j++='\\'; break;
  1374.       }; i++;
  1375.     } else *j++=*i++;
  1376.       *j++='\0';
  1377.     }
  1378.  
  1379. }
  1380.  
  1381.  
  1382. /*
  1383.  *    Look for a procedure beginning on this line
  1384.  */
  1385.    boolean
  1386. isprocNorm(unsigned char *s)
  1387. {
  1388.    pname[0] = '\0';
  1389.    if ((!l_toplex || blklevel == 0)
  1390.        && expmatch(s, l_prcbeg, (unsigned char **) NULL, pname) != NULL
  1391.        && expmatch(s, l_noproc, (unsigned char **) NULL, (unsigned char *) NULL) == NULL)
  1392.       return TRUE;
  1393.    return FALSE;
  1394. }
  1395.  
  1396. /*    Special version of the above for C functions */
  1397.    boolean 
  1398. isprocC(unsigned char *s)
  1399. {
  1400.    unsigned char        cheat[BUFFERSIZE];
  1401.    unsigned char        *j=s, *i=cheat;
  1402.    boolean    comm=FALSE, string=FALSE, schar=FALSE;
  1403.    int        brack=0;
  1404.  
  1405.    if (blklevel!=0) return FALSE;
  1406.    while (*j)
  1407.    {
  1408.      if (*j=='"' && !comm && !schar) string=(string+1)%2;
  1409.      else if (*j=='\'' && !comm && !string) schar=(schar+1)%2;
  1410.      else if (*j=='\\' && !comm) j++;
  1411.      else if (!comm && !string && !schar && *j=='{') brack++;   
  1412.      else if (!comm && !string && !schar && *j=='}') brack--;
  1413.      else if (!comm && !string && !schar && *j=='#') break;
  1414.      else if (!comm && !string && !schar && *j=='/' && *j+1=='/') break;
  1415.      else if (!comm && !string && !schar && *j=='/' && *j+1=='*') comm=TRUE;
  1416.      else if (         !string && !schar && *j=='*' && *j+1=='/') 
  1417.        {comm=FALSE; j++;}
  1418.      else if (!brack && !comm && !string && !schar)
  1419.        *i++=*j;
  1420.      j++;
  1421.    }
  1422.    *i = '\0';
  1423.  
  1424.    return isprocNorm(cheat);
  1425. }
  1426.  
  1427.  
  1428. /*
  1429.  * Get the identifier starting at @s@.    It is assumed that @s@ may indeed
  1430.  * start an identifier.  Value is %$>0$% for a keyword --- the count of
  1431.  * characters in the keyword --- and %$<0$% if not a keyword, in which
  1432.  * case the value returned is the negative of the number of bytes in
  1433.  * the matched identifier.
  1434.  *
  1435.  * This function checks @nokeyw@ and won't check to see if the
  1436.  * identifier found is a keyword if it is @TRUE@.
  1437.  */
  1438.    int
  1439. getid(unsigned char *s)
  1440. {
  1441.    unsigned char **ss    = l_keywds;
  1442.    int    i    = 1;
  1443.    unsigned char *cp    = s;
  1444.    int    firstc    = *s;
  1445.  
  1446.    while (++cp, isidchr(*cp))
  1447.       i++;
  1448.    if (nokeyw)
  1449.       return -i;
  1450.    while (cp = *ss++) {
  1451.       if (!l_onecase && firstc != *cp)
  1452.      continue;
  1453.       if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i]))
  1454.      return i;
  1455.    }
  1456.    return -i;
  1457. }
  1458.  
  1459.  
  1460.  
  1461. /*
  1462.  * @getredirection()@ is intended to aid in porting C programs
  1463.  * to VMS (Vax-11 C) which does not support %|>|% and %|<|%
  1464.  * I/O redirection.  With suitable modification, it may
  1465.  * useful for other portability problems as well.
  1466.  *
  1467.  * Modified, 24-Jan-86 by Jerry Leichter
  1468.  *    When creating a new output file, force the maximum record size to
  1469.  *    512; otherwise, it ends up as 0 (though the C I/O system won't write
  1470.  *    a record longer than 512 bytes anyway) which will cause problems if
  1471.  *    the file is later opened for @APPEND@ --- if the maximum record size
  1472.  *    is 0, C will use the length of the longest record written to the file
  1473.  *    for its buffer!
  1474.  */
  1475.  
  1476. #ifdef    vms
  1477. #  include    <stdio.h>
  1478. #  include    <errno.h>
  1479.  
  1480.    int
  1481. getredirection(argc, argv)
  1482.    int    argc;
  1483.    char **argv;
  1484. /*
  1485.  * Process VMS redirection args.  Exit if any error is seen.
  1486.  * If @getredirection()@ processes an argument, it is erased
  1487.  * from the vector.  @getredirection()@ returns a new @argc@ value.
  1488.  *
  1489.  * Warning: do not try to simplify the code for VMS.  The code
  1490.  * presupposes that @getredirection()@ is called before any data is
  1491.  * read from @stdin@ or written to @stdout@.
  1492.  *
  1493.  * Normal usage is as follows:
  1494.  *
  1495.  *@    main(argc, argv)
  1496.  *    int        argc;
  1497.  *    char        *argv[];
  1498.  *    {
  1499.  *        argc = getredirection(argc, argv);
  1500.  *    }@
  1501.  */
  1502. {
  1503.    register char    *ap;    /* Argument pointer */
  1504.    int            i;    /* @argv[]@ index */
  1505.    int            j;    /* Output index */
  1506.    int            file;    /* File_descriptor */
  1507.  
  1508.    for (j = i = 1; i < argc; i++) {   /* Do all arguments */
  1509.       switch (*(ap = argv[i])) {
  1510.       case '<':                 /* %|<file|% */
  1511.      if (freopen(++ap, "r", stdin) == NULL) {
  1512.         perror(ap);     /* Can't find file */
  1513.         exit(errno);    /* Is a fatal error */
  1514.      }
  1515.      break;
  1516.  
  1517.       case '>':                 /* %|>file|% or %|>>file|% */
  1518.      if (*++ap == '>') {    /* %|>>file|% */
  1519.         /*
  1520.          * If the file exists, and is writable by us,
  1521.          * call @freopen()@ to append to the file (using the
  1522.          * file's current attributes).  Otherwise, create
  1523.          * a new file with "vanilla" attributes as if
  1524.          * the argument was given as %|>filename|%.
  1525.          * @access(name, 2)@ is @TRUE@ if we can write on
  1526.          * the specified file.
  1527.          */
  1528.         if (access(++ap, 2) == 0) {
  1529.            if (freopen(ap, "a", stdout) != NULL)
  1530.           break;    /* Exit @case@ statement */
  1531.            perror(ap);    /* Error, can't append */
  1532.            exit(errno);    /* After @access@ test */
  1533.         }            /* If file accessable */
  1534.      }
  1535.      /*
  1536.       * On VMS, we want to create the file using "standard"
  1537.       * record attributes.    @create(...)@ creates the file
  1538.       * using the caller's default protection mask and
  1539.       * "variable length, implied carriage return"
  1540.       * attributes.  @dup2()@ associates the file with @stdout@.
  1541.       */
  1542.      if ((file = creat(ap, 0, "rat=cr", "rfm=var", "mrs=512")) == -1
  1543.          || dup2(file, fileno(stdout)) == -1) {
  1544.         perror(ap);     /* Can't create file    */
  1545.         exit(errno);    /* is a fatal error    */
  1546.      }            /* If %|>|% creation    */
  1547.      break;         /* Exit @case@ test    */
  1548.  
  1549.       default:
  1550.      argv[j++] = ap;    /* Not a redirector    */
  1551.      break;         /* Exit @case@ test    */
  1552.       }
  1553.    }                /* For all arguments    */
  1554.    argv[j] = NULL;        /* Terminate @argv[]@    */
  1555.    return j;            /* Return new @argc@    */
  1556. }
  1557.  
  1558. #else    /* @!vms@ */
  1559.  
  1560. getredirection(int argc, char *argv[])
  1561.    /*
  1562.     * Dummy routine.
  1563.     */
  1564. {
  1565.    return (argv[0], argc);
  1566. }
  1567.  
  1568. #endif    /* @!vms@ */
  1569.  
  1570. /*
  1571.  * Parses the %|lgrindefs|% file for a preamble
  1572.  */
  1573.    void
  1574. parsepreamble(unsigned char *destination)
  1575. {
  1576.     unsigned char *i=buf, *j=destination;
  1577.  
  1578.     while (*i++!=':') {}
  1579.     while (*i) {
  1580.       if (*i=='\\') {
  1581.     switch (*++i) {
  1582.       case 'n':  *j++='\n'; break;
  1583.       case 't':  *j++='\t'; break;
  1584.       case 'f':  *j++='\f'; break;
  1585.       case '\\': *j++='\\'; break;
  1586.       default:   fprintf(stderr, "Bad preamble entry: incorrect '\\'");
  1587.     }; i++;
  1588.       } else *j++=*i++;
  1589.     }
  1590. }
  1591.  
  1592. /*
  1593.  * Sets the default preambles
  1594.  */
  1595.    void
  1596. setpreambles(void)
  1597. {
  1598.     strcpy(preamble,
  1599. "\\documentclass[10pt,a4paper]{article}\n\
  1600. \\usepackage[procnames,noindent]{lgrind}\n\
  1601. \\usepackage{fancyhead}\n\
  1602. \\pagestyle{fancy}\n");
  1603.     strcpy(preambl2,
  1604. "\\lhead[\\fancyplain{}{\\bf\\thepage}]\
  1605. {\\fancyplain{}{\\bf \f}}\n\
  1606. \\rhead[\\fancyplain{}{\\bf \f}]\
  1607. {\\fancyplain{}{\\bf\\thepage}}\n\
  1608. \\cfoot{}\n");
  1609.     strcpy(config,"");
  1610. }
  1611.  
  1612. /*
  1613.  * prints a preamble, substituting %|\f|% with the current
  1614.  * file's name (sorry, no more form feeds)
  1615.  */
  1616.    void
  1617. printpreamble(unsigned char *string)
  1618. {
  1619.    int i;
  1620.    while (*string) {
  1621.     if(*string=='\f') {
  1622.         for(i=0;i<strlen(fname);i++) {
  1623.             if(fname[i]=='_') putchar('\\');
  1624.             putchar(fname[i]);
  1625.         }
  1626.         string++;
  1627.     }
  1628.     else putchar((*(string++)));
  1629.    }
  1630. /*
  1631.   This is the old while loop. It messed up if filenames
  1632.   contained '_' characters.
  1633.  
  1634.    while (*string) {
  1635.      (*string=='\f') ?
  1636.     (printf("%s", fname), string++)
  1637.       : putchar(*(string++));
  1638.    };
  1639. */
  1640. }
  1641.