LCOV - code coverage report
Current view: top level - preproc/grn - main.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 216 356 60.7 %
Date: 2026-01-16 17:51:41 Functions: 10 13 76.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Last non-groff version: main.c 1.23  (Berkeley)  85/08/05
       2             :  *
       3             :  * Originally written by Barry Roitblat, 1982.
       4             :  * Adapted to GNU troff by Daniel Senderowicz 99/12/29.
       5             :  * Further refinements by Werner Lemberg 00/02/20.
       6             :  * Modified 2000-2024 by the Free Software Foundation, Inc.
       7             :  *
       8             :  * This file contains no AT&T code and is in the public domain.
       9             :  *
      10             :  * This file contains the main and file system dependent routines for
      11             :  * processing gremlin files into troff input.  The program watches input
      12             :  * go by to standard output, only interpreting things between .GS and
      13             :  * .GE lines.  Default values (font, size, scale, thickness) may be
      14             :  * overridden with a 'default' command and are further overridden by
      15             :  * commands in the input.
      16             :  *
      17             :  * Inside the GS and GE, commands are accepted to reconfigure the
      18             :  * picture.  At most one command may reside on each line, and each
      19             :  * command is followed by a parameter separated by whitespace.  The
      20             :  * commands are as follows, and may be abbreviated down to one character
      21             :  * (with exception of 'scale' and 'stipple' down to "sc" and "st") and
      22             :  * may be upper or lower case.
      23             :  *
      24             :  *                        default  -  Make all settings in the current
      25             :  *                                    .GS/.GE the global defaults.
      26             :  *                                    Height, width and file are NOT
      27             :  *                                    saved.
      28             :  *                     1, 2, 3, 4  -  Set size 1, 2, 3, or 4 (followed
      29             :  *                                    by an integer point size).
      30             :  *  roman, italics, bold, special  -  Set gremlin's fonts to any other
      31             :  *                                    troff font (1 or 2 characters).
      32             :  *                     stipple, l  -  Use a stipple font for polygons.
      33             :  *                                    Arg is troff font name.  No
      34             :  *                                    default.  Can use only one stipple
      35             :  *                                    font per picture.  (See below for
      36             :  *                                    stipple font index.)
      37             :  *                       scale, x  -  Scale is IN ADDITION to the global
      38             :  *                                    scale factor from the default.
      39             :  *                     pointscale  -  Turn on scaling point sizes to
      40             :  *                                    match 'scale' commands.  (Optional
      41             :  *                                    operand 'off' to turn it off.)
      42             :  *          narrow, medium, thick  -  Set widths of lines.
      43             :  *                           file  -  Set the file name to read the
      44             :  *                                    gremlin picture from.  If the file
      45             :  *                                    isn't in the current directory,
      46             :  *                                    the gremlin library is tried.
      47             :  *                  width, height  -  These two commands override any
      48             :  *                                    scaling factor that is in effect,
      49             :  *                                    and forces the picture to fit into
      50             :  *                                    either the height or width
      51             :  *                                    specified, whichever makes the
      52             :  *                                    picture smaller.  The operand for
      53             :  *                                    these two commands is a
      54             :  *                                    floating-point number in units of
      55             :  *                                    inches.
      56             :  *            l<nn> (integer <nn>) -  Set association between stipple
      57             :  *                                    <nn> and a stipple 'character'.
      58             :  *                                    <nn> must be in the range 0 to
      59             :  *                                    NSTIPPLES (16) inclusive.  The
      60             :  *                                    integer operand is an index in the
      61             :  *                                    stipple font selected.  Valid cf
      62             :  *                                    (cifplot) indices are 1-32
      63             :  *                                    (although 24 is not defined),
      64             :  *                                    valid ug (unigrafix) indices are
      65             :  *                                    1-14, and valid gs (gray scale)
      66             :  *                                    indices are 0-16.  Nonetheless,
      67             :  *                                    any number between 0 and 255 is
      68             :  *                                    accepted since new stipple fonts
      69             :  *                                    may be added.  An integer operand
      70             :  *                                    is required.
      71             :  *
      72             :  * Troff number registers used: g1 through g9.  g1 is the width of the
      73             :  * picture, and g2 is the height.  g3, and g4, save information, g8 and
      74             :  * g9 are used for text processing and g5-g7 are reserved.
      75             :  */
      76             : 
      77             : #ifdef HAVE_CONFIG_H
      78             : #include <config.h>
      79             : #endif
      80             : 
      81             : #include "lib.h"
      82             : 
      83             : #include <ctype.h> // isdigit(), isupper(), tolower()
      84             : #include <errno.h>
      85             : #include <locale.h> // setlocale()
      86             : #include <stdio.h> // FILE, fclose(), fgets(), fopen(), fprintf(),
      87             :                    // fputs(), printf(), stderr, stdin, stdout
      88             : #include <stdlib.h> // exit(), EXIT_SUCCESS, free(), malloc()
      89             : #include <string.h> // strchr(), strcmp(), strcpy(), strerror(),
      90             :                     // strlen()
      91             : 
      92             : #include "device.h"
      93             : #include "font.h"
      94             : #include "gprint.h"
      95             : #include "searchpath.h"
      96             : #include "macropath.h"
      97             : 
      98             : #include "errarg.h"
      99             : #include "error.h"
     100             : #include "defs.h"
     101             : 
     102             : extern "C" const char *Version_string;
     103             : 
     104             : /* database imports */
     105             : 
     106             : extern void HGPrintElt(ELT *element, int baseline);
     107             : extern ELT *DBInit();
     108             : extern ELT *DBRead(FILE *file);
     109             : extern POINT *PTInit();
     110             : extern POINT *PTMakePoint(double x, double y, POINT **pplist);
     111             : 
     112             : #define INIT_FILE_SIZE 50  /* Initial sz of file array from cmd line. */
     113             : #define FILE_SIZE_INCR 50  /* Amount to increase array of files by. */
     114             : 
     115             : #define SUN_SCALEFACTOR 0.70
     116             : 
     117             : /* #define DEFSTIPPLE    "gs" */
     118             : #define DEFSTIPPLE      "cf"
     119             : /*
     120             :  * This grn implementation emits '.st' requests to control stipple
     121             :  * effects, but groff does not (currently) support any such request.
     122             :  *
     123             :  * This hack disables the emission of such requests, without destroying
     124             :  * the infrastructure necessary to support the feature in the future; to
     125             :  * enable the emission of '.st' requests, at a future date when groff
     126             :  * can support them, simply rewrite the following #define as:
     127             :  *
     128             :  *   #define USE_ST_REQUEST  stipple
     129             :  *
     130             :  * with accompanying comment: "emit '.st' requests as required".
     131             :  */
     132             : #define USE_ST_REQUEST  0       /* never emit '.st' requests */
     133             : 
     134             : #define MAXINLINE       100     /* input line length */
     135             : 
     136             : #define SCREENtoINCH    0.02    /* scaling factor, screen to inches */
     137             : 
     138             : #define BIG     999999999999.0  /* unwieldy large floating number */
     139             : 
     140             : 
     141             : /* static char sccsid[] = "@(#) (Berkeley) 8/5/85, 12/28/99"; */
     142             : 
     143             : int res;                        /* the printer's resolution goes here */
     144             : 
     145             : int dotshifter;                 /* for the length of dotted curves */
     146             : 
     147             : double linethickness;           /* brush styles */
     148             : int linmod;
     149             : int lastx;                      /* point registers for printing */
     150             : int lasty;                      /* elements                     */
     151             : int lastyline;                  /* A line's vertical position is NOT  */
     152             :                                 /* the same after that line is over,  */
     153             :                                 /* so for a line of drawing commands, */
     154             :                                 /* vertical spacing is kept in        */
     155             :                                 /* lastyline.                         */
     156             : 
     157             : /* These are the default fonts, sizes, line styles, */
     158             : /* and thicknesses.  They can be modified from a    */
     159             : /* 'default' command and are reset each time the    */
     160             : /* start of a picture (.GS) is found.               */
     161             : 
     162             : const char *deffont[] =
     163             : {"R", "I", "B", "S"};
     164             : int defsize[] =
     165             : {10, 16, 24, 36};
     166             : /* #define BASE_THICKNESS 1.0 */
     167             : #define BASE_THICKNESS 0.15
     168             : double defthick[STYLES] =
     169             : {1 * BASE_THICKNESS,
     170             :  1 * BASE_THICKNESS,
     171             :  5 * BASE_THICKNESS,
     172             :  1 * BASE_THICKNESS,
     173             :  1 * BASE_THICKNESS,
     174             :  3 * BASE_THICKNESS};
     175             : 
     176             : /* int cf_stipple_index[NSTIPPLES + 1] =                              */
     177             : /* {0, 1, 3, 12, 14, 16, 19, 21, 23};                                 */
     178             : /* a logarithmic scale looks better than a linear one for gray shades */
     179             : /*                                                                    */
     180             : /* int other_stipple_index[NSTIPPLES + 1] =                           */
     181             : /* {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};        */
     182             : 
     183             : int cf_stipple_index[NSTIPPLES + 1] =
     184             : {0, 18, 32, 56, 100, 178, 316, 562, 1000};      /* only 1-8 used */
     185             : int other_stipple_index[NSTIPPLES + 1] =
     186             : {0, 62, 125, 187, 250, 312, 375, 437, 500,
     187             :  562, 625, 687, 750, 812, 875, 937, 1000};
     188             : 
     189             : /* int *defstipple_index = other_stipple_index; */
     190             : int *defstipple_index = cf_stipple_index;
     191             : 
     192             : int style[STYLES] =
     193             : {DOTTED, DOTDASHED, SOLID, DASHED, SOLID, SOLID};
     194             : double scale = 1.0;             /* no scaling, default */
     195             : int defpoint = 0;               /* flag for point size scaling */
     196             : char *defstipple = (char *) 0;
     197             : enum E {
     198             :   OUTLINE, FILL, BOTH
     199             : } polyfill;
     200             : 
     201             : /* flag to control filling of polygons */
     202             : 
     203             : double adj1 = 0.0;
     204             : double adj2 = 0.0;
     205             : double adj3 = 0.0;
     206             : double adj4 = 0.0;
     207             : 
     208             : double thick[STYLES];           /* thicknesses set by defaults, then  */
     209             :                                 /* by commands                        */
     210             : char *tfont[FONTS];             /* fonts originally set to deffont    */
     211             :                                 /* values, then optionally changed by */
     212             : int tsize[SIZES];               /* commands inside grn                */
     213             : int stipple_index[NSTIPPLES + 1];       /* stipple font file indices  */
     214             : char *stipple;
     215             : 
     216             : double xscale;          /* scaling factor from individual pictures */
     217             : double troffscale;      /* scaling factor at output time */
     218             : 
     219             : double width;           /* user-request maximum width for picture */
     220             :                         /* (in inches)                            */
     221             : double height;          /* user-request height */
     222             : int pointscale;         /* flag for point size scaling */
     223             : int setdefault;         /* flag for a .GS/.GE to remember all */
     224             :                         /* settings                           */
     225             : int sflag;              /* -s flag: sort order (do polyfill first) */
     226             : 
     227             : double toppoint;        /* remember the picture */
     228             : double bottompoint;     /* bounds in these variables */
     229             : double leftpoint;
     230             : double rightpoint;
     231             : 
     232             : int ytop;               /* these are integer versions of the above */
     233             : int ybottom;            /* so not to convert each time they're used */
     234             : int xleft;
     235             : int xright;
     236             : 
     237             : static int linenum = 0;         /* line number of troff input file */
     238             : char inputline[MAXINLINE];      /* spot to filter through the file */
     239             : char *c1 = inputline;           /* c1, c2, and c3 will be used to */
     240             : char *c2 = inputline + 1;       /* hunt for lines that begin with */
     241             : char *c3 = inputline + 2;       /* '.GS' by looking individually */
     242             : char *c4 = inputline + 3;       /* needed for compatibility mode */
     243             : char GScommand[MAXINLINE];      /* put user's '.GS' command line here */
     244             : char gremlinfile[MAXINLINE];    /* filename to use for a picture */
     245             : int SUNFILE = FALSE;            /* TRUE if SUN gremlin file */
     246             : int compatibility_flag = FALSE; /* TRUE if in compatibility mode */
     247             : 
     248             : 
     249             : void getres();
     250             : int doinput(FILE *fp);
     251             : void conv(FILE *fp, int baseline);
     252             : void savestate();
     253             : int has_polygon(ELT *elist);
     254             : void interpret(char *line);
     255             : 
     256             : void *
     257        2160 : grnmalloc(size_t size,
     258             :           const char *what)
     259             : {
     260        2160 :   void *ptr = 0;
     261        2160 :   ptr = malloc(size);
     262        2160 :   if (!ptr) {
     263           0 :     fatal("memory allocation failed for %1: %2", what, strerror(errno));
     264             :   }
     265        2160 :   return ptr;
     266             : }
     267             : 
     268             : void
     269           0 : usage(FILE *stream)
     270             : {
     271           0 :   fprintf(stream,
     272             :           "usage: %s [-Cs] [-M dir] [-F dir] [-T dev] [file ...]\n"
     273             :           "usage: %s {-v | --version}\n"
     274             :           "usage: %s --help\n",
     275             :           program_name, program_name, program_name);
     276           0 :   if (stdout == stream)
     277           0 :     fputs("\n"
     278             : "Preprocess troff(1) input to incorporate gremlin image files.  See\n"
     279             : "the grn(1) manual page.\n", stream);
     280           0 : }
     281             : 
     282             : 
     283             : /* Add a new file entry in the array, expanding array if needs be. */
     284             : 
     285             : char **
     286           1 : add_file(char **file,
     287             :          char *new_file,
     288             :          int *count,
     289             :          int *cur_size)
     290             : {
     291           1 :   if (*count >= *cur_size) {
     292           0 :     *cur_size += FILE_SIZE_INCR;
     293           0 :     file = (char **) realloc(file, *cur_size * sizeof(char *));
     294           0 :     if (file == NULL) {
     295           0 :       fatal("unable to extend file array");
     296             :     }
     297             :   }
     298           1 :   file[*count] = new_file;
     299           1 :   *count += 1;
     300             : 
     301           1 :   return file;
     302             : }
     303             : 
     304             : 
     305             : /*--------------------------------------------------------------------*
     306             :  | Routine:     main (argument_count, argument_pointer)
     307             :  |
     308             :  | Results:     Parses the command line, accumulating input file names,
     309             :  |              then reads the inputs, passing it directly to output
     310             :  |              until a '.GS' line is read.  Main then passes control to
     311             :  |              'conv' to do the gremlin file conversions.
     312             :  *--------------------------------------------------------------------*/
     313             : 
     314             : int
     315          18 : main(int argc,
     316             :      char **argv)
     317             : {
     318          18 :   setlocale(LC_NUMERIC, "C");
     319          18 :   program_name = argv[0];
     320             :   FILE *fp;
     321             :   int k;
     322             :   char c;
     323          18 :   int gfil = 0;
     324          18 :   char **file = NULL;
     325          18 :   int file_cur_size = INIT_FILE_SIZE;
     326             :   char *operand(int *argcp, char ***argvp);
     327             : 
     328          18 :   file = (char **) grnmalloc(file_cur_size * sizeof(char *),
     329             :                              "file array");
     330         108 :   while (--argc) {
     331          90 :     if (**++argv != '-')
     332           1 :       file = add_file(file, *argv, &gfil, &file_cur_size);
     333             :     else
     334          89 :       switch (c = (*argv)[1]) {
     335             : 
     336           0 :       case 0:
     337           0 :         file = add_file(file, NULL, &gfil, &file_cur_size);
     338           0 :         break;
     339             : 
     340           0 :       case 'C':         /* compatibility mode */
     341           0 :         compatibility_flag = TRUE;
     342           0 :         break;
     343             : 
     344           1 :       case 'F':         /* font path to find DESC */
     345           1 :         font::command_line_font_dir(operand(&argc, &argv));
     346           1 :         break;
     347             : 
     348          17 :       case 'T':         /* final output typesetter name */
     349          17 :         device = operand(&argc, &argv);
     350          17 :         break;
     351             : 
     352          71 :       case 'M':         /* set library directory */
     353          71 :         macro_path.command_line_dir(operand(&argc, &argv));
     354          71 :         break;
     355             : 
     356           0 :       case 's':         /* preserve order of elements */
     357           0 :         sflag = 1;
     358           0 :         break;
     359             : 
     360           0 :       case '-':
     361           0 :         if (strcmp(*argv,"--version")==0) {
     362             :       case 'v':
     363           0 :           printf("GNU grn (groff) version %s\n", Version_string);
     364           0 :           exit(EXIT_SUCCESS);
     365             :           break;
     366             :         }
     367           0 :         if (strcmp(*argv,"--help")==0) {
     368             :       case '?':
     369           0 :           usage(stdout);
     370           0 :           exit(EXIT_SUCCESS);
     371             :           break;
     372             :         }
     373             :         // fallthrough
     374             :       default:
     375           0 :         error("unrecognized command-line option '%1'", *argv);
     376           0 :         usage(stderr);
     377           0 :         exit(2);
     378             :       }
     379             :   }
     380             : 
     381          18 :   getres();             /* set the resolution for an output device */
     382             : 
     383          18 :   if (gfil == 0) {              /* no filename, use standard input */
     384          17 :     file[0] = NULL;
     385          17 :     gfil++;
     386             :   }
     387             : 
     388          36 :   for (k = 0; k < gfil; k++) {
     389          18 :     if (file[k] != NULL) {
     390           1 :       if ((fp = fopen(file[k], "r")) == NULL)
     391           0 :         fatal("can't open %1", file[k]);
     392             :     } else
     393          17 :       fp = stdin;
     394             : 
     395       12396 :     while (doinput(fp)) {
     396       12378 :       if (*c1 == '.' && *c2 == 'G' && *c3 == 'S') {
     397           1 :         if (compatibility_flag ||
     398           1 :             *c4 == '\n' || *c4 == ' ' || *c4 == '\0')
     399           1 :           conv(fp, linenum);
     400             :         else
     401           0 :           fputs(inputline, stdout);
     402             :       } else
     403       12377 :         fputs(inputline, stdout);
     404             :     }
     405             :   }
     406             : 
     407          18 :   return 0;
     408             : }
     409             : 
     410             : 
     411             : /*--------------------------------------------------------------------*
     412             :  | Routine:     char  * operand (& argc, & argv)
     413             :  |
     414             :  | Results:     Returns address of the operand given with a command-line
     415             :  |              option.  It uses either '-Xoperand' or '-X operand',
     416             :  |              whichever is present.  The program is terminated if no
     417             :  |              option is present.
     418             :  |
     419             :  | Side Efct:   argc and argv are updated as necessary.
     420             :  *--------------------------------------------------------------------*/
     421             : 
     422             : char *
     423          89 : operand(int *argcp,
     424             :         char ***argvp)
     425             : {
     426          89 :   if ((**argvp)[2])
     427          88 :     return (**argvp + 2);       /* operand immediately follows */
     428           1 :   if ((--*argcp) <= 0) {     /* no operand */
     429           0 :     error("command-line option operand missing.");
     430           0 :     exit(8);
     431             :   }
     432           1 :   return (*(++(*argvp)));       /* operand is next word */
     433             : }
     434             : 
     435             : 
     436             : /*--------------------------------------------------------------------*
     437             :  | Routine:     getres ()
     438             :  |
     439             :  | Results:     Sets 'res' to the resolution of the output device.
     440             :  *--------------------------------------------------------------------*/
     441             : 
     442             : void
     443          18 : getres()
     444             : {
     445             :   int linepiece;
     446             : 
     447          18 :   if (0 /* nullptr */ == font::load_desc())
     448           0 :     fatal("cannot load 'DESC' description file for device '%1'",
     449           0 :           device);
     450             : 
     451          18 :   res = font::res;
     452             : 
     453             :   /* Correct the brush thicknesses based on res */
     454             :   /* if (res >= 256) {
     455             :       defthick[0] = res >> 8;
     456             :       defthick[1] = res >> 8;
     457             :       defthick[2] = res >> 4;
     458             :       defthick[3] = res >> 8;
     459             :       defthick[4] = res >> 8;
     460             :       defthick[5] = res >> 6;
     461             :       } */
     462             : 
     463          18 :   linepiece = res >> 9;
     464         138 :   for (dotshifter = 0; linepiece; dotshifter++)
     465         120 :     linepiece = linepiece >> 1;
     466          18 : }
     467             : 
     468             : 
     469             : /*--------------------------------------------------------------------*
     470             :  | Routine:     int  doinput (file_pointer)
     471             :  |
     472             :  | Results:     A line of input is read into 'inputline'.
     473             :  |
     474             :  | Side Efct:   "linenum" is incremented.
     475             :  |
     476             :  | Bugs:        Lines longer than MAXINLINE are NOT checked, except for
     477             :  |              updating 'linenum'.
     478             :  *--------------------------------------------------------------------*/
     479             : 
     480             : int
     481       12407 : doinput(FILE *fp)
     482             : {
     483       12407 :   if (fgets(inputline, MAXINLINE, fp) == NULL)
     484          18 :     return 0;
     485       12389 :   if (strchr(inputline, '\n'))  /* ++ only if it's a complete line */
     486       12372 :     linenum++;
     487       12389 :   return 1;
     488             : }
     489             : 
     490             : 
     491             : /*--------------------------------------------------------------------*
     492             :  | Routine:     initpic ( )
     493             :  |
     494             :  | Results:     Sets all parameters to the normal defaults, possibly
     495             :  |              overridden by a setdefault command.  Initialize the
     496             :  |              picture variables, and output the startup commands to
     497             :  |              troff to begin the picture.
     498             :  *--------------------------------------------------------------------*/
     499             : 
     500             : void
     501           1 : initpic()
     502             : {
     503             :   int i;
     504             : 
     505           7 :   for (i = 0; i < STYLES; i++) {     /* line thickness defaults */
     506           6 :     thick[i] = defthick[i];
     507             :   }
     508           5 :   for (i = 0; i < FONTS; i++) {              /* font name defaults */
     509           4 :     tfont[i] = (char *)deffont[i];
     510             :   }
     511           5 :   for (i = 0; i < SIZES; i++) {              /* font size defaults */
     512           4 :     tsize[i] = defsize[i];
     513             :   }
     514          18 :   for (i = 0; i <= NSTIPPLES; i++) { /* stipple font file default */
     515             :                                         /* indices                   */
     516          17 :     stipple_index[i] = defstipple_index[i];
     517             :   }
     518           1 :   stipple = defstipple;
     519             : 
     520           1 :   gremlinfile[0] = 0;           /* filename is 'null' */
     521           1 :   setdefault = 0;               /* not the default settings (yet) */
     522             : 
     523           1 :   toppoint = BIG;               /* set the picture bounds out */
     524           1 :   bottompoint = -BIG;           /* of range so they'll be set */
     525           1 :   leftpoint = BIG;              /* by 'savebounds' on input */
     526           1 :   rightpoint = -BIG;
     527             : 
     528           1 :   pointscale = defpoint;/* flag for scaling point sizes default */
     529           1 :   xscale = scale;       /* default scale of individual pictures */
     530           1 :   width = 0.0;          /* size specifications input by user */
     531           1 :   height = 0.0;
     532             : 
     533           1 :   linethickness = DEFTHICK;     /* brush styles */
     534           1 :   linmod = DEFSTYLE;
     535           1 : }
     536             : 
     537             : 
     538             : /*--------------------------------------------------------------------*
     539             :  | Routine:     conv (file_pointer, starting_line)
     540             :  |
     541             :  | Results:     At this point, we just passed a '.GS' line in the input
     542             :  |              file.  conv reads the input and calls 'interpret' to
     543             :  |              process commands, gathering up information until a '.GE'
     544             :  |              line is found.  It then calls 'HGPrint' to do the
     545             :  |              translation of the gremlin file to troff commands.
     546             :  *--------------------------------------------------------------------*/
     547             : 
     548             : void
     549           1 : conv(FILE *fp,
     550             :      int baseline)
     551             : {
     552           1 :   FILE *gfp = NULL;     /* input file pointer */
     553           1 :   int done = 0; /* flag to remember if finished */
     554             :   ELT *e;               /* current element pointer */
     555             :   ELT *PICTURE;         /* whole picture data base pointer */
     556             :   double temp;          /* temporary calculating area */
     557             :   /* POINT ptr; */      /* coordinates of a point to pass to 'mov' */
     558             :                         /* routine                                 */
     559             :   int flyback;          /* flag 'want to end up at the top of the */
     560             :                         /* picture?'                              */
     561             :   int compat;           /* test character after .GE or .GF */
     562             : 
     563             : 
     564           1 :   initpic();                    /* set defaults, ranges, etc. */
     565           1 :   strcpy(GScommand, inputline); /* save '.GS' line for later */
     566             : 
     567          10 :   do {
     568          11 :     done = !doinput(fp);                /* test for EOF */
     569          11 :     flyback = (*c3 == 'F');             /* and .GE or .GF */
     570          33 :     compat = (compatibility_flag ||
     571          11 :               *c4 == '\n' || *c4 == ' ' || *c4 == '\0');
     572          11 :     done |= (*c1 == '.' && *c2 == 'G' && (*c3 == 'E' || flyback) &&
     573             :              compat);
     574             : 
     575          11 :     if (done) {
     576           1 :       if (setdefault)
     577           0 :         savestate();
     578             : 
     579           1 :       if (!gremlinfile[0]) {
     580           0 :         if (!setdefault)
     581           0 :           error("no picture file name at line %1", baseline);
     582           0 :         return;
     583             :       }
     584             :       char *path;
     585           1 :       gfp = macro_path.open_file(gremlinfile, &path);
     586           1 :       if (0 /* nullptr */ == gfp) {
     587           0 :         error("cannot open picture file '%1': %2", gremlinfile,
     588           0 :               strerror(errno));
     589           0 :         return;
     590             :       }
     591           1 :       PICTURE = DBRead(gfp);    /* read picture file */
     592           1 :       fclose(gfp);
     593           1 :       free(path);
     594           1 :       if (DBNullelt(PICTURE))
     595           0 :         return;                 /* If a request is made to make the  */
     596             :                                 /* picture fit into a specific area, */
     597             :                                 /* set the scale to do that.         */
     598             : 
     599           1 :       if (stipple == (char *) NULL)     /* if user forgot stipple    */
     600           0 :         if (has_polygon(PICTURE))       /* and picture has a polygon */
     601           0 :           stipple = (char *)DEFSTIPPLE; /* then set the default      */
     602             : 
     603           1 :       if ((temp = bottompoint - toppoint) < 0.1)
     604           0 :         temp = 0.1;
     605           1 :       temp = (height != 0.0) ? height / (temp * SCREENtoINCH) : BIG;
     606           1 :       if ((troffscale = rightpoint - leftpoint) < 0.1)
     607           0 :         troffscale = 0.1;
     608           1 :       troffscale = (width != 0.0) ?
     609           1 :           width / (troffscale * SCREENtoINCH) : BIG;
     610           1 :       if (temp == BIG && troffscale == BIG)
     611           0 :         troffscale = xscale;
     612             :       else {
     613           1 :         if (temp < troffscale)
     614           0 :           troffscale = temp;
     615             :       }                         /* here, troffscale is the  */
     616             :                                 /* picture's scaling factor */
     617           1 :       if (pointscale) {
     618             :         int i;                  /* do point scaling here, when   */
     619             :                                 /* scale is known, before output */
     620           0 :         for (i = 0; i < SIZES; i++)
     621           0 :           tsize[i] = (int) (troffscale * (double) tsize[i] + 0.5);
     622             :       }
     623             : 
     624             :                                         /* change to device units */
     625           1 :       troffscale *= SCREENtoINCH * res; /* from screen units      */
     626             : 
     627             :       /* Calculate integer versions of the picture limits. */
     628           1 :       ytop = (int) (toppoint * troffscale);
     629           1 :       ybottom = (int) (bottompoint * troffscale);
     630           1 :       xleft = (int) (leftpoint * troffscale);
     631           1 :       xright = (int) (rightpoint * troffscale);
     632             : 
     633             :       /* save stuff in number registers,    */
     634             :       /*   register g1 = picture width and  */
     635             :       /*   register g2 = picture height,    */
     636             :       /*   set vertical spacing, no fill,   */
     637             :       /*   and break (to make sure picture  */
     638             :       /*   starts on left), and put out the */
     639             :       /*   user's '.GS' line.               */
     640           1 :       printf(".br\n"
     641             :              ".nr g1 %du\n"
     642             :              ".nr g2 %du\n"
     643             :              "%s"
     644             :              ".nr g3 \\n(.f\n"
     645             :              ".nr g4 \\n(.s\n"
     646             :              "\\0\n"
     647             :              ".sp -1\n",
     648             :              xright - xleft, ybottom - ytop, GScommand);
     649             : 
     650             :       if (USE_ST_REQUEST)       /* stipple requested for this picture */
     651             :         printf(".st %s\n", stipple);
     652           1 :       lastx = xleft;            /* note where we are (upper left */
     653           1 :       lastyline = lasty = ytop; /* corner of the picture)        */
     654             : 
     655             :       /* Just dump everything in the order it appears.
     656             :        *
     657             :        * If -s command-line option, traverse picture twice: First time,
     658             :        * print only the interiors of filled polygons (as borderless
     659             :        * polygons).  Second time, print the outline as series of line
     660             :        * segments.  This way, postprocessors that overwrite rather than
     661             :        * merge picture elements (such as Postscript) can still have text
     662             :        * and graphics on a shaded background.
     663             :        */
     664             :       /* if (sflag) */
     665           1 :       if (!sflag) {     /* changing the default for filled polygons */
     666           1 :         e = PICTURE;
     667           1 :         polyfill = FILL;
     668         415 :         while (!DBNullelt(e)) {
     669         414 :           printf(".mk\n");
     670         414 :           if (e->type == POLYGON)
     671          36 :             HGPrintElt(e, baseline);
     672         414 :           printf(".rt\n");
     673         414 :           lastx = xleft;
     674         414 :           lastyline = lasty = ytop;
     675         414 :           e = DBNextElt(e);
     676             :         }
     677             :       }
     678           1 :       e = PICTURE;
     679             : 
     680             :       /* polyfill = !sflag ? BOTH : OUTLINE; */
     681           1 :       polyfill = sflag ? BOTH : OUTLINE;        /* changing default */
     682         415 :       while (!DBNullelt(e)) {
     683         414 :         printf(".mk\n");
     684         414 :         HGPrintElt(e, baseline);
     685         414 :         printf(".rt\n");
     686         414 :         lastx = xleft;
     687         414 :         lastyline = lasty = ytop;
     688         414 :         e = DBNextElt(e);
     689             :       }
     690             : 
     691             :       /* decide where to end picture */
     692             : 
     693             :       /* I [Senderowicz?] changed everything here.  I always use the */
     694             :       /* combination .mk and .rt, so once finished I just space down */
     695             :       /* height of the picture that is \n(g2u.                       */
     696           1 :       if (flyback) {            /* end picture at upper left */
     697             :         /* ptr.x = leftpoint;
     698             :            ptr.y = toppoint; */
     699             :       } else {                  /* end picture at lower left */
     700             :         /* ptr.x = leftpoint;
     701             :            ptr.y = bottompoint; */
     702           1 :         printf(".sp \\n(g2u\n");
     703             :       }
     704             : 
     705             :       /* tmove(&ptr); */    /* restore default line parameters */
     706             : 
     707             :       /* Restore everything to the way it was before the .GS, then */
     708             :       /* put out the '.GE' line from user                          */
     709             : 
     710             :       /* printf("\\D't %du'\\D's %du'\n", DEFTHICK, DEFSTYLE); */
     711             :       /* groff doesn't understand the \Ds command */
     712             : 
     713           1 :       printf("\\D't %du'\n", DEFTHICK);
     714           1 :       if (flyback)              /* make sure we end up at top of */
     715           0 :         printf(".sp -1\n");   /* picture if 'flying back'      */
     716             :       if (USE_ST_REQUEST)       /* restore stipple to previous */
     717             :         printf(".st\n");
     718           1 :       printf(".br\n"
     719             :              ".ft \\n(g3\n"
     720             :              ".ps \\n(g4\n"
     721             :              "%s", inputline);
     722             :     } else
     723          10 :       interpret(inputline);     /* take commands from the input file */
     724          11 :   } while (!done);
     725             : }
     726             : 
     727             : 
     728             : /*--------------------------------------------------------------------*
     729             :  | Routine:     savestate  ( )
     730             :  |
     731             :  | Results:     All the current scaling/font size/font name/thickness/
     732             :  |              pointscale settings are made the defaults.  Scaled
     733             :  |              point sizes are NOT saved.  The scaling is done each
     734             :  |              time a new picture is started.
     735             :  |
     736             :  | Side Efct:   scale, and def* are modified.
     737             :  *--------------------------------------------------------------------*/
     738             : 
     739             : void
     740           0 : savestate()
     741             : {
     742             :   int i;
     743             : 
     744           0 :   for (i = 0; i < STYLES; i++)       /* line thickness defaults */
     745           0 :     defthick[i] = thick[i];
     746           0 :   for (i = 0; i < FONTS; i++)        /* font name defaults */
     747           0 :     deffont[i] = tfont[i];
     748           0 :   for (i = 0; i < SIZES; i++)        /* font size defaults */
     749           0 :     defsize[i] = tsize[i];
     750             :   /* stipple font file default indices */
     751           0 :   for (i = 0; i <= NSTIPPLES; i++)
     752           0 :     defstipple_index[i] = stipple_index[i];
     753             : 
     754           0 :   defstipple = stipple; /* if stipple has been set, it's remembered */
     755           0 :   scale *= xscale;      /* default scale of individual pictures */
     756           0 :   defpoint = pointscale;/* flag to scale point sizes from x factors */
     757           0 : }
     758             : 
     759             : 
     760             : /*--------------------------------------------------------------------*
     761             :  | Routine:     savebounds (x_coordinate, y_coordinate)
     762             :  |
     763             :  | Results:     Keeps track of the maximum and minimum extent of a
     764             :  |              picture in the global variables: left-, right-, top- and
     765             :  |              bottompoint.  'savebounds' assumes that the points have
     766             :  |              been oriented to the correct direction.  No scaling has
     767             :  |              taken place, though.
     768             :  *--------------------------------------------------------------------*/
     769             : 
     770             : void
     771        1309 : savebounds(double x,
     772             :            double y)
     773             : {
     774        1309 :   if (x < leftpoint)
     775          16 :     leftpoint = x;
     776        1309 :   if (x > rightpoint)
     777          15 :     rightpoint = x;
     778        1309 :   if (y < toppoint)
     779           7 :     toppoint = y;
     780        1309 :   if (y > bottompoint)
     781           9 :     bottompoint = y;
     782        1309 : }
     783             : 
     784             : 
     785             : /*--------------------------------------------------------------------*
     786             :  | Routine:     interpret (character_string)
     787             :  |
     788             :  | Results:     Commands are taken from the input string and performed.
     789             :  |              Commands are separated by newlines, and are of the
     790             :  |              format:
     791             :  |                      string1 string2
     792             :  |              where string1 is the command, string2 the argument.
     793             :  |
     794             :  | Side Efct:   Font and size strings, plus the gremlin file name and
     795             :  |              the width and height variables are set by this routine.
     796             :  *--------------------------------------------------------------------*/
     797             : 
     798             : void
     799          10 : interpret(char *line)
     800             : {
     801             :   char str1[MAXINLINE];
     802             :   char str2[MAXINLINE];
     803             :   char *chr;
     804             :   int i;
     805             :   double par;
     806             : 
     807          10 :   str2[0] = '\0';
     808          10 :   sscanf(line, "%80s%80s", &str1[0], &str2[0]);
     809          60 :   for (chr = &str1[0]; *chr; chr++) /* convert command to */
     810          50 :     if (isupper(*chr))
     811           0 :       *chr = tolower(*chr);     /* lower case */
     812             : 
     813          10 :   switch (str1[0]) {
     814             : 
     815           0 :   case '1':
     816             :   case '2':                     /* font sizes */
     817             :   case '3':
     818             :   case '4':
     819           0 :     i = atoi(str2);
     820           0 :     if (i > 0 && i < 1000)
     821           0 :       tsize[str1[0] - '1'] = i;
     822             :     else
     823           0 :       error("bad font size value at line %1", linenum);
     824           0 :     break;
     825             : 
     826           1 :   case 'r':                     /* roman */
     827           1 :     if (str2[0] < '0')
     828           0 :       goto nofont;
     829           1 :     tfont[0] = (char *) grnmalloc(strlen(str2) + 1, "roman command");
     830           1 :     strcpy(tfont[0], str2);
     831           1 :     break;
     832             : 
     833           1 :   case 'i':                     /* italics */
     834           1 :     if (str2[0] < '0')
     835           0 :       goto nofont;
     836           1 :     tfont[1] = (char *) grnmalloc(strlen(str2) + 1, "italics command");
     837           1 :     strcpy(tfont[1], str2);
     838           1 :     break;
     839             : 
     840           1 :   case 'b':                     /* bold */
     841           1 :     if (str2[0] < '0')
     842           0 :       goto nofont;
     843           1 :     tfont[2] = (char *) grnmalloc(strlen(str2) + 1, "bold command");
     844           1 :     strcpy(tfont[2], str2);
     845           1 :     break;
     846             : 
     847           1 :   case 's':                     /* special */
     848           1 :     if (str1[1] == 'c')
     849           0 :       goto scalecommand;        /* or scale */
     850             : 
     851           1 :     if (str2[0] < '0') {
     852           0 :   nofont:
     853           0 :       error("no font name specified in line %1", linenum);
     854           0 :       break;
     855             :     }
     856           1 :     if (str1[1] == 't')
     857           0 :       goto stipplecommand;      /* or stipple */
     858             : 
     859           1 :     tfont[3] = (char *) grnmalloc(strlen(str2) + 1, "special command");
     860           1 :     strcpy(tfont[3], str2);
     861           1 :     break;
     862             : 
     863           1 :   case 'l':                     /* l */
     864           1 :     if (isdigit(str1[1])) {     /* set stipple index */
     865           0 :       int idx = atoi(str1 + 1), val;
     866             : 
     867           0 :       if (idx < 0 || idx > NSTIPPLES) {
     868           0 :         error("bad stipple number %1 at line %2", idx, linenum);
     869           0 :         break;
     870             :       }
     871           0 :       if (!defstipple_index)
     872           0 :         defstipple_index = other_stipple_index;
     873           0 :       val = atoi(str2);
     874           0 :       if (val >= 0 && val < 256)
     875           0 :         stipple_index[idx] = val;
     876             :       else
     877           0 :         error("bad stipple index value at line %1", linenum);
     878           0 :       break;
     879             :     }
     880             : 
     881           1 :   stipplecommand:               /* set stipple name */
     882           1 :     stipple = (char *) grnmalloc(strlen(str2) + 1, "stipple command");
     883           1 :     strcpy(stipple, str2);
     884             :     /* if it's a 'known' font (currently only 'cf'), set indices    */
     885           1 :     if (strcmp(stipple, "cf") == 0)
     886           0 :       defstipple_index = cf_stipple_index;
     887             :     else
     888           1 :       defstipple_index = other_stipple_index;
     889          18 :     for (i = 0; i <= NSTIPPLES; i++)
     890          17 :       stipple_index[i] = defstipple_index[i];
     891           1 :     break;
     892             : 
     893           0 :   case 'a':                     /* text adjust */
     894           0 :     par = atof(str2);
     895           0 :     switch (str1[1]) {
     896           0 :     case '1':
     897           0 :       adj1 = par;
     898           0 :       break;
     899           0 :     case '2':
     900           0 :       adj2 = par;
     901           0 :       break;
     902           0 :     case '3':
     903           0 :       adj3 = par;
     904           0 :       break;
     905           0 :     case '4':
     906           0 :       adj4 = par;
     907           0 :       break;
     908           0 :     default:
     909           0 :       error("bad adjust command at line %1", linenum);
     910           0 :       break;
     911             :     }
     912           0 :     break;
     913             : 
     914           1 :   case 't':                     /* thick */
     915           1 :     thick[2] = defthick[0] * atof(str2);
     916           1 :     break;
     917             : 
     918           1 :   case 'm':                     /* medium */
     919           1 :     thick[5] = defthick[0] * atof(str2);
     920           1 :     break;
     921             : 
     922           1 :   case 'n':                     /* narrow */
     923           1 :     thick[0] = thick[1] = thick[3] = thick[4] =
     924           1 :         defthick[0] * atof(str2);
     925           1 :     break;
     926             : 
     927             :   case 'x':                     /* x */
     928           0 :   scalecommand:                 /* scale */
     929           0 :     par = atof(str2);
     930           0 :     if (par > 0.0)
     931           0 :       xscale *= par;
     932             :     else
     933           0 :       error("invalid scale value on line %1", linenum);
     934           0 :     break;
     935             : 
     936           1 :   case 'f':                     /* file */
     937           1 :     strcpy(gremlinfile, str2);
     938           1 :     break;
     939             : 
     940           1 :   case 'w':                     /* width */
     941           1 :     width = atof(str2);
     942           1 :     if (width < 0.0)
     943           0 :       width = -width;
     944           1 :     break;
     945             : 
     946           0 :   case 'h':                     /* height */
     947           0 :     height = atof(str2);
     948           0 :     if (height < 0.0)
     949           0 :       height = -height;
     950           0 :     break;
     951             : 
     952           0 :   case 'd':                     /* defaults */
     953           0 :     setdefault = 1;
     954           0 :     break;
     955             : 
     956           0 :   case 'p':                     /* pointscale */
     957           0 :     if (strcmp("off", str2))
     958           0 :       pointscale = 1;
     959             :     else
     960           0 :       pointscale = 0;
     961           0 :     break;
     962             : 
     963           0 :   default:
     964           0 :     error("unknown command '%1' on line %2", str1, linenum);
     965           0 :     exit(8);
     966             :     break;
     967             :   };
     968          10 : }
     969             : 
     970             : 
     971             : /*
     972             :  * return TRUE if picture contains a polygon
     973             :  * otherwise FALSE
     974             :  */
     975             : 
     976             : int
     977           0 : has_polygon(ELT *elist)
     978             : {
     979           0 :   while (!DBNullelt(elist)) {
     980           0 :     if (elist->type == POLYGON)
     981           0 :       return (1);
     982           0 :     elist = DBNextElt(elist);
     983             :   }
     984             : 
     985           0 :   return (0);
     986             : }
     987             : 
     988             : // Local Variables:
     989             : // fill-column: 72
     990             : // mode: C++
     991             : // End:
     992             : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:

Generated by: LCOV version 1.14