beta-0.89.2
[luatex.git] / source / texk / web2c / mplibdir / mpost.w
blobc419cdc25a2346441c5036e570c0ab76192763bb
1 % This file is part of MetaPost;
2 % the MetaPost program is in the public domain.
3 % See the <Show version...> code below for more info.
5 \font\tenlogo=logo10 % font used for the METAFONT logo
6 \def\MP{{\tenlogo META}\-{\tenlogo POST}}
8 \def\title{MetaPost executable}
9 \def\[#1]{#1.}
10 \pdfoutput=1
12 @*\MP\ executable.
14 Now that all of \MP\ is a library, a separate program is needed to
15 have our customary command-line interface.
17 @ First, here are the C includes. |avl.h| is needed because of an
18 |avl_allocator| that is defined in |mplib.h|
20 @d true 1
21 @d false 0
24 #include <w2c/config.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #if defined (HAVE_SYS_TIME_H)
29 #include <sys/time.h>
30 #elif defined (HAVE_SYS_TIMEB_H)
31 #include <sys/timeb.h>
32 #endif
33 #include <time.h> /* For `struct tm'. Moved here for Visual Studio 2005. */
34 #if HAVE_SYS_STAT_H
35 #include <sys/stat.h>
36 #endif
37 #include <mplib.h>
38 #include <mpxout.h>
39 #include <kpathsea/kpathsea.h>
40 @= /*@@null@@*/ @> static char *mpost_tex_program = NULL;
41 static int debug = 0; /* debugging for makempx */
42 static int nokpse = 0;
43 static boolean recorder_enabled = false;
44 static string recorder_name = NULL;
45 static FILE *recorder_file = NULL;
46 static char *job_name = NULL;
47 static char *job_area = NULL;
48 static int dvitomp_only = 0;
49 static int ini_version_test = false;
50 string output_directory; /* Defaults to NULL. */
52 @<getopt structures@>;
53 @<Declarations@>;
55 @ Allocating a bit of memory, with error detection:
57 @d mpost_xfree(A) do { if (A!=NULL) free(A); A=NULL; } while (0)
60 @= /*@@only@@*/ /*@@out@@*/ @> static void *mpost_xmalloc (size_t bytes) {
61 void *w = malloc (bytes);
62 if (w==NULL) {
63 fprintf(stderr,"Out of memory!\n");
64 exit(EXIT_FAILURE);
66 return w;
68 @= /*@@only@@*/ @> static char *mpost_xstrdup(const char *s) {
69 char *w;
70 w = strdup(s);
71 if (w==NULL) {
72 fprintf(stderr,"Out of memory!\n");
73 exit(EXIT_FAILURE);
75 return w;
77 static char *mpost_itoa (int i) {
78 char res[32] ;
79 unsigned idx = 30;
80 unsigned v = (unsigned)abs(i);
81 memset(res,0,32*sizeof(char));
82 while (v>=10) {
83 char d = (char)(v % 10);
84 v = v / 10;
85 res[idx--] = d + '0';
87 res[idx--] = (char)v + '0';
88 if (i<0) {
89 res[idx--] = '-';
91 return mpost_xstrdup(res+idx+1);
95 @ @c
96 #ifdef WIN32
97 static int
98 Isspace (char c)
100 return (c == ' ' || c == '\t');
102 #endif
103 static void mpost_run_editor (MP mp, char *fname, int fline) {
104 char *temp, *command, *fullcmd, *edit_value;
105 char c;
106 boolean sdone, ddone;
108 #ifdef WIN32
109 char *fp, *ffp, *env, editorname[256], buffer[256];
110 int cnt = 0;
111 int dontchange = 0;
112 #endif
114 sdone = ddone = false;
115 edit_value = kpse_var_value ("MPEDIT");
116 if (edit_value == NULL)
117 edit_value = getenv("EDITOR");
118 if (edit_value == NULL) {
119 fprintf (stderr,"call_edit: can't find a suitable MPEDIT or EDITOR variable\n");
120 exit(mp_status(mp));
122 command = (string) mpost_xmalloc (strlen (edit_value) + strlen(fname) + 11 + 3);
123 temp = command;
125 #ifdef WIN32
126 fp = editorname;
127 if ((isalpha(*edit_value) && *(edit_value + 1) == ':'
128 && IS_DIR_SEP (*(edit_value + 2)))
129 || (*edit_value == '"' && isalpha(*(edit_value + 1))
130 && *(edit_value + 2) == ':'
131 && IS_DIR_SEP (*(edit_value + 3)))
133 dontchange = 1;
134 #endif
136 while ((c = *edit_value++) != (char)0) {
137 if (c == '%') {
138 switch (c = *edit_value++) {
139 case 'd':
140 if (ddone) {
141 fprintf (stderr,"call_edit: `%%d' appears twice in editor command\n");
142 exit(EXIT_FAILURE);
143 } else {
144 char *s = mpost_itoa(fline);
145 char *ss = s;
146 if (s != NULL) {
147 while (*s != '\0')
148 *temp++ = *s++;
149 free(ss);
151 ddone = true;
153 break;
154 case 's':
155 if (sdone) {
156 fprintf (stderr,"call_edit: `%%s' appears twice in editor command\n");
157 exit(EXIT_FAILURE);
158 } else {
159 while (*fname != '\0')
160 *temp++ = *fname++;
161 *temp++ = '.';
162 *temp++ = 'm';
163 *temp++ = 'p';
164 sdone = true;
166 break;
167 case '\0':
168 *temp++ = '%';
169 /* Back up to the null to force termination. */
170 edit_value--;
171 break;
172 default:
173 *temp++ = '%';
174 *temp++ = c;
175 break;
177 } else {
178 #ifdef WIN32
179 if (dontchange)
180 *temp++ = c;
181 else { if(Isspace(c) && cnt == 0) {
182 cnt++;
183 temp = command;
184 *temp++ = c;
185 *fp = '\0';
186 } else if(!Isspace(c) && cnt == 0) {
187 *fp++ = c;
188 } else {
189 *temp++ = c;
192 #else
193 *temp++ = c;
194 #endif
197 *temp = '\0';
199 #ifdef WIN32
200 if (dontchange == 0) {
201 if(editorname[0] == '.' ||
202 editorname[0] == '/' ||
203 editorname[0] == '\\') {
204 fprintf(stderr, "%s is not allowed to execute.\n", editorname);
205 exit(EXIT_FAILURE);
207 env = (char *)getenv("PATH");
208 if(SearchPath(env, editorname, ".exe", 256, buffer, &ffp)==0) {
209 if(SearchPath(env, editorname, ".bat", 256, buffer, &ffp)==0) {
210 fprintf(stderr, "I cannot find %s in the PATH.\n", editorname);
211 exit(EXIT_FAILURE);
214 fullcmd = mpost_xmalloc(strlen(buffer)+strlen(command)+5);
215 strcpy(fullcmd, "\"");
216 strcat(fullcmd, buffer);
217 strcat(fullcmd, "\"");
218 strcat(fullcmd, command);
219 } else
220 #endif
221 fullcmd = command;
223 if (system (fullcmd) != 0)
224 fprintf (stderr, "! Trouble executing `%s'.\n", command);
225 exit(EXIT_FAILURE);
229 @<Register the callback routines@>=
230 options->run_editor = mpost_run_editor;
234 static string normalize_quotes (const char *name, const char *mesg) {
235 boolean quoted = false;
236 boolean must_quote = (strchr(name, ' ') != NULL);
237 /* Leave room for quotes and NUL. */
238 string ret = (string)mpost_xmalloc(strlen(name)+3);
239 string p;
240 const_string q;
241 p = ret;
242 if (must_quote)
243 *p++ = '"';
244 for (q = name; *q != '\0'; q++) {
245 if (*q == '"')
246 quoted = !quoted;
247 else
248 *p++ = *q;
250 if (must_quote)
251 *p++ = '"';
252 *p = '\0';
253 if (quoted) {
254 fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name);
255 exit(EXIT_FAILURE);
257 return ret;
260 @ Helpers for the filename recorder.
262 @<Declarations@>=
263 void recorder_start(char *jobname);
265 @ @c
266 void recorder_start(char *jobname) {
267 char cwd[1024];
268 if (jobname==NULL) {
269 recorder_name = mpost_xstrdup("mpout.fls");
270 } else {
271 recorder_name = (string)xmalloc((unsigned int)(strlen(jobname)+5));
272 strcpy(recorder_name, jobname);
273 strcat(recorder_name, ".fls");
275 recorder_file = xfopen(recorder_name, FOPEN_W_MODE);
277 if(getcwd(cwd,1020) != NULL) {
278 #ifdef WIN32
279 char *p;
280 for (p = cwd; *p; p++) {
281 if (*p == '\\')
282 *p = '/';
283 else if (IS_KANJI(p))
284 p++;
286 #endif
287 fprintf(recorder_file, "PWD %s\n", cwd);
288 } else {
289 fprintf(recorder_file, "PWD <unknown>\n");
294 @ @c
295 @= /*@@null@@*/ @> static char *makempx_find_file (MPX mpx, const char *nam,
296 const char *mode, int ftype) {
297 int fmt;
298 boolean req;
299 (void) mpx;
300 if ((mode[0]=='r' && !kpse_in_name_ok(nam)) ||
301 (mode[0]=='w' && !kpse_out_name_ok(nam)))
302 return NULL; /* disallowed filename */
303 if (mode[0] != 'r') {
304 return strdup(nam);
306 req = true; fmt = -1;
307 switch(ftype) {
308 case mpx_tfm_format: fmt = kpse_tfm_format; break;
309 case mpx_vf_format: fmt = kpse_vf_format; req = false; break;
310 case mpx_trfontmap_format: fmt = kpse_mpsupport_format; break;
311 case mpx_trcharadj_format: fmt = kpse_mpsupport_format; break;
312 case mpx_desc_format: fmt = kpse_troff_font_format; break;
313 case mpx_fontdesc_format: fmt = kpse_troff_font_format; break;
314 case mpx_specchar_format: fmt = kpse_mpsupport_format; break;
316 if (fmt<0) return NULL;
317 return kpse_find_file (nam, fmt, req);
320 @ Invoke {\tt makempx} (or {\tt troffmpx}) to make sure there is an
321 up-to-date {\tt .mpx} file for a given {\tt .mp} file. (Original
322 from John Hobby 3/14/90)
324 @d default_args " --parse-first-line --interaction=nonstopmode"
325 @d TEX "tex"
326 @d TROFF "soelim | eqn -Tps -d$$ | troff -Tps"
329 #ifndef MPXCOMMAND
330 #define MPXCOMMAND "makempx"
331 #endif
332 static int mpost_run_make_mpx (MP mp, char *mpname, char *mpxname) {
333 int ret;
334 char *cnf_cmd = kpse_var_value ("MPXCOMMAND");
335 if (cnf_cmd != NULL && (strcmp (cnf_cmd, "0")==0)) {
336 /* If they turned off this feature, just return success. */
337 ret = 0;
338 } else {
339 /* We will invoke something. Compile-time default if nothing else. */
340 char *cmd, *tmp, *qmpname, *qmpxname;
341 if (job_area != NULL) {
342 char *l = mpost_xmalloc(strlen(mpname)+strlen(job_area)+1);
343 strcpy(l, job_area);
344 strcat(l, mpname);
345 tmp = normalize_quotes(l, "mpname");
346 mpost_xfree(l);
347 } else {
348 tmp = normalize_quotes(mpname, "mpname");
350 if (!kpse_in_name_ok(tmp))
351 return 0; /* disallowed filename */
352 qmpname = kpse_find_file (tmp,kpse_mp_format, true);
353 mpost_xfree(tmp);
354 if (qmpname != NULL && job_area != NULL) {
355 /* if there is a usable mpx file in the source path already,
356 simply use that and return true */
357 char *l = mpost_xmalloc(strlen(qmpname)+2);
358 strcpy(l, qmpname);
359 strcat(l, "x");
360 qmpxname = l;
361 if (qmpxname) {
362 #if HAVE_SYS_STAT_H
363 struct stat source_stat, target_stat;
364 int nothingtodo = 0;
365 if ((stat(qmpxname, &target_stat) >= 0) &&
366 (stat(qmpname, &source_stat) >= 0)) {
367 #if HAVE_ST_MTIM
368 if (source_stat.st_mtim.tv_sec < target_stat.st_mtim.tv_sec ||
369 (source_stat.st_mtim.tv_sec == target_stat.st_mtim.tv_sec &&
370 source_stat.st_mtim.tv_nsec < target_stat.st_mtim.tv_nsec))
371 nothingtodo = 1;
372 #else
373 if (source_stat.st_mtime < target_stat.st_mtime)
374 nothingtodo = 1;
375 #endif
377 if (nothingtodo == 1)
378 return 1; /* success ! */
379 #endif
382 qmpxname = normalize_quotes(mpxname, "mpxname");
383 if (cnf_cmd!=NULL && (strcmp (cnf_cmd, "1")!=0)) {
384 if (mp_troff_mode(mp)!=0)
385 cmd = concatn (cnf_cmd, " -troff ",
386 qmpname, " ", qmpxname, NULL);
387 else if (mpost_tex_program!=NULL && *mpost_tex_program != '\0')
388 cmd = concatn (cnf_cmd, " -tex=", mpost_tex_program, " ",
389 qmpname, " ", qmpxname, NULL);
390 else
391 cmd = concatn (cnf_cmd, " -tex ", qmpname, " ", qmpxname, NULL);
393 /* Run it. */
394 ret = system (cmd);
395 free (cmd);
396 mpost_xfree(qmpname);
397 mpost_xfree(qmpxname);
398 } else {
399 mpx_options * mpxopt;
400 char *s = NULL;
401 char *maincmd = NULL;
402 int mpxmode = mp_troff_mode(mp);
403 char *mpversion = mp_metapost_version () ;
404 mpxopt = mpost_xmalloc(sizeof(mpx_options));
405 if (mpost_tex_program != NULL && *mpost_tex_program != '\0') {
406 maincmd = mpost_xstrdup(mpost_tex_program);
407 } else {
408 if (mpxmode == mpx_tex_mode) {
409 s = kpse_var_value("TEX");
410 if (s==NULL) s = kpse_var_value("MPXMAINCMD");
411 if (s==NULL) s = mpost_xstrdup (TEX);
412 maincmd = (char *)mpost_xmalloc (strlen(s)+strlen(default_args)+1);
413 strcpy(maincmd,s);
414 strcat(maincmd,default_args);
415 free(s);
416 } else {
417 s = kpse_var_value("TROFF");
418 if (s==NULL) s = kpse_var_value("MPXMAINCMD");
419 if (s==NULL) s = mpost_xstrdup (TROFF);
420 maincmd = s;
423 mpxopt->mode = mpxmode;
424 mpxopt->cmd = maincmd;
425 mpxopt->mptexpre = kpse_var_value("MPTEXPRE");
426 mpxopt->debug = debug;
427 mpxopt->mpname = qmpname;
428 mpxopt->mpxname = qmpxname;
429 mpxopt->find_file = makempx_find_file;
431 const char *banner = "% Written by metapost version ";
432 mpxopt->banner = mpost_xmalloc(strlen(mpversion)+strlen(banner)+1);
433 strcpy (mpxopt->banner, banner);
434 strcat (mpxopt->banner, mpversion);
436 ret = mpx_makempx(mpxopt);
437 mpost_xfree(mpxopt->cmd);
438 mpost_xfree(mpxopt->mptexpre);
439 mpost_xfree(mpxopt->banner);
440 mpost_xfree(mpxopt->mpname);
441 mpost_xfree(mpxopt->mpxname);
442 mpost_xfree(mpxopt);
443 mpost_xfree(mpversion);
447 mpost_xfree (cnf_cmd);
448 return (int)(ret == 0);
451 static int mpost_run_dvitomp (char *dviname, char *mpxname) {
452 int ret;
453 size_t i;
454 char *m, *d;
455 mpx_options * mpxopt;
456 char *mpversion = mp_metapost_version () ;
457 mpxopt = mpost_xmalloc(sizeof(mpx_options));
458 memset(mpxopt,0,sizeof(mpx_options));
459 mpxopt->mode = mpx_tex_mode;
460 if (dviname == NULL)
461 return EXIT_FAILURE;
462 i = strlen(dviname);
463 if (mpxname==NULL) {
464 m = mpost_xstrdup(dviname);
465 if (i>4 && *(m+i-4)=='.'
466 && *(m+i-3)=='d' && *(m+i-2)=='v' && *(m+i-1)=='i')
467 *(m+i-4)='\0' ;
468 } else {
469 m = mpost_xstrdup(mpxname);
471 d = mpost_xstrdup(dviname);
472 if (!(i>4 && *(d+i-4)=='.'
473 && *(d+i-3)=='d' && *(d+i-2)=='v' && *(d+i-1)=='i')) {
474 char *s = malloc (i+5);
475 memset(s,0,i+5);
476 s = strcat(s, d);
477 (void)strcat(s+i-1, ".dvi");
478 mpost_xfree (d);
479 d = s ;
482 i = strlen(m);
483 if (i>4 && *(m+i-4)=='.'
484 && *(m+i-3)=='m' && *(m+i-2)=='p' && *(m+i-1)=='x') {
485 } else {
486 char *s = malloc (i+5);
487 memset(s,0,i+5);
488 s = strcat(s, m);
489 (void)strcat(s+i-1, ".mpx");
490 mpost_xfree (m);
491 m = s ;
493 if (!(kpse_in_name_ok(d) && kpse_out_name_ok(m)))
494 return EXIT_FAILURE; /* disallowed filename */
495 mpxopt->mpname = d;
496 mpxopt->mpxname = m;
498 mpxopt->find_file = makempx_find_file;
500 const char *banner = "% Written by dvitomp version ";
501 mpxopt->banner = mpost_xmalloc(strlen(mpversion)+strlen(banner)+1);
502 strcpy (mpxopt->banner, banner);
503 strcat (mpxopt->banner, mpversion);
505 ret = mpx_run_dvitomp(mpxopt);
506 mpost_xfree(mpxopt->banner);
507 mpost_xfree(mpxopt);
508 mpost_xfree(mpversion);
509 puts(""); /* nicer in case of error */
510 return ret;
515 @<Register the callback routines@>=
516 if (!nokpse)
517 options->run_make_mpx = mpost_run_make_mpx;
520 @ @c
521 static int get_random_seed (void) {
522 int ret = 0;
523 #if defined (HAVE_GETTIMEOFDAY)
524 struct timeval tv;
525 gettimeofday(&tv, NULL);
526 ret = (int)(tv.tv_usec + 1000000 * tv.tv_usec);
527 #elif defined (HAVE_FTIME)
528 struct timeb tb;
529 ftime(&tb);
530 ret = (tb.millitm + 1000 * tb.time);
531 #else
532 time_t clock = time ((time_t*)NULL);
533 struct tm *tmptr = localtime(&clock);
534 if (tmptr!=NULL)
535 ret = (tmptr->tm_sec + 60*(tmptr->tm_min + 60*tmptr->tm_hour));
536 #endif
537 return ret;
540 @ @<Register the callback routines@>=
541 options->random_seed = get_random_seed();
544 @ Handle -output-directory.
547 static char *mpost_find_in_output_directory(const char *s,const char *fmode)
549 if (output_directory && !kpse_absolute_p(s, false)) {
550 char *ftemp = concat3(output_directory, DIR_SEP_STRING, s);
551 return ftemp;
553 return NULL;
558 @ @c
559 static char *mpost_find_file(MP mp, const char *fname, const char *fmode, int ftype) {
560 size_t l ;
561 char *s;
562 char *ofname;
563 (void)mp;
564 s = NULL;
565 ofname = NULL ;
568 if (fname == NULL || (fmode[0]=='r' && !kpse_in_name_ok(fname)) )
569 return NULL; /* disallowed filename */
572 if (fmode[0]=='w') {
573 if (output_directory) {
574 ofname = mpost_find_in_output_directory(fname,fmode);
575 if (ofname == NULL || (fmode[0]=='w' && !kpse_out_name_ok(ofname))) {
576 mpost_xfree(ofname);
577 return NULL; /* disallowed filename */
579 } else {
580 if (!kpse_out_name_ok(fname))
581 return NULL; /* disallowed filename */
586 if (fmode[0]=='r') {
587 if ((job_area != NULL) &&
588 (ftype>=mp_filetype_text || ftype==mp_filetype_program )) {
589 char *f = mpost_xmalloc(strlen(job_area)+strlen(fname)+1);
590 strcpy(f,job_area);
591 strcat(f,fname);
592 if (ftype>=mp_filetype_text) {
593 s = kpse_find_file (f, kpse_mp_format, 0);
594 } else {
595 l = strlen(f);
596 if (l>3 && strcmp(f+l-3,".mf")==0) {
597 s = kpse_find_file (f,kpse_mf_format, 0);
598 #if HAVE_SYS_STAT_H
599 } else if (l>4 && strcmp(f+l-4,".mpx")==0) {
600 struct stat source_stat, target_stat;
601 char *mpname = mpost_xstrdup(f);
602 *(mpname + strlen(mpname) -1 ) = '\0';
603 /* printf("statting %s and %s\n", mpname, f); */
604 if ((stat(f, &target_stat) >= 0) &&
605 (stat(mpname, &source_stat) >= 0)) {
606 #if HAVE_ST_MTIM
607 if (source_stat.st_mtim.tv_sec <= target_stat.st_mtim.tv_sec ||
608 (source_stat.st_mtim.tv_sec == target_stat.st_mtim.tv_sec &&
609 source_stat.st_mtim.tv_nsec <= target_stat.st_mtim.tv_nsec))
610 s = mpost_xstrdup(f);
611 #else
612 if (source_stat.st_mtime <= target_stat.st_mtime)
613 s = mpost_xstrdup(f);
614 #endif
616 mpost_xfree(mpname);
617 #endif
618 } else {
619 s = kpse_find_file (f,kpse_mp_format, 0);
622 mpost_xfree(f);
623 if (s!=NULL) {
624 return s;
627 if (ftype>=mp_filetype_text) {
628 s = kpse_find_file (fname, kpse_mp_format, 0);
629 } else {
630 switch(ftype) {
631 case mp_filetype_program:
632 l = strlen(fname);
633 if (l>3 && strcmp(fname+l-3,".mf")==0) {
634 s = kpse_find_file (fname, kpse_mf_format, 0);
635 } else {
636 s = kpse_find_file (fname, kpse_mp_format, 0);
638 break;
639 case mp_filetype_memfile:
640 s = kpse_find_file (fname, kpse_mem_format, 1);
641 break;
642 case mp_filetype_metrics:
643 s = kpse_find_file (fname, kpse_tfm_format, 0);
644 break;
645 case mp_filetype_fontmap:
646 s = kpse_find_file (fname, kpse_fontmap_format, 0);
647 break;
648 case mp_filetype_font:
649 s = kpse_find_file (fname, kpse_type1_format, 0);
650 break;
651 case mp_filetype_encoding:
652 s = kpse_find_file (fname, kpse_enc_format, 0);
653 break;
656 } else {
657 /* when writing */
658 if (ofname) {
659 s = mpost_xstrdup(ofname);
660 mpost_xfree(ofname);
661 } else {
662 s = mpost_xstrdup(fname);
666 return s;
669 @ @<Register the callback routines@>=
670 if (!nokpse)
671 options->find_file = mpost_find_file;
673 @ The |mpost| program supports setting of internal values
674 via a |-s| commandline switch. Since this switch is repeatable,
675 a structure is needed to store the found values in, which is a
676 simple linked list.
679 typedef struct set_list_item {
680 int isstring;
681 char *name;
682 char *value;
683 struct set_list_item *next;
684 } set_list_item ;
686 @ Here is the global value that is the head of the list of |-s| options.
688 struct set_list_item *set_list = NULL;
690 @ And |internal_set_option| is the routine that fills in the linked
691 list. The argument it receives starts at the first letter of the
692 internal, and should contain an internal name, an equals sign,
693 and the value (possibly in quotes) without any intervening spaces.
695 Double quotes around the right hand side are needed to make sure that
696 the right hand side is treated as a string assignment by MPlib later.
697 These outer double quote characters are stripped, but no other string
698 processing takes place.
700 As a special hidden feature, a missing right hand side is treated as if it
701 was the integer value |1|.
703 @<Declarations@>=
704 void internal_set_option(const char *opt);
706 @ @c
707 void internal_set_option(const char *opt) {
708 struct set_list_item *itm;
709 char *s, *v;
710 int isstring = 0;
711 s = mpost_xstrdup(opt) ;
712 v = strstr(s,"=") ;
713 if (v==NULL) {
714 v = xstrdup("1");
715 } else {
716 *v='\0'; /* terminates |s| */
717 v++;
718 if (*v && *v=='"') {
719 isstring=1;
720 v++;
721 *(v+strlen(v)-1)= '\0';
724 if (s && v && strlen(s)>0) {
725 if (set_list == NULL) {
726 set_list = xmalloc(sizeof(struct set_list_item));
727 itm = set_list;
728 } else {
729 itm = set_list;
730 while (itm->next != NULL)
731 itm = itm->next;
732 itm->next = xmalloc(sizeof(struct set_list_item));
733 itm = itm->next;
735 itm->name = s;
736 itm->value = v;
737 itm->isstring = isstring;
738 itm->next = NULL;
742 @ After the initialization stage is done, the next function
743 runs through the list of options and feeds them to the MPlib
744 function |mp_set_internal|.
746 @<Declarations@>=
747 void run_set_list (MP mp);
749 @ @c
750 void run_set_list (MP mp) {
751 struct set_list_item *itm;
752 itm = set_list;
753 while (itm!=NULL) {
754 mp_set_internal(mp,itm->name,itm->value, itm->isstring);
755 itm = itm->next;
761 @ @c
762 static void *mpost_open_file(MP mp, const char *fname, const char *fmode, int ftype) {
763 char realmode[3];
764 char *s;
765 if (ftype==mp_filetype_terminal) {
766 return (fmode[0] == 'r' ? stdin : stdout);
767 } else if (ftype==mp_filetype_error) {
768 return stderr;
769 } else {
770 s = mpost_find_file (mp, fname, fmode, ftype);
771 if (s!=NULL) {
772 void *ret = NULL;
773 realmode[0] = *fmode;
774 realmode[1] = 'b';
775 realmode[2] = '\0';
776 ret = (void *)fopen(s,realmode);
777 if (recorder_enabled) {
778 if (!recorder_file)
779 recorder_start(job_name);
780 if (*fmode == 'r')
781 fprintf(recorder_file, "INPUT %s\n", s);
782 else
783 fprintf(recorder_file, "OUTPUT %s\n", s);
785 free(s);
786 return ret;
789 return NULL;
792 @ @<Register the callback routines@>=
793 if (!nokpse)
794 options->open_file = mpost_open_file;
797 @<getopt structures@>=
798 #define ARGUMENT_IS(a) STREQ (mpost_options[optionid].name, a)
800 /* SunOS cc can't initialize automatic structs, so make this static. */
801 static struct option mpost_options[]
802 = { { "mem", 1, 0, 0 },
803 { "help", 0, 0, 0 },
804 { "debug", 0, &debug, 1 },
805 { "no-kpathsea", 0, &nokpse, 1 },
806 { "dvitomp", 0, &dvitomp_only, 1 },
807 { "ini", 0, &ini_version_test, 1 },
808 { "interaction", 1, 0, 0 },
809 { "math", 1, 0, 0 },
810 { "numbersystem", 1, 0, 0 },
811 { "halt-on-error", 0, 0, 0 },
812 { "kpathsea-debug", 1, 0, 0 },
813 { "progname", 1, 0, 0 },
814 { "version", 0, 0, 0 },
815 { "recorder", 0, &recorder_enabled, 1 },
816 { "file-line-error-style", 0, 0, 0 },
817 { "no-file-line-error-style", 0, 0, 0 },
818 { "file-line-error", 0, 0, 0 },
819 { "no-file-line-error", 0, 0, 0 },
820 { "jobname", 1, 0, 0 },
821 { "output-directory", 1, 0, 0 },
822 { "s", 1, 0, 0 },
823 { "parse-first-line", 0, 0, 0 },
824 { "no-parse-first-line", 0, 0, 0 },
825 { "8bit", 0, 0, 0 },
826 { "T", 0, 0, 0 },
827 { "troff", 0, 0, 0 },
828 { "tex", 1, 0, 0 },
829 { 0, 0, 0, 0 } };
833 @ Parsing the commandline options.
835 @<Read and set command line options@>=
837 int g; /* `getopt' return code. */
838 int optionid;
839 for (;;) {
840 g = getopt_long_only (argc, argv, "+", mpost_options, &optionid);
842 if (g == -1) /* End of arguments, exit the loop. */
843 break;
845 if (g == '?') { /* Unknown option. */
846 exit(EXIT_FAILURE);
849 if (ARGUMENT_IS ("kpathsea-debug")) {
850 kpathsea_debug |= (unsigned)atoi (optarg);
852 } else if (ARGUMENT_IS("jobname")) {
853 if (optarg!=NULL) {
854 mpost_xfree(options->job_name);
855 options->job_name = mpost_xstrdup(optarg);
858 } else if (ARGUMENT_IS ("progname")) {
859 user_progname = optarg;
861 } else if (ARGUMENT_IS ("mem")) {
862 if (optarg!=NULL) {
863 mpost_xfree(options->mem_name);
864 options->mem_name = mpost_xstrdup(optarg);
865 if (user_progname == NULL)
866 user_progname = optarg;
869 } else if (ARGUMENT_IS ("interaction")) {
870 if (STREQ (optarg, "batchmode")) {
871 options->interaction = mp_batch_mode;
872 } else if (STREQ (optarg, "nonstopmode")) {
873 options->interaction = mp_nonstop_mode;
874 } else if (STREQ (optarg, "scrollmode")) {
875 options->interaction = mp_scroll_mode;
876 } else if (STREQ (optarg, "errorstopmode")) {
877 options->interaction = mp_error_stop_mode;
878 } else {
879 fprintf(stdout,"Ignoring unknown argument `%s' to --interaction\n", optarg);
881 } else if (ARGUMENT_IS ("math") || ARGUMENT_IS ("numbersystem")) {
882 if (STREQ (optarg, "scaled")) {
883 options->math_mode = mp_math_scaled_mode;
884 internal_set_option("numbersystem=\"scaled\"");
885 } else if (STREQ (optarg, "double")) {
886 options->math_mode = mp_math_double_mode;
887 internal_set_option("numbersystem=\"double\"");
888 } else if (STREQ (optarg, "decimal")) {
889 options->math_mode = mp_math_decimal_mode;
890 internal_set_option("numbersystem=\"decimal\"");
891 } else if (STREQ (optarg, "binary")) {
892 options->math_mode = mp_math_binary_mode;
893 internal_set_option("numbersystem=\"binary\"");
894 } else {
895 fprintf(stdout,"Ignoring unknown argument `%s' to --numbersystem\n", optarg);
897 } else if (ARGUMENT_IS("troff") ||
898 ARGUMENT_IS("T")) {
899 options->troff_mode = (int)true;
900 } else if (ARGUMENT_IS ("tex")) {
901 mpost_tex_program = optarg;
902 } else if (ARGUMENT_IS("file-line-error") ||
903 ARGUMENT_IS("file-line-error-style")) {
904 options->file_line_error_style=true;
905 } else if (ARGUMENT_IS("no-file-line-error") ||
906 ARGUMENT_IS("no-file-line-error-style")) {
907 options->file_line_error_style=false;
908 } else if (ARGUMENT_IS("help")) {
909 if (dvitomp_only) {
910 @<Show short help and exit@>;
911 } else {
912 @<Show help and exit@>;
914 } else if (ARGUMENT_IS("version")) {
915 @<Show version and exit@>;
916 } else if (ARGUMENT_IS("s")) {
917 if (strchr(optarg,'=')==NULL) {
918 fprintf(stdout,"fatal error: %s: missing -s argument\n", argv[0]);
919 exit (EXIT_FAILURE);
920 } else {
921 internal_set_option(optarg);
923 } else if (ARGUMENT_IS("halt-on-error")) {
924 options->halt_on_error = true;
925 } else if (ARGUMENT_IS("output-directory")) {
926 output_directory = optarg ;
927 } else if (ARGUMENT_IS("8bit") ||
928 ARGUMENT_IS("parse-first-line")) {
929 /* do nothing, these are always on */
930 } else if (ARGUMENT_IS("translate-file") ||
931 ARGUMENT_IS("no-parse-first-line")) {
932 fprintf(stdout,"warning: %s: unimplemented option %s\n", argv[0], argv[optind]);
935 options->ini_version = (int)ini_version_test;
939 @<getopt structures@>=
940 #define option_is(a) STREQ (dvitomp_options[optionid].name, a)
942 /* SunOS cc can't initialize automatic structs, so make this static. */
943 static struct option dvitomp_options[]
944 = { { "help", 0, 0, 0 },
945 { "no-kpathsea", 0, &nokpse, 1 },
946 { "kpathsea-debug", 1, 0, 0 },
947 { "progname", 1, 0, 0 },
948 { "version", 0, 0, 0 },
949 { 0, 0, 0, 0 } };
954 @<Read and set dvitomp command line options@>=
956 int g; /* `getopt' return code. */
957 int optionid;
958 for (;;) {
959 g = getopt_long_only (argc, argv, "+", dvitomp_options, &optionid);
961 if (g == -1) /* End of arguments, exit the loop. */
962 break;
964 if (g == '?') { /* Unknown option. */
965 fprintf(stdout,"fatal error: %s: unknown option %s\n", argv[0], argv[optind]);
966 exit(EXIT_FAILURE);
968 if (option_is ("kpathsea-debug")) {
969 if (optarg!=NULL)
970 kpathsea_debug |= (unsigned)atoi (optarg);
971 } else if (option_is ("progname")) {
972 user_progname = optarg;
973 } else if (option_is("help")) {
974 @<Show short help and exit@>;
975 } else if (option_is("version")) {
976 @<Show version and exit@>;
982 @<Show help...@>=
984 char *s = mp_metapost_version();
985 if (dvitomp_only)
986 fprintf(stdout, "This is dvitomp %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
987 else
988 fprintf(stdout, "This is MetaPost %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
989 mpost_xfree(s);
990 fprintf(stdout,
991 "\n"
992 "Usage: mpost [OPTION] [&MEMNAME] [MPNAME[.mp]] [COMMANDS]\n"
993 " mpost --dvitomp DVINAME[.dvi] [MPXNAME[.mpx]]\n"
994 "\n"
995 " Run MetaPost on MPNAME, usually creating MPNAME.NNN (and perhaps\n"
996 " MPNAME.tfm), where NNN are the character numbers generated.\n"
997 " Any remaining COMMANDS are processed as MetaPost input,\n"
998 " after MPNAME is read.\n\n"
999 " With a --dvitomp argument, MetaPost acts as DVI-to-MPX converter only.\n"
1000 " Call MetaPost with --dvitomp --help for option explanations.\n\n");
1001 fprintf(stdout,
1002 " -ini be inimpost, for dumping mem files\n"
1003 " -interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/\n"
1004 " scrollmode/errorstopmode)\n"
1005 " -numbersystem=STRING set number system mode (STRING=scaled/double/binary/decimal)\n"
1006 " -jobname=STRING set the job name to STRING\n"
1007 " -progname=STRING set program (and mem) name to STRING\n"
1008 " -tex=TEXPROGRAM use TEXPROGRAM for text labels\n"
1009 " [-no]-file-line-error disable/enable file:line:error style messages\n"
1011 fprintf(stdout,
1012 " -debug print debugging info and leave temporary files in place\n"
1013 " -kpathsea-debug=NUMBER set path searching debugging flags according to\n"
1014 " the bits of NUMBER\n"
1015 " -mem=MEMNAME or &MEMNAME use MEMNAME instead of program name or a %%& line\n"
1016 " -recorder enable filename recorder\n"
1017 " -troff set prologues:=1 and assume TEXPROGRAM is really troff\n"
1018 " -s INTERNAL=\"STRING\" set internal INTERNAL to the string value STRING\n"
1019 " -s INTERNAL=NUMBER set internal INTERNAL to the integer value NUMBER\n"
1020 " -help display this help and exit\n"
1021 " -version output version information and exit\n"
1022 "\n"
1023 "Email bug reports to mp-implementors@@tug.org.\n"
1024 "\n");
1025 exit(EXIT_SUCCESS);
1029 @<Show short help...@>=
1031 char *s = mp_metapost_version();
1032 if (dvitomp_only)
1033 fprintf(stdout, "This is dvitomp %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
1034 else
1035 fprintf(stdout, "This is MetaPost %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
1036 mpost_xfree(s);
1037 fprintf(stdout,
1038 "\n"
1039 "Usage: dvitomp DVINAME[.dvi] [MPXNAME[.mpx]]\n"
1040 " mpost --dvitomp DVINAME[.dvi] [MPXNAME[.mpx]]\n"
1041 "\n"
1042 " Convert a TeX DVI file to a MetaPost MPX file.\n\n");
1043 fprintf(stdout,
1044 " -progname=STRING set program name to STRING\n"
1045 " -kpathsea-debug=NUMBER set path searching debugging flags according to\n"
1046 " the bits of NUMBER\n"
1047 " -help display this help and exit\n"
1048 " -version output version information and exit\n"
1049 "\n"
1050 "Email bug reports to mp-implementors@@tug.org.\n"
1051 "\n");
1052 exit(EXIT_SUCCESS);
1056 @<Show version...@>=
1058 char *s = mp_metapost_version();
1059 if (dvitomp_only)
1060 fprintf(stdout, "dvitomp (MetaPost) %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
1061 else
1062 fprintf(stdout, "MetaPost %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
1063 fprintf(stdout,
1064 "The MetaPost source code in the public domain.\n"
1065 "MetaPost also uses code available under the\n"
1066 "GNU Lesser General Public License (version 3 or later);\n"
1067 "therefore MetaPost executables are covered by the LGPL.\n"
1068 "There is NO warranty.\n"
1069 "For more information about these matters, see the file\n"
1070 "COPYING.LESSER or <http://gnu.org/licenses/lgpl.html>.\n"
1071 "Original author of MetaPost: John Hobby.\n"
1072 "Author of the CWEB MetaPost: Taco Hoekwater.\n"
1073 "Current maintainer of MetaPost: Luigi Scarso.\n\n"
1075 mpost_xfree(s);
1076 if (!dvitomp_only) {
1077 mp_show_library_versions();
1079 exit(EXIT_SUCCESS);
1082 @ The final part of the command line, after option processing, is
1083 stored in the \MP\ instance, this will be taken as the first line of
1084 input.
1086 @d command_line_size 256
1088 @<Copy the rest of the command line@>=
1090 mpost_xfree(options->command_line);
1091 options->command_line = mpost_xmalloc(command_line_size);
1092 strcpy(options->command_line,"");
1093 if (optind<argc) {
1094 k=0;
1095 for(;optind<argc;optind++) {
1096 char *c = argv[optind];
1097 while (*c != '\0') {
1098 if (k<(command_line_size-1)) {
1099 options->command_line[k++] = *c;
1101 c++;
1103 options->command_line[k++] = ' ';
1105 while (k>0) {
1106 if (options->command_line[(k-1)] == ' ')
1107 k--;
1108 else
1109 break;
1111 options->command_line[k] = '\0';
1115 @ A simple function to get numerical |texmf.cnf| values
1117 static int setup_var (int def, const char *var_name, boolean nokpse) {
1118 if (!nokpse) {
1119 char * expansion = kpse_var_value (var_name);
1120 if (expansion) {
1121 int conf_val = atoi (expansion);
1122 free (expansion);
1123 if (conf_val > 0) {
1124 return conf_val;
1128 return def;
1131 @ @<Set up the banner line@>=
1133 char * mpversion = mp_metapost_version () ;
1134 const char * banner = "This is MetaPost, version ";
1135 const char * kpsebanner_start = " (";
1136 const char * kpsebanner_stop = ")";
1137 mpost_xfree(options->banner);
1138 options->banner = mpost_xmalloc(strlen(banner)+
1139 strlen(mpversion)+
1140 strlen(WEB2CVERSION)+
1141 strlen(kpsebanner_start)+
1142 strlen(kpathsea_version_string)+
1143 strlen(kpsebanner_stop)+1);
1144 strcpy (options->banner, banner);
1145 strcat (options->banner, mpversion);
1146 strcat (options->banner, WEB2CVERSION);
1147 strcat (options->banner, kpsebanner_start);
1148 strcat (options->banner, kpathsea_version_string);
1149 strcat (options->banner, kpsebanner_stop);
1150 mpost_xfree(mpversion);
1153 @ Precedence order is:
1155 \item {} \.{-mem=MEMNAME} on the command line
1156 \item {} \.{\&MEMNAME} on the command line
1157 \item {} \.{\%\&MEM} as first line inside input file
1158 \item {} \.{argv[0]} if all else fails
1160 @<Discover the mem name@>=
1162 char *m = NULL; /* head of potential |mem_name| */
1163 char *n = NULL; /* a moving pointer */
1164 if (options->command_line != NULL && *(options->command_line) == '&'){
1165 m = mpost_xstrdup(options->command_line+1);
1166 n = m;
1167 while (*n != '\0' && *n != ' ') n++;
1168 while (*n == ' ') n++;
1169 if (*n != '\0') { /* more command line to follow */
1170 char *s = mpost_xstrdup(n);
1171 if (n>m) n--;
1172 while (*n == ' ' && n>m) n--;
1173 n++;
1174 *n ='\0'; /* this terminates |m| */
1175 mpost_xfree(options->command_line);
1176 options->command_line = s;
1177 } else { /* only \.{\&MEMNAME} on command line */
1178 if (n>m) n--;
1179 while (*n == ' ' && n>m) n--;
1180 n++;
1181 *n ='\0'; /* this terminates |m| */
1182 mpost_xfree(options->command_line);
1184 if ( options->mem_name == NULL && *m != '\0') {
1185 mpost_xfree(options->mem_name); /* for lint only */
1186 options->mem_name = m;
1187 } else {
1188 mpost_xfree(m);
1192 if ( options->mem_name == NULL ) {
1193 char *m = NULL; /* head of potential |job_name| */
1194 char *n = NULL; /* a moving pointer */
1195 if (options->command_line != NULL && *(options->command_line) != '\\'){
1196 m = mpost_xstrdup(options->command_line);
1197 n = m;
1198 while (*n != '\0' && *n != ' ') n++;
1199 if (n>m) {
1200 char *fname;
1201 *n='\0';
1202 fname = m;
1203 if (!nokpse)
1204 fname = kpse_find_file(m,kpse_mp_format,true);
1205 if (fname == NULL) {
1206 mpost_xfree(m);
1207 } else {
1208 FILE *F = fopen(fname,"r");
1209 if (F==NULL) {
1210 mpost_xfree(fname);
1211 } else {
1212 char *line = mpost_xmalloc(256);
1213 if (fgets(line,255,F) == NULL) {
1214 (void)fclose(F);
1215 mpost_xfree(fname);
1216 mpost_xfree(line);
1217 } else {
1218 (void)fclose(F);
1219 while (*line != '\0' && *line == ' ') line++;
1220 if (*line == '%') {
1221 n = m = line+1;
1222 while (*n != '\0' && *n == ' ') n++;
1223 if (*n == '&') {
1224 m = n+1;
1225 while (*n != '\0' && *n != ' ') n++;
1226 if (n>(m+1)) {
1227 n--;
1228 while (*n == ' ' && n>m) n--;
1229 *n ='\0'; /* this terminates |m| */
1230 options->mem_name = mpost_xstrdup(m);
1231 mpost_xfree(fname);
1232 } else {
1233 mpost_xfree(fname);
1234 mpost_xfree(line);
1241 } else {
1242 mpost_xfree(m);
1246 if ( options->mem_name == NULL )
1247 if (kpse_program_name!=NULL)
1248 options->mem_name = mpost_xstrdup(kpse_program_name);
1251 @ The job name needs to be known for the recorder to work,
1252 so we have to fix up |job_name| and |job_area|. If there
1253 was a \.{--jobname} on the command line, we have to reset
1254 the options structure as well.
1256 @<Discover the job name@>=
1258 char *tmp_job = NULL;
1259 if (options->job_name != NULL) {
1260 tmp_job = mpost_xstrdup(options->job_name);
1261 mpost_xfree(options->job_name);
1262 options->job_name = NULL;
1263 } else {
1264 char *m = NULL; /* head of potential |job_name| */
1265 char *n = NULL; /* a moving pointer */
1266 if (options->command_line != NULL){
1267 m = mpost_xstrdup(options->command_line);
1268 n = m;
1269 if (*(options->command_line) != '\\') { /* this is the simple case */
1270 while (*n != '\0' && *n != ' ') n++;
1271 if (n>m) {
1272 *n='\0';
1273 tmp_job = mpost_xstrdup(m);
1275 } else { /* this is still not perfect, but better */
1276 char *mm = strstr(m,"input ");
1277 if (mm != NULL) {
1278 mm += 6;
1279 n = mm;
1280 while (*n != '\0' && *n != ' ' && *n!=';') n++;
1281 if (n>mm) {
1282 *n='\0';
1283 tmp_job = mpost_xstrdup(mm);
1287 free(m);
1289 if (tmp_job == NULL) {
1290 if (options->ini_version == 1 &&
1291 options->mem_name != NULL) {
1292 tmp_job = mpost_xstrdup(options->mem_name);
1295 if (tmp_job == NULL) {
1296 tmp_job = mpost_xstrdup("mpout");
1297 } else {
1298 char *ext = strrchr(tmp_job,'.');
1299 if (ext != NULL)
1300 *ext = '\0';
1303 /* now split |tmp_job| into |job_area| and |job_name| */
1305 char *s = tmp_job + strlen(tmp_job);
1306 if (!IS_DIR_SEP(*s)) { /* just in case */
1307 while (s>tmp_job) {
1308 if (IS_DIR_SEP(*s)) {
1309 break;
1311 s--;
1313 if (s>tmp_job) {
1314 /* there was a directory part */
1315 if (strlen(s)>1) {
1316 job_name = mpost_xstrdup((s+1));
1317 *(s+1) = '\0';
1318 job_area = tmp_job;
1320 } else {
1321 job_name = tmp_job;
1322 /* |job_area| stays NULL */
1327 options->job_name = job_name;
1329 @ We |#define DLLPROC dllmpostmain| in order to build \MP\ as DLL for
1330 W32\TeX.
1332 @<Declarations@>=
1333 #define DLLPROC dllmpostmain
1334 #if defined(WIN32) && !defined(__MINGW32__) && defined(DLLPROC)
1335 extern __declspec(dllexport) int DLLPROC (int argc, char **argv);
1336 #else
1337 #undef DLLPROC
1338 #endif
1340 @ Now this is really it: \MP\ starts and ends here.
1343 static char *cleaned_invocation_name(char *arg)
1345 char *ret, *dot;
1346 const char *start = xbasename(arg);
1347 ret = xstrdup(start);
1348 dot = strrchr(ret, '.');
1349 if (dot != NULL) {
1350 *dot = 0; /* chop */
1352 return ret;
1355 #if defined(DLLPROC)
1356 DLLPROC (int argc, char **argv)
1357 #else
1358 main (int argc, char **argv)
1359 #endif
1360 { /* |start_here| */
1361 int k; /* index into buffer */
1362 int history; /* the exit status */
1363 MP mp; /* a metapost instance */
1364 struct MP_options * options; /* instance options */
1365 char *user_progname = NULL; /* If the user overrides |argv[0]| with {\tt -progname}. */
1366 options = mp_options();
1367 options->ini_version = (int)false;
1368 options->print_found_names = (int)true;
1370 const char *base = cleaned_invocation_name(argv[0]);
1371 if (FILESTRCASEEQ(base, "dvitomp"))
1372 dvitomp_only=1;
1374 if (dvitomp_only) {
1375 @<Read and set dvitomp command line options@>;
1376 } else {
1377 @<Read and set command line options@>;
1379 if (dvitomp_only) {
1380 char *mpx = NULL, *dvi = NULL;
1381 if (optind>=argc) {
1382 /* error ? */
1383 } else {
1384 dvi = argv[optind++];
1385 if (optind<argc) {
1386 mpx = argv[optind++];
1389 if (dvi == NULL) {
1390 @<Show short help and exit@>;
1391 } else {
1392 if (!nokpse)
1393 kpse_set_program_name(argv[0],
1394 user_progname ? user_progname : "dvitomp");
1395 exit (mpost_run_dvitomp(dvi, mpx));
1399 @= /*@@-nullpass@@*/ @>
1400 if (!nokpse) {
1401 kpse_set_program_enabled (kpse_mem_format, MAKE_TEX_FMT_BY_DEFAULT,
1402 kpse_src_compile);
1403 kpse_set_program_name(argv[0], user_progname);
1405 @= /*@@=nullpass@@*/ @>
1406 if(putenv(xstrdup("engine=metapost")))
1407 fprintf(stdout,"warning: could not set up $engine\n");
1408 options->error_line = setup_var (79,"error_line",nokpse);
1409 options->half_error_line = setup_var (50,"half_error_line",nokpse);
1410 options->max_print_line = setup_var (100,"max_print_line",nokpse);
1411 @<Set up the banner line@>;
1412 @<Copy the rest of the command line@>;
1413 @<Discover the mem name@>;
1414 @<Discover the job name@>;
1415 @<Register the callback routines@>;
1416 mp = mp_initialize(options);
1417 mpost_xfree(options->command_line);
1418 mpost_xfree(options->mem_name);
1419 mpost_xfree(options->job_name);
1420 mpost_xfree(options->banner);
1421 free(options);
1422 if (mp==NULL)
1423 exit(EXIT_FAILURE);
1424 history = mp_status(mp);
1425 if (history!=0 && history!=mp_warning_issued)
1426 exit(history);
1427 if (set_list!=NULL) {
1428 run_set_list(mp);
1430 history = mp_run(mp);
1431 (void)mp_finish(mp);
1432 if (history!=0 && history!=mp_warning_issued)
1433 exit(history);
1434 else
1435 exit(0);