summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mplibdir/mp.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mplibdir/mp.w')
-rw-r--r--Build/source/texk/web2c/mplibdir/mp.w591
1 files changed, 496 insertions, 95 deletions
diff --git a/Build/source/texk/web2c/mplibdir/mp.w b/Build/source/texk/web2c/mplibdir/mp.w
index 1303cf6f9e4..f49d5a451f9 100644
--- a/Build/source/texk/web2c/mplibdir/mp.w
+++ b/Build/source/texk/web2c/mplibdir/mp.w
@@ -1,4 +1,4 @@
-% $Id: mp.w 873 2009-03-19 07:44:11Z taco $
+% $Id: mp.w 976 2009-04-22 07:55:33Z taco $
%
% Copyright 2008 Taco Hoekwater.
%
@@ -89,13 +89,13 @@ undergoes any modifications, so that it will be clear which version of
@^extensions to \MP@>
@^system dependencies@>
-@d default_banner "This is MetaPost, Version 1.110" /* printed when \MP\ starts */
+@d default_banner "This is MetaPost, Version 1.200" /* printed when \MP\ starts */
@d true 1
@d false 0
@(mpmp.h@>=
-#define metapost_version "1.110"
-#define metapost_magic (('M'*256) + 'P')*65536 + 1110
+#define metapost_version "1.200"
+#define metapost_magic (('M'*256) + 'P')*65536 + 1200
#define metapost_old_magic (('M'*256) + 'P')*65536 + 1080
@ The external library header for \MP\ is |mplib.h|. It contains a
@@ -282,6 +282,7 @@ MP mp_initialize (MP_options *opt) {
} else {
mp->history=mp_spotless;
}
+ @<Fix up |mp->internal[mp_job_name]|@>;
return mp;
}
@@ -663,6 +664,9 @@ int file_line_error_style; /* configuration parameter */
mp->file_line_error_style = (opt->file_line_error_style>0 ? true : false);
mp->long_name = NULL;
+@ @<Dealloc variables@>=
+mp_xfree(mp->long_name);
+
@ \MP's file-opening procedures return |false| if no file identified by
|name_of_file| could be opened.
@@ -1482,6 +1486,21 @@ static boolean mp_str_eq_buf (MP mp,str_number s, integer k) {
return true;
}
+@ This routine compares a pool string with a sequence of characters
+of equal length.
+
+@c
+static boolean mp_str_eq_cstr (MP mp,str_number s, char *k) {
+ /* test equality of strings */
+ pool_pointer j; /* running index */
+ j=mp->str_start[s];
+ while ( j<str_stop(s) ) {
+ if ( mp->str_pool[j++]!=*k++ )
+ return false;
+ }
+ return true;
+}
+
@ Here is a similar routine, but it compares two strings in the string pool,
and it does not assume that they have the same length. If the first string
is lexicographically greater than, less than, or equal to the second,
@@ -3996,10 +4015,12 @@ void mp_do_snprintf (char *str, int size, const char *format, ...) {
if (*fmt=='%') {
fw=0;
pad=0;
+ RESTART:
fmt++;
switch(*fmt) {
case '0':
pad=1;
+ goto RESTART;
break;
case '1':
case '2':
@@ -4010,9 +4031,10 @@ void mp_do_snprintf (char *str, int size, const char *format, ...) {
case '7':
case '8':
case '9':
- assert(fw==0);
- fw = *fmt-'0';
- break;
+ assert(fw==0);
+ fw = *fmt-'0';
+ goto RESTART;
+ break;
case 's':
{
char *s = va_arg(ap, char *);
@@ -4022,10 +4044,18 @@ void mp_do_snprintf (char *str, int size, const char *format, ...) {
}
}
break;
+ case 'c':
+ {
+ int s = va_arg(ap, int);
+ *res = s;
+ if (size-->0) res++;
+ }
+ break;
case 'i':
case 'd':
{
- char *s = mp_itoa(va_arg(ap, int));
+ char *sstart, *s = mp_itoa(va_arg(ap, int));
+ sstart = s;
if (fw) {
int ffw = fw-strlen(s);
while (ffw-->0) {
@@ -4038,12 +4068,14 @@ void mp_do_snprintf (char *str, int size, const char *format, ...) {
*res = *s++;
if (size-->0) res++;
}
+ mp_xfree(sstart);
}
}
break;
case 'u':
{
- char *s = mp_utoa(va_arg(ap, unsigned));
+ char *sstart, *s = mp_utoa(va_arg(ap, unsigned));
+ sstart = s;
if (fw) {
int ffw = fw-strlen(s);
while (ffw-->0) {
@@ -4056,6 +4088,7 @@ void mp_do_snprintf (char *str, int size, const char *format, ...) {
*res = *s++;
if (size-->0) res++;
}
+ mp_xfree(sstart);
}
}
break;
@@ -4786,7 +4819,8 @@ and |string_type| in that order.
@<Types...@>=
enum mp_variable_type {
-mp_vacuous=1, /* no expression was present */
+mp_internal_type=0, /* an internal that has not been frozen yet */
+mp_vacuous, /* no expression was present */
mp_boolean_type, /* \&{boolean} with a known value */
mp_unknown_boolean,
mp_string_type, /* \&{string} with a known value */
@@ -4818,6 +4852,7 @@ static void mp_print_type (MP mp,quarterword t) ;
@ @<Basic printing procedures@>=
void mp_print_type (MP mp,quarterword t) {
switch (t) {
+ case mp_internal_type:mp_print(mp, "new internal"); break;
case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
case mp_boolean_type:mp_print(mp, "boolean"); break;
case mp_unknown_boolean:mp_print(mp, "unknown boolean"); break;
@@ -4892,7 +4927,6 @@ values they test for.
@d false_code 31 /* operation code for \.{false} */
@d null_picture_code 32 /* operation code for \.{nullpicture} */
@d null_pen_code 33 /* operation code for \.{nullpen} */
-@d job_name_op 34 /* operation code for \.{jobname} */
@d read_string_op 35 /* operation code for \.{readstring} */
@d pen_circle 36 /* operation code for \.{pencircle} */
@d normal_deviate 37 /* operation code for \.{normaldeviate} */
@@ -4990,6 +5024,7 @@ values they test for.
@d arc_time_of 128 /* operation code for \.{arctime} */
@d mp_version 129 /* operation code for \.{mpversion} */
@d envelope_of 130 /* operation code for \.{envelope} */
+@d glyph_infont 131 /* operation code for \.{glyph} */
@c static void mp_print_op (MP mp,quarterword c) {
if (c<=mp_numeric_type ) {
@@ -5000,7 +5035,6 @@ values they test for.
case false_code:mp_print(mp, "false"); break;
case null_picture_code:mp_print(mp, "nullpicture"); break;
case null_pen_code:mp_print(mp, "nullpen"); break;
- case job_name_op:mp_print(mp, "jobname"); break;
case read_string_op:mp_print(mp, "readstring"); break;
case pen_circle:mp_print(mp, "pencircle"); break;
case normal_deviate:mp_print(mp, "normaldeviate"); break;
@@ -5096,6 +5130,7 @@ values they test for.
case arc_time_of:mp_print(mp, "arctime"); break;
case mp_version:mp_print(mp, "mpversion"); break;
case envelope_of:mp_print(mp, "envelope"); break;
+ case glyph_infont:mp_print(mp, "glyph"); break;
default: mp_print(mp, ".."); break;
}
}
@@ -5108,6 +5143,8 @@ fuss with. Every such parameter has an identifying code number, defined here.
enum mp_given_internal {
mp_output_template=1, /* a string set up by \&{outputtemplate} */
mp_output_format, /* the output format set up by \&{outputformat} */
+ mp_job_name, /* the perceived jobname, as set up from the options stucture,
+ the name of the input file, or by \&{jobname} */
mp_tracing_titles, /* show titles online when they appear */
mp_tracing_equations, /* show each variable when it becomes known */
mp_tracing_capsules, /* show capsules too */
@@ -5124,6 +5161,8 @@ enum mp_given_internal {
mp_month, /* the current month (e.g., 3 $\equiv$ March) */
mp_day, /* the current day of the month */
mp_time, /* the number of minutes past midnight when this job started */
+ mp_hour, /* the number of hours past midnight when this job started */
+ mp_minute, /* the number of minutes in that hour when this job started */
mp_char_code, /* the number of the next character to be output */
mp_char_ext, /* the extension code of the next character to be output */
mp_char_wd, /* the width of the next character to be output */
@@ -5153,6 +5192,7 @@ enum mp_given_internal {
@<Glob...@>=
scaled *internal; /* the values of internal quantities */
+int *int_type; /* their types */
char **int_name; /* their names */
int int_ptr; /* the maximum internal quantity defined so far */
int max_internal; /* current maximum number of internal quantities */
@@ -5166,6 +5206,16 @@ mp->internal = xmalloc ((mp->max_internal+1), sizeof(scaled));
memset(mp->internal,0,(mp->max_internal+1)* sizeof(scaled));
mp->int_name = xmalloc ((mp->max_internal+1), sizeof(char *));
memset(mp->int_name,0,(mp->max_internal+1) * sizeof(char *));
+mp->int_type = xmalloc ((mp->max_internal+1), sizeof(int));
+memset(mp->int_type,0,(mp->max_internal+1) * sizeof(int));
+{
+ int i;
+ for (i=1;i<=max_given_internal;i++)
+ mp->int_type[i]=mp_known;
+}
+mp->int_type[mp_output_format]=mp_string_type;
+mp->int_type[mp_output_template]=mp_string_type;
+mp->int_type[mp_job_name]=mp_string_type;
mp->troff_mode=(opt->troff_mode>0 ? true : false);
@ @<Exported function ...@>=
@@ -5215,6 +5265,10 @@ mp_primitive(mp, "day",internal_quantity,mp_day);
@:mp_day_}{\&{day} primitive@>
mp_primitive(mp, "time",internal_quantity,mp_time);
@:time_}{\&{time} primitive@>
+mp_primitive(mp, "hour",internal_quantity,mp_hour);
+@:hour_}{\&{hour} primitive@>
+mp_primitive(mp, "minute",internal_quantity,mp_minute);
+@:minute_}{\&{minute} primitive@>
mp_primitive(mp, "charcode",internal_quantity,mp_char_code);
@:mp_char_code_}{\&{charcode} primitive@>
mp_primitive(mp, "charext",internal_quantity,mp_char_ext);
@@ -5261,6 +5315,8 @@ mp_primitive(mp, "outputtemplate",internal_quantity,mp_output_template);
@:mp_output_template_}{\&{outputtemplate} primitive@>
mp_primitive(mp, "outputformat",internal_quantity,mp_output_format);
@:mp_output_format_}{\&{outputformat} primitive@>
+mp_primitive(mp, "jobname",internal_quantity,mp_job_name);
+@:mp_job_name_}{\&{jobname} primitive@>
@ Colors can be specified in four color models. In the special
case of |no_model|, MetaPost does not output any color operator to
@@ -5310,6 +5366,8 @@ mp->int_name[mp_year]=xstrdup("year");
mp->int_name[mp_month]=xstrdup("month");
mp->int_name[mp_day]=xstrdup("day");
mp->int_name[mp_time]=xstrdup("time");
+mp->int_name[mp_hour]=xstrdup("hour");
+mp->int_name[mp_minute]=xstrdup("minute");
mp->int_name[mp_char_code]=xstrdup("charcode");
mp->int_name[mp_char_ext]=xstrdup("charext");
mp->int_name[mp_char_wd]=xstrdup("charwd");
@@ -5333,6 +5391,7 @@ mp->int_name[mp_gtroffmode]=xstrdup("troffmode");
mp->int_name[mp_restore_clip_color]=xstrdup("restoreclipcolor");
mp->int_name[mp_output_template]=xstrdup("outputtemplate");
mp->int_name[mp_output_format]=xstrdup("outputformat");
+mp->int_name[mp_job_name]=xstrdup("jobname");
@ The following procedure, which is called just before \MP\ initializes its
input and output, establishes the initial values of the date and time.
@@ -5347,6 +5406,8 @@ static void mp_fix_date_and_time (MP mp) {
struct tm *tmptr = localtime (&aclock);
mp->internal[mp_time]=
(tmptr->tm_hour*60+tmptr->tm_min)*unity; /* minutes since midnight */
+ mp->internal[mp_hour]= (tmptr->tm_hour)*unity; /* hours since midnight */
+ mp->internal[mp_minute]= (tmptr->tm_min)*unity; /* minutes since the hour */
mp->internal[mp_day]=(tmptr->tm_mday)*unity; /* fourth day of the month */
mp->internal[mp_month]=(tmptr->tm_mon+1)*unity; /* seventh month of the year */
mp->internal[mp_year]=(tmptr->tm_year+1900)*unity; /* Anno Domini */
@@ -5576,6 +5637,24 @@ eq_type(frozen_right_delimiter)=right_delimiter;
@ @<Check the ``constant'' values...@>=
if ( hash_end+mp->max_internal>max_halfword ) mp->bad=17;
+@ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
+should be a prime number. The theory of hashing tells us to expect fewer
+than two table probes, on the average, when the search is successful.
+[See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
+@^Vitter, Jeffrey Scott@>
+
+@c
+static integer mp_compute_hash (MP mp, const char *s, int l) {
+ integer k;
+ integer h = *s;
+ for (k=1;k<l;k++){
+ h=h+h+(*(s+k));
+ while ( h>=mp->hash_prime ) h=h-mp->hash_prime;
+ }
+ return h;
+}
+
+
@ Here is the subroutine that searches the hash table for an identifier
that matches a given string of length~|l| appearing in |buffer[j..
(j+l-1)]|. If the identifier is not found, it is inserted; hence it
@@ -5630,19 +5709,9 @@ incr(mp->st_count);
break;
}
+@ @<Compute the hash code |h|@>=
+h=mp_compute_hash(mp, (char *)mp->buffer+j, l)
-@ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it
-should be a prime number. The theory of hashing tells us to expect fewer
-than two table probes, on the average, when the search is successful.
-[See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.]
-@^Vitter, Jeffrey Scott@>
-
-@<Compute the hash code |h|@>=
-h=mp->buffer[j];
-for (k=j+1;k<j+l;k++){
- h=h+h+mp->buffer[k];
- while ( h>=mp->hash_prime ) h=h-mp->hash_prime;
-}
@ @<Search |eqtb| for equivalents equal to |p|@>=
for (q=1;q<=hash_end;q++) {
@@ -6874,8 +6943,11 @@ third kind.
static void mp_save_internal (MP mp,halfword q) {
pointer p; /* new item for the save stack */
if ( mp->save_ptr!=null ){
- p=mp_get_node(mp, save_node_size); mp_info(p)=hash_end+q;
- mp_link(p)=mp->save_ptr; value(p)=mp->internal[q]; mp->save_ptr=p;
+ p=mp_get_node(mp, save_node_size);
+ mp_info(p)=hash_end+q;
+ mp_link(p)=mp->save_ptr;
+ value(p)=mp->internal[q];
+ mp->save_ptr=p;
}
}
@@ -6891,16 +6963,29 @@ static void mp_unsave (MP mp) {
q=mp_info(mp->save_ptr);
if ( q>hash_end ) {
if ( mp->internal[mp_tracing_restores]>0 ) {
- mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
- mp_print(mp, mp->int_name[q-(hash_end)]); mp_print_char(mp, xord('='));
- mp_print_scaled(mp, value(mp->save_ptr)); mp_print_char(mp, xord('}'));
+ mp_begin_diagnostic(mp);
+ mp_print_nl(mp, "{restoring ");
+ mp_print(mp, mp->int_name[q-(hash_end)]);
+ mp_print_char(mp, xord('='));
+ if (mp->int_type[q-(hash_end)]==mp_known) {
+ mp_print_scaled(mp, value(mp->save_ptr));
+ } else if (mp->int_type[q-(hash_end)]==mp_string_type) {
+ char *s = mp_str(mp, value(mp->save_ptr));
+ mp_print(mp, s);
+ free(s);
+ } else {
+ mp_confusion(mp,"internal_restore");
+ }
+ mp_print_char(mp, xord('}'));
mp_end_diagnostic(mp, false);
}
mp->internal[q-(hash_end)]=value(mp->save_ptr);
} else {
if ( mp->internal[mp_tracing_restores]>0 ) {
- mp_begin_diagnostic(mp); mp_print_nl(mp, "{restoring ");
- mp_print_text(q); mp_print_char(mp, xord('}'));
+ mp_begin_diagnostic(mp);
+ mp_print_nl(mp, "{restoring ");
+ mp_print_text(q);
+ mp_print_char(mp, xord('}'));
mp_end_diagnostic(mp, false);
}
mp_clear_symbol(mp, q,false);
@@ -7244,6 +7329,22 @@ static mp_knot *mp_export_knot (MP mp,pointer p) {
gr_originator(q) = (unsigned char)mp_originator(p);
return q;
}
+static pointer mp_import_knot (MP mp, mp_knot *q) {
+ pointer p; /* the copy */
+ if (q==NULL)
+ return null;
+ p=mp_get_node(mp, knot_node_size);
+ mp_left_type(p) = gr_left_type(q);
+ mp_right_type(p) = gr_right_type(q);
+ mp_x_coord(p) = gr_x_coord(q);
+ mp_y_coord(p) = gr_y_coord(q);
+ mp_left_x(p) = gr_left_x(q);
+ mp_left_y(p) = gr_left_y(q);
+ mp_right_x(p) = gr_right_x(q);
+ mp_right_y(p) = gr_right_y(q);
+ mp_originator(p) = gr_originator(q);
+ return p;
+}
@ The |export_knot_list| routine therefore also makes a clone
of a given path.
@@ -7264,6 +7365,21 @@ static mp_knot *mp_export_knot_list (MP mp, pointer p) {
gr_next_knot(qq)=q;
return q;
}
+static pointer mp_import_knot_list (MP mp, mp_knot *q) {
+ mp_knot *qq; /* for list manipulation */
+ pointer p, pp; /* for list manipulation */
+ if (q==NULL)
+ return null;
+ p=mp_import_knot(mp, q);
+ pp=p; qq=gr_link(q);
+ while ( qq!=q ) {
+ mp_link(pp)=mp_import_knot(mp, qq);
+ qq=gr_next_knot(qq);
+ pp=mp_link(pp);
+ }
+ mp_link(pp)=p;
+ return p;
+}
@ Similarly, there's a way to copy the {\sl reverse\/} of a path. This procedure
@@ -16281,9 +16397,11 @@ void mp_ptr_scan_file (MP mp, char *s) {
}
-@ The global variable |job_name| contains the file name that was first
-\&{input} by the user. This name is extended by `\.{.log}' and `\.{ps}' and
-`\.{.mem}' and `\.{.tfm}' in order to make the names of \MP's output files.
+@ The option variable |job_name| contains the file name that was first
+\&{input} by the user. This name is used to initialize the |job_name| global
+as well as the |mp_job_name| internal, and is extended by `\.{.log}' and
+`\.{ps}' and `\.{.mem}' and `\.{.tfm}' in order to make the names of \MP's
+output files.
@<Glob...@>=
boolean log_opened; /* has the transcript file been opened? */
@@ -16312,6 +16430,17 @@ if (opt->noninteractive && opt->ini_version) {
}
mp->log_opened=false;
+@ Cannot do this earlier because at the |@<Allocate or ...@>|, the string
+pool is not yet initialized.
+
+@<Fix up |mp->internal[mp_job_name]|@>=
+if (mp->job_name != NULL) {
+ if (mp->internal[mp_job_name]!=0)
+ delete_str_ref(mp->internal[mp_job_name]);
+ mp->internal[mp_job_name]=mp_rts(mp,mp->job_name);
+}
+
+
@ @<Dealloc variables@>=
xfree(mp->job_name);
@@ -16354,7 +16483,11 @@ void mp_prompt_file_name (MP mp, const char * s, const char * e) ;
print_err("I can\'t write on file `");
@.I can't write on file x@>
}
- mp_print_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext);
+ if (strcmp(s,"file name for output")==0) {
+ mp_print(mp, mp->output_file);
+ } else {
+ mp_print_file_name(mp, mp->cur_name,mp->cur_area,mp->cur_ext);
+ }
mp_print(mp, "'.");
if (strcmp(e,"")==0)
mp_show_context(mp);
@@ -16400,6 +16533,7 @@ it catch up to what has previously been printed on the terminal.
old_setting=mp->selector;
if ( mp->job_name==NULL ) {
mp->job_name=xstrdup("mpout");
+ @<Fix up |mp->internal[mp_job_name]|@>;
}
mp_pack_job_name(mp,".log");
while ( ! mp_a_open_out(mp, &mp->log_file, mp_filetype_log) ) {
@@ -16414,7 +16548,7 @@ it catch up to what has previously been printed on the terminal.
mp_print_nl(mp, "**");
@.**@>
l=mp->input_stack[0].limit_field-1; /* last position of first line */
- for (k=0;k<=l;k++) mp_print_str(mp, mp->buffer[k]);
+ for (k=1;k<=l;k++) mp_print_str(mp, mp->buffer[k]);
mp_print_ln(mp); /* now the transcript file contains the first line of input */
}
mp->selector=old_setting+2; /* |log_only| or |term_and_log| */
@@ -16454,8 +16588,9 @@ this file.
mp_print_char(mp, xord(' '));
mp_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_year]));
mp_print_char(mp, xord(' '));
- m=mp_round_unscaled(mp, mp->internal[mp_time]);
- mp_print_dd(mp, m / 60); mp_print_char(mp, xord(':')); mp_print_dd(mp, m % 60);
+ mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[mp_hour]));
+ mp_print_char(mp, xord(':'));
+ mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[mp_minute]));
}
@ The |try_extension| function tries to open an input file determined by
@@ -16498,6 +16633,7 @@ when an `\.{input}' command is being processed.
fname = xstrdup(mp->name_of_file);
if ( mp->job_name==NULL ) {
mp->job_name=xstrdup(mp->cur_name);
+ @<Fix up |mp->internal[mp_job_name]|@>;
mp_open_log_file(mp);
} /* |open_log_file| doesn't |show_context|, so |limit|
and |loc| needn't be set to meaningful values yet */
@@ -16604,7 +16740,7 @@ int mp_run_make_mpx (MP mp, char *origname, char *mtxname) {
origname = mp_xstrdup(mp,mp->name_of_file);
*(origname+strlen(origname)-1)=0; /* drop the x */
if (!(mp->run_make_mpx)(mp, origname, mp->name_of_file))
- goto NOT_FOUND
+ goto NOT_FOUND
@ @<Explain that the \.{MPX} file can't be read and |succumb|@>=
if ( mp->interaction==mp_error_stop_mode ) wake_up_terminal;
@@ -16617,6 +16753,7 @@ help4("The two files given above are one of your source files",
"and an auxiliary file I need to read to find out what your",
"btex..etex blocks mean. If you don't know why I had trouble,",
"try running it manually through MPtoTeX, TeX, and DVItoMP");
+xfree(origname);
succumb;
@ The last file-opening commands are for files accessed via the \&{readfrom}
@@ -16965,6 +17102,7 @@ case mp_vacuous:mp_print(mp, "mp_vacuous"); break;
case mp_boolean_type:
if ( v==true_code ) mp_print(mp, "true"); else mp_print(mp, "false");
break;
+case mp_internal_type:
case unknown_types: case mp_numeric_type:
@<Display a variable that's been declared but not defined@>;
break;
@@ -17037,8 +17175,8 @@ the ring consists entirely of capsules.
{ mp_print_type(mp, t);
if ( v!=null )
{ mp_print_char(mp, xord(' '));
- while ( (mp_name_type(v)==mp_capsule) && (v!=p) ) v=value(v);
- mp_print_variable_name(mp, v);
+ while ( (mp_name_type(v)==mp_capsule) && (v!=p) ) v=value(v);
+ mp_print_variable_name(mp, v);
};
}
@@ -17729,12 +17867,19 @@ of the save stack, as described earlier.)
mp->cur_exp=mp_get_avail(mp);
mp_info(mp->cur_exp)=q+hash_end; mp->cur_type=mp_token_list;
goto DONE;
+ } else {
+ if (mp->int_type[q]==mp_internal_type)
+ mp->int_type[q] = mp_known;
}
mp_back_input(mp);
+ } else {
+ if (mp->int_type[q]==mp_internal_type)
+ mp->int_type[q] = mp_known;
}
- mp->cur_type=mp_known; mp->cur_exp=mp->internal[q];
- if (q == mp_output_format || q == mp_output_template)
- mp->cur_type=mp_string_type;
+ mp->cur_exp=mp->internal[q];
+ if (mp->int_type[q]==mp_string_type)
+ add_str_ref(mp->cur_exp);
+ mp->cur_type=mp->int_type[q];
}
@ The most difficult part of |scan_primary| has been saved for last, since
@@ -18695,8 +18840,6 @@ mp_primitive(mp, "nullpicture",nullary,null_picture_code);
@:null_picture_}{\&{nullpicture} primitive@>
mp_primitive(mp, "nullpen",nullary,null_pen_code);
@:null_pen_}{\&{nullpen} primitive@>
-mp_primitive(mp, "jobname",nullary,job_name_op);
-@:job_name_}{\&{jobname} primitive@>
mp_primitive(mp, "readstring",nullary,read_string_op);
@:read_string_}{\&{readstring} primitive@>
mp_primitive(mp, "pencircle",nullary,pen_circle);
@@ -18887,6 +19030,8 @@ mp_primitive(mp, "intersectiontimes",tertiary_binary,intersect);
@:intersection_times_}{\&{intersectiontimes} primitive@>
mp_primitive(mp, "envelope",primary_binary,envelope_of);
@:envelope_}{\&{envelope} primitive@>
+mp_primitive(mp, "glyph",primary_binary,glyph_infont);
+@:glyph_infont_}{\&{envelope} primitive@>
@ @<Cases of |print_cmd...@>=
case nullary:
@@ -18929,10 +19074,6 @@ static void mp_do_nullary (MP mp,quarterword c) {
case pen_circle:
mp->cur_type=mp_pen_type; mp->cur_exp=mp_get_pen_circle(mp, unity);
break;
- case job_name_op:
- if ( mp->job_name==NULL ) mp_open_log_file(mp);
- mp->cur_type=mp_string_type; mp->cur_exp=rts(mp->job_name);
- break;
case mp_version:
mp->cur_type=mp_string_type;
mp->cur_exp=intern(metapost_version) ;
@@ -21374,6 +21515,14 @@ case envelope_of:
else
mp_set_up_envelope(mp, p);
break;
+case glyph_infont:
+ if ( (mp_type(p) != mp_string_type &&
+ mp_type(p) != mp_known) || (mp->cur_type != mp_string_type) )
+ mp_bad_binary(mp, p,glyph_infont);
+ else
+ mp_set_up_glyph_infont(mp, p);
+ break;
+ break;
@ @<Declare binary action...@>=
static void mp_set_up_offset (MP mp,pointer p) {
@@ -21409,6 +21558,44 @@ static void mp_set_up_envelope (MP mp,pointer p) {
mp->cur_type = mp_path_type;
}
+
+@ This is pretty straightfoward. The one silly thing is that
+the output of |mp_ps_do_font_charstring| has to be un-exported.
+
+@<Declare binary action...@>=
+static void mp_set_up_glyph_infont (MP mp, pointer p) {
+ mp_edge_object *h = NULL;
+ mp_ps_font *f = NULL;
+ char *n = mp_str(mp, mp->cur_exp);
+ f = mp_ps_font_parse(mp, mp_find_font(mp, n));
+ if (f!=NULL) {
+ if (mp_type(p) == mp_known) {
+ int v = mp_round_unscaled(mp,value(p));
+ if (v<0 || v>255) {
+ print_err ("glyph index too high (");
+ mp_print_int(mp,v);
+ mp_print(mp,")");
+ mp_error(mp);
+ } else {
+ h = mp_ps_font_charstring (mp,f,v);
+ }
+ } else {
+ n = mp_str(mp, value(p));
+ delete_str_ref(value(p));
+ h = mp_ps_do_font_charstring (mp,f,n);
+ free(n);
+ }
+ mp_ps_font_free(mp,f);
+ }
+ if (h!=NULL) {
+ mp->cur_exp=mp_gr_unexport(mp, h);
+ } else {
+ mp->cur_exp=mp_get_node(mp, edge_header_size);
+ mp_init_edges(mp, mp->cur_exp);
+ }
+ mp->cur_type=mp_picture_type;
+}
+
@ @<Declare binary action...@>=
static void mp_find_point (MP mp,scaled v, quarterword c) {
pointer p; /* the path */
@@ -21478,7 +21665,7 @@ case intersect:
@ @<Additional cases of bin...@>=
case in_font:
- if ( (mp->cur_type!=mp_string_type)||(mp_type(p)!=mp_string_type))
+ if ( (mp->cur_type!=mp_string_type)||mp_type(p)!=mp_string_type)
mp_bad_binary(mp, p,in_font);
else { mp_do_infont(mp, p); binary_return; }
break;
@@ -21712,16 +21899,42 @@ void mp_do_assignment (MP mp) {
@ @<Assign the current expression to an internal variable@>=
if ( mp->cur_type==mp_known || mp->cur_type==mp_string_type ) {
- if (mp->cur_type==mp_string_type)
- add_str_ref(mp->cur_exp);
- mp->internal[mp_info(lhs)-(hash_end)]=mp->cur_exp;
+ if (mp->int_type[mp_info(lhs)-(hash_end)]==mp_internal_type) {
+ mp->int_type[mp_info(lhs)-(hash_end)]=mp->cur_type;
+ }
+ if (mp->cur_type==mp_string_type) {
+ if (mp->int_type[mp_info(lhs)-(hash_end)]!=mp->cur_type) {
+ exp_err("Internal quantity `");
+@.Internal quantity...@>
+ mp_print(mp, mp->int_name[mp_info(lhs)-(hash_end)]);
+ mp_print(mp, "' must receive a known numeric value");
+ help2("I can\'t set this internal quantity to anything but a known",
+ "numeric value, so I'll have to ignore this assignment.");
+ mp_put_get_error(mp);
+ } else {
+ add_str_ref(mp->cur_exp);
+ mp->internal[mp_info(lhs)-(hash_end)]=mp->cur_exp;
+ }
+ } else { /* mp_known */
+ if (mp->int_type[mp_info(lhs)-(hash_end)]!=mp->cur_type) {
+ exp_err("Internal quantity `");
+@.Internal quantity...@>
+ mp_print(mp, mp->int_name[mp_info(lhs)-(hash_end)]);
+ mp_print(mp, "' must receive a known string");
+ help2("I can\'t set this internal quantity to anything but a known",
+ "string, so I'll have to ignore this assignment.");
+ mp_put_get_error(mp);
+ } else {
+ mp->internal[mp_info(lhs)-(hash_end)]=mp->cur_exp;
+ }
+ }
} else {
exp_err("Internal quantity `");
@.Internal quantity...@>
mp_print(mp, mp->int_name[mp_info(lhs)-(hash_end)]);
- mp_print(mp, "' must receive a known value");
- help2("I can\'t set an internal quantity to anything but a known",
- "numeric value, so I'll have to ignore this assignment.");
+ mp_print(mp, "' must receive a known numeric or string");
+ help2("I can\'t set an internal quantity to anything but a known string",
+ "or known numeric value, so I'll have to ignore this assignment.");
mp_put_get_error(mp);
}
@@ -22118,6 +22331,66 @@ int mp_run (MP mp) {
return mp->history;
}
+@ This function allows setting of internals from an external
+source (like the command line or a controlling application).
+
+It accepts two |char *|'s, even for numeric assignments when
+it calls |atoi| to get an integer from the start of the string.
+
+@c
+void mp_set_internal (MP mp, char *n, char *v, int isstring) {
+ integer l = strlen(n);
+ char err[256];
+ char *errid = NULL;
+ if (l>0) {
+ integer h = mp_compute_hash(mp, n,l);
+ pointer p = h+hash_base; /* we start searching here */
+ while (true) {
+ if (text(p)>0 && length(text(p))==l &&
+ mp_str_eq_cstr(mp, text(p),n)) {
+ if (eq_type(p)==internal_quantity) {
+ if (mp->int_type[equiv(p)]==mp_internal_type) {
+ mp->int_type[equiv(p)] = (isstring ? mp_string_type : mp_known);
+ }
+ if ((mp->int_type[equiv(p)]==mp_string_type) && (isstring)) {
+ mp->internal[equiv(p)] = mp_rts(mp,v);
+ } else if ((mp->int_type[equiv(p)]==mp_known) && (!isstring)) {
+ scaled test = (scaled)atoi(v);
+ if (test>16383 ) {
+ errid = "value is too large";
+ } else if (test<-16383) {
+ errid = "value is too small";
+ } else {
+ mp->internal[equiv(p)] = test*unity;
+ }
+ } else {
+ errid = "value has the wrong type";
+ }
+ } else {
+ errid = "variable is not an internal";
+ }
+ break;
+ }
+ if ( mp_next(p)==0 ) {
+ errid = "variable does not exist";
+ break;
+ }
+ p=mp_next(p);
+ }
+ }
+ if (errid != NULL) {
+ if (isstring) {
+ mp_snprintf(err,256,"%s=\"%s\": %s, assignment ignored.",n,v, errid);
+ } else {
+ mp_snprintf(err,256,"%s=%d: %s, assignment ignored.",n,atoi(v),errid);
+ }
+ mp_warn(mp,err);
+ }
+}
+
+@ @<Exported function headers@>=
+void mp_set_internal (MP mp, char *n, char *v, int isstring);
+
@ For |mp_execute|, we need to define a structure to store the
redirected input and output. This structure holds the five relevant
streams: the three informational output streams, the PostScript
@@ -22839,22 +23112,27 @@ void mp_grow_internals (MP mp, int l);
void mp_grow_internals (MP mp, int l) {
scaled *internal;
char * *int_name;
+ int *int_type;
int k;
if ( hash_end+l>max_halfword ) {
mp_confusion(mp, "out of memory space"); /* can't be reached */
}
int_name = xmalloc ((l+1),sizeof(char *));
+ int_type = xmalloc ((l+1),sizeof(int));
internal = xmalloc ((l+1),sizeof(scaled));
for (k=0;k<=l; k++ ) {
if (k<=mp->max_internal) {
internal[k]=mp->internal[k];
int_name[k]=mp->int_name[k];
+ int_type[k]=mp->int_type[k];
} else {
internal[k]=0;
int_name[k]=NULL;
+ int_type[k]=mp_internal_type;
}
}
- xfree(mp->internal); xfree(mp->int_name);
+ xfree(mp->internal); xfree(mp->int_name); xfree(mp->int_type);
+ mp->int_type = int_type;
mp->int_name = int_name;
mp->internal = internal;
mp->max_internal = l;
@@ -22882,6 +23160,7 @@ for (k=0;k<=mp->max_internal;k++) {
}
xfree(mp->internal);
xfree(mp->int_name);
+xfree(mp->int_type);
@ The various `\&{show}' commands are distinguished by modifier fields
@@ -23760,7 +24039,9 @@ mp->start_sym=0;
@d err_message_code 1
@d err_help_code 2
@d filename_template_code 3
-@d print_with_leading_zeroes(A) g = mp->pool_ptr;
+@d print_with_leading_zeroes(A,B) do {
+ integer g = mp->pool_ptr;
+ integer f = (B);
mp_print_int(mp, (A)); g = mp->pool_ptr-g;
if ( f>g ) {
mp->pool_ptr = mp->pool_ptr - g;
@@ -23770,7 +24051,8 @@ mp->start_sym=0;
};
mp_print_int(mp, (A));
};
- f = 0
+ f = 0;
+ } while (0)
@<Put each...@>=
mp_primitive(mp, "message",message_command,message_code);
@@ -25516,13 +25798,22 @@ etcetera to make it worthwile to move the code to |psout.w|.
void mp_open_output_file (MP mp) ;
@ @c
+static void mp_append_to_template (MP mp, integer ff, integer c) {
+ if (mp->int_type[c]==mp_string_type) {
+ char *ss = str(mp->internal[c]);
+ mp_print(mp,ss);
+ mp_xfree(ss);
+ } else if (mp->int_type[c]==mp_known) {
+ integer cc = mp_round_unscaled(mp, mp->internal[c]);
+ print_with_leading_zeroes(cc, ff);
+ }
+}
static char *mp_set_output_file_name (MP mp, integer c) {
char *ss = NULL; /* filename extension proposal */
char *nn = NULL; /* temp string for str() */
unsigned old_setting; /* previous |selector| setting */
pool_pointer i; /* indexes into |filename_template| */
- integer cc; /* a temporary integer for template building */
- integer f,g=0; /* field widths */
+ integer f; /* field width */
if ( mp->job_name==NULL ) mp_open_log_file(mp);
if ( mp->internal[mp_output_template]==0) {
char *s; /* a file extension derived from |c| */
@@ -25535,48 +25826,108 @@ static char *mp_set_output_file_name (MP mp, integer c) {
ss = xstrdup(mp->name_of_file);
} else { /* initializations */
str_number s, n; /* a file extension derived from |c| */
+ scaled saved_char_code = mp->internal[mp_char_code];
+ mp->internal[mp_char_code] = (c*unity);
+ if (mp->internal[mp_job_name]==0) {
+ if ( mp->job_name==NULL ) {
+ mp->job_name=xstrdup("mpout");
+ }
+ @<Fix up |mp->internal[mp_job_name]|@>;
+ }
old_setting=mp->selector;
mp->selector=new_string;
- f = 0;
i = mp->str_start[mp->internal[mp_output_template]];
n = null_str; /* initialize */
while ( i<str_stop(mp->internal[mp_output_template]) ) {
+ f=0;
if ( mp->str_pool[i]=='%' ) {
CONTINUE:
incr(i);
if ( i<str_stop(mp->internal[mp_output_template]) ) {
- if ( mp->str_pool[i]=='j' ) {
- mp_print(mp, mp->job_name);
- } else if ( mp->str_pool[i]=='o' ) {
- { char *s;
- s = str(mp->internal[mp_output_format]);
- mp_print(mp, s);
- mp_xfree(s);
- }
- } else if ( mp->str_pool[i]=='d' ) {
- cc= mp_round_unscaled(mp, mp->internal[mp_day]);
- print_with_leading_zeroes(cc);
- } else if ( mp->str_pool[i]=='m' ) {
- cc= mp_round_unscaled(mp, mp->internal[mp_month]);
- print_with_leading_zeroes(cc);
- } else if ( mp->str_pool[i]=='y' ) {
- cc= mp_round_unscaled(mp, mp->internal[mp_year]);
- print_with_leading_zeroes(cc);
- } else if ( mp->str_pool[i]=='H' ) {
- cc= mp_round_unscaled(mp, mp->internal[mp_time]) / 60;
- print_with_leading_zeroes(cc);
- } else if ( mp->str_pool[i]=='M' ) {
- cc= mp_round_unscaled(mp, mp->internal[mp_time]) % 60;
- print_with_leading_zeroes(cc);
- } else if ( mp->str_pool[i]=='c' ) {
- if ( c<0 ) mp_print(mp, "ps");
- else print_with_leading_zeroes(c);
- } else if ( (mp->str_pool[i]>='0') &&
- (mp->str_pool[i]<='9') ) {
+ switch (mp->str_pool[i]) {
+ case 'j':
+ mp_append_to_template(mp,f,mp_job_name);
+ break;
+ case 'c':
+ mp_append_to_template(mp,f,mp_char_code);
+ break;
+ case 'o':
+ mp_append_to_template(mp,f,mp_output_format);
+ break;
+ case 'd':
+ mp_append_to_template(mp,f,mp_day);
+ break;
+ case 'm':
+ mp_append_to_template(mp,f,mp_month);
+ break;
+ case 'y':
+ mp_append_to_template(mp,f,mp_year);
+ break;
+ case 'H':
+ mp_append_to_template(mp,f,mp_hour);
+ break;
+ case 'M':
+ mp_append_to_template(mp,f,mp_minute);
+ break;
+ case '{':
+ {
+ /* look up a name */
+ integer l=0;
+ integer frst = i+1;
+ while ( i<str_stop(mp->internal[mp_output_template]) ) {
+ i++;
+ if (mp->str_pool[i] == '}')
+ break;
+ l++;
+ }
+ if (l>0) {
+ integer h = mp_compute_hash(mp, (char *)(mp->str_pool+frst),l);
+ pointer p=h+hash_base; /* we start searching here */
+ char *id = xmalloc(mp, (l+1));
+ strncpy(id,(char *)(mp->str_pool+frst),l);
+ *(id+l)=0;
+ while (true) {
+ if (text(p)>0 && length(text(p))==l &&
+ mp_str_eq_cstr(mp, text(p),id)) {
+ if (eq_type(p)==internal_quantity) {
+ mp_append_to_template(mp,f,equiv(p));
+ } else {
+ char err[256];
+ mp_snprintf(err,256,
+ "requested identifier (%s) in outputtemplate is not an internal.",id);
+ mp_warn(mp,err);
+ }
+ break;
+ }
+ if ( mp_next(p)==0 ) {
+ char err[256];
+ mp_snprintf(err,256,
+ "requested identifier (%s) in outputtemplate not found.",id);
+ mp_warn(mp,err);
+ break;
+ }
+ p=mp_next(p);
+ }
+ free(id);
+ }
+ }
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
if ( (f<10) )
f = (f*10) + mp->str_pool[i]-'0';
goto CONTINUE;
- } else {
+ break;
+ case '%':
+ mp_print_str(mp, mp->str_pool[i]);
+ break;
+ default:
+ {
+ char err[256];
+ mp_snprintf(err,256,
+ "requested format (%c) in outputtemplate is unknown.",mp->str_pool[i]);
+ mp_warn(mp,err);
+ }
mp_print_str(mp, mp->str_pool[i]);
}
}
@@ -25589,6 +25940,7 @@ static char *mp_set_output_file_name (MP mp, integer c) {
incr(i);
}
s = mp_make_string(mp);
+ mp->internal[mp_char_code] = saved_char_code;
mp->selector= old_setting;
if (length(n)==0) {
n=s;
@@ -25597,7 +25949,7 @@ static char *mp_set_output_file_name (MP mp, integer c) {
ss = str(s);
nn = str(n);
mp_pack_file_name(mp, nn,"",ss);
- free(nn);
+ mp_xfree(nn);
delete_str_ref(n);
delete_str_ref(s);
}
@@ -25608,7 +25960,7 @@ static char * mp_get_output_file_name (MP mp) {
char *f;
char *saved_name; /* saved |name_of_file| */
saved_name = xstrdup(mp->name_of_file);
- f = xstrdup(mp_set_output_file_name(mp, mp_round_unscaled(mp, mp->internal[mp_char_code])));
+ f = mp_set_output_file_name(mp, mp_round_unscaled(mp, mp->internal[mp_char_code]));
mp_pack_file_name(mp, saved_name,NULL,NULL);
free(saved_name);
return f;
@@ -25920,8 +26272,56 @@ struct mp_edge_object *mp_gr_export(MP mp, pointer h) {
return hh;
}
+@ This function is only used for the |glyph| operator, so
+it takes quite a few shortcuts for cases that cannot appear
+in the output of |mp_ps_font_charstring|.
+
+@c
+pointer mp_gr_unexport(MP mp, struct mp_edge_object *hh) {
+ pointer h; /* the edge object */
+ pointer ph, pn; /* for adding items */
+ mp_graphic_object *p; /* the current graphical object */
+ h = mp_get_node(mp, edge_header_size);
+ mp_init_edges(mp, h);
+ ph = dummy_loc(h);
+ p = hh->body;
+ minx_val(h) = hh->minx;
+ miny_val(h) = hh->miny;
+ maxx_val(h) = hh->maxx;
+ maxy_val(h) = hh->maxy;
+ while ( p!=NULL ) {
+ switch (gr_type(p)) {
+ case mp_fill_code:
+ if ( gr_pen_p((mp_fill_object *)p)==NULL ) {
+ pn = mp_new_fill_node (mp, null);
+ mp_path_p(pn) = mp_import_knot_list(mp,gr_path_p((mp_fill_object *)p));
+ if (mp_new_turn_cycles(mp, mp_path_p(pn))<0) {
+ mp_color_model(pn)=mp_grey_model;
+ grey_val(pn) = unity;
+ }
+ mp_link(ph) = pn;
+ ph = mp_link(ph);
+ }
+ break;
+ case mp_stroked_code:
+ case mp_text_code:
+ case mp_start_clip_code:
+ case mp_stop_clip_code:
+ case mp_start_bounds_code:
+ case mp_stop_bounds_code:
+ case mp_special_code:
+ break;
+ } /* all cases are enumerated */
+ p=p->next;
+ }
+ mp_gr_toss_objects(hh);
+ return h;
+}
+
+
@ @<Declarations@>=
-static struct mp_edge_object *mp_gr_export(MP mp, int h);
+static struct mp_edge_object *mp_gr_export(MP mp, pointer h);
+static pointer mp_gr_unexport(MP mp, struct mp_edge_object *h);
@ This function is now nearly trivial.
@@ -25958,6 +26358,7 @@ void mp_shipout_backend (MP mp, pointer h) {
(mp->internal[mp_procset]/65536),
false);
}
+ mp_xfree(s);
mp_gr_toss_objects(hh);
}