Back to index

tetex-bin  3.0
mpost.c
Go to the documentation of this file.
00001 /*  $Header: SCCS/s.mpost.c 1.1 00/08/05 01:52:14-00:00 mwicks@gaspra $
00002     
00003     This is dvipdfm, a DVI to PDF translator.
00004     Copyright (C) 1998, 1999 by Mark A. Wicks
00005     
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010     
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015     
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019     
00020     The author may be contacted via the e-mail address
00021     
00022     mwicks@kettering.edu
00023 */
00024 
00025 #include <stdlib.h>
00026 #include <ctype.h>
00027 #include <math.h>
00028 #include <string.h>
00029 #include "system.h"
00030 #include "mem.h"
00031 #include "error.h"
00032 #include "mfileio.h"
00033 #include "dvi.h"
00034 #include "pdfobj.h"
00035 #include "pdfspecial.h"
00036 #include "pdfparse.h"
00037 #include "mpost.h"
00038 #include "pdfparse.h"
00039 #include "pdflimits.h"
00040 #include "pdfdev.h"
00041 #include "pdfdoc.h"
00042 
00043 int check_for_mp (FILE *image_file) 
00044 {
00045   rewind (image_file);
00046   /* For now, this is an exact test that must be passed, character for
00047      character */
00048   mfgets (work_buffer, WORK_BUFFER_SIZE, image_file);
00049   if (strncmp (work_buffer, "%!PS", 4))
00050     return 0;
00051   mfgets (work_buffer, WORK_BUFFER_SIZE, image_file);
00052   if (strncmp (work_buffer, "%%BoundingBox", strlen("%%BoundingBox")))
00053     return 0;
00054   mfgets (work_buffer, WORK_BUFFER_SIZE, image_file);
00055   if (strncmp (work_buffer, "%%Creator: MetaPost", strlen("%%Creator: MetaPost")))
00056     return 0;
00057   return 1;
00058 }
00059 
00060 static struct mp_fonts 
00061 {
00062   char *tex_name;
00063   int font_id;
00064   double pt_size;
00065 } *mp_fonts = NULL;
00066 
00067 int n_mp_fonts = 0, max_mp_fonts = 0;
00068 
00069 static void need_more_mp_fonts (unsigned n)
00070 {
00071   if (n_mp_fonts + n > max_mp_fonts) {
00072     max_mp_fonts += MAX_FONTS;
00073     mp_fonts = RENEW (mp_fonts, max_mp_fonts, struct mp_fonts);
00074   }
00075 }
00076 
00077 
00078 
00079 int mp_locate_font (char *tex_name, double pt_size)
00080 {
00081   int result=-1, i;
00082   for (i=0; i<n_mp_fonts; i++) {
00083     if (!strcmp (tex_name, mp_fonts[i].tex_name) &&
00084        mp_fonts[i].pt_size == pt_size)
00085       break;
00086   }
00087   need_more_mp_fonts (1);
00088   if (i == n_mp_fonts) {
00089     n_mp_fonts += 1;
00090     mp_fonts[i].tex_name = NEW (strlen(tex_name)+1, char);
00091     strcpy (mp_fonts[i].tex_name, tex_name);
00092     mp_fonts[i].pt_size = pt_size;
00093     /* The following line is a bit of a kludge.  MetaPost inclusion
00094        was an afterthought */
00095     mp_fonts[i].font_id = dev_locate_font (tex_name,
00096                                       pt_size/dvi_unit_size());
00097     result = mp_fonts[i].font_id;
00098   } else 
00099     result = -1;
00100   return result;
00101 }
00102 
00103 static void release_fonts (void)
00104 {
00105   int i;
00106   for (i=0; i<n_mp_fonts; i++) {
00107     RELEASE (mp_fonts[i].tex_name);
00108   }
00109   if (mp_fonts) {
00110     RELEASE (mp_fonts);
00111     mp_fonts = NULL;
00112   }
00113   n_mp_fonts = 0;
00114   max_mp_fonts = 0;
00115 }
00116 
00117 int mp_is_font_name (char *tex_name)
00118 {
00119   int i;
00120   for (i=0; i<n_mp_fonts; i++) {
00121     if (!strcmp (tex_name, mp_fonts[i].tex_name))
00122       break;
00123   }
00124   if (i < n_mp_fonts)
00125     return 1;
00126   else
00127     return 0;
00128 }
00129 
00130 int mp_fontid (char *tex_name, double pt_size)
00131 {
00132   int i;
00133   for (i=0; i<n_mp_fonts; i++) {
00134     if (!strcmp (tex_name, mp_fonts[i].tex_name) &&
00135        (mp_fonts[i].pt_size == pt_size))
00136       break;
00137   }
00138   if (i < n_mp_fonts) {
00139     return i;
00140   }
00141   else {
00142     return -1;
00143   }
00144 }
00145 
00146 static int mp_parse_headers (FILE *image_file, struct xform_info *p)
00147 {
00148   int error = 0;
00149   char *start, *end, *token, *name;
00150   char *llx = NULL, *lly = NULL, *urx = NULL, *ury = NULL;
00151   unsigned long save_position;
00152 #ifdef MEM_DEBUG
00153   MEM_START
00154 #endif
00155  /* Scan for bounding box record */
00156   for (;;) {
00157     mfgets (work_buffer, WORK_BUFFER_SIZE, image_file);
00158     if (work_buffer[0] != '%' ||
00159        !strncmp (work_buffer, "%%BoundingBox:",
00160                strlen("%%BoundingBox")))
00161       break;
00162   }
00163   if (work_buffer[0] == '%') { /* Found %%BoundingBox */
00164     start = work_buffer + strlen("%%BoundingBox:");
00165     end = start+strlen(start);
00166     skip_white (&start, end);
00167     /* Expect 4 numbers or fail */
00168     if ((llx = parse_number (&start, end)) &&
00169        (lly = parse_number (&start, end)) &&
00170        (urx = parse_number (&start, end)) &&
00171        (ury = parse_number (&start, end))) {
00172       /* Set the crop box to the true bounding box specified in the
00173         file */
00174       p->c_llx = atof (llx);
00175       p->c_lly = atof (lly);
00176       p->c_urx = atof (urx);
00177       p->c_ury = atof (ury);
00178     } else{
00179       fprintf (stderr, "\nMissing expected number in bounding box specification:\n");
00180       dump (start, end);
00181       error = 1;
00182     }
00183   } else {    /* Didn't find Bounding box */
00184     fprintf (stderr, "\nFailed to find an expected BoundingBox record.\n");
00185     error = 1;
00186   }
00187   if (llx) RELEASE(llx);
00188   if (lly) RELEASE(lly);
00189   if (urx) RELEASE(urx);
00190   if (ury) RELEASE(ury);
00191   /* Got four numbers */
00192   /* Read all headers--act on *Font records */
00193   save_position = tell_position(image_file);
00194   while (!error && !feof(image_file) && mfgets (work_buffer, WORK_BUFFER_SIZE,
00195                                   image_file)) {
00196     if (*work_buffer != '%') {
00197       seek_absolute (image_file, save_position);
00198       break;
00199     }
00200     save_position = tell_position (image_file);
00201     if (*(work_buffer+1) == '*' &&
00202        !strncmp (work_buffer+2, "Font:", strlen("Font:"))) {
00203       double ps_ptsize;
00204       start = work_buffer+strlen("%*Font:");
00205       end = start+strlen(start);
00206       skip_white (&start, end);
00207       if ((name = parse_ident (&start, end))) {
00208        skip_white (&start, end);
00209       } else {
00210        fprintf (stderr, "\nMissing expected font name:\n");
00211        dump (start, end);
00212        error = 1;
00213        break;
00214       }
00215       if ((token = parse_number (&start, end))) {
00216        ps_ptsize = atof (token);
00217        RELEASE (token);
00218       } else {
00219        fprintf (stderr, "\nMissing expected font point size specification:\n");
00220        dump (start, end);
00221        error = 1;
00222        break;
00223       }
00224       mp_locate_font (name, ps_ptsize);
00225       RELEASE (name);
00226     }
00227   }
00228 #ifdef MEM_DEBUG
00229   MEM_END
00230 #endif
00231     return !error;
00232 }
00233 
00234 struct point {
00235   double x, y;
00236 };
00237 
00238 struct curve {
00239   double x[3], y[3];
00240 };
00241 
00242 static struct path_element
00243 {
00244   char type;
00245   void  *element;
00246 } *path = NULL;
00247 static int n_path_pts = 0, max_path_pts = 0;
00248 static int path_clip = 0, path_close = 0;
00249 
00250 #define MORE_PATH_POINTS 64
00251 
00252 static void need_points (int n)
00253 {
00254   if (n_path_pts+n > max_path_pts) {
00255     max_path_pts += MORE_PATH_POINTS;
00256     path = RENEW (path, max_path_pts, struct path_element);
00257   }
00258   return;
00259 }
00260 
00261 static void clip_path (void)
00262 {
00263   path_clip = 1;
00264 }
00265 
00266 static void close_path (void)
00267 {
00268   path_close = 1;
00269 }
00270 
00271 static void add_point_to_path (double x, double y, char type)
00272 {
00273   struct point *p;
00274   need_points (1);
00275   path[n_path_pts].type = type;
00276   p = NEW (1, struct point);
00277   p->x = x; p->y = y;
00278   path[n_path_pts].element = p;
00279   n_path_pts += 1;
00280   return;
00281 }
00282 
00283 static void add_curve_to_path (double x0, double y0,
00284                             double x1, double y1,
00285                             double x2, double y2)
00286 {
00287   struct curve *c;
00288   need_points (1);
00289   c = NEW (1, struct curve);
00290   path[n_path_pts].type = 'c';
00291   (c->x)[0] = x0; (c->y)[0] = y0;
00292   (c->x)[1] = x1; (c->y)[1] = y1;
00293   (c->x)[2] = x2; (c->y)[2] = y2;
00294   path[n_path_pts].element = c;
00295   n_path_pts += 1;
00296   return;
00297 }
00298 
00299 static void void_path (void)
00300 {
00301   int i;
00302   for (i=0; i<n_path_pts; i++) {
00303     RELEASE (path[i].element);
00304   }
00305   path_clip = 0;
00306   path_close = 0;
00307   n_path_pts = 0;
00308 }
00309 
00310 static void flush_path (void)
00311 {
00312   int i, len;
00313   for (i=0; i<n_path_pts; i++) {
00314     switch (path[i].type) {
00315     case 'm': /* moveto */ 
00316       /* Moveto must start a new path */
00317       /*      void_path (); */
00318     case 'l': /* lineto */ 
00319       {
00320        struct point *p;
00321        p = path[i].element;
00322        sprintf (work_buffer, "\n%g %g %c",
00323                      ROUND(p->x, 0.001), ROUND(p->y, 0.001),
00324                      path[i].type);
00325         len = strlen (work_buffer);
00326        pdf_doc_add_to_page (work_buffer, len);
00327        RELEASE (p);
00328       }
00329       break;
00330     case 'c': /* curveto */
00331       {
00332        struct curve *p;
00333        p = path[i].element;
00334        sprintf (work_buffer, "\n%g %g %g %g %g %g c",
00335                      ROUND((p->x)[0], 0.001), ROUND((p->y)[0], 0.001),
00336                      ROUND((p->x)[1], 0.001), ROUND((p->y)[1], 0.001),
00337                      ROUND((p->x)[2], 0.001), ROUND((p->y)[2], 0.001));
00338         len = strlen (work_buffer);
00339        pdf_doc_add_to_page (work_buffer, len);
00340        RELEASE (p);
00341       }
00342       break;
00343     default: /* This shouldn't happen! */
00344       ERROR ("Internal error in mpost.c, flush_path ()");
00345     }
00346   }
00347   n_path_pts = 0;
00348   if (path_close) {
00349     pdf_doc_add_to_page (" h", 2);
00350     path_close = 0;
00351   }
00352   if (path_clip) {
00353     pdf_doc_add_to_page (" W", 2);
00354     path_clip = 0;
00355   }
00356   return;
00357 }
00358 
00359 static void transform_path (double a, double b, double c, double d,
00360                          double e, double f)
00361 {
00362   double an, bn, cn, dn, en, fn, delta, xn, yn;
00363   unsigned i;
00364   delta = a*d-b*c;
00365   if (delta == 0.0) {
00366     ERROR ("Determinant exactly zero in transform_path()");
00367   }
00368   an=d/delta; bn=-b/delta; cn=-c/delta; dn=a/delta;
00369   en=(c*f-e*d)/delta, fn=(b*e-a*f)/delta;
00370   for (i=0; i<n_path_pts; i++) {
00371     switch (path[i].type) {
00372     case 'l':
00373     case 'm':
00374       {
00375        struct point *p;
00376        p = path[i].element;
00377        xn = an*(p->x)+cn*(p->y)+en;
00378        yn = bn*(p->x)+dn*(p->y)+fn;
00379        p->x = xn;
00380        p->y = yn;
00381       }
00382       break;
00383     case 'c':
00384       {
00385        int j;
00386        struct curve *c;
00387        c = path[i].element;
00388        for (j=0; j<3; j++) {
00389          xn = an*(c->x)[j]+cn*(c->y)[j]+en;
00390          yn = bn*(c->x)[j]+dn*(c->y)[j]+fn;
00391          (c->x)[j] = xn; (c->y)[j] = yn;
00392        }
00393       }
00394     }
00395   }
00396 }
00397 static void dump_path (void)
00398 {
00399   unsigned i;
00400   for (i=0; i<n_path_pts; i++) {
00401     switch (path[i].type) {
00402     case 'l':
00403     case 'm': 
00404       {
00405        struct point *p;
00406        p = path[i].element;
00407        fprintf (stderr, "\t%g %g %c\n", p->x, p->y, path[i].type);
00408       }
00409       break;
00410     case 'c': 
00411       {
00412        struct curve *c;
00413        int j;
00414        c = path[i].element;
00415        for (j=0; j<3; j++) {
00416          fprintf (stderr, "\t%g %g\n", (c->x)[j], (c->y)[j]);
00417        }
00418        fprintf (stderr, "\t\t\tcurveto\n");
00419        break;
00420       }
00421     }
00422   }
00423 }
00424 
00425 #define PS_STACK_SIZE 1024
00426 static pdf_obj *stack[PS_STACK_SIZE];
00427 static unsigned top_stack;
00428 
00429 double x_state, y_state;
00430 static int state = 0;
00431 static int num_saves = 0;
00432 
00433 #define PUSH(o) { \
00434   if (top_stack<PS_STACK_SIZE) { \
00435     stack[top_stack++] = o; \
00436   } else { \
00437     fprintf (stderr, "PS stack overflow including MetaPost file or inline PS code"); \
00438     error=1; \
00439     break; \
00440   } \
00441   }
00442 
00443 #define POP_STACK() (top_stack>0?stack[--top_stack]:NULL)
00444 
00445 void dump_stack()
00446 {
00447   int i;
00448   fprintf (stderr, "\ndump_stack\n");
00449   for (i=0; i<top_stack; i++) {
00450     pdf_write_obj (stderr, stack[i]);
00451     fprintf (stderr, "\n");
00452   }
00453 }
00454 #define ADD                 1
00455 #define CLIP                2
00456 #define CLOSEPATH           3
00457 #define CONCAT              4
00458 #define CURVETO      5
00459 #define DIV          6
00460 #define DTRANSFORM   7
00461 #define EXCH         8
00462 #define FILL         9
00463 #define FSHOW        10
00464 #define GSAVE        11
00465 #define GRESTORE     12
00466 #define IDTRANSFORM  13
00467 #define LINETO              14
00468 #define MOVETO              15
00469 #define MUL          16
00470 #define NEWPATH             17
00471 #define POP          18
00472 #define RLINETO             19
00473 #define SCALE        20
00474 #define SETCMYKCOLOR 21
00475 #define SETDASH             22
00476 #define SETGRAY             23
00477 #define SETLINECAP   24
00478 #define SETLINEJOIN  25
00479 #define SETLINEWIDTH 26
00480 #define SETMITERLIMIT       27
00481 #define SETRGBCOLOR  28
00482 #define SHOW         29
00483 #define SHOWPAGE     30
00484 #define STROKE              31
00485 #define SUB          32
00486 #define TRANSLATE    33
00487 #define TRUNCATE     34
00488 #define CURRENTPOINT    35
00489 #define NEG                  36
00490 #define ROTATE          37
00491 #define TEXFIG          38
00492 #define ETEXFIG         39
00493 #define FONTNAME     99
00494 
00495 struct operators 
00496 {
00497   char *t;
00498   int v;
00499 } operators[] = {
00500   {"add", ADD},
00501   {"clip", CLIP},
00502   {"closepath", CLOSEPATH},
00503   {"concat", CONCAT},
00504   {"curveto", CURVETO},
00505   {"currentpoint", CURRENTPOINT},  /* This is here for rotate
00506                                   support in graphics package-not MP support */
00507   {"div", DIV},
00508   {"dtransform", DTRANSFORM},
00509   {"exch", EXCH},
00510   {"fill", FILL},
00511   {"fshow", FSHOW},
00512   {"gsave", GSAVE},
00513   {"grestore", GRESTORE},
00514   {"idtransform", IDTRANSFORM},
00515   {"lineto", LINETO},
00516   {"moveto", MOVETO},
00517   {"mul", MUL},
00518   {"neg", NEG},
00519   {"newpath", NEWPATH},
00520   {"pop", POP},
00521   {"rlineto", RLINETO},
00522   {"rotate", ROTATE},
00523   {"scale", SCALE},
00524   {"setcmykcolor", SETCMYKCOLOR},
00525   {"setdash", SETDASH},
00526   {"setgray", SETGRAY},
00527   {"setlinecap", SETLINECAP},
00528   {"setlinejoin", SETLINEJOIN},
00529   {"setlinewidth", SETLINEWIDTH},
00530   {"setmiterlimit", SETMITERLIMIT},
00531   {"setrgbcolor", SETRGBCOLOR},
00532   {"show", SHOW},
00533   {"showpage", SHOWPAGE},
00534   {"startTexFig", TEXFIG},
00535   {"endTexFig", ETEXFIG},
00536   {"stroke", STROKE},  
00537   {"sub", SUB},  
00538   {"translate", TRANSLATE},
00539   {"truncate", TRUNCATE}
00540 };
00541 
00542 static int lookup_operator(char *token)
00543 {
00544   int i, operator;
00545   operator = -1;
00546   for (i=0; i<sizeof(operators)/sizeof(operators[0]); i++) {
00547     if (!strcmp (token, operators[i].t)) {
00548       operator = operators[i].v;
00549       break;
00550     }
00551   }
00552   if (i == sizeof(operators)/sizeof(operators[0]) &&
00553       mp_is_font_name (token)) {
00554     operator = FONTNAME;
00555   }
00556   return operator;
00557 }
00558 
00559 
00560 /* Following needed to save texfig state */
00561 
00562 static long next_fig = 1;
00563 static pdf_obj *fig_xobj = NULL;
00564 struct xform_info *fig_p;
00565 static char fig_res_name[16];
00566 
00567 static int do_operator(char *token,
00568                      double x_user, double y_user)
00569      /* Again, the only piece that needs x_user and y_user is
00570        that piece dealing with texfig */
00571 {
00572   int operator, error = 0;
00573   pdf_obj *tmp1=NULL, *tmp2=NULL, *tmp3=NULL, *tmp4 = NULL;
00574   pdf_obj *tmp5=NULL, *tmp6=NULL;
00575   int len;
00576   /* PS to PDF conversion is not so simple.  We maintain
00577      state so we can change "gsave fill grestore stroke" to "B".
00578      We need to keep track of what we have seen.   This code is not
00579      too smart and could be easily fooled by real postscript. 
00580      It makes some assumptions since it is only looking at MetaPost
00581 
00582      States are as follows:
00583      0: Nothing special
00584      1: Started a path
00585      2: Saw gsave in path
00586      3: Saw a painting operator in state 2(fill, stroke, or newpath)
00587      4: Saw a grestore in state 3
00588   */
00589   operator = lookup_operator (token);
00590   switch (operator) {
00591   case ADD:
00592     tmp1 = POP_STACK();
00593     tmp2 = POP_STACK();
00594     if (tmp1 && tmp2)
00595       pdf_set_number (tmp1,
00596                     pdf_number_value(tmp1)+pdf_number_value(tmp2));
00597     if (tmp2)
00598       pdf_release_obj (tmp2);
00599     if (tmp1)
00600       PUSH(tmp1);
00601     break;
00602   case CLIP:
00603     clip_path();
00604     break;
00605   case CLOSEPATH:
00606     close_path();
00607     break;
00608   case CONCAT:
00609     tmp1 = POP_STACK();
00610     if (tmp1 && tmp1 -> type == PDF_ARRAY) {
00611       int i, len = 0;
00612       for (i=0; i<6; i++) {
00613        if (!(tmp2 = pdf_get_array(tmp1, i)))
00614          break;
00615        if (i == 0) {
00616           sprintf (work_buffer+len, "\n");
00617            len += strlen (work_buffer+len);
00618         } else  {
00619           sprintf (work_buffer+len, " ");
00620            len += strlen (work_buffer+len);
00621         }
00622        sprintf (work_buffer+len, "%g",
00623                ROUND(pdf_number_value(tmp2),0.0001));
00624         len += strlen (work_buffer+len);
00625       }
00626       sprintf (work_buffer+len, " cm");
00627       len += strlen (work_buffer+len);
00628       pdf_doc_add_to_page (work_buffer, len);
00629       /* Transform pending path, if any */
00630       transform_path (pdf_number_value(pdf_get_array(tmp1, 0)),
00631                     pdf_number_value(pdf_get_array(tmp1, 1)),
00632                     pdf_number_value(pdf_get_array(tmp1, 2)),
00633                     pdf_number_value(pdf_get_array(tmp1, 3)),
00634                     pdf_number_value(pdf_get_array(tmp1, 4)),
00635                     pdf_number_value(pdf_get_array(tmp1, 5)));
00636     } else {
00637       fprintf (stderr, "\nMissing array before \"concat\"\n");
00638     }
00639     if (tmp1)
00640       pdf_release_obj (tmp1);
00641     break;
00642   case CURRENTPOINT:
00643     state = 0;
00644     PUSH (pdf_new_number (x_user)); /* Remember that x_user and y_user */
00645     PUSH (pdf_new_number (y_user)); /* are off by 0.02 % */
00646     break;
00647   case CURVETO:
00648     if (state <= 1) /* In path now */
00649       state = 1;
00650     else {
00651       fprintf (stderr, "\nUnexpected path segment\n");
00652     }
00653     if ((tmp6 = POP_STACK()) && tmp6->type == PDF_NUMBER &&
00654        (tmp5 = POP_STACK()) && tmp5->type == PDF_NUMBER &&
00655        (tmp4 = POP_STACK()) && tmp4->type == PDF_NUMBER &&
00656        (tmp3 = POP_STACK()) && tmp3->type == PDF_NUMBER &&
00657        (tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER &&
00658        (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
00659       add_curve_to_path (pdf_number_value(tmp1),
00660                       pdf_number_value(tmp2),
00661                       pdf_number_value(tmp3),
00662                       pdf_number_value(tmp4),
00663                       pdf_number_value(tmp5),
00664                       pdf_number_value(tmp6));
00665       x_state = pdf_number_value (tmp5);
00666       y_state = pdf_number_value (tmp6);
00667     } else {
00668       fprintf (stderr, "\nMissing number(s) before \"curveto\"\n");
00669     }
00670     if (tmp1) pdf_release_obj (tmp1);
00671     if (tmp2) pdf_release_obj (tmp2);
00672     if (tmp3) pdf_release_obj (tmp3);
00673     if (tmp4) pdf_release_obj (tmp4);
00674     if (tmp5) pdf_release_obj (tmp5);
00675     if (tmp6) pdf_release_obj (tmp6);
00676     break;
00677   case DIV:
00678     tmp2 = POP_STACK();
00679     tmp1 = POP_STACK();
00680     if (tmp1 && tmp2)
00681       pdf_set_number (tmp1,
00682                     pdf_number_value(tmp1)/pdf_number_value(tmp2));
00683     if (tmp1)
00684       PUSH(tmp1);
00685     if (tmp2)
00686       pdf_release_obj (tmp2);
00687     break;
00688   case DTRANSFORM:
00689     if ((tmp2 = POP_STACK()) && tmp2 -> type == PDF_NUMBER &&
00690        (tmp1 = POP_STACK()) && tmp1 -> type == PDF_NUMBER) {
00691       pdf_set_number (tmp1, pdf_number_value(tmp1)*100.0);
00692       pdf_set_number (tmp2, pdf_number_value(tmp2)*100.0);
00693       PUSH(tmp1);
00694       PUSH(tmp2);
00695     } else {
00696       if (tmp1)
00697        pdf_release_obj (tmp1);
00698       if (tmp2)
00699        pdf_release_obj (tmp2);
00700       fprintf (stderr, "\nExpecting two numbers before \"dtransform\"");
00701     }
00702     break;
00703   case EXCH:
00704     if ((tmp1 = POP_STACK()) &&
00705        (tmp2 = POP_STACK())) {
00706       PUSH (tmp1);
00707       PUSH (tmp2);
00708     } else {
00709       if (tmp1)
00710        pdf_release_obj (tmp1);
00711     }
00712     break;
00713   case FILL:
00714     switch (state) {
00715     case 0:
00716       state = 0;
00717       break;
00718     case 1:
00719       flush_path ();
00720       pdf_doc_add_to_page (" f", 2);
00721       state = 0;
00722       break;
00723     case 2:
00724       state = 3;
00725       break;
00726     case 3:
00727       fprintf (stderr, "\nUnexpected fill\n");
00728       break;
00729     case 4:
00730       flush_path ();
00731       pdf_doc_add_to_page (" B", 2);
00732       state = 0;
00733       break;
00734     }
00735     break;
00736   case FSHOW: 
00737     {
00738       int fontid;
00739       if ((tmp3 = POP_STACK()) && (tmp3->type == PDF_NUMBER) &&
00740          (tmp2 = POP_STACK()) && (tmp2->type == PDF_STRING) &&
00741          (tmp1 = POP_STACK()) && (tmp1->type == PDF_STRING)) {
00742        if ((fontid = mp_fontid (pdf_string_value(tmp2),
00743                              pdf_number_value(tmp3))) < 0) {
00744          fprintf (stderr, "\n\"fshow\": Missing font in MetaPost file? %s@%g\n", 
00745                  (char *) pdf_string_value(tmp2), pdf_number_value(tmp3));
00746        }
00747        dev_set_string (x_state/dvi_unit_size(), y_state/dvi_unit_size(),
00748                      pdf_string_value(tmp1),
00749                      pdf_string_length(tmp1), 0, mp_fonts[fontid].font_id);
00750        graphics_mode();
00751       }
00752       /* Treat fshow as a path terminator of sorts */
00753       state = 0;
00754 
00755       if (tmp1)
00756        pdf_release_obj (tmp1);
00757       if (tmp2)
00758        pdf_release_obj (tmp2);
00759       if (tmp3)
00760        pdf_release_obj (tmp3);
00761     }
00762     break;
00763   case GSAVE:
00764     switch (state) {
00765     case 0:
00766       pdf_doc_add_to_page ("\nq", 2);
00767       num_saves += 1;
00768       break;
00769     case 1:
00770       state = 2;
00771       break;
00772     case 4:
00773       state = 2;
00774       break;
00775     default:
00776       fprintf (stderr, "\nUnexpected gsave\n");
00777       break;
00778     }
00779     break;
00780   case GRESTORE:
00781     switch (state) {
00782     case 0:
00783       if (num_saves > 0) {
00784        num_saves -= 1;
00785        pdf_doc_add_to_page ("\nQ", 2);
00786        /* Unfortunately, the following two lines are necessary in case of a font or color
00787           change inside of the save/restore pair.  Anything that was done
00788           there must be redone, so in effect, we make no assumptions about
00789           what fonts are active.  We act like we are starting a new page */
00790        dev_reselect_font();
00791        /* The following line was causing trouble - 1/30/01 */
00792        /*     dev_do_color(); */
00793       }
00794       else {
00795        fprintf (stderr, "PS special: \"grestore\" ignored.  More restores than saves on a page.\n");
00796       }
00797       break;
00798     case 2:
00799       state = 1;
00800       break;
00801     case 3:
00802       state = 4;
00803       break;
00804     default:
00805       fprintf (stderr, "\nUnexpected grestore\n");
00806       break;
00807     }
00808     break;
00809   case IDTRANSFORM:
00810     if ((tmp2 = POP_STACK()) && tmp2 -> type == PDF_NUMBER &&
00811        (tmp1 = POP_STACK()) && tmp1 -> type == PDF_NUMBER) {
00812       pdf_set_number (tmp1, pdf_number_value(tmp1)/100.0);
00813       pdf_set_number (tmp2, pdf_number_value(tmp2)/100.0);
00814       PUSH(tmp1);
00815       PUSH(tmp2);
00816     } else {
00817       if (tmp1)
00818        pdf_release_obj (tmp1);
00819       if (tmp2)
00820        pdf_release_obj (tmp2);
00821       fprintf (stderr, "\nExpecting two numbers before \"idtransform\"");
00822     }
00823     break;
00824   case LINETO: 
00825     {
00826       if (state <= 1) /* In path now */
00827        state = 1;
00828       else {
00829        fprintf (stderr, "\nUnexpected path segment\n");
00830       }
00831       if ((tmp2 = POP_STACK()) && tmp2-> type == PDF_NUMBER &&
00832          (tmp1 = POP_STACK()) && tmp1-> type == PDF_NUMBER) {
00833        x_state = pdf_number_value (tmp1);
00834        y_state = pdf_number_value (tmp2);
00835        add_point_to_path (x_state, y_state, 'l');
00836       }
00837       if (tmp1)
00838        pdf_release_obj (tmp1);
00839       if (tmp2)
00840        pdf_release_obj (tmp2);
00841     }
00842     break;
00843   case MOVETO:
00844     if (state <= 1) /* In path now */
00845       state = 1;
00846     else {
00847       fprintf (stderr, "\nUnexpected path segment\n");
00848     }
00849     if ((tmp2 = POP_STACK()) && tmp2-> type == PDF_NUMBER &&
00850        (tmp1 = POP_STACK()) && tmp1-> type == PDF_NUMBER) {
00851       /* MetaPost likes to ship out a moveto before displayed text.
00852         Save the results so we know where to place the text.  Save
00853         the move but don't actually do it unless the next operator is
00854         a graphics operator */
00855       x_state = pdf_number_value (tmp1);
00856       y_state = pdf_number_value (tmp2);
00857       add_point_to_path (x_state, y_state, 'm');
00858     }
00859     if (tmp1)
00860       pdf_release_obj (tmp1);
00861     if (tmp2)
00862       pdf_release_obj (tmp2);
00863     break;
00864   case MUL:
00865     tmp2 = POP_STACK();
00866     tmp1 = POP_STACK();
00867     if (tmp1 && tmp2)
00868       pdf_set_number (tmp1,
00869                     pdf_number_value(tmp1)*pdf_number_value(tmp2));
00870     if (tmp1)
00871       PUSH(tmp1);
00872     if (tmp2)
00873       pdf_release_obj (tmp2);
00874     break;
00875   case NEG:
00876     tmp1 = POP_STACK();
00877     if (tmp1 && tmp1 -> type == PDF_NUMBER) {
00878       pdf_set_number (tmp1, -pdf_number_value(tmp1));
00879       PUSH (tmp1);
00880     }
00881     break;
00882   case NEWPATH:
00883     flush_path ();
00884     pdf_doc_add_to_page ("\nn", 2);
00885     break;
00886   case POP:
00887     tmp1 = POP_STACK();
00888     if (tmp1)
00889       pdf_release_obj (tmp1);
00890     break;
00891   case RLINETO: 
00892     if (state <= 1) /* In path now */
00893       state = 1;
00894     else {
00895       fprintf (stderr, "\nUnexpected path segment\n");
00896     }
00897     if ((tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER &&
00898        (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
00899       x_state += pdf_number_value (tmp1);
00900       y_state += pdf_number_value (tmp2);
00901       add_point_to_path (x_state, y_state, 'l');
00902     }
00903     if (tmp1)
00904       pdf_release_obj (tmp1);
00905     if (tmp2)
00906       pdf_release_obj (tmp2);
00907     break;
00908   case SCALE: 
00909     if ((tmp2 = POP_STACK()) &&  tmp2->type == PDF_NUMBER &&
00910        (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
00911       sprintf (work_buffer, "\n%g 0 0 %g 0 0 cm",
00912               ROUND(pdf_number_value (tmp1),0.01),
00913               ROUND(pdf_number_value (tmp2),0.01));
00914       len = strlen (work_buffer);
00915       transform_path (pdf_number_value(tmp1), 0.0,
00916                     0.0, pdf_number_value(tmp2), 0.0, 0.0);
00917       pdf_doc_add_to_page (work_buffer, len);
00918     }
00919     if (tmp1)
00920       pdf_release_obj (tmp1);
00921     if (tmp2)
00922       pdf_release_obj (tmp2);
00923     break;
00924   case SETCMYKCOLOR:
00925     if ((tmp4 = POP_STACK()) && tmp4->type == PDF_NUMBER &&
00926        (tmp3 = POP_STACK()) && tmp3->type == PDF_NUMBER &&
00927        (tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER &&
00928        (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
00929       sprintf (work_buffer, "\n%g %g %g %g k",
00930               ROUND(pdf_number_value (tmp1),0.001),
00931               ROUND(pdf_number_value (tmp2),0.001),
00932               ROUND(pdf_number_value (tmp3),0.001),
00933               ROUND(pdf_number_value (tmp4),0.001));
00934       len = strlen (work_buffer);
00935       pdf_doc_add_to_page (work_buffer, len);
00936       sprintf (work_buffer, "\n%g %g %g %g K",
00937                ROUND(pdf_number_value (tmp1),0.001),
00938                ROUND(pdf_number_value (tmp2),0.001),
00939                ROUND(pdf_number_value (tmp3),0.001),
00940                ROUND(pdf_number_value (tmp4),0.001));
00941       len = strlen (work_buffer);
00942       pdf_doc_add_to_page (work_buffer, len);
00943     } else {
00944       fprintf (stderr, "\nExpecting four numbers before \"setcmykcolor\"\n");
00945     }
00946     if (tmp1)
00947       pdf_release_obj (tmp1);
00948     if (tmp2)
00949       pdf_release_obj (tmp2);
00950     if (tmp3)
00951       pdf_release_obj (tmp3);
00952     if (tmp4)
00953       pdf_release_obj (tmp4);
00954     break;
00955   case SETDASH:
00956     if ((tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER &&
00957        (tmp1 = POP_STACK()) && tmp1->type == PDF_ARRAY) {
00958       int i;
00959       pdf_doc_add_to_page ("\n[", 2);
00960       for (i=0;; i++) {
00961        if ((tmp3 = pdf_get_array (tmp1, i)) &&
00962            tmp3 -> type == PDF_NUMBER) {
00963          sprintf (work_buffer, " %g", ROUND(pdf_number_value(tmp3),0.01));
00964           len = strlen (work_buffer);
00965          pdf_doc_add_to_page (work_buffer, len);
00966        } else 
00967          break;
00968       }
00969       pdf_doc_add_to_page (" ]", 2);
00970       if (tmp2 -> type == PDF_NUMBER) {
00971        sprintf (work_buffer, " %g d", ROUND(pdf_number_value(tmp2),0.01));
00972         len = strlen (work_buffer);
00973        pdf_doc_add_to_page (work_buffer, len);
00974       }
00975     } else {
00976       fprintf (stderr, "\nExpecting array and number before \"setdash\"");
00977     }
00978     if (tmp1)
00979       pdf_release_obj (tmp1);
00980     if (tmp2)
00981       pdf_release_obj (tmp2);
00982     break;
00983   case SETGRAY:
00984     if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
00985       sprintf (work_buffer, "\n%g g",
00986               ROUND(pdf_number_value (tmp1),0.001));
00987       len = strlen (work_buffer);
00988       pdf_doc_add_to_page (work_buffer, len);
00989       sprintf (work_buffer, " %g G",
00990               ROUND(pdf_number_value (tmp1),0.001));
00991       len = strlen (work_buffer);
00992       pdf_doc_add_to_page (work_buffer, len);
00993     } else {
00994       fprintf (stderr, "\nExpecting a number before \"setgray\"\n");
00995     }
00996     if (tmp1)
00997       pdf_release_obj (tmp1);
00998     break;
00999   case SETLINECAP:
01000     if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
01001       sprintf (work_buffer, "\n%g J", pdf_number_value (tmp1));
01002       len = strlen (work_buffer);
01003       pdf_doc_add_to_page (work_buffer, len);
01004     } else {
01005       fprintf (stderr, "\nExpecting a number before \"setlinecap\"\n");
01006     }
01007     if (tmp1)
01008       pdf_release_obj (tmp1);
01009     break;
01010   case SETLINEJOIN:
01011     if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
01012       sprintf (work_buffer, "\n%g j", pdf_number_value (tmp1));
01013       len = strlen (work_buffer);
01014       pdf_doc_add_to_page (work_buffer, len);
01015     } else {
01016       fprintf (stderr, "\nExpecting a number before \"setlinejoin\"\n");
01017     }
01018     if (tmp1)
01019       pdf_release_obj (tmp1);
01020     break;
01021   case SETLINEWIDTH:
01022     if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
01023       sprintf (work_buffer, "\n%g w", ROUND(pdf_number_value (tmp1),0.01));
01024       len = strlen (work_buffer);
01025       pdf_doc_add_to_page (work_buffer, len);
01026     } else {
01027       fprintf (stderr, "\nExpecting a number before \"setlinewidth\"\n");
01028     }
01029     if (tmp1)
01030       pdf_release_obj (tmp1);
01031     break;
01032   case SETMITERLIMIT:
01033     if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
01034       sprintf (work_buffer, "\n%g M", ROUND(pdf_number_value
01035                                        (tmp1),0.01));
01036       len = strlen (work_buffer);
01037       pdf_doc_add_to_page (work_buffer, len);
01038     } else {
01039       fprintf (stderr, "\nExpecting a number before \"setmiterlimit\"\n");
01040     }
01041     if (tmp1)
01042       pdf_release_obj (tmp1);
01043     break;
01044   case SETRGBCOLOR:
01045     if ((tmp3 = POP_STACK()) && tmp3->type == PDF_NUMBER &&
01046        (tmp2 = POP_STACK()) && tmp2->type == PDF_NUMBER &&
01047        (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
01048       sprintf (work_buffer, "\n%g %g %g rg",
01049               ROUND(pdf_number_value (tmp1),0.001),
01050               ROUND(pdf_number_value (tmp2),0.001),
01051               ROUND(pdf_number_value (tmp3),0.001));
01052       len = strlen (work_buffer);
01053       pdf_doc_add_to_page (work_buffer, len);
01054       sprintf (work_buffer, "\n%g %g %g RG",
01055               ROUND(pdf_number_value (tmp1),0.001),
01056               ROUND(pdf_number_value (tmp2),0.001),
01057               ROUND(pdf_number_value (tmp3),0.001));
01058       len = strlen (work_buffer);
01059       pdf_doc_add_to_page (work_buffer, len);
01060     } else {
01061       fprintf (stderr, "\nExpecting three numbers before \"setrgbcolor\"\n");
01062     }
01063     if (tmp1)
01064       pdf_release_obj (tmp1);
01065     if (tmp2)
01066       pdf_release_obj (tmp2);
01067     if (tmp3)
01068       pdf_release_obj (tmp3);
01069     break;
01070   case SHOWPAGE:
01071     /* Let's ignore this for now */
01072     void_path ();
01073     break;
01074   case STROKE:
01075     switch (state) {
01076     case 0:
01077       state = 0;
01078       break;
01079     case 1:
01080       flush_path ();
01081       pdf_doc_add_to_page (" S", 2);
01082       state = 0;
01083       break;
01084     case 2:
01085       state = 3;
01086       break;
01087     case 3:
01088       fprintf (stderr, "\nUnexpected fill\n");
01089       break;
01090     case 4:
01091       flush_path ();
01092       pdf_doc_add_to_page (" B", 2);
01093       state = 0;
01094       break;
01095     }
01096     break;
01097   case SUB:
01098     tmp2 = POP_STACK();
01099     tmp1 = POP_STACK();
01100     if (tmp1 && tmp2)
01101       pdf_set_number (tmp1,
01102                     pdf_number_value(tmp1)-pdf_number_value(tmp2));
01103     if (tmp1)
01104       PUSH(tmp1);
01105     if (tmp2)
01106       pdf_release_obj (tmp2);
01107     break;
01108   case ROTATE:
01109     if ((tmp1 = POP_STACK()) && (tmp1 -> type == PDF_NUMBER)) {
01110       double theta = pdf_number_value(tmp1)*M_PI/180.0;
01111       sprintf (work_buffer, "\n%.4f %.4f %.4f %.4f 0 0 cm",
01112               cos(theta), -sin(theta),
01113               sin(theta), cos(theta));
01114       len = strlen (work_buffer);
01115       pdf_doc_add_to_page (work_buffer, len);
01116     }
01117     if (tmp1)
01118       pdf_release_obj (tmp1);
01119     break;
01120   case TEXFIG:
01121     if ((tmp6 = POP_STACK()) && (tmp6 -> type == PDF_NUMBER) &&
01122        (tmp5 = POP_STACK()) && (tmp5 -> type == PDF_NUMBER) &&
01123        (tmp4 = POP_STACK()) && (tmp4 -> type == PDF_NUMBER) &&
01124        (tmp3 = POP_STACK()) && (tmp3 -> type == PDF_NUMBER) &&
01125        (tmp2 = POP_STACK()) && (tmp2 -> type == PDF_NUMBER) &&
01126        (tmp1 = POP_STACK()) && (tmp1 -> type == PDF_NUMBER)) {
01127       double dvi2pts = dvi_unit_size();
01128       fig_p = new_xform_info ();
01129       fig_p -> width = pdf_number_value(tmp1)*dvi2pts;
01130       fig_p -> height = pdf_number_value(tmp2)*dvi2pts;
01131       fig_p -> c_llx = pdf_number_value(tmp3)*dvi2pts;
01132       fig_p -> c_lly = pdf_number_value(tmp4)*dvi2pts;
01133       fig_p -> c_urx = pdf_number_value(tmp5)*dvi2pts;
01134       fig_p -> c_ury = pdf_number_value(tmp6)*dvi2pts;
01135       pdf_scale_image (fig_p);
01136       sprintf (fig_res_name, "Tf%ld", next_fig);
01137       fig_xobj = begin_form_xobj (fig_p->c_llx, -fig_p->c_ury, fig_p->c_llx, -fig_p->c_lly, 
01138                               fig_p->c_urx, -fig_p->c_ury, fig_res_name);
01139     }
01140     if (tmp1) pdf_release_obj(tmp1);
01141     if (tmp2) pdf_release_obj(tmp2);
01142     if (tmp3) pdf_release_obj(tmp3);
01143     if (tmp4) pdf_release_obj(tmp4);
01144     if (tmp5) pdf_release_obj(tmp5);
01145     if (tmp6) pdf_release_obj(tmp6);
01146     break;
01147   case ETEXFIG:
01148     if (fig_xobj) {
01149       next_fig += 1;
01150       end_form_xobj ();
01151       pdf_doc_add_to_page_xobjects (fig_res_name, pdf_ref_obj(fig_xobj));
01152       pdf_release_obj (fig_xobj);
01153       fig_xobj = NULL;
01154       pdf_doc_add_to_page ("\nq", 2);
01155       add_xform_matrix (x_user, y_user, fig_p->xscale, -fig_p->yscale, fig_p->rotate);
01156       if (fig_p->depth != 0.0)
01157        add_xform_matrix (0.0, -fig_p->depth, 1.0, -1.0, 0.0);
01158       release_xform_info (fig_p);
01159       sprintf (work_buffer, " /%s Do Q", fig_res_name);
01160       len = strlen (work_buffer);
01161       pdf_doc_add_to_page (work_buffer, len);
01162     } else {
01163       fprintf (stderr, "\nendTexFig without valid startTexFig ignored\n");
01164     }
01165     break;
01166   case TRANSLATE:
01167     if ((tmp2 = POP_STACK()) &&  tmp2->type == PDF_NUMBER &&
01168        (tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
01169       sprintf (work_buffer, "\n1 0 0 1 %g %g cm", 
01170               ROUND(pdf_number_value (tmp1),0.01),
01171               ROUND(pdf_number_value (tmp2),0.01));
01172       len = strlen (work_buffer);
01173       pdf_doc_add_to_page (work_buffer, len);
01174       transform_path (1.0, 0.0, 0.0, 1.0,
01175                     pdf_number_value (tmp1),
01176                     pdf_number_value (tmp2));
01177     }
01178     if (tmp1)
01179       pdf_release_obj (tmp1);
01180     if (tmp2)
01181       pdf_release_obj (tmp2);
01182     break;
01183   case TRUNCATE:
01184     if ((tmp1 = POP_STACK()) && tmp1->type == PDF_NUMBER) {
01185       double val=pdf_number_value(tmp1);
01186       pdf_set_number (tmp1, val>0? floor(val): ceil(val));
01187       PUSH (tmp1);
01188     } else if (tmp1)
01189       pdf_release_obj (tmp1);
01190     break;
01191   case FONTNAME:
01192     PUSH (pdf_new_string (token, strlen(token)));
01193     break;
01194   default: 
01195     fprintf (stderr,
01196             "\nIgnoring remaining special text following unknown PS operator: \"%s\"\n", token);
01197     error = 1;
01198     break;
01199   }
01200   return !error;
01201 }
01202 
01203 static int do_one_ps_line (char **start, char *end,
01204                         double x_user, double y_user)
01205  /* the only sections that need to know x_user and y _user are those
01206     dealing with texfig */
01207 {
01208   char *token, *save = NULL;
01209   pdf_obj *obj;
01210   int error = 0;
01211   skip_white (start, end);
01212   while (*start < end && !error) {
01213     save = *start;
01214     if (isdigit (**start) || **start == '-' || **start == '.' ) {
01215       token = parse_number (start, end);
01216       PUSH (pdf_new_number(atof(token)));
01217       RELEASE (token);
01218     } else if (**start == '[' && /* This code assumes that arrays are contained on one line */
01219               (obj = parse_pdf_array (start, end))) {
01220       PUSH (obj);
01221     } else if (**start == '(' &&
01222               (obj = parse_pdf_string (start, end))) {
01223       PUSH (obj);
01224     } else if (**start == '/') {
01225       fprintf (stderr, "\nUnable to handle names in raw PS code.");
01226       dump (*start, end);
01227       error = 1;
01228     } else {
01229       token = parse_ident (start, end);
01230       if (!token || !do_operator (token, x_user, y_user)) {
01231        error = 1;
01232       }
01233       if (token)
01234        RELEASE (token);
01235     }
01236     skip_white (start, end);
01237   }
01238   if (*start < end) {
01239     fprintf (stderr, "\nRemainder of line unparsed.");
01240     dump (*start, end);
01241   }
01242   return !error;
01243 }
01244 
01245 static char line_buffer[1024];
01246 int parse_contents (FILE *image_file)
01247 {
01248   int error = 0;
01249   top_stack = 0;
01250   x_state = 0.0;
01251   y_state = 0.0;
01252   state = 0;
01253   while (!feof(image_file) && mfgets (line_buffer, sizeof(line_buffer),
01254                                   image_file)) {
01255     char *start, *end;
01256     start = line_buffer;
01257     end = start+strlen(line_buffer);
01258     if (!do_one_ps_line (&start, end, 0.0, 0.0)) {
01259       error = 1;
01260       break;
01261     }
01262   }
01263   return !error;
01264 }
01265 
01266 int do_raw_ps_special (char **start, char* end, int cleanup,
01267                      double x_user, double y_user)
01268 {
01269   int error = 0;
01270   state = 0;
01271   do_one_ps_line (start, end, x_user, y_user);
01272   if (cleanup)
01273     mp_cleanup(1);
01274   return !error;
01275 }
01276 
01277 void mp_cleanup (int sloppy_ok)
01278 {
01279   release_fonts();
01280   if (state != 0) {
01281     if (!sloppy_ok)
01282       fprintf (stderr, "mp_cleanup(): State not zero\n");
01283     state = 0;
01284   }
01285   if (top_stack != 0) {
01286     if (!sloppy_ok)
01287       fprintf (stderr, "\nPS/MetaPost: PS stack not empty at end of figure!\n");
01288   }
01289   /* Cleanup paths */
01290   while (top_stack > 0) {
01291     pdf_obj *p;
01292     if ((p=POP_STACK()))
01293       pdf_release_obj (p);
01294   }
01295   if (n_path_pts > 0) {
01296     if (!sloppy_ok) {
01297       fprintf (stderr, "\nPS/MetaPost: Pending path at end of figure!\n");
01298       dump_path (); 
01299     }
01300     void_path ();
01301   }
01302   if (max_path_pts > 0) {
01303     RELEASE (path);
01304     path = NULL;
01305     max_path_pts = 0;
01306   }
01307 }
01308 
01309 void mp_eop_cleanup(void)
01310 {
01311   mp_cleanup(1);
01312   num_saves = 0;
01313 }
01314 
01315 
01316 /* mp inclusion is a bit of a hack.  The routine
01317  * starts a form at the lower left corner of
01318  * the page and then calls begin_form_xobj telling
01319  * it to record the image drawn there and bundle it
01320  * up in an xojbect.  This allows us to use the coordinates
01321  * in the MP file directly.  This appears to be the
01322  * easiest way to be able to use the dev_set_string()
01323  * command (with its scaled and extended fonts) without
01324  * getting all confused about the coordinate system.
01325  * After the xobject is created, the whole thing can
01326  * be scaled any way the user wants */
01327  
01328 pdf_obj *mp_include (FILE *image_file,  struct xform_info *p,
01329                    char *res_name, double x_user, double y_user)
01330 {
01331    pdf_obj *xobj = NULL;
01332    rewind (image_file);
01333    if (mp_parse_headers (image_file, p)) {
01334       /* Looks like an MP file.  Setup xobj "capture" */
01335      pdf_scale_image (p);
01336      xobj = begin_form_xobj (p->u_llx,p->u_lly, p->c_llx, p->c_lly,
01337                           p->c_urx, p->c_ury, res_name);
01338      if (!xobj)
01339        return NULL;
01340      /* Flesh out the contents */
01341      if (!parse_contents (image_file)) {
01342        fprintf (stderr, "Errors occured while interpreting MetaPost file.\n\n");
01343      }
01344      /* Finish off the form */
01345      end_form_xobj();
01346    } else {
01347      fprintf (stderr, "\nErrors occured while scanning MetaPost file headers.\n");
01348    }
01349    mp_cleanup(0);
01350    return xobj;
01351 }
01352 
01353 /* struct xform_info *texfig_info (void)
01354 {
01355   struct xform_info *p;
01356   p = new_xform_info ();
01357   p -> user_bbox = 1;
01358   p -> width = fig_width;
01359   p -> height = fig_height;
01360   p -> u_llx = fig_llx;
01361   p -> u_lly = fig_lly;
01362   p -> u_urx = fig_urx;
01363   p -> u_ury = fig_ury;
01364   return p;
01365 } */