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@>=
124 options.run_make_mpx = mpost_run_make_mpx;
127 @ @c scaled mpost_get_random_seed (MP mp) {
128 if (mp==NULL) exit(1); /* for -W */
129 #if defined (HAVE_GETTIMEOFDAY)
131 gettimeofday(&tv, NULL);
132 return (tv.tv_usec + 1000000 * tv.tv_usec);
133 #elif defined (HAVE_FTIME)
136 return (tb.millitm + 1000 * tb.time);
138 time_t clock = time ((time_t*)NULL);
139 struct tm *tmptr = localtime(&clock);
140 return (tmptr->tm_sec + 60*(tmptr->tm_min + 60*tmptr->tm_hour));
144 @ @<Register the callback routines@>=
145 options.get_random_seed = mpost_get_random_seed;
148 @c char *mpost_find_file(char *fname, char *fmode, int ftype) {
153 case mp_filetype_program:
155 if (l>3 && strcmp(fname+l-3,".mf")==0) {
156 s = kpse_find_file (fname, kpse_mf_format, 0);
158 s = kpse_find_file (fname, kpse_mp_format, 0);
161 case mp_filetype_text:
162 s = kpse_find_file (fname, kpse_mp_format, 0);
164 case mp_filetype_memfile:
165 s = kpse_find_file (fname, kpse_mem_format, 0);
167 case mp_filetype_metrics:
168 s = kpse_find_file (fname, kpse_tfm_format, 0);
170 case mp_filetype_fontmap:
171 s = kpse_find_file (fname, kpse_fontmap_format, 0);
173 case mp_filetype_font:
174 s = kpse_find_file (fname, kpse_type1_format, 0);
176 case mp_filetype_encoding:
177 s = kpse_find_file (fname, kpse_enc_format, 0);
181 s = mp_xstrdup(fname); /* when writing */
186 @ @<Register the callback routines@>=
187 options.find_file = mpost_find_file;
189 @ At the moment, the command line is very simple.
191 @d option_is(A) ((strncmp(argv[a],"--" A, strlen(A)+2)==0) ||
192 (strncmp(argv[a],"-" A, strlen(A)+1)==0))
193 @d option_arg(B) (optarg && strncmp(optarg,B, strlen(B))==0)
196 @<Read and set commmand line options@>=
200 optarg = strstr(argv[a],"=") ;
203 if (!*optarg) optarg=NULL;
205 if (option_is("ini")) {
206 options.ini_version = true;
207 } else if (option_is ("kpathsea-debug")) {
208 kpathsea_debug |= atoi (optarg);
209 } else if (option_is("mem")) {
210 options.mem_name = mp_xstrdup(optarg);
212 user_progname = optarg;
213 } else if (option_is("jobname")) {
214 options.job_name = mp_xstrdup(optarg);
215 } else if (option_is ("progname")) {
216 user_progname = optarg;
217 } else if (option_is("troff")) {
218 options.troff_mode = true;
219 } else if (option_is ("tex")) {
220 mpost_tex_program = optarg;
221 } else if (option_is("interaction")) {
222 if (option_arg("batchmode")) {
223 options.interaction = mp_batch_mode;
224 } else if (option_arg("nonstopmode")) {
225 options.interaction = mp_nonstop_mode;
226 } else if (option_arg("scrollmode")) {
227 options.interaction = mp_scroll_mode;
228 } else if (option_arg("errorstopmode")) {
229 options.interaction = mp_error_stop_mode;
231 fprintf(stdout,"unknown option argument %s\n", argv[a]);
233 } else if (option_is("help")) {
234 @<Show help and exit@>;
235 } else if (option_is("version")) {
236 @<Show version and exit@>;
237 } else if (option_is("")) {
238 continue; /* ignore unknown options */
250 "Usage: mpost [OPTION] [MPNAME[.mp]] [COMMANDS]\n"
252 " Run MetaPost on MPNAME, usually creating MPNAME.NNN (and perhaps\n"
253 " MPNAME.tfm), where NNN are the character numbers generated.\n"
254 " Any remaining COMMANDS are processed as MetaPost input,\n"
255 " after MPNAME is read.\n"
257 " If no arguments or options are specified, prompt for input.\n"
259 " -ini be inimpost, for dumping mems\n"
260 " -interaction=STRING set interaction mode (STRING=batchmode/nonstopmode/\n"
261 " scrollmode/errorstopmode)\n"
262 " -jobname=STRING set the job name to STRING\n"
263 " -progname=STRING set program (and mem) name to STRING\n"
264 " -tex=TEXPROGRAM use TEXPROGRAM for text labels\n"
265 " -kpathsea-debug=NUMBER set path searching debugging flags according to\n"
266 " the bits of NUMBER\n"
267 " -mem=MEMNAME use MEMNAME instead of program name or a %%& line\n"
268 " -troff set the prologues variable, use `makempx -troff'\n"
269 " -help display this help and exit\n"
270 " -version output version information and exit\n"
272 "Email bug reports to mp-implementors@@tug.org.\n"
282 "MetaPost %s (CWeb version %s)\n"
283 "Copyright 2008 AT&T Bell Laboratories.\n"
284 "There is NO warranty. Redistribution of this software is\n"
285 "covered by the terms of both the MetaPost copyright and\n"
286 "the Lesser GNU General Public License.\n"
287 "For more information about these matters, see the file\n"
288 "named COPYING and the MetaPost source.\n"
289 "Primary author of MetaPost: John Hobby.\n"
290 "Current maintainer of MetaPost: Taco Hoekwater.\n"
291 "\n", mp_metapost_version(mp), mp_mplib_version(mp));
295 @ The final part of the command line, after option processing, is
296 stored in the \MP\ instance, this will be taken as the first line of
299 @d command_line_size 256
301 @<Copy the rest of the command line@>=
303 options.command_line = mp_xmalloc(command_line_size,1);
304 if (options.command_line==NULL) {
305 fprintf(stderr,"Out of memory!\n");
308 strcpy(options.command_line,"");
314 if (k<(command_line_size-1)) {
315 options.command_line[k++] = *c;
319 options.command_line[k++] = ' ';
322 if (options.command_line[(k-1)] == ' ')
327 options.command_line[k] = 0;
331 @ A simple function to get numerical |texmf.cnf| values
333 int setup_kpse_var (int def, char *var_name) {
334 char * expansion = kpse_var_value (var_name);
336 int conf_val = atoi (expansion);
337 mp_xfree (expansion);
346 @ Now this is really it: \MP\ starts and ends here.
349 int main (int argc, char **argv) { /* |start_here| */
350 int a=0; /* argc counter */
351 int k; /* index into buffer */
352 int history; /* the exit status */
353 MP mp; /* a metapost instance */
354 struct MP_options options; /* instance options */
355 char *user_progname = NULL; /* If the user overrides argv[0] with -progname. */
356 options = mp_options();
357 options.ini_version = false;
358 options.print_found_names = true;
359 @<Read and set commmand line options@>;
360 kpse_set_program_name("mpost",user_progname);
361 options.main_memory = setup_kpse_var (50000,"main_memory");
362 options.hash_size = setup_kpse_var (9500,"hash_size");
363 options.hash_prime = 7919;
364 options.max_in_open = setup_kpse_var (25,"max_in_open");
365 options.param_size = setup_kpse_var (1500,"param_size");
366 options.error_line = setup_kpse_var (79,"error_line");
367 options.half_error_line = setup_kpse_var (50,"half_error_line");
368 options.max_print_line = setup_kpse_var (50,"max_print_line");
369 @<Copy the rest of the command line@>;
370 @<Register the callback routines@>;
371 mp = mp_new(options);
374 if(!mp_initialize(mp))
376 history = mp_run(mp);