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_PROTOTYPES 1
29 #include <kpathsea/progname.h>
30 #include <kpathsea/tex-file.h>
31 #include <kpathsea/variable.h>
32 extern unsigned kpathsea_debug;
33 #include <kpathsea/concatn.h>
34 static string mpost_tex_program = "";
36 @ Allocating a bit of memory, with error detection:
39 void *xmalloc (size_t bytes) {
40 void *w = malloc (bytes);
42 fprintf(stderr,"Out of memory!\n");
47 char *xstrdup(const char *s) {
49 if (s==NULL) return NULL;
52 fprintf(stderr,"Out of memory!\n");
61 void mpost_run_editor (MP mp, char *fname, int fline) {
63 fprintf(stdout,"Ok, bye (%s,%d)!",fname, fline);
68 @<Register the callback routines@>=
69 options->run_editor = mpost_run_editor;
73 string normalize_quotes (const char *name, const char *mesg) {
75 int must_quote = (strchr(name, ' ') != NULL);
76 /* Leave room for quotes and NUL. */
77 string ret = (string)xmalloc(strlen(name)+3);
83 for (q = name; *q; q++) {
93 fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name);
100 @ Invoke makempx (or troffmpx) to make sure there is an up-to-date
101 .mpx file for a given .mp file. (Original from John Hobby 3/14/90)
106 #define MPXCOMMAND "makempx"
108 int mpost_run_make_mpx (MP mp, char *mpname, char *mpxname) {
110 string cnf_cmd = kpse_var_value ("MPXCOMMAND");
112 if (cnf_cmd && (strcmp (cnf_cmd, "0")==0)) {
113 /* If they turned off this feature, just return success. */
117 /* We will invoke something. Compile-time default if nothing else. */
119 string qmpname = normalize_quotes(mpname, "mpname");
120 string qmpxname = normalize_quotes(mpxname, "mpxname");
122 cnf_cmd = xstrdup (MPXCOMMAND);
124 if (mp_troff_mode(mp))
125 cmd = concatn (cnf_cmd, " -troff ",
126 qmpname, " ", qmpxname, NULL);
127 else if (mpost_tex_program && *mpost_tex_program)
128 cmd = concatn (cnf_cmd, " -tex=", mpost_tex_program, " ",
129 qmpname, " ", qmpxname, NULL);
131 cmd = concatn (cnf_cmd, " -tex ", qmpname, " ", qmpxname, NULL);
145 @<Register the callback routines@>=
147 options->run_make_mpx = mpost_run_make_mpx;
150 @ @c int mpost_get_random_seed (MP mp) {
152 #if defined (HAVE_GETTIMEOFDAY)
154 gettimeofday(&tv, NULL);
155 ret = (tv.tv_usec + 1000000 * tv.tv_usec);
156 #elif defined (HAVE_FTIME)
159 ret = (tb.millitm + 1000 * tb.time);
161 time_t clock = time ((time_t*)NULL);
162 struct tm *tmptr = localtime(&clock);
163 ret = (tmptr->tm_sec + 60*(tmptr->tm_min + 60*tmptr->tm_hour));
165 return (mp ? ret : ret); /* for -W */
168 @ @<Register the callback routines@>=
169 options->get_random_seed = mpost_get_random_seed;
172 @c char *mpost_find_file(char *fname, char *fmode, int ftype) {
177 case mp_filetype_program:
179 if (l>3 && strcmp(fname+l-3,".mf")==0) {
180 s = kpse_find_file (fname, kpse_mf_format, 0);
182 s = kpse_find_file (fname, kpse_mp_format, 0);
185 case mp_filetype_text:
186 s = kpse_find_file (fname, kpse_mp_format, 0);
188 case mp_filetype_memfile:
189 s = kpse_find_file (fname, kpse_mem_format, 0);
191 case mp_filetype_metrics:
192 s = kpse_find_file (fname, kpse_tfm_format, 0);
194 case mp_filetype_fontmap:
195 s = kpse_find_file (fname, kpse_fontmap_format, 0);
197 case mp_filetype_font:
198 s = kpse_find_file (fname, kpse_type1_format, 0);
200 case mp_filetype_encoding:
201 s = kpse_find_file (fname, kpse_enc_format, 0);
205 s = xstrdup(fname); /* when writing */
210 @ @<Register the callback routines@>=
212 options->find_file = mpost_find_file;
214 @ At the moment, the command line is very simple.
216 @d option_is(A) ((strncmp(argv[a],"--" A, strlen(A)+2)==0) ||
217 (strncmp(argv[a],"-" A, strlen(A)+1)==0))
218 @d option_arg(B) (optarg && strncmp(optarg,B, strlen(B))==0)
221 @<Read and set commmand line options@>=
225 optarg = strstr(argv[a],"=") ;
228 if (!*optarg) optarg=NULL;
230 if (option_is("ini")) {
231 options->ini_version = true;
232 } else if (option_is ("kpathsea-debug")) {
233 kpathsea_debug |= atoi (optarg);
234 } else if (option_is("mem")) {
235 options->mem_name = xstrdup(optarg);
237 user_progname = optarg;
238 } else if (option_is("jobname")) {
239 options->job_name = xstrdup(optarg);
240 } else if (option_is ("progname")) {
241 user_progname = optarg;
242 } else if (option_is("troff")) {
243 options->troff_mode = true;
244 } else if (option_is ("tex")) {
245 mpost_tex_program = optarg;
246 } else if (option_is("interaction")) {
247 if (option_arg("batchmode")) {
248 options->interaction = mp_batch_mode;
249 } else if (option_arg("nonstopmode")) {
250 options->interaction = mp_nonstop_mode;
251 } else if (option_arg("scrollmode")) {
252 options->interaction = mp_scroll_mode;
253 } else if (option_arg("errorstopmode")) {
254 options->interaction = mp_error_stop_mode;
256 fprintf(stdout,"unknown option argument %s\n", argv[a]);
258 } else if (option_is("no-kpathsea")) {
260 } else if (option_is("help")) {
261 @<Show help and exit@>;
262 } else if (option_is("version")) {
263 @<Show version and exit@>;
264 } else if (option_is("")) {
265 continue; /* ignore unknown options */
277 "Usage: mpost [OPTION] [MPNAME[.mp]] [COMMANDS]\n"
279 " Run MetaPost on MPNAME, usually creating MPNAME.NNN (and perhaps\n"
280 " MPNAME.tfm), where NNN are the character numbers generated.\n"
281 " Any remaining COMMANDS are processed as MetaPost input,\n"
282 " after MPNAME is read.\n"
284 " If no arguments or options are specified, prompt for input.\n"
286 " -ini be inimpost, for dumping mems\n"
287 " -interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/\n"
288 " scrollmode/errorstopmode)\n"
289 " -jobname=STRING set the job name to STRING\n"
290 " -progname=STRING set program (and mem) name to STRING\n"
291 " -tex=TEXPROGRAM use TEXPROGRAM for text labels\n"
292 " -kpathsea-debug=NUMBER set path searching debugging flags according to\n"
293 " the bits of NUMBER\n"
294 " -mem=MEMNAME use MEMNAME instead of program name or a %%& line\n"
295 " -troff set the prologues variable, use `makempx -troff'\n"
296 " -help display this help and exit\n"
297 " -version output version information and exit\n"
299 "Email bug reports to mp-implementors@@tug.org.\n"
309 "MetaPost %s (CWeb version %s)\n"
310 "Copyright 2008 AT&T Bell Laboratories.\n"
311 "There is NO warranty. Redistribution of this software is\n"
312 "covered by the terms of both the MetaPost copyright and\n"
313 "the Lesser GNU General Public License.\n"
314 "For more information about these matters, see the file\n"
315 "named COPYING and the MetaPost source.\n"
316 "Primary author of MetaPost: John Hobby.\n"
317 "Current maintainer of MetaPost: Taco Hoekwater.\n"
318 "\n", mp_metapost_version(mp), mp_mplib_version(mp));
322 @ The final part of the command line, after option processing, is
323 stored in the \MP\ instance, this will be taken as the first line of
326 @d command_line_size 256
328 @<Copy the rest of the command line@>=
330 options->command_line = xmalloc(command_line_size);
331 strcpy(options->command_line,"");
337 if (k<(command_line_size-1)) {
338 options->command_line[k++] = *c;
342 options->command_line[k++] = ' ';
345 if (options->command_line[(k-1)] == ' ')
350 options->command_line[k] = 0;
354 @ A simple function to get numerical |texmf.cnf| values
356 int setup_var (int def, char *var_name, int nokpse) {
358 char * expansion = kpse_var_value (var_name);
360 int conf_val = atoi (expansion);
371 @ Now this is really it: \MP\ starts and ends here.
374 int main (int argc, char **argv) { /* |start_here| */
375 int a=0; /* argc counter */
376 int k; /* index into buffer */
377 int history; /* the exit status */
378 MP mp; /* a metapost instance */
379 struct MP_options * options; /* instance options */
380 int nokpse = 0; /* switch to {\it not} enable kpse */
381 char *user_progname = NULL; /* If the user overrides argv[0] with -progname. */
382 options = mp_options();
383 options->ini_version = false;
384 options->print_found_names = true;
385 @<Read and set commmand line options@>;
387 kpse_set_program_name("mpost",user_progname);
388 if(putenv("engine=newmetapost"))
389 fprintf(stdout,"warning: could not set up $engine\n");
390 options->main_memory = setup_var (50000,"main_memory",nokpse);
391 options->hash_size = setup_var (9500,"hash_size",nokpse);
392 options->hash_prime = 7919;
393 options->max_in_open = setup_var (25,"max_in_open",nokpse);
394 options->param_size = setup_var (1500,"param_size",nokpse);
395 options->error_line = setup_var (79,"error_line",nokpse);
396 options->half_error_line = setup_var (50,"half_error_line",nokpse);
397 options->max_print_line = setup_var (50,"max_print_line",nokpse);
398 @<Copy the rest of the command line@>;
399 @<Register the callback routines@>;
400 mp = mp_new(options);
401 free((void *)options);
404 history = mp_initialize(mp);
407 history = mp_run(mp);