2 % MetaPost command-line program, by Taco Hoekwater. Public domain.
4 \font\tenlogo=logo10 % font used for the METAFONT logo
5 \def\MP{{\tenlogo META}\-{\tenlogo POST}}
7 \def\title{MetaPost executable}
11 @* \[1] Metapost executable.
13 Now that all of \MP\ is a library, a separate program is needed to
14 have our customary command-line interface.
16 @ First, here are the C includes. |avl.h| is needed because of an
17 |avl_allocator| that is defined in |mplib.h|
28 #define HAVE_BOOLEAN 1
29 #define HAVE_PROTOTYPES 1
30 #include <kpathsea/progname.h>
31 #include <kpathsea/tex-file.h>
32 #include <kpathsea/variable.h>
33 extern unsigned kpathsea_debug;
34 #include <kpathsea/concatn.h>
35 static string mpost_tex_program = "";
39 void mpost_run_editor (MP mp, char *fname, int fline) {
41 fprintf(stdout,"Ok, bye (%s,%d)!",fname, fline);
46 @<Register the callback routines@>=
47 options->run_editor = mpost_run_editor;
51 string normalize_quotes (const char *name, const char *mesg) {
52 boolean quoted = false;
53 boolean must_quote = (strchr(name, ' ') != NULL);
54 /* Leave room for quotes and NUL. */
55 string ret = (string)mp_xmalloc(strlen(name)+3, sizeof(char));
61 for (q = name; *q; q++) {
71 fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name);
78 @ Invoke makempx (or troffmpx) to make sure there is an up-to-date
79 .mpx file for a given .mp file. (Original from John Hobby 3/14/90)
84 #define MPXCOMMAND "makempx"
86 boolean mpost_run_make_mpx (MP mp, char *mpname, char *mpxname) {
88 string cnf_cmd = kpse_var_value ("MPXCOMMAND");
90 if (cnf_cmd && (strcmp (cnf_cmd, "0")==0)) {
91 /* If they turned off this feature, just return success. */
95 /* We will invoke something. Compile-time default if nothing else. */
97 string qmpname = normalize_quotes(mpname, "mpname");
98 string qmpxname = normalize_quotes(mpxname, "mpxname");
100 cnf_cmd = mp_xstrdup (MPXCOMMAND);
102 if (mp_troff_mode(mp))
103 cmd = concatn (cnf_cmd, " -troff ",
104 qmpname, " ", qmpxname, NULL);
105 else if (mpost_tex_program && *mpost_tex_program)
106 cmd = concatn (cnf_cmd, " -tex=", mpost_tex_program, " ",
107 qmpname, " ", qmpxname, NULL);
109 cmd = concatn (cnf_cmd, " -tex ", qmpname, " ", qmpxname, NULL);
123 @<Register the callback routines@>=
125 options->run_make_mpx = mpost_run_make_mpx;
128 @ @c scaled mpost_get_random_seed (MP mp) {
129 if (mp==NULL) exit(1); /* for -W */
130 #if defined (HAVE_GETTIMEOFDAY)
132 gettimeofday(&tv, NULL);
133 return (tv.tv_usec + 1000000 * tv.tv_usec);
134 #elif defined (HAVE_FTIME)
137 return (tb.millitm + 1000 * tb.time);
139 time_t clock = time ((time_t*)NULL);
140 struct tm *tmptr = localtime(&clock);
141 return (tmptr->tm_sec + 60*(tmptr->tm_min + 60*tmptr->tm_hour));
145 @ @<Register the callback routines@>=
146 options->get_random_seed = mpost_get_random_seed;
149 @c char *mpost_find_file(char *fname, char *fmode, int ftype) {
154 case mp_filetype_program:
156 if (l>3 && strcmp(fname+l-3,".mf")==0) {
157 s = kpse_find_file (fname, kpse_mf_format, 0);
159 s = kpse_find_file (fname, kpse_mp_format, 0);
162 case mp_filetype_text:
163 s = kpse_find_file (fname, kpse_mp_format, 0);
165 case mp_filetype_memfile:
166 s = kpse_find_file (fname, kpse_mem_format, 0);
168 case mp_filetype_metrics:
169 s = kpse_find_file (fname, kpse_tfm_format, 0);
171 case mp_filetype_fontmap:
172 s = kpse_find_file (fname, kpse_fontmap_format, 0);
174 case mp_filetype_font:
175 s = kpse_find_file (fname, kpse_type1_format, 0);
177 case mp_filetype_encoding:
178 s = kpse_find_file (fname, kpse_enc_format, 0);
182 s = mp_xstrdup(fname); /* when writing */
187 @ @<Register the callback routines@>=
189 options->find_file = mpost_find_file;
191 @ At the moment, the command line is very simple.
193 @d option_is(A) ((strncmp(argv[a],"--" A, strlen(A)+2)==0) ||
194 (strncmp(argv[a],"-" A, strlen(A)+1)==0))
195 @d option_arg(B) (optarg && strncmp(optarg,B, strlen(B))==0)
198 @<Read and set commmand line options@>=
202 optarg = strstr(argv[a],"=") ;
205 if (!*optarg) optarg=NULL;
207 if (option_is("ini")) {
208 options->ini_version = true;
209 } else if (option_is ("kpathsea-debug")) {
210 kpathsea_debug |= atoi (optarg);
211 } else if (option_is("mem")) {
212 options->mem_name = mp_xstrdup(optarg);
214 user_progname = optarg;
215 } else if (option_is("jobname")) {
216 options->job_name = mp_xstrdup(optarg);
217 } else if (option_is ("progname")) {
218 user_progname = optarg;
219 } else if (option_is("troff")) {
220 options->troff_mode = true;
221 } else if (option_is ("tex")) {
222 mpost_tex_program = optarg;
223 } else if (option_is("interaction")) {
224 if (option_arg("batchmode")) {
225 options->interaction = mp_batch_mode;
226 } else if (option_arg("nonstopmode")) {
227 options->interaction = mp_nonstop_mode;
228 } else if (option_arg("scrollmode")) {
229 options->interaction = mp_scroll_mode;
230 } else if (option_arg("errorstopmode")) {
231 options->interaction = mp_error_stop_mode;
233 fprintf(stdout,"unknown option argument %s\n", argv[a]);
235 } else if (option_is("no-kpathsea")) {
237 } else if (option_is("help")) {
238 @<Show help and exit@>;
239 } else if (option_is("version")) {
240 @<Show version and exit@>;
241 } else if (option_is("")) {
242 continue; /* ignore unknown options */
254 "Usage: mpost [OPTION] [MPNAME[.mp]] [COMMANDS]\n"
256 " Run MetaPost on MPNAME, usually creating MPNAME.NNN (and perhaps\n"
257 " MPNAME.tfm), where NNN are the character numbers generated.\n"
258 " Any remaining COMMANDS are processed as MetaPost input,\n"
259 " after MPNAME is read.\n"
261 " If no arguments or options are specified, prompt for input.\n"
263 " -ini be inimpost, for dumping mems\n"
264 " -interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/\n"
265 " scrollmode/errorstopmode)\n"
266 " -jobname=STRING set the job name to STRING\n"
267 " -progname=STRING set program (and mem) name to STRING\n"
268 " -tex=TEXPROGRAM use TEXPROGRAM for text labels\n"
269 " -kpathsea-debug=NUMBER set path searching debugging flags according to\n"
270 " the bits of NUMBER\n"
271 " -mem=MEMNAME use MEMNAME instead of program name or a %%& line\n"
272 " -troff set the prologues variable, use `makempx -troff'\n"
273 " -help display this help and exit\n"
274 " -version output version information and exit\n"
276 "Email bug reports to mp-implementors@@tug.org.\n"
286 "MetaPost %s (CWeb version %s)\n"
287 "Copyright 2008 AT&T Bell Laboratories.\n"
288 "There is NO warranty. Redistribution of this software is\n"
289 "covered by the terms of both the MetaPost copyright and\n"
290 "the Lesser GNU General Public License.\n"
291 "For more information about these matters, see the file\n"
292 "named COPYING and the MetaPost source.\n"
293 "Primary author of MetaPost: John Hobby.\n"
294 "Current maintainer of MetaPost: Taco Hoekwater.\n"
295 "\n", mp_metapost_version(mp), mp_mplib_version(mp));
299 @ The final part of the command line, after option processing, is
300 stored in the \MP\ instance, this will be taken as the first line of
303 @d command_line_size 256
305 @<Copy the rest of the command line@>=
307 options->command_line = mp_xmalloc(command_line_size,1);
308 if (options->command_line==NULL) {
309 fprintf(stderr,"Out of memory!\n");
312 strcpy(options->command_line,"");
318 if (k<(command_line_size-1)) {
319 options->command_line[k++] = *c;
323 options->command_line[k++] = ' ';
326 if (options->command_line[(k-1)] == ' ')
331 options->command_line[k] = 0;
335 @ A simple function to get numerical |texmf.cnf| values
337 int setup_var (int def, char *var_name, int nokpse) {
339 char * expansion = kpse_var_value (var_name);
341 int conf_val = atoi (expansion);
342 mp_xfree (expansion);
352 @ Now this is really it: \MP\ starts and ends here.
355 int main (int argc, char **argv) { /* |start_here| */
356 int a=0; /* argc counter */
357 int k; /* index into buffer */
358 int history; /* the exit status */
359 MP mp; /* a metapost instance */
360 struct MP_options * options; /* instance options */
361 int nokpse = 0; /* switch to {\it not} enable kpse */
362 char *user_progname = NULL; /* If the user overrides argv[0] with -progname. */
363 options = mp_options();
364 options->ini_version = false;
365 options->print_found_names = true;
366 @<Read and set commmand line options@>;
368 kpse_set_program_name("mpost",user_progname);
369 if(putenv("engine=newmetapost"))
370 fprintf(stdout,"warning: could not set up $engine\n");
371 options->main_memory = setup_var (50000,"main_memory",nokpse);
372 options->hash_size = setup_var (9500,"hash_size",nokpse);
373 options->hash_prime = 7919;
374 options->max_in_open = setup_var (25,"max_in_open",nokpse);
375 options->param_size = setup_var (1500,"param_size",nokpse);
376 options->error_line = setup_var (79,"error_line",nokpse);
377 options->half_error_line = setup_var (50,"half_error_line",nokpse);
378 options->max_print_line = setup_var (50,"max_print_line",nokpse);
379 @<Copy the rest of the command line@>;
380 @<Register the callback routines@>;
381 mp = mp_new(options);
382 mp_xfree((void *)options);
385 if(!mp_initialize(mp))
387 history = mp_run(mp);