File: aspic.c

package info (click to toggle)
aspic 1.05-4
  • links: PTS
  • area: main
  • in suites: bullseye, buster, jessie, jessie-kfreebsd, stretch, wheezy
  • size: 2,092 kB
  • sloc: ansic: 5,786; xml: 3,852; sh: 226; makefile: 67
file content (431 lines) | stat: -rw-r--r-- 13,053 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
/*************************************************
*                      ASPIC                     *
*************************************************/
 
/* Copyright (c) University of Cambridge 1991 - 2008 */
/* Created: February 1991 */
/* Last modified: March 2008 */
 
/* ASPIC is an Amazingly Simple PICture composing program. It reads a
description of a "line-art" picture from a file and outputs commands for
another program to draw it. Typically the other program is a text processor,
and sometimes ASPIC can be called dynamically from within such processors,
enabling its input to be embedded within the text processor's source.

Aspic used only to support output for SGCAL. Now it also supports encapsulated 
PostScript and SVG (Scalable Vector Graphics), and the SGCAL support has become 
a legacy feature. */
 
 
#include "aspic.h"
 
 

/*************************************************
*                 Global variables               *
*************************************************/
 
FILE *main_input;
FILE *out_file;

includestr *included_from = NULL; /* chain for included files */
uschar **file_line_stack;         /* line stack for included files */
int  *file_chptr_stack;           /* chptr stack ditto */
int inc_stack_ptr = 0;            /* stack position */
 
item *main_item_base;
 
double pi;
colour black;
colour unfilled;

bindfont *font_base = NULL;    /* chain of font bindings */
BOOL use_fonts = TRUE;         /* expect to use fonts */
BOOL translate_chars = FALSE;  /* don't translate by default */
 
uschar **in_line_stack;        /* stack of pointers to saved in_lines */
int  *chptr_stack;	       /* stack of saved chptrs */
int  max_level = 0;            /* uppermost level */
int  min_level = 0;            /* lowermost level */
int  *mac_count_stack;
int  mac_stack_ptr = 0;        /* the stack position */
int  macro_count;	       /* for generating id's */
int  macro_id;
unit minimum_thickness = 0;    /* this is ok for SGCAL & PS */
BOOL no_variables = FALSE;     /* variables are available by default */
int  outstyle = OUT_UNSET;     /* output style */
unit resolution = 1;           /* default resolution is now exact */
BOOL strings_exist = FALSE;    /* at least one item has a string */

unit joined_xx;                /* Coordinates of explicit join position */
unit joined_yy; 
 
macro *macroot = NULL;         /* root of all macros */
macro *macactive = NULL;       /* chain of active macros */

BOOL started = FALSE;          /* done init */
BOOL testing = FALSE;          /* suppress version/date in output */

tree_node *varroot = NULL;     /* root of variables tree */


/*************************************************
*                Error messages                  *
*************************************************/
 
static uschar *error_messages[] = {
  US"Unrecognized command line option \"%s\"",              /* 0 */ 
  US"Failed to open %s for %s: %s",                         /* 1 */
  US"Unknown aspic command \"%s\"",                         /* 2 */
  US"Semicolon expected (unexpected text follows command)", /* 3 */
  US"Font %d has not been bound",                           /* 4 */ 
  US"Font number must be > 0 and < 64",                     /* 5 */ 
  US"Unknown%s variable \"%s\"",                            /* 6 */  
  US"Unknown option word \"%s\"",                           /* 7 */
  US"Dimension expected",                                   /* 8 */
  US"Label \"%s\" incorrectly placed (can only precede drawing command)", /* 9 */
  US"Can't find item labelled \"%s\"",                      /* 10 */
  US"%s expected",                                          /* 11 */
  US"No previous item",                                     /* 12 */
  US"Inappropriate position descriptor applied to a %s",    /* 13 */
  US"Inappropriate fraction encountered",                   /* 14 */
  US"Unable to get store - %d bytes requested",             /* 15 */
  US"Aspic command word expected",                          /* 16 */
  US"Empty variable name",                                  /* 17 */
  US"No stacked environment to restore",                    /* 18 */
  US"Too many constraints for arc - %s ignored",            /* 19 */
  US"An edge join cannot be explicitly positioned",         /* 20 */
  US"A positioned join must refer to a corner",             /* 21 */
  US"No previous item to join to",                          /* 22 */
  US"\"depth\" or \"via\" for arc given without end point - ignored",  /* 23 */
  US"An arc cannot be constructed using the given via point", /* 24 */
  US"Line too long while substituting \"%s\"",              /* 25 */ 
  US"Line too long after substitutions",                    /* 26 */ 
  US"Missing } after \"${%s\"",                             /* 27 */ 
  US"Only one of -ps, -sgcal, or -svg is allowed",          /* 28 */ 
  US"File name expected",                                   /* 29 */ 
  US"\"include\" is not allowed in a macro"                 /* 30 */ 
  };
 
 
 
/*************************************************
*            Supply missing div() if needed      *
*************************************************/
 
#ifdef __needs_div__
 
udiv_t udiv(unit numer, unit denom)
{
udiv_t div_yield;
div_yield.quot = numer / denom;
div_yield.rem  = numer % denom;
return div_yield;
}
 
#endif
 
 
 
/*************************************************
*                Error routine                   *
*************************************************/

/* Error messages go to stderr, with information about the line at fault
if there is one. Give up if not yet fully initialized.

Arguments:
  n            the error number
  ...          substitutions into the message
  
Returns:       nothing
*/  
 
void 
error_moan(int n, ...)
{
unit ptr, i;
va_list ap;
va_start(ap, n);
 
fprintf(stderr, "Aspic: ");
vfprintf(stderr, CS error_messages[n], ap);
fprintf(stderr, "\n");

if (!started) return;

if (chptr > 0)
  {
  ptr = chptr;
  fprintf(stderr, "%s", CS in_line);
  if (in_line[Ustrlen(in_line)-1] != '\n') fprintf(stderr, "\n");
  }
else
  {
  ptr = Ustrlen(in_last);
  fprintf(stderr, "%s", CS in_last);
  if (in_last[ptr-1] != '\n') fprintf(stderr, "\n");
  }

for (i = 0; i < ptr; i++) fprintf(stderr, " ");
fprintf(stderr, "^\n");
 
va_end(ap);
}
 
 
/*************************************************
*           Checked store allocator              *
*************************************************/

/* Calls malloc() and checks the result. Disaster on failure.

Arguments:
  size         store wanted
  
Returns:       pointer to the store
*/ 
 
void 
*getstore(size_t size)
{
void *yield = malloc(size);
if (yield == NULL)
  {
  error_moan(15, size);
  freechain();
  exit(EXIT_FAILURE);
  }
return yield;
}
 
 
 
/*************************************************
*         Set up the timestamp string            *
*************************************************/

/* This is a local function, used to initialize the $date variable.

Arguments:
  timebuf       where to put the output
  size          size of the buffer
  
Returns:        timebuf
*/

static uschar *
time_stamp(uschar *timebuf, int size)
{
int diff_hour, diff_min, len;
time_t now = time(NULL);
struct tm *gmt;
struct tm local;

memcpy(&local, localtime(&now), sizeof(struct tm));
gmt = gmtime(&now);

diff_min = 60*(local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
if (local.tm_year != gmt->tm_year)
  diff_min += (local.tm_year > gmt->tm_year)? 1440 : -1440;
else if (local.tm_yday != gmt->tm_yday)
  diff_min += (local.tm_yday > gmt->tm_yday)? 1440 : -1440;
diff_hour = diff_min/60;
diff_min  = abs(diff_min - diff_hour*60);

len = Ustrftime(timebuf, size, "%a, ", &local);
(void) sprintf(CS timebuf + len, "%02d ", local.tm_mday);
len += Ustrlen(timebuf + len);
len += Ustrftime(timebuf + len, size - len, "%b %Y %H:%M:%S", &local);
(void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);

return timebuf;
}


/*************************************************
*                 Usage                          *
*************************************************/

/* f is either stdout or stderr, depending on whether this is called by
-help or as a result of an error

Arguments:
  f            file on which to write
  
Returns:       nothing
*/ 

static 
void usage(FILE *f)
{
fprintf(f, "Usage:\n");
fprintf(f, "aspic [<options>] [<infile>] [<outfile>]\n\n");
fprintf(f, "Options:\n");
fprintf(f, "  -help          show usage information and exit\n");
fprintf(f, "  -nv            disable variable substitutions\n");
fprintf(f, "  -ps            generate Encapsulated PostScript\n");
fprintf(f, "  -sgcal         generate SGCAL input\n");
fprintf(f, "  -svg           generate SVG\n");
fprintf(f, "  -testing       used by 'make test'\n");
fprintf(f, "  -tr            translate quotes and double-hyphens\n");
fprintf(f, "  -v             show version and exit\n\n");

fprintf(f, "Omit file names or use \"-\" for stdin and stdout.\n");
fprintf(f, "The default output format is PostScript.\n");
fprintf(f, "Only one of -ps, -sgcal, and -sv is permitted.\n");
}



/*************************************************
*		    Entry point			 *
*************************************************/
 
int 
main(int argc, char **argv)
{
tree_node *tn;
uschar timebuf[sizeof("www, dd-mmm-yyyy hh:mm:ss +zzzz")];
int firstarg = 1;       /* points after options */
int yield = EXIT_SUCCESS;

in_raw  = getstore(INPUT_LINESIZE);
in_line = getstore(INPUT_LINESIZE);
in_last = getstore(INPUT_LINESIZE);
in_last[0] = 0;		/* to avoid junk in error messages */

in_line_stack = getstore(MAC_STACKSIZE * sizeof(uschar *));
chptr_stack = getstore(MAC_STACKSIZE * sizeof(int));
mac_count_stack = getstore(MAC_STACKSIZE * sizeof(int));

file_line_stack = getstore(MAC_STACKSIZE * sizeof(uschar *));
file_chptr_stack = getstore(MAC_STACKSIZE * sizeof(int));
 
pi = 4 * atan2(1.0, 1.0);

black.red = black.green = black.blue = 0;
unfilled.red = unfilled.green = unfilled.blue = -1000;

/* Handle options */

while (firstarg < argc && argv[firstarg][0] == '-' && argv[firstarg][1] != 0)
  {
  uschar *arg = US argv[firstarg++];
  if (Ustrcmp(arg, "-nv") == 0)
    no_variables = TRUE;  
  else if (Ustrcmp(arg, "-testing") == 0)
    testing = TRUE;    
  else if (Ustrcmp(arg, "-ps") == 0)    
    { if (outstyle == OUT_UNSET) outstyle = OUT_PS; else error_moan(28); }
  else if (Ustrcmp(arg, "-sgcal") == 0)
    { if (outstyle == OUT_UNSET) outstyle = OUT_SG; else error_moan(28); }
  else if (Ustrcmp(arg, "-svg") == 0)  
    { if (outstyle == OUT_UNSET) outstyle = OUT_SV; else error_moan(28); }
  else if (Ustrcmp(arg, "-tr") == 0)
    translate_chars = TRUE;     
  else if (Ustrcmp(arg, "-v") == 0) 
    {
    printf("\rAspic %s\n", Version_String);
    goto TIDYUP;
    } 
  else if (Ustrcmp(arg, "-help") == 0 || Ustrcmp(arg, "--help") == 0)
    {
    usage(stdout);
    goto TIDYUP;
    } 
  else 
    { 
    error_moan(0, arg); 
    usage(stderr);
    yield = EXIT_FAILURE;
    goto TIDYUP;  
    }  
  } 
  
if (outstyle == OUT_UNSET) outstyle = OUT_PS; 
  
/* The file names are given in the command line. If both are missing, use stdin 
and stdout; if one is given, use it to stdout. The name "-" can also be used to 
mean stdin or stdout. */
 
if (firstarg >= argc || Ustrcmp(argv[firstarg], "-") == 0) 
  {
  main_input = stdin; 
  } 
else
  {
  if ((main_input = fopen(argv[firstarg], "r")) == NULL)
    { 
    error_moan(1, argv[firstarg], "input", strerror(errno)); 
    yield = EXIT_FAILURE;
    goto TIDYUP;  
    }
  }   
  
/* Set up some default value for certain conventional variables */

tn = getstore(sizeof(tree_node) + 7);
Ustrcpy(tn->name, "creator");
tn->value = US"Unknown";
(void)tree_insertnode(&varroot, tn);

tn = getstore(sizeof(tree_node) + 4);
Ustrcpy(tn->name, "date");
tn->value = time_stamp(timebuf, sizeof(timebuf));
(void)tree_insertnode(&varroot, tn);

tn = getstore(sizeof(tree_node) + 5);
Ustrcpy(tn->name, "title");
tn->value = US"Unknown";
(void)tree_insertnode(&varroot, tn);

/* Initialization that depends on the output style */

switch (outstyle)
  {
  case OUT_PS: init_ps(); break;
  case OUT_SG: init_sg(); break;  
  case OUT_SV: init_sv(); break;
  }  
 
/* Process the input and then write the output if successful. */

started = TRUE; 
if (read_inputfile())
  {
  fclose(main_input);
   
  if (firstarg + 1 >= argc || Ustrcmp(argv[firstarg + 1], "-") == 0)
    { 
    out_file = stdout;
    } 
  else
    {
    if ((out_file = fopen(argv[firstarg + 1], "w")) == NULL)
      { 
      error_moan(1, argv[firstarg+1], "output", strerror(errno)); 
      yield = EXIT_FAILURE;
      goto TIDYUP;  
      }
    } 
     
  switch(outstyle)
    {
    case OUT_PS: write_ps(); break;
    case OUT_SG: write_sg(); break;
    case OUT_SV: write_sv(); break;      
    }
    
  fclose(out_file);
  }
 
/* Free up store used, and return */

TIDYUP: 
freechain();
while (env != NULL) { environment *p = env; env = env->previous; free(p); }
return yield;
}
 
/* End of asmain.c */