~ubuntu-branches/ubuntu/jaunty/texlive-bin/jaunty

« back to all changes in this revision

Viewing changes to build/source/texk/seetexk/dviselect.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Preining
  • Date: 2008-06-26 23:14:59 UTC
  • mfrom: (2.1.30 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080626231459-y02rjsrgtafu83yr
Tags: 2007.dfsg.2-3
add missing source roadmap.fig of roadmap.eps in fontinst documentation
(Closes: #482915) (urgency medium due to RC bug)
(new patch add-missing-fontinst-source)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 1987, 1989 University of Maryland
 
3
 * Department of Computer Science.  All rights reserved.
 
4
 * Permission to copy for any purpose is hereby granted
 
5
 * so long as this copyright notice remains intact.
 
6
 */
 
7
 
 
8
#ifndef lint
 
9
static char rcsid[] = "$Header: /usr/src/local/tex/local/mctex/dvi/RCS/dviselect.c,v 3.1 89/08/22 17:16:13 chris Exp $";
 
10
#endif
 
11
 
 
12
/*
 
13
 * DVI page selection program
 
14
 *
 
15
 * Reads DVI version 2 files and selects pages, writing a new DVI
 
16
 * file.  The new DVI file is technically correct, though we do not
 
17
 * adjust the tallest and widest page values, nor the DVI stack size.
 
18
 * This is all right since the values will never become too small,
 
19
 * but it might be nice to fix them up.  Perhaps someday . . . .
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
#include <config.h>
 
24
#endif
 
25
 
 
26
#ifdef KPATHSEA
 
27
#include <kpathsea/c-fopen.h>
 
28
#include <kpathsea/getopt.h>
 
29
#else
 
30
#define FOPEN_RBIN_MODE  "rb"
 
31
#define FOPEN_RBIN_MODE  "wb"
 
32
#define SET_BINARY(x)
 
33
extern char *optarg;
 
34
extern int optind;
 
35
#endif
 
36
 
 
37
#include "types.h"
 
38
#include "dviclass.h"
 
39
#include "dvicodes.h"
 
40
#include "error.h"
 
41
#include "fio.h"
 
42
#include "gripes.h"
 
43
#include "search.h"
 
44
#include <stdio.h>
 
45
#include <ctype.h>
 
46
 
 
47
#define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
 
48
 
 
49
char  *ProgName;
 
50
/* Globals */
 
51
char    serrbuf[BUFSIZ];        /* buffer for stderr */
 
52
 
 
53
/*
 
54
 * We will try to keep output lines shorter than MAXCOL characters.
 
55
 */
 
56
#define MAXCOL  75
 
57
 
 
58
/*
 
59
 * We use the following structure to keep track of fonts we have seen.
 
60
 * The final DVI file lists only the fonts it uses.
 
61
 */
 
62
struct fontinfo {
 
63
        i32     fi_newindex;    /* font number in output file */
 
64
        int     fi_reallyused;  /* true => used on a page we copied */
 
65
        i32     fi_checksum;    /* the checksum */
 
66
        i32     fi_mag;         /* the magnification */
 
67
        i32     fi_designsize;  /* the design size */
 
68
        short   fi_n1;          /* the name header length */
 
69
        short   fi_n2;          /* the name body length */
 
70
        char    *fi_name;       /* the name itself */
 
71
};
 
72
 
 
73
/*
 
74
 * We need to remember which pages the user would like.  We build a linked
 
75
 * list that allows us to decide (for any given page) whether it should
 
76
 * be included in the output file.  Each page has ten \count variables
 
77
 * associated with it.  We put a bound on the values allowed for each, and
 
78
 * keep a linked list of alternatives should any be outside the allowed
 
79
 * range.  For example, `dviselect *.3,10-15' would generate a two-element
 
80
 * page list, with the first allowing any value for \count0 (and \counts 2 to
 
81
 * 9) but \count1 restricted to the range 3-3, and the second restricting
 
82
 * \count0 to the range 10-15 but leaving \counts 1 to 9 unrestrained.
 
83
 *
 
84
 * We remember whether a bound is specified, so that we need not fix
 
85
 * some `large' number as a maximum value.
 
86
 *
 
87
 * We also allow `absolute' page references, where the first page is
 
88
 * page 1, the second 2, and so forth.  These are specified with an
 
89
 * equal sign: `dviselect =4:10' picks up the fourth through tenth
 
90
 * sequential pages, irrespective of \count values.
 
91
 *
 
92
 * There is also an even/odd switch (which can be applied to absolute
 
93
 * or relative pages): dviselect =even, even.3, etc.
 
94
 */
 
95
enum pstype {
 
96
        pt_lu,                  /* have both lower and upper bounds */
 
97
        pt_l,                   /* lower bound only */
 
98
        pt_u,                   /* upper bound only */
 
99
        pt_unbounded,           /* any value at all */
 
100
        pt_even,                /* even values only */
 
101
        pt_odd                  /* odd values only */
 
102
};
 
103
struct pagesel {
 
104
        enum pstype ps_type;    /* type of selector */
 
105
        i32     ps_low;         /* lower bound */
 
106
        i32     ps_high;        /* upper bound */
 
107
};
 
108
struct pagelist {
 
109
        struct  pagelist *pl_alt;       /* next in a series of alternates */
 
110
        int     pl_len;                 /* number of ranges to check */
 
111
        int     pl_abs;                 /* true iff absolute page ref */
 
112
        struct  pagesel pl_pages[10];   /* one for each \count variable */
 
113
};
 
114
 
 
115
int     SFlag;                  /* true => -s, silent operation */
 
116
 
 
117
struct  search *FontFinder;     /* maps from input indicies to fontinfo */
 
118
i32     NextOutputFontIndex;    /* generates output indicies */
 
119
i32     CurrentFontIndex;       /* current (old) index in input */
 
120
i32     OutputFontIndex;        /* current (new) index in ouput */
 
121
 
 
122
struct  pagelist *PageList;     /* the list of allowed pages */
 
123
 
 
124
char    *DVIFileName;           /* name of input DVI file */
 
125
FILE    *inf;                   /* the input file itself */
 
126
FILE    *outf;                  /* the output DVI file */
 
127
 
 
128
long    StartOfLastPage;        /* The file position just before we started
 
129
                                   the last page (this is later written to
 
130
                                   the output file as the previous page
 
131
                                   pointer). */
 
132
long    CurrentPosition;        /* The current position of the file */
 
133
 
 
134
int     UseThisPage;            /* true => current page is selected */
 
135
 
 
136
i32     InputPageNumber;        /* current absolute page in old DVI file */
 
137
int     NumberOfOutputPages;    /* number of pages in new DVI file */
 
138
 
 
139
i32     Numerator;              /* numerator from DVI file */
 
140
i32     Denominator;            /* denominator from DVI file */
 
141
i32     DVIMag;                 /* magnification from DVI file */
 
142
 
 
143
i32     Count[10];              /* the 10 \count variables */
 
144
 
 
145
/* save some string space: we use this a lot */
 
146
char    writeerr[] = "error writing DVI file";
 
147
 
 
148
#ifdef NeedFunctionPrototypes
 
149
#include <string.h>
 
150
void WriteFont(struct fontinfo *);
 
151
int evenodd(char *);
 
152
int ParsePages(char *);
 
153
void HandleDVIFile();
 
154
void PutFontSelector(i32);
 
155
 
 
156
#ifdef _AMIGA
 
157
#define bcmp(s1, s2, len) memcmp(s1, s2, len)
 
158
#define bzero(s, len) memset(s, '\0', len)
 
159
#define index(s, c) strchr(s, c)
 
160
#endif /* _AMIGA */
 
161
 
 
162
#ifndef KPATHSEA
 
163
char    *malloc(), *realloc();
 
164
#endif /* not WIN32 */
 
165
#endif
 
166
/*
 
167
 * You may get lint warnings about sprintf's return value.
 
168
 * Older versions of 4BSD have `char *sprintf()'.  ANSI and
 
169
 * SysV use `int sprintf()'; so ignore the warnings.
 
170
 */
 
171
 
 
172
/*
 
173
 * Lint gets somewhat confused over putc.
 
174
 */
 
175
#ifdef lint
 
176
#undef putc
 
177
#ifdef ultrix /* grr */
 
178
#define putc(c, f) fputc((char)(c), f)
 
179
#else
 
180
#define putc(c, f) fputc((int)(c), f)
 
181
#endif
 
182
#endif
 
183
 
 
184
/*
 
185
 * Return true iff the 10 \counts are one of the desired output pages.
 
186
 */
 
187
DesiredPageP()
 
188
{
 
189
        register struct pagelist *pl;
 
190
 
 
191
        for (pl = PageList; pl != NULL; pl = pl->pl_alt) {
 
192
                register struct pagesel *ps = pl->pl_pages;
 
193
                register int i;
 
194
                register i32 *pagep;
 
195
 
 
196
                pagep = pl->pl_abs ? &InputPageNumber : &Count[0];
 
197
                for (i = 0; i < pl->pl_len; i++, ps++, pagep++) {
 
198
                        switch (ps->ps_type) {
 
199
 
 
200
                        case pt_lu:     /* check upper, fall through */
 
201
                                if (*pagep > ps->ps_high)
 
202
                                        goto no_good;
 
203
                                /* FALLTHROUGH */
 
204
 
 
205
                        case pt_l:      /* only if not too low */
 
206
                                if (*pagep < ps->ps_low)
 
207
                                        goto no_good;
 
208
                                break;
 
209
 
 
210
                        case pt_u:      /* only if not too high */
 
211
                                if (*pagep > ps->ps_high)
 
212
                                        goto no_good;
 
213
                                break;
 
214
 
 
215
                        case pt_unbounded:
 
216
                                break;
 
217
 
 
218
                        case pt_even:   /* only if even */
 
219
                                if (*pagep & 1)
 
220
                                        goto no_good;
 
221
                                break;
 
222
 
 
223
                        case pt_odd:    /* only if odd */
 
224
                                if ((*pagep & 1) == 0)
 
225
                                        goto no_good;
 
226
                                break;
 
227
                        }
 
228
                }
 
229
                return (1);     /* success */
 
230
        no_good:
 
231
                continue;
 
232
        }
 
233
        return (0);
 
234
}
 
235
 
 
236
/*
 
237
 * Print a message to stderr, with an optional leading space, and handling
 
238
 * long line wraps.
 
239
 */
 
240
void message(space, str, len)
 
241
        int space;
 
242
        register char *str;
 
243
        register int len;
 
244
{
 
245
        static int beenhere;
 
246
        static int col;
 
247
 
 
248
        if (!beenhere)
 
249
                space = 0, beenhere++;
 
250
        if (len == 0)
 
251
                len = strlen(str);
 
252
        col += len;
 
253
        if (space) {
 
254
                if (col >= MAXCOL)
 
255
                        (void) putc('\n', stderr), col = len;
 
256
                else
 
257
                        (void) putc(' ', stderr), col++;
 
258
        }
 
259
        while (--len >= 0)
 
260
                (void) putc(*str++, stderr);
 
261
        (void) fflush(stderr);
 
262
}
 
263
 
 
264
/*
 
265
 * Start a page (process a DVI_BOP).
 
266
 */
 
267
void BeginPage()
 
268
{
 
269
        register i32 *i;
 
270
 
 
271
        OutputFontIndex = -1;   /* new page requires respecifying font */
 
272
        InputPageNumber++;      /* count it */
 
273
        for (i = Count; i < &Count[10]; i++)
 
274
                fGetLong(inf, *i);
 
275
        (void) GetLong(inf);    /* previous page pointer */
 
276
 
 
277
        if ((UseThisPage = DesiredPageP()) == 0)
 
278
                return;
 
279
 
 
280
        putbyte(outf, DVI_BOP);
 
281
        for (i = Count; i < &Count[10]; i++)
 
282
                PutLong(outf, *i);
 
283
        PutLong(outf, StartOfLastPage);
 
284
        if (ferror(outf))
 
285
                error(1, -1, writeerr);
 
286
 
 
287
        StartOfLastPage = CurrentPosition;
 
288
        CurrentPosition += 45;  /* we just wrote this much */
 
289
 
 
290
        if (!SFlag) {           /* write nice page usage messages */
 
291
                register int z = 0;
 
292
                register int mlen = 0;
 
293
                char msg[80];
 
294
 
 
295
                (void) sprintf(msg, "[%ld", (long)Count[0]);
 
296
                mlen = strlen(msg);
 
297
                for (i = &Count[1]; i < &Count[10]; i++) {
 
298
                        if (*i == 0) {
 
299
                                z++;
 
300
                                continue;
 
301
                        }
 
302
                        while (--z >= 0)
 
303
                                msg[mlen++] = '.', msg[mlen++] = '0';
 
304
                        z = 0;
 
305
                        (void) sprintf(msg + mlen, ".%ld", (long)*i);
 
306
                        mlen += strlen(msg + mlen);
 
307
                }
 
308
                message(1, msg, mlen);
 
309
        }
 
310
}
 
311
 
 
312
/*
 
313
 * End a page (process a DVI_EOP).
 
314
 */
 
315
void EndPage()
 
316
{
 
317
 
 
318
        if (!UseThisPage)
 
319
                return;
 
320
        if (!SFlag)
 
321
                message(0, "]", 1);
 
322
        putbyte(outf, DVI_EOP);
 
323
        if (ferror(outf))
 
324
                error(1, -1, writeerr);
 
325
        CurrentPosition++;
 
326
        NumberOfOutputPages++;
 
327
}
 
328
 
 
329
/*
 
330
 * For each of the fonts used in the new DVI file, write out a definition.
 
331
 */
 
332
/* ARGSUSED */
 
333
void
 
334
PostAmbleFontEnumerator(addr, key)
 
335
        char *addr;
 
336
        i32 key;
 
337
{
 
338
 
 
339
        if (((struct fontinfo *)addr)->fi_reallyused)
 
340
                WriteFont((struct fontinfo *)addr);
 
341
}
 
342
 
 
343
void HandlePostAmble()
 
344
{
 
345
        register i32 c;
 
346
 
 
347
        (void) GetLong(inf);    /* previous page pointer */
 
348
        if (GetLong(inf) != Numerator)
 
349
                GripeMismatchedValue("numerator");
 
350
        if (GetLong(inf) != Denominator)
 
351
                GripeMismatchedValue("denominator");
 
352
        if (GetLong(inf) != DVIMag)
 
353
                GripeMismatchedValue("\\magnification");
 
354
 
 
355
        putbyte(outf, DVI_POST);
 
356
        PutLong(outf, StartOfLastPage);
 
357
        PutLong(outf, Numerator);
 
358
        PutLong(outf, Denominator);
 
359
        PutLong(outf, DVIMag);
 
360
        c = GetLong(inf);
 
361
        PutLong(outf, c);       /* tallest page height */
 
362
        c = GetLong(inf);
 
363
        PutLong(outf, c);       /* widest page width */
 
364
        c = GetWord(inf);
 
365
        PutWord(outf, c);       /* DVI stack size */
 
366
        PutWord(outf, NumberOfOutputPages);
 
367
        StartOfLastPage = CurrentPosition;      /* point at post */
 
368
        CurrentPosition += 29;  /* count all those `put's */
 
369
#ifdef notdef
 
370
        (void) GetWord(inf);    /* skip original number of pages */
 
371
#endif
 
372
 
 
373
        /*
 
374
         * just ignore all the incoming font definitions; we are done with
 
375
         * input file 
 
376
         */
 
377
 
 
378
        /*
 
379
         * run through the FontFinder table and dump definitions for the
 
380
         * fonts we have used. 
 
381
         */
 
382
        SEnumerate(FontFinder, PostAmbleFontEnumerator);
 
383
 
 
384
        putbyte(outf, DVI_POSTPOST);
 
385
        PutLong(outf, StartOfLastPage); /* actually start of postamble */
 
386
        putbyte(outf, DVI_VERSION);
 
387
        putbyte(outf, DVI_FILLER);
 
388
        putbyte(outf, DVI_FILLER);
 
389
        putbyte(outf, DVI_FILLER);
 
390
        putbyte(outf, DVI_FILLER);
 
391
        CurrentPosition += 10;
 
392
        while (CurrentPosition & 3) {
 
393
                putbyte(outf, DVI_FILLER);
 
394
                CurrentPosition++;
 
395
        }
 
396
        if (ferror(outf))
 
397
                error(1, -1, writeerr);
 
398
}
 
399
 
 
400
/*
 
401
 * Write a font definition to the output file
 
402
 */
 
403
void WriteFont(fi)
 
404
        register struct fontinfo *fi;
 
405
{
 
406
        register int l;
 
407
        register char *s;
 
408
 
 
409
        if (fi->fi_newindex < 256) {
 
410
                putbyte(outf, DVI_FNTDEF1);
 
411
                putbyte(outf, fi->fi_newindex);
 
412
                CurrentPosition += 2;
 
413
        } else if (fi->fi_newindex < 65536) {
 
414
                putbyte(outf, DVI_FNTDEF2);
 
415
                PutWord(outf, fi->fi_newindex);
 
416
                CurrentPosition += 3;
 
417
        } else if (fi->fi_newindex < 16777216) {
 
418
                putbyte(outf, DVI_FNTDEF3);
 
419
                Put3Byte(outf, fi->fi_newindex);
 
420
                CurrentPosition += 4;
 
421
        } else {
 
422
                putbyte(outf, DVI_FNTDEF4);
 
423
                PutLong(outf, fi->fi_newindex);
 
424
                CurrentPosition += 5;
 
425
        }
 
426
        PutLong(outf, fi->fi_checksum);
 
427
        PutLong(outf, fi->fi_mag);
 
428
        PutLong(outf, fi->fi_designsize);
 
429
        putbyte(outf, fi->fi_n1);
 
430
        putbyte(outf, fi->fi_n2);
 
431
        l = fi->fi_n1 + fi->fi_n2;
 
432
        CurrentPosition += 14 + l;
 
433
        s = fi->fi_name;
 
434
        while (--l >= 0)
 
435
                putbyte(outf, *s++);
 
436
}
 
437
 
 
438
/*
 
439
 * Handle the preamble.  Someday we should update the comment field.
 
440
 */
 
441
void HandlePreAmble()
 
442
{
 
443
        register int n, c;
 
444
 
 
445
        c = getc(inf);
 
446
        if (c == EOF)
 
447
                GripeUnexpectedDVIEOF();
 
448
        if (c != DVI_PRE)
 
449
                GripeMissingOp("PRE");
 
450
        if (getc(inf) != DVI_VERSION)
 
451
                error(1, 0, "%s is not a DVI version %d file",
 
452
                    DVIFileName, DVI_VERSION);
 
453
        Numerator = GetLong(inf);
 
454
        Denominator = GetLong(inf);
 
455
        DVIMag = GetLong(inf);
 
456
        putbyte(outf, DVI_PRE);
 
457
        putbyte(outf, DVI_VERSION);
 
458
        PutLong(outf, Numerator);
 
459
        PutLong(outf, Denominator);
 
460
        PutLong(outf, DVIMag);
 
461
 
 
462
        n = UnSign8(GetByte(inf));
 
463
        CurrentPosition = 15 + n;       /* well, almost */
 
464
        putbyte(outf, n);
 
465
        while (--n >= 0) {
 
466
                c = GetByte(inf);
 
467
                putbyte(outf, c);
 
468
        }
 
469
}
 
470
 
 
471
int
 
472
main(argc, argv)
 
473
        int argc;
 
474
        register char **argv;
 
475
{
 
476
        register int c;
 
477
        register char *s;
 
478
        char *outname = NULL;
 
479
 
 
480
        ProgName = *argv;
 
481
        setbuf(stderr, serrbuf);
 
482
 
 
483
        while ((c = getopt(argc, argv, "i:o:s")) != EOF) {
 
484
                switch (c) {
 
485
 
 
486
                case 's':       /* silent */
 
487
                        SFlag++;
 
488
                        break;
 
489
 
 
490
                case 'i':
 
491
                        if (DVIFileName != NULL)
 
492
                                goto usage;
 
493
                        DVIFileName = optarg;
 
494
                        break;
 
495
 
 
496
                case 'o':
 
497
                        if (outname != NULL)
 
498
                                goto usage;
 
499
                        outname = optarg;
 
500
                        break;
 
501
 
 
502
                case '?':
 
503
usage:
 
504
                        (void) fprintf(stderr, "\
 
505
Usage: %s [-s] [-i infile] [-o outfile] pages [...] [infile [outfile]]\n",
 
506
                                ProgName);
 
507
                        (void) fflush(stderr);
 
508
                        exit(1);
 
509
                }
 
510
        }
 
511
 
 
512
        while (optind < argc) {
 
513
                s = argv[optind++];
 
514
                c = *s;
 
515
                if (!isalpha(c) && c != '/' ||
 
516
                    (c == 'e' || c == 'o') && evenodd(s)) {
 
517
                        if (ParsePages(s))
 
518
                                goto usage;
 
519
                } else if (DVIFileName == NULL)
 
520
                        DVIFileName = s;
 
521
                else if (outname == NULL)
 
522
                        outname = s;
 
523
                else
 
524
                        goto usage;
 
525
        }
 
526
        if (PageList == NULL)
 
527
                goto usage;
 
528
        if (DVIFileName == NULL) {
 
529
                DVIFileName = "`stdin'";
 
530
                inf = stdin;
 
531
                if (!isatty(fileno(inf)))
 
532
                  SET_BINARY(fileno(inf));
 
533
        } else if ((inf = fopen(DVIFileName, FOPEN_RBIN_MODE)) == 0)
 
534
                error(1, -1, "cannot read %s", DVIFileName);
 
535
        if (outname == NULL) {
 
536
                outf = stdout;
 
537
                if (!isatty(fileno(outf)))
 
538
                  SET_BINARY(fileno(outf));
 
539
        } else if ((outf = fopen(outname, FOPEN_WBIN_MODE)) == 0)
 
540
                error(1, -1, "cannot write %s", outname);
 
541
 
 
542
        if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
 
543
                error(1, 0, "cannot create font finder (out of memory?)");
 
544
 
 
545
        StartOfLastPage = -1;
 
546
        HandlePreAmble();
 
547
        HandleDVIFile();
 
548
        HandlePostAmble();
 
549
        if (!SFlag)
 
550
                (void) fprintf(stderr, "\nWrote %d page%s, %ld bytes\n",
 
551
                    NumberOfOutputPages, NumberOfOutputPages == 1 ? "" : "s",
 
552
                    (long)CurrentPosition);
 
553
        return 0;
 
554
}
 
555
 
 
556
struct pagelist *
 
557
InstallPL(ps, n, absolute)
 
558
        register struct pagesel *ps;
 
559
        register int n;
 
560
        int absolute;
 
561
{
 
562
        register struct pagelist *pl;
 
563
 
 
564
        pl = (struct pagelist *)malloc(sizeof *pl);
 
565
        if (pl == NULL)
 
566
                GripeOutOfMemory(sizeof *pl, "page list");
 
567
        pl->pl_alt = PageList;
 
568
        PageList = pl;
 
569
        pl->pl_len = n;
 
570
        while (--n >= 0)
 
571
                pl->pl_pages[n] = ps[n];
 
572
        pl->pl_abs = absolute;
 
573
        return pl;
 
574
}
 
575
 
 
576
/*
 
577
 * Return true iff the string `s' is the word `even' or `odd',
 
578
 * followed by `.' or `white' characters.
 
579
 */
 
580
int
 
581
evenodd(s)
 
582
        char *s;
 
583
{
 
584
        register int c;
 
585
 
 
586
        if (strncmp(s, "even", 4) == 0)
 
587
                c = s[4];
 
588
        else if (strncmp(s, "odd", 3) == 0)
 
589
                c = s[3];
 
590
        else
 
591
                return (0);
 
592
        if (c == 0 || c == '.' || white(c))
 
593
                return (1);
 
594
        return (0);
 
595
}
 
596
 
 
597
/*
 
598
 * Parse a string representing a list of pages.  Return 0 iff ok.  As a
 
599
 * side effect, the page selection(s) is (are) prepended to PageList.
 
600
 */
 
601
int ParsePages(s)
 
602
        register char *s;
 
603
{
 
604
        register struct pagesel *ps;
 
605
        register int c;         /* current character */
 
606
        register i32 n;         /* current numeric value */
 
607
        register int innumber;  /* true => gathering a number */
 
608
        int i;                  /* next index in page select list */
 
609
        int range;              /* true => saw a range indicator */
 
610
        int negative;           /* true => number being built is negative */
 
611
        int absolute;           /* true => absolute, not \count */
 
612
        int lb, ub, even, odd;  /* flags for lower,upper,even,odd */
 
613
        struct pagesel pagesel[10];
 
614
 
 
615
        range = 0;
 
616
        innumber = 0;
 
617
        absolute = 0;
 
618
        i = 0;
 
619
        ps = pagesel;
 
620
        lb = ub = even = odd = 0;
 
621
        /*
 
622
         * Talk about ad hoc!  (Not to mention convoluted.)
 
623
         */
 
624
        for (;;) {
 
625
                c = *s++;
 
626
                if (i == 0 && !innumber && !range) {
 
627
                        /* nothing special going on */
 
628
                        if (c == 0)
 
629
                                return 0;
 
630
                        if (white(c))
 
631
                                continue;
 
632
                }
 
633
                if ((c == 'e' || c == 'o') && evenodd(s - 1)) {
 
634
                        if (innumber || range)
 
635
                                return (-1);
 
636
                        if (c == 'e') {
 
637
                                s += 3;
 
638
                                even = 1;
 
639
                        } else {
 
640
                                s += 2;
 
641
                                odd = 1;
 
642
                        }
 
643
                        c = *s++;
 
644
                        goto finishnum;
 
645
                }
 
646
                if (c == '_') {
 
647
                        /* kludge: should be '-' for negatives */
 
648
                        if (innumber || absolute)
 
649
                                return (-1);
 
650
                        innumber = 1;
 
651
                        negative = 1;
 
652
                        n = 0;
 
653
                        continue;
 
654
                }
 
655
                if (c == '=') {
 
656
                        /* absolute page */
 
657
                        if (innumber || range || i > 0)
 
658
                                return (-1);
 
659
                        absolute = 1;
 
660
                        negative = 0;
 
661
                        n = 0;
 
662
                        continue;
 
663
                }
 
664
                if (isdigit(c)) {
 
665
                        /* accumulate numeric value */
 
666
                        if (!innumber) {
 
667
                                innumber = 1;
 
668
                                negative = 0;
 
669
                                n = c - '0';
 
670
                                continue;
 
671
                        }
 
672
                        n *= 10;
 
673
                        n += negative ? '0' - c : c - '0';
 
674
                        continue;
 
675
                }
 
676
                if (c == '-' || c == ':') {
 
677
                        /* here is a range */
 
678
                        if (range)
 
679
                                return (-1);
 
680
                        if (innumber) { /* have a lower bound */
 
681
                                ps->ps_low = n;
 
682
                                lb = 1;
 
683
                        }
 
684
                        range = 1;
 
685
                        innumber = 0;
 
686
                        continue;
 
687
                }
 
688
                if (c == '*') {
 
689
                        /* no lower bound, no upper bound */
 
690
                        c = *s++;
 
691
                        if (innumber || range || (c && c != '.' && !white(c)))
 
692
                                return (-1);
 
693
                        goto finishnum;
 
694
                }
 
695
                if (c == 0 || c == '.' || white(c)) {
 
696
                        /* end of this range */
 
697
                        if (innumber) {         /* have an upper bound */
 
698
                                ps->ps_high = n;
 
699
                                ub = 1;
 
700
                                if (!range) {
 
701
                                        /* no range => lower bound == upper */
 
702
                                        ps->ps_low = ps->ps_high;
 
703
                                        lb = 1;
 
704
                                }
 
705
                        }
 
706
finishnum:
 
707
                        if (even)
 
708
                                ps->ps_type = pt_even;
 
709
                        else if (odd)
 
710
                                ps->ps_type = pt_odd;
 
711
                        else if (lb)
 
712
                                ps->ps_type = ub ? pt_lu : pt_l;
 
713
                        else
 
714
                                ps->ps_type = ub ? pt_u : pt_unbounded;
 
715
                        if (c == '.') {
 
716
                                if (absolute)
 
717
                                        return (-1);
 
718
                                if (++i >= 10)  /* too many specifiers */
 
719
                                        return (-1);
 
720
                                ps++;
 
721
                        } else {
 
722
                                InstallPL(pagesel, i + 1, absolute);
 
723
                                ps = pagesel;
 
724
                                i = 0;
 
725
                                absolute = 0;
 
726
                        }
 
727
                        if (c == 0)
 
728
                                return (0);
 
729
                        range = 0;
 
730
                        innumber = 0;
 
731
                        lb = ub = even = odd = 0;
 
732
                        continue;
 
733
                }
 
734
                /* illegal character */
 
735
                return (-1);
 
736
        }
 
737
}
 
738
 
 
739
/*
 
740
 * Handle a font definition.
 
741
 */
 
742
void HandleFontDef(index)
 
743
        i32 index;
 
744
{
 
745
        register struct fontinfo *fi;
 
746
        register int i;
 
747
        register char *s;
 
748
        int def = S_CREATE | S_EXCL;
 
749
 
 
750
        if ((fi = (struct fontinfo *)SSearch(FontFinder, index, &def)) == 0)
 
751
                if (def & S_COLL)
 
752
                        error(1, 0, "font %ld already defined", (long)index);
 
753
                else
 
754
                        error(1, 0, "cannot stash font %ld (out of memory?)",
 
755
                                (long)index);
 
756
        fi->fi_reallyused = 0;
 
757
        fi->fi_checksum = GetLong(inf);
 
758
        fi->fi_mag = GetLong(inf);
 
759
        fi->fi_designsize = GetLong(inf);
 
760
        fi->fi_n1 = UnSign8(GetByte(inf));
 
761
        fi->fi_n2 = UnSign8(GetByte(inf));
 
762
        i = fi->fi_n1 + fi->fi_n2;
 
763
        if ((s = malloc((unsigned)i)) == 0)
 
764
                GripeOutOfMemory(i, "font name");
 
765
        fi->fi_name = s;
 
766
        while (--i >= 0)
 
767
                *s++ = GetByte(inf);
 
768
}
 
769
 
 
770
/*
 
771
 * Handle a \special.
 
772
 */
 
773
void HandleSpecial(c, l, p)
 
774
        int c;
 
775
        register int l;
 
776
        register i32 p;
 
777
{
 
778
        register int i;
 
779
 
 
780
        if (UseThisPage) {
 
781
                putbyte(outf, c);
 
782
                switch (l) {
 
783
 
 
784
                case DPL_UNS1:
 
785
                        putbyte(outf, p);
 
786
                        CurrentPosition += 2;
 
787
                        break;
 
788
 
 
789
                case DPL_UNS2:
 
790
                        PutWord(outf, p);
 
791
                        CurrentPosition += 3;
 
792
                        break;
 
793
 
 
794
                case DPL_UNS3:
 
795
                        Put3Byte(outf, p);
 
796
                        CurrentPosition += 4;
 
797
                        break;
 
798
 
 
799
                case DPL_SGN4:
 
800
                        PutLong(outf, p);
 
801
                        CurrentPosition += 5;
 
802
                        break;
 
803
 
 
804
                default:
 
805
                        panic("HandleSpecial l=%d", l);
 
806
                        /* NOTREACHED */
 
807
                }
 
808
                CurrentPosition += p;
 
809
                while (--p >= 0) {
 
810
                        i = getc(inf);
 
811
                        putbyte(outf, i);
 
812
                }
 
813
                if (feof(inf))
 
814
                        GripeUnexpectedDVIEOF();
 
815
                if (ferror(outf))
 
816
                        error(1, -1, writeerr);
 
817
        } else
 
818
                while (--p >= 0)
 
819
                        (void) getc(inf);
 
820
}
 
821
 
 
822
void ReallyUseFont()
 
823
{
 
824
        register struct fontinfo *fi;
 
825
        int look = S_LOOKUP;
 
826
 
 
827
        fi = (struct fontinfo *)SSearch(FontFinder, CurrentFontIndex, &look);
 
828
        if (fi == NULL)
 
829
                error(1, 0, "DVI file requested font %ld without defining it",
 
830
                    (long)CurrentFontIndex);
 
831
        if (fi->fi_reallyused == 0) {
 
832
                fi->fi_reallyused++;
 
833
                fi->fi_newindex = NextOutputFontIndex++;
 
834
                WriteFont(fi);
 
835
        }
 
836
        if (fi->fi_newindex != OutputFontIndex) {
 
837
                PutFontSelector(fi->fi_newindex);
 
838
                OutputFontIndex = fi->fi_newindex;
 
839
        }
 
840
}
 
841
 
 
842
/*
 
843
 * Write a font selection command to the output file
 
844
 */
 
845
void PutFontSelector(index)
 
846
        i32 index;
 
847
{
 
848
 
 
849
        if (index < 64) {
 
850
                putbyte(outf, index + DVI_FNTNUM0);
 
851
                CurrentPosition++;
 
852
        } else if (index < 256) {
 
853
                putbyte(outf, DVI_FNT1);
 
854
                putbyte(outf, index);
 
855
                CurrentPosition += 2;
 
856
        } else if (index < 65536) {
 
857
                putbyte(outf, DVI_FNT2);
 
858
                PutWord(outf, index);
 
859
                CurrentPosition += 3;
 
860
        } else if (index < 16777216) {
 
861
                putbyte(outf, DVI_FNT3);
 
862
                Put3Byte(outf, index);
 
863
                CurrentPosition += 4;
 
864
        } else {
 
865
                putbyte(outf, DVI_FNT4);
 
866
                PutLong(outf, index);
 
867
                CurrentPosition += 5;
 
868
        }
 
869
}
 
870
 
 
871
/*
 
872
 * The following table describes the length (in bytes) of each of the DVI
 
873
 * commands that we can simply copy, starting with DVI_SET1 (128).
 
874
 */
 
875
char    oplen[128] = {
 
876
        0, 0, 0, 0,             /* DVI_SET1 .. DVI_SET4 */
 
877
        9,                      /* DVI_SETRULE */
 
878
        0, 0, 0, 0,             /* DVI_PUT1 .. DVI_PUT4 */
 
879
        9,                      /* DVI_PUTRULE */
 
880
        1,                      /* DVI_NOP */
 
881
        0,                      /* DVI_BOP */
 
882
        0,                      /* DVI_EOP */
 
883
        1,                      /* DVI_PUSH */
 
884
        1,                      /* DVI_POP */
 
885
        2, 3, 4, 5,             /* DVI_RIGHT1 .. DVI_RIGHT4 */
 
886
        1,                      /* DVI_W0 */
 
887
        2, 3, 4, 5,             /* DVI_W1 .. DVI_W4 */
 
888
        1,                      /* DVI_X0 */
 
889
        2, 3, 4, 5,             /* DVI_X1 .. DVI_X4 */
 
890
        2, 3, 4, 5,             /* DVI_DOWN1 .. DVI_DOWN4 */
 
891
        1,                      /* DVI_Y0 */
 
892
        2, 3, 4, 5,             /* DVI_Y1 .. DVI_Y4 */
 
893
        1,                      /* DVI_Z0 */
 
894
        2, 3, 4, 5,             /* DVI_Z1 .. DVI_Z4 */
 
895
        0,                      /* DVI_FNTNUM0 (171) */
 
896
        0, 0, 0, 0, 0, 0, 0, 0, /* 172 .. 179 */
 
897
        0, 0, 0, 0, 0, 0, 0, 0, /* 180 .. 187 */
 
898
        0, 0, 0, 0, 0, 0, 0, 0, /* 188 .. 195 */
 
899
        0, 0, 0, 0, 0, 0, 0, 0, /* 196 .. 203 */
 
900
        0, 0, 0, 0, 0, 0, 0, 0, /* 204 .. 211 */
 
901
        0, 0, 0, 0, 0, 0, 0, 0, /* 212 .. 219 */
 
902
        0, 0, 0, 0, 0, 0, 0, 0, /* 220 .. 227 */
 
903
        0, 0, 0, 0, 0, 0, 0,    /* 228 .. 234 */
 
904
        0, 0, 0, 0,             /* DVI_FNT1 .. DVI_FNT4 */
 
905
        0, 0, 0, 0,             /* DVI_XXX1 .. DVI_XXX4 */
 
906
        0, 0, 0, 0,             /* DVI_FNTDEF1 .. DVI_FNTDEF4 */
 
907
        0,                      /* DVI_PRE */
 
908
        0,                      /* DVI_POST */
 
909
        0,                      /* DVI_POSTPOST */
 
910
        0, 0, 0, 0, 0, 0,       /* 250 .. 255 */
 
911
};
 
912
 
 
913
/*
 
914
 * Here we read the input DVI file and write relevant pages to the
 
915
 * output DVI file. We also keep track of font changes, handle font
 
916
 * definitions, and perform some other housekeeping.
 
917
 */
 
918
void HandleDVIFile()
 
919
{
 
920
        register int c, l;
 
921
        register i32 p;
 
922
        register int CurrentFontOK = 0;
 
923
        int doingpage = 0;
 
924
 
 
925
        /* Only way out is via "return" statement */
 
926
        for (;;) {
 
927
                c = getc(inf);  /* getc() returns unsigned values */
 
928
                if (DVI_IsChar(c)) {
 
929
                        /*
 
930
                         * Copy chars, note font usage, but ignore if
 
931
                         * page is not interesting.
 
932
                         */
 
933
                        if (!UseThisPage)
 
934
                                continue;
 
935
                        if (!CurrentFontOK) {
 
936
                                ReallyUseFont();
 
937
                                CurrentFontOK++;
 
938
                        }
 
939
                        putbyte(outf, c);
 
940
                        CurrentPosition++;
 
941
                        continue;
 
942
                }
 
943
                if (DVI_IsFont(c)) {    /* note font change */
 
944
                        CurrentFontIndex = c - DVI_FNTNUM0;
 
945
                        CurrentFontOK = 0;
 
946
                        continue;
 
947
                }
 
948
                if (c == EOF)
 
949
                        GripeUnexpectedDVIEOF();
 
950
                if ((l = (oplen - 128)[c]) != 0) {      /* simple copy */
 
951
                        if (!UseThisPage) {
 
952
                                while (--l > 0)
 
953
                                        (void) getc(inf);
 
954
                                continue;
 
955
                        }
 
956
                        CurrentPosition += l;
 
957
                        putbyte(outf, c);
 
958
                        while (--l > 0) {
 
959
                                c = getc(inf);
 
960
                                putbyte(outf, c);
 
961
                        }
 
962
                        if (ferror(outf))
 
963
                                error(1, -1, writeerr);
 
964
                        continue;
 
965
                }
 
966
                if ((l = DVI_OpLen(c)) != 0) {
 
967
                        /*
 
968
                         * Handle other generics.
 
969
                         * N.B.: there should only be unsigned parameters
 
970
                         * here (save SGN4), for commands with negative
 
971
                         * parameters have been taken care of above.
 
972
                         */
 
973
                        switch (l) {
 
974
 
 
975
                        case DPL_UNS1:
 
976
                                p = getc(inf);
 
977
                                break;
 
978
 
 
979
                        case DPL_UNS2:
 
980
                                fGetWord(inf, p);
 
981
                                break;
 
982
 
 
983
                        case DPL_UNS3:
 
984
                                fGet3Byte(inf, p);
 
985
                                break;
 
986
 
 
987
                        case DPL_SGN4:
 
988
                                fGetLong(inf, p);
 
989
                                break;
 
990
 
 
991
                        default:
 
992
                                panic("HandleDVIFile l=%d", l);
 
993
                        }
 
994
 
 
995
                        /*
 
996
                         * Now that we have the parameter, perform the
 
997
                         * command.
 
998
                         */
 
999
                        switch (DVI_DT(c)) {
 
1000
 
 
1001
                        case DT_SET:
 
1002
                        case DT_PUT:
 
1003
                                if (!UseThisPage)
 
1004
                                        continue;
 
1005
                                if (!CurrentFontOK) {
 
1006
                                        ReallyUseFont();
 
1007
                                        CurrentFontOK++;
 
1008
                                }
 
1009
                                putbyte(outf, c);
 
1010
                                switch (l) {
 
1011
 
 
1012
                                case DPL_UNS1:
 
1013
                                        putbyte(outf, p);
 
1014
                                        CurrentPosition += 2;
 
1015
                                        continue;
 
1016
 
 
1017
                                case DPL_UNS2:
 
1018
                                        PutWord(outf, p);
 
1019
                                        CurrentPosition += 3;
 
1020
                                        continue;
 
1021
 
 
1022
                                case DPL_UNS3:
 
1023
                                        Put3Byte(outf, p);
 
1024
                                        CurrentPosition += 4;
 
1025
                                        continue;
 
1026
 
 
1027
                                case DPL_SGN4:
 
1028
                                        PutLong(outf, p);
 
1029
                                        CurrentPosition += 5;
 
1030
                                        continue;
 
1031
                                }
 
1032
 
 
1033
                        case DT_FNT:
 
1034
                                CurrentFontIndex = p;
 
1035
                                CurrentFontOK = 0;
 
1036
                                continue;
 
1037
 
 
1038
                        case DT_XXX:
 
1039
                                HandleSpecial(c, l, p);
 
1040
                                continue;
 
1041
 
 
1042
                        case DT_FNTDEF:
 
1043
                                HandleFontDef(p);
 
1044
                                continue;
 
1045
 
 
1046
                        default:
 
1047
                                panic("HandleDVIFile DVI_DT(%d)=%d",
 
1048
                                      c, DVI_DT(c));
 
1049
                        }
 
1050
                        continue;
 
1051
                }
 
1052
 
 
1053
                switch (c) {    /* handle the few remaining cases */
 
1054
 
 
1055
                case DVI_BOP:
 
1056
                        if (doingpage)
 
1057
                                GripeUnexpectedOp("BOP (during page)");
 
1058
                        BeginPage();
 
1059
                        doingpage = 1;
 
1060
                        CurrentFontOK = 0;
 
1061
                        break;
 
1062
 
 
1063
                case DVI_EOP:
 
1064
                        if (!doingpage)
 
1065
                                GripeUnexpectedOp("EOP (outside page)");
 
1066
                        EndPage();
 
1067
                        doingpage = 0;
 
1068
                        break;
 
1069
 
 
1070
                case DVI_PRE:
 
1071
                        GripeUnexpectedOp("PRE");
 
1072
                        /* NOTREACHED */
 
1073
 
 
1074
                case DVI_POST:
 
1075
                        if (doingpage)
 
1076
                                GripeUnexpectedOp("POST (inside page)");
 
1077
                        return;
 
1078
 
 
1079
                case DVI_POSTPOST:
 
1080
                        GripeUnexpectedOp("POSTPOST");
 
1081
                        /* NOTREACHED */
 
1082
 
 
1083
                default:
 
1084
                        GripeUndefinedOp(c);
 
1085
                        /* NOTREACHED */
 
1086
                }
 
1087
        }
 
1088
}