~ubuntu-branches/ubuntu/oneiric/lgrind/oneiric

« back to all changes in this revision

Viewing changes to source/lgrind.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Piefel
  • Date: 2002-01-28 11:16:34 UTC
  • Revision ID: james.westby@ubuntu.com-20020128111634-gx07d7rqveysbcc1
Tags: upstream-3.67
ImportĀ upstreamĀ versionĀ 3.67

Show diffs side-by-side

added added

removed removed

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