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 #include "mpbasictypes.h"
29 #include "mppstypes.h"
31 #define HAVE_BOOLEAN 1
32 #define HAVE_PROTOTYPES 1
33 #include <kpathsea/progname.h>
34 #include <kpathsea/tex-file.h>
35 #include <kpathsea/variable.h>
36 extern unsigned kpathsea_debug;
37 #include <kpathsea/concatn.h>
38 static string mpost_tex_program = "";
42 void mpost_run_editor (MP mp, char *fname, int fline) {
44 fprintf(stdout,"Ok, bye (%s,%d)!",fname, fline);
49 @<Register the callback routines@>=
50 options.run_editor = mpost_run_editor;
54 string normalize_quotes (const char *name, const char *mesg) {
55 boolean quoted = false;
56 boolean must_quote = (strchr(name, ' ') != NULL);
57 /* Leave room for quotes and NUL. */
58 string ret = (string)mp_xmalloc(strlen(name)+3, sizeof(char));
64 for (q = name; *q; q++) {
74 fprintf(stderr, "! Unbalanced quotes in %s %s\n", mesg, name);
81 @ Invoke makempx (or troffmpx) to make sure there is an up-to-date
82 .mpx file for a given .mp file. (Original from John Hobby 3/14/90)
87 #define MPXCOMMAND "makempx"
89 boolean mpost_run_make_mpx (MP mp, char *mpname, char *mpxname) {
91 string cnf_cmd = kpse_var_value ("MPXCOMMAND");
93 if (cnf_cmd && (strcmp (cnf_cmd, "0")==0)) {
94 /* If they turned off this feature, just return success. */
98 /* We will invoke something. Compile-time default if nothing else. */
100 string qmpname = normalize_quotes(mpname, "mpname");
101 string qmpxname = normalize_quotes(mpxname, "mpxname");
103 cnf_cmd = mp_xstrdup (MPXCOMMAND);
106 cmd = concatn (cnf_cmd, " -troff ",
107 qmpname, " ", qmpxname, NULL);
108 else if (mpost_tex_program && *mpost_tex_program)
109 cmd = concatn (cnf_cmd, " -tex=", mpost_tex_program, " ",
110 qmpname, " ", qmpxname, NULL);
112 cmd = concatn (cnf_cmd, " -tex ", qmpname, " ", qmpxname, NULL);
126 @<Register the callback routines@>=
127 options.run_make_mpx = mpost_run_make_mpx;
130 @ @c scaled mpost_get_random_seed (MP mp) {
131 if (mp==NULL) exit(1); /* for -W */
132 #if defined (HAVE_GETTIMEOFDAY)
134 gettimeofday(&tv, NULL);
135 return (tv.tv_usec + 1000000 * tv.tv_usec);
136 #elif defined (HAVE_FTIME)
139 return (tb.millitm + 1000 * tb.time);
141 time_t clock = time ((time_t*)NULL);
142 struct tm *tmptr = localtime(&clock);
143 return (tmptr->tm_sec + 60*(tmptr->tm_min + 60*tmptr->tm_hour));
147 @ @<Register the callback routines@>=
148 options.get_random_seed = mpost_get_random_seed;
151 @c char *mpost_find_file(char *fname, char *fmode, int ftype) {
156 case mp_filetype_program:
158 if (l>3 && strcmp(fname+l-3,".mf")==0) {
159 s = kpse_find_file (fname, kpse_mf_format, 0);
161 s = kpse_find_file (fname, kpse_mp_format, 0);
164 case mp_filetype_text:
165 s = kpse_find_file (fname, kpse_mp_format, 0);
167 case mp_filetype_memfile:
168 s = kpse_find_file (fname, kpse_mem_format, 0);
170 case mp_filetype_metrics:
171 s = kpse_find_file (fname, kpse_tfm_format, 0);
173 case mp_filetype_fontmap:
174 s = kpse_find_file (fname, kpse_fontmap_format, 0);
176 case mp_filetype_font:
177 s = kpse_find_file (fname, kpse_type1_format, 0);
179 case mp_filetype_encoding:
180 s = kpse_find_file (fname, kpse_enc_format, 0);
184 s = mp_xstrdup(fname); /* when writing */
189 @ @<Register the callback routines@>=
190 options.find_file = mpost_find_file;
192 @ At the moment, the command line is very simple.
194 @d option_is(A) ((strncmp(argv[a],"--" A, strlen(A)+2)==0) ||
195 (strncmp(argv[a],"-" A, strlen(A)+1)==0))
196 @d option_arg(B) (optarg && strncmp(optarg,B, strlen(B))==0)
199 @<Read and set commmand line options@>=
203 optarg = strstr(argv[a],"=") ;
206 if (!*optarg) optarg=NULL;
208 if (option_is("ini")) {
209 options.ini_version = true;
210 } else if (option_is ("kpathsea-debug")) {
211 kpathsea_debug |= atoi (optarg);
212 } else if (option_is("mem")) {
213 options.mem_name = mp_xstrdup(optarg);
215 user_progname = optarg;
216 } else if (option_is("jobname")) {
217 options.job_name = mp_xstrdup(optarg);
218 } else if (option_is ("progname")) {
219 user_progname = optarg;
220 } else if (option_is("troff")) {
221 options.troff_mode = true;
222 } else if (option_is ("tex")) {
223 mpost_tex_program = optarg;
224 } else if (option_is("interaction")) {
225 if (option_arg("batchmode")) {
226 options.interaction = mp_batch_mode;
227 } else if (option_arg("nonstopmode")) {
228 options.interaction = mp_nonstop_mode;
229 } else if (option_arg("scrollmode")) {
230 options.interaction = mp_scroll_mode;
231 } else if (option_arg("errorstopmode")) {
232 options.interaction = mp_error_stop_mode;
234 fprintf(stdout,"unknown option argument %s\n", argv[a]);
236 } else if (option_is("help")) {
237 @<Show help and exit@>;
238 } else if (option_is("version")) {
239 @<Show version and exit@>;
240 } else if (option_is("")) {
241 continue; /* ignore unknown options */
253 "Usage: mpost [OPTION] [MPNAME[.mp]] [COMMANDS]\n"
255 " Run MetaPost on MPNAME, usually creating MPNAME.NNN (and perhaps\n"
256 " MPNAME.tfm), where NNN are the character numbers generated.\n"
257 " Any remaining COMMANDS are processed as MetaPost input,\n"
258 " after MPNAME is read.\n"
260 " If no arguments or options are specified, prompt for input.\n"
262 " -ini be inimpost, for dumping mems\n"
263 " -interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/\n"
264 " scrollmode/errorstopmode)\n"
265 " -jobname=STRING set the job name to STRING\n"
266 " -progname=STRING set program (and mem) name to STRING\n"
267 " -tex=TEXPROGRAM use TEXPROGRAM for text labels\n"
268 " -kpathsea-debug=NUMBER set path searching debugging flags according to\n"
269 " the bits of NUMBER\n"
270 " -mem=MEMNAME use MEMNAME instead of program name or a %%& line\n"
271 " -troff set the prologues variable, use `makempx -troff'\n"
272 " -help display this help and exit\n"
273 " -version output version information and exit\n"
275 "Email bug reports to mp-implementors@@tug.org.\n"
285 "MetaPost %s (CWeb version %s)\n"
286 "Copyright 2008 AT&T Bell Laboratories.\n"
287 "There is NO warranty. Redistribution of this software is\n"
288 "covered by the terms of both the MetaPost copyright and\n"
289 "the Lesser GNU General Public License.\n"
290 "For more information about these matters, see the file\n"
291 "named COPYING and the MetaPost source.\n"
292 "Primary author of MetaPost: John Hobby.\n"
293 "Current maintainer of MetaPost: Taco Hoekwater.\n"
294 "\n", mp_metapost_version(mp), mp_mplib_version(mp));
298 @ The final part of the command line, after option processing, is
299 stored in the \MP\ instance, this will be taken as the first line of
302 @d command_line_size 256
304 @<Copy the rest of the command line@>=
306 options.command_line = mp_xmalloc(command_line_size,1);
307 if (options.command_line==NULL) {
308 fprintf(stderr,"Out of memory!\n");
311 strcpy(options.command_line,"");
317 if (k<(command_line_size-1)) {
318 options.command_line[k++] = *c;
322 options.command_line[k++] = ' ';
325 if (options.command_line[(k-1)] == ' ')
330 options.command_line[k] = 0;
334 @ A simple function to get numerical |texmf.cnf| values
336 int setup_kpse_var (int def, char *var_name) {
337 char * expansion = kpse_var_value (var_name);
339 int conf_val = atoi (expansion);
340 mp_xfree (expansion);
349 @ Now this is really it: \MP\ starts and ends here.
352 int main (int argc, char **argv) { /* |start_here| */
353 int a=0; /* argc counter */
354 int k; /* index into buffer */
355 int history; /* the exit status */
356 MP mp; /* a metapost instance */
357 struct MP_options options; /* instance options */
358 char *user_progname = NULL; /* If the user overrides argv[0] with -progname. */
359 options = mp_options();
360 options.ini_version = false;
361 options.print_found_names = true;
362 @<Read and set commmand line options@>;
363 kpse_set_program_name("mpost",user_progname);
364 options.main_memory = setup_kpse_var (50000,"main_memory");
365 options.hash_size = setup_kpse_var (9500,"hash_size");
366 options.hash_prime = 7919;
367 options.max_in_open = setup_kpse_var (25,"max_in_open");
368 options.param_size = setup_kpse_var (1500,"param_size");
369 options.error_line = setup_kpse_var (79,"error_line");
370 options.half_error_line = setup_kpse_var (50,"half_error_line");
371 options.max_print_line = setup_kpse_var (50,"max_print_line");
372 @<Copy the rest of the command line@>;
373 @<Register the callback routines@>;
374 mp = mp_new(options);
377 if(!mp_initialize(mp))
380 history = mp->history;