Back to index

tetex-bin  3.0
dvisel.c
Go to the documentation of this file.
00001 /*
00002  * select pages from a DVI file.
00003  *
00004  * Copyright (c) 1999
00005  *      WATANABE Takeshi        watanabe@komadori.planet.sci.kobe-u.ac.jp
00006  * Copyright (c) 2002-2004 the xdvik development team
00007  *
00008  * Permission is hereby granted, free of charge, to any person obtaining a copy
00009  * of this software and associated documentation files (the "Software"), to
00010  * deal in the Software without restriction, including without limitation the
00011  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00012  * sell copies of the Software, and to permit persons to whom the Software is
00013  * furnished to do so, subject to the following conditions:
00014  * 
00015  * The above copyright notice and this permission notice shall be included in
00016  * all copies or substantial portions of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00019  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00021  * NONINFRINGEMENT.  IN NO EVENT SHALL ANY AUTHO OF THIS SOFTWARE BE
00022  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
00023  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00024  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00025  * SOFTWARE.
00026  */
00027 
00028 #include <string.h>
00029 #include <ctype.h>
00030 
00031 #include "dvi.h"
00032 #include "pagesel.h"
00033 #include "dvisel.h"
00034 #include "util.h"
00035 #include "dvi-init.h"
00036 #include "events.h"
00037 #include "dvi-draw.h"
00038 #include "message-window.h"
00039 #include "statusline.h"
00040 #include "print-dialog.h"
00041 
00042 /* stack for HTEX / Color stack */
00043 typedef enum { IS_A_HREF, IS_A_COLOR } stackElemT;
00044 
00045 /*
00046  * Length of BOP command, without p[4] (previous BOP pointer):
00047  * bop c_0[4] ... c_9[4]
00048  */
00049 static const int BOP_PART_LEN = 1 + 10 * 4;
00050 /*
00051  * Like above but with p[4]:
00052  */
00053 static const int BOP_LEN = 1 + 10 * 4 + 4;
00054 /*
00055  * Lenght of postamble:
00056  * post p[4] num[4] den[4] mag[4] l[4] u[4] s[2] t[2]
00057  */
00058 static const int POSTAMBLE_LEN = 1 + 4 * 6 + 2 + 2;
00059 /*
00060  * Postamble without p[4] (final bop offset) and t[2] (total page number):
00061  * num[4] den[4] mag[4] l[4] u[4] s[2]
00062  */
00063 static const int POSTAMBLE_PART_LEN = 4 * 5 + 2; 
00064 
00065 static char *dvips_papersize_special = NULL;
00066 
00067 /*
00068  * Struct to save specials that need to be copied verbatim into the output file
00069  * (things like `draftcopy'; see dvips manual, `Literal headers')
00070  */
00071 struct literal_headers {
00072     size_t size;
00073     char **headers;
00074 };
00075 static struct literal_headers literal_headers = { 0, NULL };
00076 
00077 static struct specials_stack color_stack = { 0, NULL};
00078 static struct specials_stack href_stack = { 0, NULL};
00079 
00080 /*
00081   stacks saved from the previous page (i.e. active at the
00082   beginning of the page)
00083  */
00084 static struct specials_stack color_save_stack = { 0, NULL };
00085 static struct specials_stack href_save_stack = { 0, NULL };
00086 
00087 static void
00088 push_stack(struct specials_stack *stack, const char *content)
00089 {
00090     stack->items = xrealloc(stack->items, (stack->stack_len + 1) * sizeof *(stack->items));
00091     stack->items[stack->stack_len].content = xstrdup(content);
00092     stack->stack_len++;
00093 }
00094 
00095 static Boolean
00096 stack_contains_item(struct specials_stack *stack, const char *str)
00097 {
00098     size_t i;
00099     for (i = 0; i < stack->stack_len; i++) {
00100        if (strcmp(str, stack->items[i].content) == 0) {
00101            return True;
00102        }
00103     }
00104     return False;
00105 }
00106 
00107 static void
00108 pop_stack(struct specials_stack *stack)
00109 {
00110     ASSERT(stack->stack_len >= 1, "Attempt to pop empty stack");
00111     free(stack->items[stack->stack_len - 1].content);
00112     stack->stack_len--;
00113 }
00114 
00115 static void
00116 empty_stack(struct specials_stack *stack)
00117 {
00118     while(stack->stack_len > 0) {
00119        pop_stack(stack);
00120     }
00121 }
00122 
00123 /*
00124   This is used instead of struct tn, and struct font* from dvi-init.h,
00125   since it appears that we don't need all the information from there.
00126 */
00127 static struct fontinfo {
00128     long TeXnumber;
00129     unsigned char info[14];
00130     char *fontname;
00131     struct fontinfo *next;
00132     Boolean used;
00133 } *fontinfo_head;
00134 
00135 #define PutFour(num, fp) {         \
00136     putc(((num) >> 24) & 0xff, (fp));     \
00137     putc(((num) >> 16) & 0xff, (fp));     \
00138     putc(((num) >> 8)  & 0xff, (fp));     \
00139     putc( (num)        & 0xff, (fp));     \
00140 }
00141 
00142 #define CopyNum(fin, fout, num) {         \
00143     int m = num;                          \
00144     while (--m >= 0) putc(getc(fin), fout);      \
00145 }
00146 
00147 static void
00148 FontWrite(FILE *fout, struct fontinfo *fontp, long *fout_pos)
00149 {
00150     if (fontp->TeXnumber > 0xff) {
00151        if (fontp->TeXnumber > 0xffff) {
00152            if (fontp->TeXnumber > 0xffffff) {
00153               putc(FNTDEF4, fout);
00154               putc((fontp->TeXnumber >> 24) & 0xff, fout);
00155               (*fout_pos)++;
00156            }
00157            else {
00158               putc(FNTDEF3, fout);
00159            }
00160            putc((fontp->TeXnumber >> 16) & 0xff, fout);
00161            (*fout_pos)++;
00162        }
00163        else {
00164            putc(FNTDEF2, fout);
00165        }
00166        putc((fontp->TeXnumber >> 8) & 0xff, fout);
00167        (*fout_pos)++;
00168     }
00169     else {
00170        putc(FNTDEF1, fout);
00171     }
00172     putc(fontp->TeXnumber & 0xff, fout);
00173     fwrite(fontp->info, sizeof(char), 14, fout);
00174     fwrite(fontp->fontname, sizeof(char), fontp->info[12] + fontp->info[13], fout);
00175     (*fout_pos) += 2 + 14 + fontp->info[12] + fontp->info[13];
00176 }
00177 
00178 /*
00179   Invoked by spcl_scan; saves file names referenced by special commands
00180   into the `warn_files' field of `info'.
00181 */
00182 static Boolean
00183 scan_for_included_files(char *special, int str_len, void *my_info)
00184 {
00185     struct select_pages_info *info = (struct select_pages_info *)my_info;
00186     UNUSED(str_len);
00187     if (info->warn_files.items == NULL) /* no info needed, e.g. when printing */
00188        return True;
00189     
00190     while (*special == ' ' || *special == '\t')
00191        ++special;
00192 
00193     if (memicmp(special, "psfile=", strlen("psfile=")) == 0) {
00194        char *b_ptr = special + strlen("psfile=");
00195        char *e_ptr;
00196        
00197        while (*b_ptr == '"')
00198            b_ptr++;
00199        
00200        if ((e_ptr = strchr(b_ptr, '"')) != NULL) {
00201            size_t len = e_ptr - b_ptr;
00202            char *tmp = xmalloc(len + 1);
00203            memcpy(tmp, b_ptr, len);
00204            tmp[len] = '\0';
00205            if (!stack_contains_item(&(info->warn_files), tmp)) {
00206               push_stack(&(info->warn_files), tmp);
00207            }
00208            free(tmp);
00209        }
00210     }
00211     
00212     return True; /* dummy */
00213 }
00214 
00215 /*
00216   Invoked by spcl_scan; saves hyperref and color commands
00217   into the global stacks `color_stack' and `hyperref_stack'.
00218   FIXME: In reality char *special is treated as const, but the declaration
00219   of spcl_scan doesn't allow for this.
00220 */
00221 static Boolean
00222 stack_save(char *special, int str_len, void *data)
00223 {
00224     char *ptr;
00225     size_t len;
00226 
00227     UNUSED(data);
00228     UNUSED(str_len);
00229     
00230     while (isspace((int)*special))
00231        ++special;
00232     
00233     ptr = special;
00234     
00235     if (memicmp(special, "color ", len = strlen("color ")) == 0) {
00236        special += len;
00237        while (*special == ' ' || *special == '\t')
00238            ++special;
00239        if (memicmp(special, "push ", 5) == 0) {
00240            push_stack(&color_stack, ptr);
00241        }
00242        else if (memicmp(special, "pop", 3) == 0) {
00243            pop_stack(&color_stack);
00244        }
00245     }
00246     else if (memicmp(special, "html:", len = strlen("html:")) == 0) {
00247        /*     fprintf(stderr, "++++ special: %s; fd: %ld\n", special + 5, ftell(globals.dvi_file.bak_fp)); */
00248        special += len;
00249        if (memicmp(special, "<a href=", 8) == 0
00250            || memicmp(special, "<a name=", 8) == 0) {
00251            push_stack(&href_stack, ptr);
00252        }
00253        else if (memicmp(special, "</a>", 4) == 0) {
00254            pop_stack(&href_stack);
00255        }
00256     }
00257     else if (memicmp(special, "papersize", len = strlen("papersize")) == 0) {
00258        free(dvips_papersize_special);
00259        dvips_papersize_special = xstrdup(special);
00260     }
00261     else  if (*special == '!'
00262              || memcmp(special, "header", strlen("header")) == 0) {
00263        size_t idx = literal_headers.size++;
00264        if (globals.debug & DBG_GUI)
00265            fprintf(stderr, "(literal) header %lu: |%s|\n", (unsigned long)idx, special);
00266        literal_headers.headers = xrealloc(literal_headers.headers,
00267                                       literal_headers.size * sizeof *(literal_headers.headers));
00268        literal_headers.headers[idx] = xstrdup(special);
00269     }
00270     return True; /* dummy */
00271 }
00272 
00273 /* write a special to the FILE *fp, updating offset as appropriate. */
00274 static void
00275 write_special(const char *str, FILE *fp, long *offset)
00276 {
00277     unsigned int len = strlen(str);
00278     if (len < 256) {
00279        unsigned char c = len;
00280        putc(XXX1, fp);
00281        putc(c, fp);
00282        *offset += 2;
00283     }
00284     else { /* how about xxx2, xxx3? It seems that TeX doesn't use them either? */
00285        putc(XXX4, fp);
00286        PutFour(len, fp);
00287        *offset += 5;
00288     }
00289     fputs(str, fp);
00290     *offset += len;
00291 }
00292 
00293 /*
00294  * Dump the headers in the global list `literal_headers',
00295  * and free up resources
00296  */
00297 static void
00298 dump_literal_headers(FILE *fp, long *pos)
00299 {
00300     size_t i;
00301     for (i = 0; i < literal_headers.size; i++) {
00302        write_special(literal_headers.headers[i], fp, pos);
00303        free(literal_headers.headers[i]);
00304     }
00305     free(literal_headers.headers);
00306     literal_headers.headers = NULL;
00307     literal_headers.size = 0;
00308 }
00309 
00310 
00311 static void
00312 scan_page_for_specials(FILE *fp, int page, Boolean save_stack,
00313                      Boolean (*special_proc)(char *str, int str_len, void *data),
00314                      struct select_pages_info *info)
00315 {
00316     off_t pos_save;
00317     static ubyte my_scan_buffer[DVI_BUFFER_LEN];
00318 
00319     struct drawinf currinf_save;
00320     ubyte maxchar_save;
00321     size_t i;
00322     TRACE_GUI((stderr, "parsing page: %d", page));
00323     if (save_stack) {
00324        /*
00325          first, copy the current stacks (which reflect the state on the
00326          preceding page) to color_save_stack and href_save_stack:
00327        */
00328        empty_stack(&color_save_stack);
00329        empty_stack(&href_save_stack);
00330        for (i = 0; i < color_stack.stack_len; i++) {
00331            TRACE_GUI((stderr, "saving stack: |%s|", color_stack.items[i].content));
00332            push_stack(&color_save_stack, color_stack.items[i].content);
00333        }
00334        for (i = 0; i < href_stack.stack_len; i++) {
00335            TRACE_GUI((stderr, "saving stack: |%s|", href_stack.items[i].content));
00336            push_stack(&href_save_stack, href_stack.items[i].content);
00337        }
00338     }
00339     
00340     /*     (void)fseek(fp, pageinfo_get_offset(page), SEEK_SET); */
00341     /*
00342       The datastructures in dvi-draw are rather weird in requiring
00343       us to provide a buffer, and point the global currinf.pos and end
00344       pointers to that buffer, for spcl_scan to be able to scan the file.
00345       First save the contents of the exising currinf, pointing to the main file:
00346     */
00347     pos_save = save_file_status(fp, &currinf_save, &maxchar_save);
00348 
00349     lseek(fileno(fp), pageinfo_get_offset(page), SEEK_SET);
00350     memset((char *)&currinf.data, 0, sizeof currinf.data);
00351     currinf.tn_table_len = TNTABLELEN;
00352     currinf.tn_table = tn_table;
00353     currinf.tn_head = tn_head;
00354 
00355     /* then point currinf to our own buffer: */
00356     G_dvi_buf_ptr = my_scan_buffer;
00357     currinf.pos = currinf.end = G_dvi_buf_ptr;
00358     lseek(fileno(fp), pageinfo_get_offset(page), SEEK_SET);
00359     /*
00360       finally we may invoke spcl_scan(). I hope we can do without
00361       the
00362       (!setjmp(some_env))
00363       black magic since there shouldn't be any interruptions ...
00364     */
00365 #if 1    
00366     spcl_scan(special_proc, info, False, fp);
00367 #else
00368     /* this is an attempt at using setjmp(), but it's just too ugly ... */
00369     for (;;) {
00370        int page_bak;
00371        if (read_events(EV_NOWAIT) & EV_GE_NEWPAGE)
00372            break;
00373        page_bak = page;
00374        if (!setjmp(globals.ev.canit)) {
00375            fprintf(stderr, "current position: %lu; seeking to: %lu\n",
00376                   (unsigned long)pos_save,
00377                   (unsigned long)pageinfo_get_offset(page));
00378            (void) fprintf(stderr, "seeking to offset %ld, page %d of file %d\n",
00379                         pageinfo_get_offset(page),
00380                         page, fileno(globals.dvi_file.bak_fp));
00381            fseek(fp, pageinfo_get_offset(page), SEEK_SET);
00382            spcl_scan(special_proc, info, False);
00383        }
00384        else { /* if interrupted */
00385            fprintf(stderr, "========= interrupted!\n");
00386            if (page >= page_bak)
00387               page = page_bak;
00388            break;
00389        }
00390        if (page >= current_page)
00391            break;
00392        page++;
00393     }
00394 #endif
00395     /* now we restore those pesky globals, hoping that nobody
00396        has stamped upon them in the meantime. */
00397     restore_file_status(fp, currinf_save, maxchar_save, pos_save);
00398 
00399     /* reposition file pointer */
00400     (void)fseek(fp, pageinfo_get_offset(page), SEEK_SET);
00401 }
00402 
00403 
00404 /* dump the `open' commands on the current stack to the FILE *fp */
00405 static void
00406 stack_dump_open_commands(FILE *fp, long *pos)
00407 {
00408     size_t i;
00409     TRACE_GUI((stderr, "length of stacks: %lu, %lu",
00410               (unsigned long)color_save_stack.stack_len,
00411               (unsigned long)href_save_stack.stack_len));
00412     for (i = 0; i < color_save_stack.stack_len; i++) {
00413        TRACE_GUI((stderr, "dumping: |%s|", color_save_stack.items[i].content));
00414        write_special(color_save_stack.items[i].content, fp, pos);
00415     }
00416     for (i = 0; i < href_save_stack.stack_len; i++) {
00417        TRACE_GUI((stderr, "dumping: |%s|", href_save_stack.items[i].content));
00418        write_special(href_save_stack.items[i].content, fp, pos);
00419     }
00420     if (dvips_papersize_special != NULL)
00421        write_special(dvips_papersize_special, fp, pos);
00422     TRACE_GUI((stderr, "end of dumping open\n"));
00423 }
00424 
00425 /* dump `close' commands for all the `open' commands on the
00426    current stack (not the saved one, but the one active at the end of the page)
00427    to the FILE *fp (closing tags for hyperref anchors,
00428    `pop' commands for color specials).
00429 */
00430 static void
00431 stack_dump_close_commands(FILE *fp, long *pos)
00432 {
00433     size_t i;
00434 
00435     for (i = color_stack.stack_len; i > 0; i--) {
00436        TRACE_GUI((stderr, "===== color pop"));
00437        write_special("color pop", fp, pos);
00438     }
00439     for (i = href_stack.stack_len; i > 0; i--) {
00440        TRACE_GUI((stderr, "===== html:</a>"));
00441        write_special("html:</a>", fp, pos);
00442     }
00443 }
00444 
00445 
00446 static void
00447 WriteDVI(FILE *fin, FILE *fout, long *fout_pos, int c)
00448 {
00449     int i, n;
00450     struct fontinfo *fontp;
00451 
00452     if (c >= FNTNUM0 && c <= FNT4) {
00453        if (c >= FNT1)
00454            n = get_bytes(fin, c - FNT1 + 1);
00455        else
00456            n = c - FNTNUM0;
00457        for (fontp = fontinfo_head; fontp; fontp = fontp->next)
00458            if (n == fontp->TeXnumber)
00459               break;
00460        if (fontp && fontp->used == False) {
00461            fontp->used = True;
00462            FontWrite(fout, fontp, fout_pos);
00463        }
00464        putc(c, fout);
00465        (*fout_pos)++;
00466        switch (c) {
00467        case FNT4:
00468            putc((n >> 24) & 0xff, fout);
00469            (*fout_pos)++;
00470        case FNT3:
00471            putc((n >> 16) & 0xff, fout);
00472            (*fout_pos)++;
00473        case FNT2:
00474            putc((n >> 8) & 0xff, fout);
00475            (*fout_pos)++;
00476        case FNT1:
00477            putc(n & 0xff, fout);
00478            (*fout_pos)++;
00479        default:
00480            break;
00481        }
00482     }
00483     else if (c >= FNTDEF1 && c <= FNTDEF4) {
00484        n = get_bytes(fin, c - FNTDEF1 + 1);
00485        for (fontp = fontinfo_head; fontp; fontp = fontp->next)
00486            if (n == fontp->TeXnumber)
00487               break;
00488        if (fontp && fontp->used == False) {
00489            fontp->used = True;
00490            FontWrite(fout, fontp, fout_pos);
00491        }
00492        (void) get_bytes(fin, 12);
00493        (void) get_bytes(fin, (int)(get_byte(fin) + get_byte(fin)));
00494     }
00495     else {
00496        putc(c, fout);
00497        (*fout_pos)++;
00498        n = 0;
00499        if (c <= XXX4) {
00500            for (i = 0; i < c - XXX1 + 1; i++) {
00501               int x = get_byte(fin);
00502               putc(x, fout);
00503               (*fout_pos)++;
00504               n = (n << 8) | x;
00505            }
00506        }
00507        switch (c) {
00508        case SETRULE:
00509        case PUTRULE:
00510            n += 4;
00511            /* fall through */
00512            
00513        case RIGHT4:
00514        case W4:
00515        case X4:
00516        case DOWN4:
00517        case Y4:
00518        case Z4:
00519            n++;
00520            /* fall through */
00521 
00522        case RIGHT3:
00523        case W3:
00524        case X3:
00525        case DOWN3:
00526        case Y3:
00527        case Z3:
00528            n++;
00529            /* fall through */
00530 
00531        case SET2:
00532        case PUT2: 
00533            if (!resource.omega) {
00534               dvi_fmt_error("%s:%d: WriteDVI: op-code %d only works with the \"-omega\" option",
00535                            __FILE__, __LINE__, c);
00536            }
00537        case RIGHT2:
00538        case W2:
00539        case X2:
00540        case DOWN2:
00541        case Y2:
00542        case Z2:
00543            n++;
00544            /* fall through */
00545 
00546        case SET1:
00547        case PUT1:
00548        case RIGHT1:
00549        case W1:
00550        case X1:
00551        case DOWN1:
00552        case Y1:
00553        case Z1:
00554 #ifdef PTEX
00555        case TDIR:
00556 #endif
00557            n++;
00558            /* fall through */
00559 
00560        case XXX1:
00561        case XXX2:
00562        case XXX3:
00563        case XXX4:
00564            CopyNum(fin, fout, n);
00565            (*fout_pos) += n;
00566            /* fall through */
00567 
00568        default:
00569            break;
00570        }
00571     }
00572 }
00573 
00574 /* public functions */
00575 
00576 
00577 /* callback functions for selecting pages */
00578 Boolean
00579 check_pagerange(struct select_pages_info *info, int page)
00580 {
00581     return (page >= info->from && page <= info->to);
00582 }
00583 
00584 Boolean
00585 check_marked(struct select_pages_info *info, int page)
00586 {
00587     UNUSED(info);
00588     return pageinfo_is_marked(page);
00589 }
00590 
00591 void
00592 select_pages(struct select_pages_info *pinfo)
00593 {
00594     int c, n, page, pagecnt;
00595     long fout_pos = 0L;
00596     unsigned long curr_page_offset = 0xffffffff; /* pattern to be overwritten later */
00597     unsigned long post_cmd_offset = 0xffffffff; /* pattern to be overwritten later */
00598     struct fontinfo *fontp;
00599     FILE *in_fp = pinfo->finfo->dvi_in.fp;
00600     FILE *out_fp = pinfo->finfo->dvi_tmp.fp;
00601     
00602     Boolean headers_dumped = False;
00603     free(dvips_papersize_special); /* re-initialize */
00604     dvips_papersize_special = NULL;
00605 
00606     ASSERT(in_fp != NULL, "input file mustn't be NULL in select_pages()!");
00607     ASSERT(out_fp != NULL, "output file mustn't be NULL in select_pages()!");
00608     
00609     pinfo->errflag = NO_ERROR; /* reset errflag, in case we're recovering from a previous error */
00610     
00611     /* get font list from postamble; in_fp already has been positioned
00612        at correct position (start of postamble) in caller. */
00613     (void)fseek(in_fp, ftell(in_fp), SEEK_SET); /* paranoia */
00614     (void)get_bytes(in_fp, POSTAMBLE_LEN);
00615     fontinfo_head = NULL;
00616     for (;;) {
00617        if ((c = get_byte(in_fp)) < FNTDEF1 || c > FNTDEF4) /* maybe POSTPOST */
00618            break;
00619        fontp = (struct fontinfo *) xmalloc(sizeof(struct fontinfo));
00620        fontp->TeXnumber = get_bytes(in_fp, c - FNTDEF1 + 1);
00621        fread(fontp->info, sizeof(char), 14, in_fp);
00622        n = fontp->info[12] + fontp->info[13];
00623        fontp->fontname = xmalloc(n);
00624        fread(fontp->fontname, sizeof(char), n, in_fp);
00625        fontp->next = fontinfo_head;
00626        fontinfo_head = fontp;
00627        fontp->used = False;
00628     }
00629 
00630     /* preamble */
00631     fseek(in_fp, 0L, SEEK_SET);
00632     fout_pos = pageinfo_get_offset(0);
00633     CopyNum(in_fp, out_fp, fout_pos);
00634 
00635     /* each page */
00636     pagecnt = 0;
00637     for (page = 0; page < total_pages; page++) {
00638        scan_page_for_specials(in_fp, page, True, stack_save, NULL);
00639 
00640        /* should the current page be selected? */
00641        if (pinfo->callback == NULL || pinfo->callback(pinfo, page)) {
00642            scan_page_for_specials(in_fp, page, False, scan_for_included_files, pinfo);
00643 
00644            /* read BOP except for p[4] */
00645            CopyNum(in_fp, out_fp, BOP_PART_LEN);
00646            /* read p[4] (previous bop pointer */
00647            (void)get_bytes(in_fp, 4);
00648            /* write actual value of p[4] */
00649            PutFour(curr_page_offset, out_fp);
00650            /* remember offset of current page, for postamble */
00651            curr_page_offset = fout_pos;
00652            /* update fout_pos to current position */
00653            fout_pos += BOP_LEN;
00654            
00655            if (!headers_dumped) {
00656               headers_dumped = True;
00657               dump_literal_headers(out_fp, &fout_pos);
00658            }
00659 
00660            /*            if (!written_pre_cmds) { */
00661            stack_dump_open_commands(out_fp, &fout_pos);
00662 /*            written_pre_cmds = True; */
00663 /*         } */
00664 
00665            while ((c = getc(in_fp)) != EOF) {
00666               if ((c & 0x80) == 0) { /* ordinary character */
00667                   putc(c, out_fp);
00668                   fout_pos++;
00669               }
00670               else if (c == EOP) { /* End Of Page */
00671 /*                fprintf(stderr, "EOP at %ld\n", ftell(fin)); */
00672 
00673 /*                if (page == to) {  */ /* print close stack for last page */
00674                   stack_dump_close_commands(out_fp, &fout_pos);
00675 /*                } */
00676 
00677                   putc(c, out_fp);
00678                   fout_pos++;
00679                   break;
00680               }
00681               else {
00682 /*                fprintf(stderr, "WRITE_DVI before: %ld, in_fp before: %ld\n", fout_pos, ftell(in_fp)); */
00683                   WriteDVI(in_fp, out_fp, &fout_pos, c);
00684 /*                fprintf(stderr, "WRITE_DVI after: %ld; in_fp after: %ld\n", fout_pos, ftell(in_fp)); */
00685               }
00686               /* HACK alert: force synchronization - why is this neccessary?
00687                  Seems to have something do with the fact that two FILE *'s on the same
00688                  file are open. POSIX.1,
00689                  `Interaction of File Descriptors and Standard I/O Streams' seems to
00690                  say the seek()s on one of them also affect the other, but I'm not sure
00691                  about this.
00692                */
00693               fseek(in_fp, 0L, SEEK_CUR);
00694            }
00695            pagecnt++;
00696        }
00697     }
00698 
00699     /* postamble */
00700     if (!find_postamble(in_fp, &(pinfo->errflag))) {
00701        return;
00702     }
00703 
00704     /* read/write POST command */
00705     putc(get_byte(in_fp), out_fp);
00706     /* read over last page offset */
00707     get_bytes(in_fp, 4);
00708     /* write last page offset */
00709     PutFour(curr_page_offset, out_fp);
00710     /* remember start of POST */
00711     post_cmd_offset = fout_pos;
00712     /* copy part of postamble */
00713     CopyNum(in_fp, out_fp, POSTAMBLE_PART_LEN);
00714     /* read t[2], total number of pages */
00715     get_bytes(in_fp, 2);
00716     /* write t[2] (two calls) */
00717     putc((pagecnt >> 8) & 0xff, out_fp);
00718     putc(pagecnt & 0xff, out_fp);
00719     /* update fout_pos to current pos */
00720     fout_pos += POSTAMBLE_LEN;
00721 
00722     /* output font list */
00723     for (;;) {
00724        if ((c = get_byte(in_fp)) < FNTDEF1 || c > FNTDEF4) /* maybe POSTPOST */
00725            break;
00726        n = get_bytes(in_fp, c - FNTDEF1 + 1);
00727        for (fontp = fontinfo_head; fontp; fontp = fontp->next)
00728            if (n == fontp->TeXnumber)
00729               break;
00730        if (fontp && fontp->used == True)
00731            FontWrite(out_fp, fontp, &fout_pos);
00732        (void) get_bytes(in_fp, 12);
00733        (void) get_bytes(in_fp, (int)(get_byte(in_fp) + get_byte(in_fp)));
00734     }
00735 
00736     /* free list */
00737     for (fontp = fontinfo_head; fontp;) {
00738        struct fontinfo *nextp;
00739        free(fontp->fontname);
00740        nextp = fontp->next;
00741        free(fontp);
00742        fontp = nextp;
00743     }
00744 
00745     /* POSTPOST */
00746     putc(c, out_fp);
00747     get_bytes(in_fp, 4);
00748     PutFour(post_cmd_offset, out_fp);
00749     CopyNum(in_fp, out_fp, 1 + 4);
00750     for (fout_pos += 1 + 4 + 1 + 4;
00751         fout_pos & 3;
00752         fout_pos++) {
00753        putc(TRAILER, out_fp);
00754     }
00755 
00756 /*      fclose(in_fp); */
00757     fflush(out_fp);
00758 }
00759