summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mplibdir/mpost.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mplibdir/mpost.w')
-rw-r--r--Build/source/texk/web2c/mplibdir/mpost.w1492
1 files changed, 1492 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mplibdir/mpost.w b/Build/source/texk/web2c/mplibdir/mpost.w
new file mode 100644
index 00000000000..5e447270678
--- /dev/null
+++ b/Build/source/texk/web2c/mplibdir/mpost.w
@@ -0,0 +1,1492 @@
+% This file is part of MetaPost;
+% the MetaPost program is in the public domain.
+% See the <Show version...> code below for more info.
+
+\font\tenlogo=logo10 % font used for the METAFONT logo
+\def\MP{{\tenlogo META}\-{\tenlogo POST}}
+\def\MF{{\tenlogo META}\-{\tenlogo FONT}}
+\def\MP{{\tenlogo META}\-{\tenlogo POST}}
+\def\pct!{{\char`\%}} % percent sign in ordinary text
+\def\psqrt#1{\sqrt{\mathstrut#1}}
+
+
+\def\title{MetaPost executable}
+\def\[#1]{#1.}
+\pdfoutput=1
+
+@s line normal
+
+@s MP int
+@s MPX int
+@s MP_options int
+@s boolean int
+@s const_string int
+@s mpx_options int
+@s option int
+@s string int
+@s timeb int
+@s timeval int
+
+@*\MP\ executable.
+
+Now that all of \MP\ is a library, a separate program is needed to
+have our customary command-line interface.
+
+@ First, here are the \CEE/ includes.
+
+@d true 1
+@d false 0
+
+@c
+#include <w2c/config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined (HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#elif defined (HAVE_SYS_TIMEB_H)
+#include <sys/timeb.h>
+#endif
+#include <time.h> /* For `|struct tm|'. Moved here for Visual Studio 2005. */
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <mplib.h>
+#include <mpxout.h>
+#include <kpathsea/kpathsea.h>
+@= /*@@null@@*/ @> static char *mpost_tex_program = NULL;
+static int debug = 0; /* debugging for \.{makempx} */
+static int nokpse = 0;
+static boolean recorder_enabled = false;
+static string recorder_name = NULL;
+static FILE *recorder_file = NULL;
+static char *job_name = NULL;
+static char *job_area = NULL;
+static int dvitomp_only = 0;
+static int ini_version_test = false;
+string output_directory; /* Defaults to |NULL|. */
+static boolean restricted_mode = false;
+
+@<Structures for |getopt|@>@;
+@<Declarations@>@;
+
+@ Allocating a bit of memory, with error detection:
+
+@d mpost_xfree(A) do { if (A!=NULL) free(A); A=NULL; } while (0)
+
+@c
+@= /*@@only@@*/ /*@@out@@*/ @> static void *mpost_xmalloc (size_t bytes) {
+ void *w = malloc (bytes);
+ if (w==NULL) {
+ fprintf(stderr,"Out of memory!\n");
+ exit(EXIT_FAILURE);
+ }
+ return w;
+}
+@= /*@@only@@*/ @> static char *mpost_xstrdup(const char *s) {
+ char *w;
+ w = strdup(s);
+ if (w==NULL) {
+ fprintf(stderr,"Out of memory!\n");
+ exit(EXIT_FAILURE);
+ }
+ return w;
+}
+static char *mpost_itoa (int i) {
+ char res[32] ;
+ unsigned idx = 30;
+ unsigned v = (unsigned)abs(i);
+ memset(res,0,32*sizeof(char));
+ while (v>=10) {
+ char d = (char)(v % 10);
+ v = v / 10;
+ res[idx--] = d + '0';
+ }
+ res[idx--] = (char)v + '0';
+ if (i<0) {
+ res[idx--] = '-';
+ }
+ return mpost_xstrdup(res+idx+1);
+}
+
+
+@ @c
+#ifdef WIN32
+static int
+Isspace (char c)
+{
+ return (c == ' ' || c == '\t');
+}
+#endif
+static void mpost_run_editor (MP mp, char *fname, int fline) {
+ char *temp, *command, *fullcmd, *edit_value;
+ char c;
+ boolean sdone, ddone;
+
+#ifdef WIN32
+ char *fp, *ffp, *env, editorname[256], buffer[256];
+ int cnt = 0;
+ int dontchange = 0;
+#endif
+
+ if (restricted_mode)
+ return;
+
+ sdone = ddone = false;
+ edit_value = kpse_var_value ("MPEDIT");
+ if (edit_value == NULL)
+ edit_value = getenv("EDITOR");
+ if (edit_value == NULL) {
+ fprintf (stderr,"call_edit: can't find a suitable MPEDIT or EDITOR variable\n");
+ exit(mp_status(mp));
+ }
+ command = (string) mpost_xmalloc (strlen (edit_value) + strlen(fname) + 11 + 3);
+ temp = command;
+
+#ifdef WIN32
+ fp = editorname;
+ if ((isalpha(*edit_value) && *(edit_value + 1) == ':'
+ && IS_DIR_SEP (*(edit_value + 2)))
+ || (*edit_value == '"' && isalpha(*(edit_value + 1))
+ && *(edit_value + 2) == ':'
+ && IS_DIR_SEP (*(edit_value + 3)))
+ )
+ dontchange = 1;
+#endif
+
+ while ((c = *edit_value++) != (char)0) {
+ if (c == '%') {
+ switch (c = *edit_value++) {
+ case 'd':
+ if (ddone) {
+ fprintf (stderr,"call_edit: `%%d' appears twice in editor command\n");
+ exit(EXIT_FAILURE);
+ } else {
+ char *s = mpost_itoa(fline);
+ char *ss = s;
+ if (s != NULL) {
+ while (*s != '\0')
+ *temp++ = *s++;
+ free(ss);
+ }
+ ddone = true;
+ }
+ break;
+ case 's':
+ if (sdone) {
+ fprintf (stderr,"call_edit: `%%s' appears twice in editor command\n");
+ exit(EXIT_FAILURE);
+ } else {
+ while (*fname != '\0')
+ *temp++ = *fname++;
+ *temp++ = '.';
+ *temp++ = 'm';
+ *temp++ = 'p';
+ sdone = true;
+ }
+ break;
+ case '\0':
+ *temp++ = '%';
+ /* Back up to the |NULL| to force termination. */
+ edit_value--;
+ break;
+ default:
+ *temp++ = '%';
+ *temp++ = c;
+ break;
+ }
+ } else {
+#ifdef WIN32
+ if (dontchange)
+ *temp++ = c;
+ else { if(Isspace(c) && cnt == 0) {
+ cnt++;
+ temp = command;
+ *temp++ = c;
+ *fp = '\0';
+ } else if(!Isspace(c) && cnt == 0) {
+ *fp++ = c;
+ } else {
+ *temp++ = c;
+ }
+ }
+#else
+ *temp++ = c;
+#endif
+ }
+ }
+ *temp = '\0';
+
+#ifdef WIN32
+ if (dontchange == 0) {
+ if(editorname[0] == '.' ||
+ editorname[0] == '/' ||
+ editorname[0] == '\\') {
+ fprintf(stderr, "%s is not allowed to execute.\n", editorname);
+ exit(EXIT_FAILURE);
+ }
+ env = (char *)getenv("PATH");
+ if(SearchPath(env, editorname, ".exe", 256, buffer, &ffp)==0) {
+ if(SearchPath(env, editorname, ".bat", 256, buffer, &ffp)==0) {
+ fprintf(stderr, "I cannot find %s in the PATH.\n", editorname);
+ exit(EXIT_FAILURE);
+ }
+ }
+ fullcmd = mpost_xmalloc(strlen(buffer)+strlen(command)+5);
+ strcpy(fullcmd, "\"");
+ strcat(fullcmd, buffer);
+ strcat(fullcmd, "\"");
+ strcat(fullcmd, command);
+ } else
+#endif
+ fullcmd = command;
+
+ if (system (fullcmd) != 0)
+ fprintf (stderr, "! Trouble executing `%s'.\n", command);
+ exit(EXIT_FAILURE);
+}
+
+@
+@<Register the callback routines@>=
+options->run_editor = mpost_run_editor;
+
+@
+@c
+static string normalize_quotes (const char *name, const char *mesg) {
+ boolean quoted = false;
+ boolean must_quote = (strchr(name, ' ') != NULL);
+ /* Leave room for quotes and |NULL|. */
+ string ret = (string)mpost_xmalloc(strlen(name)+3);
+ string p;
+ const_string q;
+ p = ret;
+ if (must_quote)
+ *p++ = '"';
+ for (q = name; *q != '\0'; q++) {
+ if (*q == '"')
+ quoted = !quoted;
+ else
+ *p++ = *q;
+ }
+ if (must_quote)
+ *p++ = '"';
+ *p = '\0';
+ if (quoted) {
+ fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name);
+ exit(EXIT_FAILURE);
+ }
+ return ret;
+}
+
+@ Helpers for the filename recorder.
+
+@<Declarations@>=
+void recorder_start(char *jobname);
+
+@ @c
+void recorder_start(char *jobname) {
+ char cwd[1024];
+ if (jobname==NULL) {
+ recorder_name = mpost_xstrdup("mpout.fls");
+ } else {
+ recorder_name = (string)xmalloc((unsigned int)(strlen(jobname)+5));
+ strcpy(recorder_name, jobname);
+ strcat(recorder_name, ".fls");
+ }
+ recorder_file = xfopen(recorder_name, FOPEN_W_MODE);
+
+ if(getcwd(cwd,1020) != NULL) {
+#ifdef WIN32
+ char *p;
+ for (p = cwd; *p; p++) {
+ if (*p == '\\')
+ *p = '/';
+ else if (IS_KANJI(p))
+ p++;
+ }
+#endif
+ fprintf(recorder_file, "PWD %s\n", cwd);
+ } else {
+ fprintf(recorder_file, "PWD <unknown>\n");
+ }
+}
+
+
+@ @c
+@= /*@@null@@*/ @> static char *makempx_find_file (MPX mpx, const char *nam,
+ const char *mode, int ftype) {
+ int fmt;
+ boolean req;
+ (void) mpx;
+ if ((mode[0]=='r' && !kpse_in_name_ok(nam)) ||
+ (mode[0]=='w' && !kpse_out_name_ok(nam)))
+ return NULL; /* disallowed filename */
+ if (mode[0] != 'r') {
+ return strdup(nam);
+ }
+ req = true; fmt = -1;
+ switch(ftype) {
+ case mpx_tfm_format: fmt = kpse_tfm_format; break;
+ case mpx_vf_format: fmt = kpse_vf_format; req = false; break;
+ case mpx_trfontmap_format: fmt = kpse_mpsupport_format; break;
+ case mpx_trcharadj_format: fmt = kpse_mpsupport_format; break;
+ case mpx_desc_format: fmt = kpse_troff_font_format; break;
+ case mpx_fontdesc_format: fmt = kpse_troff_font_format; break;
+ case mpx_specchar_format: fmt = kpse_mpsupport_format; break;
+ }
+ if (fmt<0) return NULL;
+ return kpse_find_file (nam, fmt, req);
+}
+
+@ Invoke \.{makempx} (or \.{troffmpx}) to make sure there is an
+ up-to-date \.{.mpx} file for a given \.{.mp} file. (Original
+ from John Hobby 3/14/90)
+
+@d default_args " --parse-first-line --interaction=nonstopmode"
+@d TEX "tex"
+@d TROFF "soelim | eqn -Tps -d$$ | troff -Tps"
+
+@c
+#ifndef MPXCOMMAND
+#define MPXCOMMAND "makempx"
+#endif
+static int mpost_run_make_mpx (MP mp, char *mpname, char *mpxname) {
+ int ret;
+ char *cnf_cmd = kpse_var_value ("MPXCOMMAND");
+ if (restricted_mode) {
+ /* In the restricted mode, just return success */
+ return 0;
+ }
+ if (cnf_cmd != NULL && (strcmp (cnf_cmd, "0")==0)) {
+ /* If they turned off this feature, just return success. */
+ ret = 0;
+ } else {
+ /* We will invoke something. Compile-time default if nothing else. */
+ char *cmd, *tmp, *qmpname, *qmpxname;
+ if (job_area != NULL) {
+ char *l = mpost_xmalloc(strlen(mpname)+strlen(job_area)+1);
+ strcpy(l, job_area);
+ strcat(l, mpname);
+ tmp = normalize_quotes(l, "mpname");
+ mpost_xfree(l);
+ } else {
+ tmp = normalize_quotes(mpname, "mpname");
+ }
+ if (!kpse_in_name_ok(tmp))
+ return 0; /* disallowed filename */
+ qmpname = kpse_find_file (tmp,kpse_mp_format, true);
+ mpost_xfree(tmp);
+ if (qmpname != NULL && job_area != NULL) {
+ /* if there is a usable mpx file in the source path already,
+ simply use that and return true */
+ char *l = mpost_xmalloc(strlen(qmpname)+2);
+ strcpy(l, qmpname);
+ strcat(l, "x");
+ qmpxname = l;
+ if (qmpxname) {
+#if HAVE_SYS_STAT_H
+ struct stat source_stat, target_stat;
+ int nothingtodo = 0;
+ if ((stat(qmpxname, &target_stat) >= 0) &&
+ (stat(qmpname, &source_stat) >= 0)) {
+#if HAVE_ST_MTIM
+ if (source_stat.st_mtim.tv_sec < target_stat.st_mtim.tv_sec ||
+ (source_stat.st_mtim.tv_sec == target_stat.st_mtim.tv_sec &&
+ source_stat.st_mtim.tv_nsec < target_stat.st_mtim.tv_nsec))
+ nothingtodo = 1;
+#else
+ if (source_stat.st_mtime < target_stat.st_mtime)
+ nothingtodo = 1;
+#endif
+ }
+ if (nothingtodo == 1)
+ return 1; /* success ! */
+#endif
+ }
+ }
+ qmpxname = normalize_quotes(mpxname, "mpxname");
+ if (cnf_cmd!=NULL && (strcmp (cnf_cmd, "1")!=0)) {
+ if (mp_troff_mode(mp)!=0)
+ cmd = concatn (cnf_cmd, " -troff ",
+ qmpname, " ", qmpxname, NULL);
+ else if (mpost_tex_program!=NULL && *mpost_tex_program != '\0')
+ cmd = concatn (cnf_cmd, " -tex=", mpost_tex_program, " ",
+ qmpname, " ", qmpxname, NULL);
+ else
+ cmd = concatn (cnf_cmd, " -tex ", qmpname, " ", qmpxname, NULL);
+
+ /* Run it. */
+ ret = system (cmd);
+ free (cmd);
+ mpost_xfree(qmpname);
+ mpost_xfree(qmpxname);
+ } else {
+ mpx_options * mpxopt;
+ char *s = NULL;
+ char *maincmd = NULL;
+ int mpxmode = mp_troff_mode(mp);
+ char *mpversion = mp_metapost_version () ;
+ mpxopt = mpost_xmalloc(sizeof(mpx_options));
+ if (mpost_tex_program != NULL && *mpost_tex_program != '\0') {
+ maincmd = mpost_xstrdup(mpost_tex_program);
+ } else {
+ if (mpxmode == mpx_tex_mode) {
+ s = kpse_var_value("TEX");
+ if (s==NULL) s = kpse_var_value("MPXMAINCMD");
+ if (s==NULL) s = mpost_xstrdup (TEX);
+ maincmd = (char *)mpost_xmalloc (strlen(s)+strlen(default_args)+1);
+ strcpy(maincmd,s);
+ strcat(maincmd,default_args);
+ free(s);
+ } else {
+ s = kpse_var_value("TROFF");
+ if (s==NULL) s = kpse_var_value("MPXMAINCMD");
+ if (s==NULL) s = mpost_xstrdup (TROFF);
+ maincmd = s;
+ }
+ }
+ mpxopt->mode = mpxmode;
+ mpxopt->cmd = maincmd;
+ mpxopt->mptexpre = kpse_var_value("MPTEXPRE");
+ mpxopt->debug = debug;
+ mpxopt->mpname = qmpname;
+ mpxopt->mpxname = qmpxname;
+ mpxopt->find_file = makempx_find_file;
+ {
+ const char *banner = "% Written by metapost version ";
+ mpxopt->banner = mpost_xmalloc(strlen(mpversion)+strlen(banner)+1);
+ strcpy (mpxopt->banner, banner);
+ strcat (mpxopt->banner, mpversion);
+ }
+ ret = mpx_makempx(mpxopt);
+ mpost_xfree(mpxopt->cmd);
+ mpost_xfree(mpxopt->mptexpre);
+ mpost_xfree(mpxopt->banner);
+ mpost_xfree(mpxopt->mpname);
+ mpost_xfree(mpxopt->mpxname);
+ mpost_xfree(mpxopt);
+ mpost_xfree(mpversion);
+ }
+ }
+
+ mpost_xfree (cnf_cmd);
+ return (int)(ret == 0);
+}
+
+static int mpost_run_dvitomp (char *dviname, char *mpxname) {
+ int ret;
+ size_t i;
+ char *m, *d;
+ mpx_options * mpxopt;
+ char *mpversion = mp_metapost_version () ;
+ mpxopt = mpost_xmalloc(sizeof(mpx_options));
+ memset(mpxopt,0,sizeof(mpx_options));
+ mpxopt->mode = mpx_tex_mode;
+ if (dviname == NULL)
+ return EXIT_FAILURE;
+ i = strlen(dviname);
+ if (mpxname==NULL) {
+ m = mpost_xstrdup(dviname);
+ if (i>4 && *(m+i-4)=='.'
+ && *(m+i-3)=='d' && *(m+i-2)=='v' && *(m+i-1)=='i')
+ *(m+i-4)='\0' ;
+ } else {
+ m = mpost_xstrdup(mpxname);
+ }
+ d = mpost_xstrdup(dviname);
+ if (!(i>4 && *(d+i-4)=='.'
+ && *(d+i-3)=='d' && *(d+i-2)=='v' && *(d+i-1)=='i')) {
+ char *s = malloc (i+5);
+ memset(s,0,i+5);
+ s = strcat(s, d);
+ (void)strcat(s+i-1, ".dvi");
+ mpost_xfree (d);
+ d = s ;
+ }
+
+ i = strlen(m);
+ if (i>4 && *(m+i-4)=='.'
+ && *(m+i-3)=='m' && *(m+i-2)=='p' && *(m+i-1)=='x') {
+ } else {
+ char *s = malloc (i+5);
+ memset(s,0,i+5);
+ s = strcat(s, m);
+ (void)strcat(s+i-1, ".mpx");
+ mpost_xfree (m);
+ m = s ;
+ }
+ if (!(kpse_in_name_ok(d) && kpse_out_name_ok(m)))
+ return EXIT_FAILURE; /* disallowed filename */
+ mpxopt->mpname = d;
+ mpxopt->mpxname = m;
+
+ mpxopt->find_file = makempx_find_file;
+ {
+ const char *banner = "% Written by dvitomp version ";
+ mpxopt->banner = mpost_xmalloc(strlen(mpversion)+strlen(banner)+1);
+ strcpy (mpxopt->banner, banner);
+ strcat (mpxopt->banner, mpversion);
+ }
+ ret = mpx_run_dvitomp(mpxopt);
+ mpost_xfree(mpxopt->banner);
+ mpost_xfree(mpxopt);
+ mpost_xfree(mpversion);
+ puts(""); /* nicer in case of error */
+ return ret;
+}
+
+
+@
+@<Register the callback routines@>=
+if (!nokpse)
+ options->run_make_mpx = mpost_run_make_mpx;
+
+
+@ @c
+static int get_random_seed (void) {
+ int ret = 0;
+#if defined (HAVE_GETTIMEOFDAY)
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ ret = (int)(tv.tv_usec + 1000000 * tv.tv_usec);
+#elif defined (HAVE_FTIME)
+ struct timeb tb;
+ ftime(&tb);
+ ret = (tb.millitm + 1000 * tb.time);
+#else
+ time_t clock = time ((time_t*)NULL);
+ struct tm *tmptr = localtime(&clock);
+ if (tmptr!=NULL)
+ ret = (tmptr->tm_sec + 60*(tmptr->tm_min + 60*tmptr->tm_hour));
+#endif
+ return ret;
+}
+
+@ @<Register the callback routines@>=
+options->random_seed = get_random_seed();
+
+
+@ Handle -output-directory.
+
+@c
+static char *mpost_find_in_output_directory(const char *s,const char *fmode)
+{
+ if (output_directory && !kpse_absolute_p(s, false)) {
+ char *ftemp = concat3(output_directory, DIR_SEP_STRING, s);
+ return ftemp;
+ }
+ return NULL;
+}
+
+
+
+@ @c
+static char *mpost_find_file(MP mp, const char *fname, const char *fmode, int ftype) {
+ size_t l ;
+ char *s;
+ char *ofname;
+ (void)mp;
+ s = NULL;
+ ofname = NULL ;
+
+
+ if (fname == NULL || (fmode[0]=='r' && !kpse_in_name_ok(fname)) )
+ return NULL; /* disallowed filename */
+
+
+ if (fmode[0]=='w') {
+ if (output_directory) {
+ ofname = mpost_find_in_output_directory(fname,fmode);
+ if (ofname == NULL || (fmode[0]=='w' && !kpse_out_name_ok(ofname))) {
+ mpost_xfree(ofname);
+ return NULL; /* disallowed filename */
+ }
+ } else {
+ if (!kpse_out_name_ok(fname))
+ return NULL; /* disallowed filename */
+ }
+ }
+
+
+ if (fmode[0]=='r') {
+ if ((job_area != NULL) &&
+ (ftype>=mp_filetype_text || ftype==mp_filetype_program )) {
+ char *f = mpost_xmalloc(strlen(job_area)+strlen(fname)+1);
+ strcpy(f,job_area);
+ strcat(f,fname);
+ if (ftype>=mp_filetype_text) {
+ s = kpse_find_file (f, kpse_mp_format, 0);
+ } else {
+ l = strlen(f);
+ if (l>3 && strcmp(f+l-3,".mf")==0) {
+ s = kpse_find_file (f,kpse_mf_format, 0);
+#if HAVE_SYS_STAT_H
+ } else if (l>4 && strcmp(f+l-4,".mpx")==0) {
+ struct stat source_stat, target_stat;
+ char *mpname = mpost_xstrdup(f);
+ *(mpname + strlen(mpname) -1 ) = '\0';
+ if ((stat(f, &target_stat) >= 0) &&
+ (stat(mpname, &source_stat) >= 0)) {
+#if HAVE_ST_MTIM
+ if (source_stat.st_mtim.tv_sec <= target_stat.st_mtim.tv_sec ||
+ (source_stat.st_mtim.tv_sec == target_stat.st_mtim.tv_sec &&
+ source_stat.st_mtim.tv_nsec <= target_stat.st_mtim.tv_nsec))
+ s = mpost_xstrdup(f);
+#else
+ if (source_stat.st_mtime <= target_stat.st_mtime)
+ s = mpost_xstrdup(f);
+#endif
+ }
+ mpost_xfree(mpname);
+#endif
+ } else {
+ s = kpse_find_file (f,kpse_mp_format, 0);
+ }
+ }
+ mpost_xfree(f);
+ if (s!=NULL) {
+ return s;
+ }
+ }
+ if (ftype>=mp_filetype_text) {
+ s = kpse_find_file (fname, kpse_mp_format, 0);
+ } else {
+ switch(ftype) {
+ case mp_filetype_program:
+ l = strlen(fname);
+ if (l>3 && strcmp(fname+l-3,".mf")==0) {
+ s = kpse_find_file (fname, kpse_mf_format, 0);
+ } else {
+ s = kpse_find_file (fname, kpse_mp_format, 0);
+ }
+ break;
+ case mp_filetype_memfile:
+ s = kpse_find_file (fname, kpse_mem_format, 1);
+ break;
+ case mp_filetype_metrics:
+ s = kpse_find_file (fname, kpse_tfm_format, 0);
+ break;
+ case mp_filetype_fontmap:
+ s = kpse_find_file (fname, kpse_fontmap_format, 0);
+ break;
+ case mp_filetype_font:
+ s = kpse_find_file (fname, kpse_type1_format, 0);
+ break;
+ case mp_filetype_encoding:
+ s = kpse_find_file (fname, kpse_enc_format, 0);
+ break;
+ }
+ }
+ } else {
+ /* when writing */
+ if (ofname) {
+ s = mpost_xstrdup(ofname);
+ mpost_xfree(ofname);
+ } else {
+ s = mpost_xstrdup(fname);
+ }
+
+ }
+ return s;
+}
+
+@ @<Register the callback routines@>=
+if (!nokpse)
+ options->find_file = mpost_find_file;
+
+@ The |mpost| program supports setting of internal values
+via a \.{-s} commandline switch. Since this switch is repeatable,
+a structure is needed to store the found values in, which is a
+simple linked list.
+
+@c
+typedef struct set_list_item {
+ int isstring;
+ char *name;
+ char *value;
+ struct set_list_item *next;
+} set_list_item ;
+
+@ Here is the global value that is the head of the list of \.{-s} options.
+@c
+struct set_list_item *set_list = NULL;
+
+@ And |internal_set_option| is the routine that fills in the linked
+list. The argument it receives starts at the first letter of the
+internal, and should contain an internal name, an equals sign,
+and the value (possibly in quotes) without any intervening spaces.
+
+Double quotes around the right hand side are needed to make sure that
+the right hand side is treated as a string assignment by MPlib later.
+These outer double quote characters are stripped, but no other string
+processing takes place.
+
+As a special hidden feature, a missing right hand side is treated as if it
+was the integer value |1|.
+
+@<Declarations@>=
+void internal_set_option(const char *opt);
+
+@ @c
+void internal_set_option(const char *opt) {
+ struct set_list_item *itm;
+ char *s, *v;
+ int isstring = 0;
+ s = mpost_xstrdup(opt) ;
+ v = strstr(s,"=") ;
+ if (v==NULL) {
+ v = xstrdup("1");
+ } else {
+ *v='\0'; /* terminates |s| */
+ v++;
+ if (*v && *v=='"') {
+ isstring=1;
+ v++;
+ *(v+strlen(v)-1)= '\0';
+ }
+ }
+ if (s && v && strlen(s)>0) {
+ if (set_list == NULL) {
+ set_list = xmalloc(sizeof(struct set_list_item));
+ itm = set_list;
+ } else {
+ itm = set_list;
+ while (itm->next != NULL)
+ itm = itm->next;
+ itm->next = xmalloc(sizeof(struct set_list_item));
+ itm = itm->next;
+ }
+ itm->name = s;
+ itm->value = v;
+ itm->isstring = isstring;
+ itm->next = NULL;
+ }
+}
+
+@ After the initialization stage is done, the next function
+runs through the list of options and feeds them to the MPlib
+function |mp_set_internal|.
+
+@<Declarations@>=
+void run_set_list (MP mp);
+
+@ @c
+void run_set_list (MP mp) {
+ struct set_list_item *itm;
+ itm = set_list;
+ while (itm!=NULL) {
+ mp_set_internal(mp,itm->name,itm->value, itm->isstring);
+ itm = itm->next;
+ }
+}
+
+
+
+@ @c
+static void *mpost_open_file(MP mp, const char *fname, const char *fmode, int ftype) {
+ char realmode[3];
+ char *s;
+ if (ftype==mp_filetype_terminal) {
+ return (fmode[0] == 'r' ? stdin : stdout);
+ } else if (ftype==mp_filetype_error) {
+ return stderr;
+ } else {
+ s = mpost_find_file (mp, fname, fmode, ftype);
+ if (s!=NULL) {
+ void *ret = NULL;
+ realmode[0] = *fmode;
+ realmode[1] = 'b';
+ realmode[2] = '\0';
+ ret = (void *)fopen(s,realmode);
+ if (recorder_enabled) {
+ if (!recorder_file)
+ recorder_start(job_name);
+ if (*fmode == 'r')
+ fprintf(recorder_file, "INPUT %s\n", s);
+ else
+ fprintf(recorder_file, "OUTPUT %s\n", s);
+ }
+ free(s);
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+@ @<Register the callback routines@>=
+if (!nokpse)
+ options->open_file = mpost_open_file;
+
+@ @d ARGUMENT_IS(a) STREQ (mpost_options[optionid].name, a)
+@<Structures for |getopt|@>=
+
+/* SunOS cc can't initialize automatic structs, so make this static. */
+static struct option mpost_options[]
+ = { { "mem", 1, 0, 0 },
+ { "help", 0, 0, 0 },
+ { "debug", 0, &debug, 1 },
+ { "no-kpathsea", 0, &nokpse, 1 },
+ { "dvitomp", 0, &dvitomp_only, 1 },
+ { "ini", 0, &ini_version_test, 1 },
+ { "interaction", 1, 0, 0 },
+ { "math", 1, 0, 0 },
+ { "numbersystem", 1, 0, 0 },
+ { "halt-on-error", 0, 0, 0 },
+ { "kpathsea-debug", 1, 0, 0 },
+ { "progname", 1, 0, 0 },
+ { "version", 0, 0, 0 },
+ { "recorder", 0, &recorder_enabled, 1 },
+ { "restricted", 0, 0, 0 },
+ { "file-line-error-style", 0, 0, 0 },
+ { "no-file-line-error-style", 0, 0, 0 },
+ { "file-line-error", 0, 0, 0 },
+ { "no-file-line-error", 0, 0, 0 },
+ { "jobname", 1, 0, 0 },
+ { "output-directory", 1, 0, 0 },
+ { "s", 1, 0, 0 },
+ { "parse-first-line", 0, 0, 0 },
+ { "no-parse-first-line", 0, 0, 0 },
+ { "8bit", 0, 0, 0 },
+ { "T", 0, 0, 0 },
+ { "troff", 0, 0, 0 },
+ { "tex", 1, 0, 0 },
+ { 0, 0, 0, 0 } };
+
+
+
+@ Parsing the commandline options.
+
+@<Read and set command line options@>=
+{
+ int g; /* `|getopt|' return code. */
+ int optionid;
+ for (;;) {
+ g = getopt_long_only (argc, argv, "+", mpost_options, &optionid);
+
+ if (g == -1) /* End of arguments, exit the loop. */
+ break;
+
+ if (g == '?') { /* Unknown option. */
+ exit(EXIT_FAILURE);
+ }
+
+ if (ARGUMENT_IS ("kpathsea-debug")) {
+ kpathsea_debug |= (unsigned)atoi (optarg);
+
+ } else if (ARGUMENT_IS("jobname")) {
+ if (optarg!=NULL) {
+ mpost_xfree(options->job_name);
+ options->job_name = mpost_xstrdup(optarg);
+ }
+
+ } else if (ARGUMENT_IS ("progname")) {
+ user_progname = optarg;
+
+ } else if (ARGUMENT_IS ("mem")) {
+ if (optarg!=NULL) {
+ mpost_xfree(options->mem_name);
+ options->mem_name = mpost_xstrdup(optarg);
+ if (user_progname == NULL)
+ user_progname = optarg;
+ }
+
+ } else if (ARGUMENT_IS ("interaction")) {
+ if (STREQ (optarg, "batchmode")) {
+ options->interaction = mp_batch_mode;
+ } else if (STREQ (optarg, "nonstopmode")) {
+ options->interaction = mp_nonstop_mode;
+ } else if (STREQ (optarg, "scrollmode")) {
+ options->interaction = mp_scroll_mode;
+ } else if (STREQ (optarg, "errorstopmode")) {
+ options->interaction = mp_error_stop_mode;
+ } else {
+ fprintf(stdout,"Ignoring unknown argument `%s' to --interaction\n", optarg);
+ }
+ } else if (ARGUMENT_IS ("math") || ARGUMENT_IS ("numbersystem")) {
+ if (STREQ (optarg, "scaled")) {
+ options->math_mode = mp_math_scaled_mode;
+ internal_set_option("numbersystem=\"scaled\"");
+ } else if (STREQ (optarg, "double")) {
+ options->math_mode = mp_math_double_mode;
+ internal_set_option("numbersystem=\"double\"");
+ } else if (STREQ (optarg, "decimal")) {
+ options->math_mode = mp_math_decimal_mode;
+ internal_set_option("numbersystem=\"decimal\"");
+ } else if (STREQ (optarg, "binary")) {
+ options->math_mode = mp_math_binary_mode;
+ internal_set_option("numbersystem=\"binary\"");
+ } else {
+ fprintf(stdout,"Ignoring unknown argument `%s' to --numbersystem\n", optarg);
+ }
+ } else if (ARGUMENT_IS ("restricted")) {
+ restricted_mode = true;
+ mpost_tex_program = NULL;
+ } else if (ARGUMENT_IS("troff") ||
+ ARGUMENT_IS("T")) {
+ options->troff_mode = (int)true;
+ } else if (ARGUMENT_IS ("tex")) {
+ if (!restricted_mode)
+ mpost_tex_program = optarg;
+ } else if (ARGUMENT_IS("file-line-error") ||
+ ARGUMENT_IS("file-line-error-style")) {
+ options->file_line_error_style=true;
+ } else if (ARGUMENT_IS("no-file-line-error") ||
+ ARGUMENT_IS("no-file-line-error-style")) {
+ options->file_line_error_style=false;
+ } else if (ARGUMENT_IS("help")) {
+ if (dvitomp_only) {
+ @<Show short help and exit@>;
+ } else {
+ @<Show help and exit@>;
+ }
+ } else if (ARGUMENT_IS("version")) {
+ @<Show version and exit@>;
+ } else if (ARGUMENT_IS("s")) {
+ if (strchr(optarg,'=')==NULL) {
+ fprintf(stdout,"fatal error: %s: missing -s argument\n", argv[0]);
+ exit (EXIT_FAILURE);
+ } else {
+ internal_set_option(optarg);
+ }
+ } else if (ARGUMENT_IS("halt-on-error")) {
+ options->halt_on_error = true;
+ } else if (ARGUMENT_IS("output-directory")) {
+ output_directory = optarg ;
+ } else if (ARGUMENT_IS("8bit") ||
+ ARGUMENT_IS("parse-first-line")) {
+ /* do nothing, these are always on */
+ } else if (ARGUMENT_IS("translate-file") ||
+ ARGUMENT_IS("no-parse-first-line")) {
+ fprintf(stdout,"warning: %s: unimplemented option %s\n", argv[0], argv[optind]);
+ }
+ }
+ options->ini_version = (int)ini_version_test;
+}
+
+@ @d option_is(a) STREQ (dvitomp_options[optionid].name, a)
+@<Structures for |getopt|@>=
+
+/* SunOS cc can't initialize automatic structs, so make this static. */
+static struct option dvitomp_options[]
+ = { { "help", 0, 0, 0 },
+ { "no-kpathsea", 0, &nokpse, 1 },
+ { "kpathsea-debug", 1, 0, 0 },
+ { "progname", 1, 0, 0 },
+ { "version", 0, 0, 0 },
+ { 0, 0, 0, 0 } };
+
+
+
+@
+@<Read and set \.{dvitomp} command line options@>=
+{
+ int g; /* `|getopt|' return code. */
+ int optionid;
+ for (;;) {
+ g = getopt_long_only (argc, argv, "+", dvitomp_options, &optionid);
+
+ if (g == -1) /* End of arguments, exit the loop. */
+ break;
+
+ if (g == '?') { /* Unknown option. */
+ fprintf(stdout,"fatal error: %s: unknown option %s\n", argv[0], argv[optind]);
+ exit(EXIT_FAILURE);
+ }
+ if (option_is ("kpathsea-debug")) {
+ if (optarg!=NULL)
+ kpathsea_debug |= (unsigned)atoi (optarg);
+ } else if (option_is ("progname")) {
+ user_progname = optarg;
+ } else if (option_is("help")) {
+ @<Show short help and exit@>;
+ } else if (option_is("version")) {
+ @<Show version and exit@>;
+ }
+ }
+}
+
+@
+@<Show help...@>=
+{
+char *s = mp_metapost_version();
+if (dvitomp_only)
+ fprintf(stdout, "This is dvitomp %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
+else
+ fprintf(stdout, "This is MetaPost %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
+mpost_xfree(s);
+fprintf(stdout,
+"\n"
+"Usage: mpost [OPTION] [&MEMNAME] [MPNAME[.mp]] [COMMANDS]\n"
+" mpost --dvitomp DVINAME[.dvi] [MPXNAME[.mpx]]\n"
+"\n"
+" Run MetaPost on MPNAME, usually creating MPNAME.NNN (and perhaps\n"
+" MPNAME.tfm), where NNN are the character numbers generated.\n"
+" Any remaining COMMANDS are processed as MetaPost input,\n"
+" after MPNAME is read.\n\n"
+" With a --dvitomp argument, MetaPost acts as DVI-to-MPX converter only.\n"
+" Call MetaPost with --dvitomp --help for option explanations.\n\n");
+fprintf(stdout,
+" -ini be inimpost, for dumping mem files\n"
+" -interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/\n"
+" scrollmode/errorstopmode)\n"
+" -numbersystem=STRING set number system mode (STRING=scaled/double/binary/decimal)\n"
+" -jobname=STRING set the job name to STRING\n"
+" -progname=STRING set program (and mem) name to STRING\n"
+" -tex=TEXPROGRAM use TEXPROGRAM for text labels\n"
+" [-no]-file-line-error disable/enable file:line:error style messages\n"
+);
+fprintf(stdout,
+" -debug print debugging info and leave temporary files in place\n"
+" -kpathsea-debug=NUMBER set path searching debugging flags according to\n"
+" the bits of NUMBER\n"
+" -mem=MEMNAME or &MEMNAME use MEMNAME instead of program name or a %%& line\n"
+" -recorder enable filename recorder\n"
+" -restricted be secure: disable tex, makempx and editor commands\n"
+" -troff set prologues:=1 and assume TEXPROGRAM is really troff\n"
+" -T same as -troff\n"
+" -s INTERNAL=\"STRING\" set internal INTERNAL to the string value STRING\n"
+" -s INTERNAL=NUMBER set internal INTERNAL to the integer value NUMBER\n"
+" -help display this help and exit\n"
+" -version output version information and exit\n"
+"\n"
+"Email bug reports to mp-implementors@@tug.org.\n"
+"\n");
+ exit(EXIT_SUCCESS);
+}
+
+@
+@<Show short help...@>=
+{
+char *s = mp_metapost_version();
+if (dvitomp_only)
+ fprintf(stdout, "This is dvitomp %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
+else
+ fprintf(stdout, "This is MetaPost %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
+mpost_xfree(s);
+fprintf(stdout,
+"\n"
+"Usage: dvitomp DVINAME[.dvi] [MPXNAME[.mpx]]\n"
+" mpost --dvitomp DVINAME[.dvi] [MPXNAME[.mpx]]\n"
+"\n"
+" Convert a TeX DVI file to a MetaPost MPX file.\n\n");
+fprintf(stdout,
+" -progname=STRING set program name to STRING\n"
+" -kpathsea-debug=NUMBER set path searching debugging flags according to\n"
+" the bits of NUMBER\n"
+" -help display this help and exit\n"
+" -version output version information and exit\n"
+"\n"
+"Email bug reports to mp-implementors@@tug.org.\n"
+"\n");
+ exit(EXIT_SUCCESS);
+}
+
+@
+@<Show version...@>=
+{
+ char *s = mp_metapost_version();
+if (dvitomp_only)
+ fprintf(stdout, "dvitomp (MetaPost) %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
+else
+ fprintf(stdout, "MetaPost %s" WEB2CVERSION " (%s)\n", s, kpathsea_version_string);
+fprintf(stdout,
+"The MetaPost source code in the public domain.\n"
+"MetaPost also uses code available under the\n"
+"GNU Lesser General Public License (version 3 or later);\n"
+"therefore MetaPost executables are covered by the LGPL.\n"
+"There is NO warranty.\n"
+"For more information about these matters, see the file\n"
+"COPYING.LESSER or <http://gnu.org/licenses/lgpl.html>.\n"
+"Original author of MetaPost: John Hobby.\n"
+"Author of the CWEB MetaPost: Taco Hoekwater.\n"
+"Current maintainer of MetaPost: Luigi Scarso.\n\n"
+);
+ mpost_xfree(s);
+ if (!dvitomp_only) {
+ mp_show_library_versions();
+ }
+ exit(EXIT_SUCCESS);
+}
+
+@ The final part of the command line, after option processing, is
+stored in the \MP\ instance, this will be taken as the first line of
+input.
+
+@d command_line_size 256
+@d max_command_line_size 0xFFFFFFF /* should be the same of |max_halfword| (see |mp_reallocate_buffer|) */
+
+@<Copy the rest of the command line@>=
+{
+ mpost_xfree(options->command_line);
+ options->command_line = mpost_xmalloc(command_line_size);
+ strcpy(options->command_line,"");
+ if (optind<argc) {
+ int optind_aux = optind;
+ size_t buflen = 0;
+ for(;optind_aux<argc;optind_aux++) {
+ buflen +=(strlen(argv[optind_aux])+1); /* reserve space for |' '| as separator */
+ }
+ /* Last char is |' '|, no need to reserve space for final |'\0'| */
+ if (buflen > max_command_line_size) {
+ fprintf(stderr,"length of command line too long!\n");
+ exit(EXIT_FAILURE);
+ }
+ mpost_xfree(options->command_line);
+ options->command_line = mpost_xmalloc(buflen);
+ k=0;
+ for(;optind<argc;optind++) {
+ char *c = argv[optind];
+ while (*c != '\0') {
+ options->command_line[k++] = *c;
+ c++;
+ }
+ options->command_line[k++] = ' ';
+ }
+ while (k>0) {
+ if (options->command_line[(k-1)] == ' ')
+ k--;
+ else
+ break;
+ }
+ options->command_line[k] = '\0';
+ }
+}
+
+@ A simple function to get numerical \.{texmf.cnf} values
+@c
+static int setup_var (int def, const char *var_name, boolean nokpse) {
+ if (!nokpse) {
+ char * expansion = kpse_var_value (var_name);
+ if (expansion) {
+ int conf_val = atoi (expansion);
+ free (expansion);
+ if (conf_val > 0) {
+ return conf_val;
+ }
+ }
+ }
+ return def;
+}
+
+@ @<Set up the banner line@>=
+{
+ char * mpversion = mp_metapost_version () ;
+ const char * banner = "This is MetaPost, version ";
+ const char * kpsebanner_start = " (";
+ const char * kpsebanner_stop = ")";
+ mpost_xfree(options->banner);
+ options->banner = mpost_xmalloc(strlen(banner)+
+ strlen(mpversion)+
+ strlen(WEB2CVERSION)+
+ strlen(kpsebanner_start)+
+ strlen(kpathsea_version_string)+
+ strlen(kpsebanner_stop)+1);
+ strcpy (options->banner, banner);
+ strcat (options->banner, mpversion);
+ strcat (options->banner, WEB2CVERSION);
+ strcat (options->banner, kpsebanner_start);
+ strcat (options->banner, kpathsea_version_string);
+ strcat (options->banner, kpsebanner_stop);
+ mpost_xfree(mpversion);
+}
+
+@ Precedence order is:
+
+\item {} \.{-mem=MEMNAME} on the command line
+\item {} \.{\&MEMNAME} on the command line
+\item {} \.{\%\&MEM} as first line inside input file
+\item {} \.{argv[0]} if all else fails
+
+@<Discover the mem name@>=
+{
+ char *m = NULL; /* head of potential |mem_name| */
+ char *n = NULL; /* a moving pointer */
+ if (options->command_line != NULL && *(options->command_line) == '&'){
+ m = mpost_xstrdup(options->command_line+1);
+ n = m;
+ while (*n != '\0' && *n != ' ') n++;
+ while (*n == ' ') n++;
+ if (*n != '\0') { /* more command line to follow */
+ char *s = mpost_xstrdup(n);
+ if (n>m) n--;
+ while (*n == ' ' && n>m) n--;
+ n++;
+ *n ='\0'; /* this terminates |m| */
+ mpost_xfree(options->command_line);
+ options->command_line = s;
+ } else { /* only \.{\&MEMNAME} on command line */
+ if (n>m) n--;
+ while (*n == ' ' && n>m) n--;
+ n++;
+ *n ='\0'; /* this terminates |m| */
+ mpost_xfree(options->command_line);
+ }
+ if ( options->mem_name == NULL && *m != '\0') {
+ mpost_xfree(options->mem_name); /* for lint only */
+ options->mem_name = m;
+ } else {
+ mpost_xfree(m);
+ }
+ }
+}
+if ( options->mem_name == NULL ) {
+ char *m = NULL; /* head of potential |job_name| */
+ char *n = NULL; /* a moving pointer */
+ if (options->command_line != NULL && *(options->command_line) != '\\'){
+ m = mpost_xstrdup(options->command_line);
+ n = m;
+ while (*n != '\0' && *n != ' ') n++;
+ if (n>m) {
+ char *fname;
+ *n='\0';
+ fname = m;
+ if (!nokpse)
+ fname = kpse_find_file(m,kpse_mp_format,true);
+ if (fname == NULL) {
+ mpost_xfree(m);
+ } else {
+ FILE *F = fopen(fname,"r");
+ if (F==NULL) {
+ mpost_xfree(fname);
+ } else {
+ char *line = mpost_xmalloc(256);
+ if (fgets(line,255,F) == NULL) {
+ (void)fclose(F);
+ mpost_xfree(fname);
+ mpost_xfree(line);
+ } else {
+ (void)fclose(F);
+ while (*line != '\0' && *line == ' ') line++;
+ if (*line == '%') {
+ n = m = line+1;
+ while (*n != '\0' && *n == ' ') n++;
+ if (*n == '&') {
+ m = n+1;
+ while (*n != '\0' && *n != ' ') n++;
+ if (n>(m+1)) {
+ n--;
+ while (*n == ' ' && n>m) n--;
+ *n ='\0'; /* this terminates |m| */
+ options->mem_name = mpost_xstrdup(m);
+ mpost_xfree(fname);
+ } else {
+ mpost_xfree(fname);
+ mpost_xfree(line);
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ mpost_xfree(m);
+ }
+ }
+}
+if ( options->mem_name == NULL )
+ if (kpse_program_name!=NULL)
+ options->mem_name = mpost_xstrdup(kpse_program_name);
+
+
+@ The job name needs to be known for the recorder to work,
+so we have to fix up |job_name| and |job_area|. If there
+was a \.{--jobname} on the command line, we have to reset
+the options structure as well.
+
+@<Discover the job name@>=
+{
+char *tmp_job = NULL;
+if (options->job_name != NULL) {
+ tmp_job = mpost_xstrdup(options->job_name);
+ mpost_xfree(options->job_name);
+ options->job_name = NULL;
+} else {
+ char *m = NULL; /* head of potential |job_name| */
+ char *n = NULL; /* a moving pointer */
+ if (options->command_line != NULL){
+ m = mpost_xstrdup(options->command_line);
+ n = m;
+ if (*(options->command_line) != '\\') { /* this is the simple case */
+ while (*n != '\0' && *n != ' ') n++;
+ if (n>m) {
+ *n='\0';
+ tmp_job = mpost_xstrdup(m);
+ }
+ } else { /* this is still not perfect, but better */
+ char *mm = strstr(m,"input ");
+ if (mm != NULL) {
+ mm += 6;
+ n = mm;
+ while (*n != '\0' && *n != ' ' && *n!=';') n++;
+ if (n>mm) {
+ *n='\0';
+ tmp_job = mpost_xstrdup(mm);
+ }
+ }
+ }
+ free(m);
+ }
+ if (tmp_job == NULL) {
+ if (options->ini_version == 1 &&
+ options->mem_name != NULL) {
+ tmp_job = mpost_xstrdup(options->mem_name);
+ }
+ }
+ if (tmp_job == NULL) {
+ tmp_job = mpost_xstrdup("mpout");
+ } else {
+ char *ext = strrchr(tmp_job,'.');
+ if (ext != NULL)
+ *ext = '\0';
+ }
+}
+/* now split |tmp_job| into |job_area| and |job_name| */
+{
+ char *s = tmp_job + strlen(tmp_job);
+ if (!IS_DIR_SEP(*s)) { /* just in case */
+ while (s>tmp_job) {
+ if (IS_DIR_SEP(*s)) {
+ break;
+ }
+ s--;
+ }
+ if (s>tmp_job) {
+ /* there was a directory part */
+ if (strlen(s)>1) {
+ job_name = mpost_xstrdup((s+1));
+ *(s+1) = '\0';
+ job_area = tmp_job;
+ }
+ } else {
+ job_name = tmp_job;
+ /* |job_area| stays |NULL| */
+ }
+ }
+}
+}
+options->job_name = job_name;
+
+@ We |
+#define DLLPROC dllmpostmain
+| in order to build \MP\ as DLL for W32\TeX.
+
+@<Declarations@>=
+#define DLLPROC dllmpostmain
+#if defined(WIN32) && !defined(__MINGW32__) && defined(DLLPROC)
+extern __declspec(dllexport) int DLLPROC (int argc, char **argv);
+#else
+#undef DLLPROC
+#endif
+
+@ Now this is really it: \MP\ starts and ends here.
+
+@c
+static char *cleaned_invocation_name(char *arg)
+{
+ char *ret, *dot;
+ const char *start = xbasename(arg);
+ ret = xstrdup(start);
+ dot = strrchr(ret, '.');
+ if (dot != NULL) {
+ *dot = 0; /* chop */
+ }
+ return ret;
+}
+int
+#if defined(DLLPROC)
+DLLPROC (int argc, char **argv)
+#else
+main (int argc, char **argv)
+#endif
+@;
+{ @t\1@> /* |start_here| */
+ int k; /* index into buffer */
+ int history; /* the exit status */
+ MP mp; /* a metapost instance */
+ struct MP_options * options; /* instance options */
+ char *user_progname = NULL; /* If the user overrides |argv[0]| with \.{-progname}. */
+ options = mp_options();
+ options->ini_version = (int)false;
+ options->print_found_names = (int)true;
+ {
+ const char *base = cleaned_invocation_name(argv[0]);
+ if (FILESTRCASEEQ(base, "rmpost")){
+ base++;
+ restricted_mode = true;
+ } else if (FILESTRCASEEQ(base, "r-mpost")){
+ base += 2;
+ restricted_mode = true;
+ }
+ if (FILESTRCASEEQ(base, "dvitomp"))
+ dvitomp_only=1;
+ }
+ if (dvitomp_only) {
+ @<Read and set \.{dvitomp} command line options@>;
+ } else {
+ @<Read and set command line options@>;
+ }
+ if (dvitomp_only) {
+ char *mpx = NULL, *dvi = NULL;
+ if (optind>=argc) {
+ /* error ? */
+ } else {
+ dvi = argv[optind++];
+ if (optind<argc) {
+ mpx = argv[optind++];
+ }
+ }
+ if (dvi == NULL) {
+ @<Show short help and exit@>;
+ } else {
+ if (!nokpse)
+ kpse_set_program_name(argv[0],
+ user_progname ? user_progname : "dvitomp");
+ exit (mpost_run_dvitomp(dvi, mpx));
+ }
+ }
+
+ @= /*@@-nullpass@@*/ @>
+ if (!nokpse) {
+ kpse_set_program_enabled (kpse_mem_format, MAKE_TEX_FMT_BY_DEFAULT,
+ kpse_src_compile);
+ kpse_set_program_name(argv[0], user_progname);
+ if (FILESTRCASEEQ(kpse_program_name, "rmpost"))
+ kpse_program_name++;
+ else if (FILESTRCASEEQ(kpse_program_name, "r-mpost"))
+ kpse_program_name += 2;
+ }
+ @= /*@@=nullpass@@*/ @>
+ if(putenv(xstrdup("engine=metapost")))
+ fprintf(stdout,"warning: could not set up $engine\n");
+ options->error_line = setup_var (79,"error_line",nokpse);
+ options->half_error_line = setup_var (50,"half_error_line",nokpse);
+ options->max_print_line = setup_var (100,"max_print_line",nokpse);
+ @<Set up the banner line@>;
+ @<Copy the rest of the command line@>;
+ @<Discover the mem name@>;
+ @<Discover the job name@>;
+ @<Register the callback routines@>;
+ mp = mp_initialize(options);
+ mpost_xfree(options->command_line);
+ mpost_xfree(options->mem_name);
+ mpost_xfree(options->job_name);
+ mpost_xfree(options->banner);
+ free(options);
+ if (mp==NULL)
+ exit(EXIT_FAILURE);
+ history = mp_status(mp);
+ if (history!=0 && history!=mp_warning_issued)
+ exit(history);
+ if (set_list!=NULL) {
+ run_set_list(mp);
+ }
+ history = mp_run(mp);
+ (void)mp_finish(mp);
+ if (history!=0 && history!=mp_warning_issued)
+ exit(history);
+ else
+ exit(0);
+@t\8@>
+}
+
+@* Index.