diff options
Diffstat (limited to 'Build/source')
28 files changed, 7178 insertions, 494 deletions
diff --git a/Build/source/texk/web2c/Makefile.in b/Build/source/texk/web2c/Makefile.in index 4126f6b11da..c19bb3f6051 100644 --- a/Build/source/texk/web2c/Makefile.in +++ b/Build/source/texk/web2c/Makefile.in @@ -482,6 +482,7 @@ trap-clean: # # MetaPost kpse_include metapost.mk +kpse_include mpdir/mpostlib.mk # # TeX tex_c = texini.c tex0.c tex1.c tex2.c @@ -1116,7 +1117,7 @@ installcheck: # # Cleaning. -all_subdirs = doc lib man $(mpware) web2c window $(omegafonts) $(otps) $(pdftexdir) $(pdfetexdir) +all_subdirs = doc lib man $(mpware) web2c window $(omegafonts) $(otps) $(pdftexdir) $(pdfetexdir) $(mpostdir) # Having a multiple-target rule with the subdir loop fails because of # the dependencies introduced by clean.mk. Yet, we want the diff --git a/Build/source/texk/web2c/configure b/Build/source/texk/web2c/configure index 97a9ad58f0b..9c10be2cbd3 100755 --- a/Build/source/texk/web2c/configure +++ b/Build/source/texk/web2c/configure @@ -4943,7 +4943,7 @@ fi fi ac_config_files="$ac_config_files Makefile doc/Makefile lib/Makefile man/Makefile mpware/Makefile - web2c/Makefile window/Makefile" + mpdir/Makefile web2c/Makefile window/Makefile" ac_config_files="$ac_config_files fmtutil.cnf:fmtutil.in" diff --git a/Build/source/texk/web2c/configure.in b/Build/source/texk/web2c/configure.in index f00c3bdea6c..b350439f8d9 100644 --- a/Build/source/texk/web2c/configure.in +++ b/Build/source/texk/web2c/configure.in @@ -401,6 +401,6 @@ fi dnl Generate `Makefile's, `config.status', and our header file. KPSE_CONFIG_FILES([Makefile doc/Makefile lib/Makefile man/Makefile mpware/Makefile - web2c/Makefile window/Makefile]) + mpdir/Makefile web2c/Makefile window/Makefile]) AC_CONFIG_FILES([fmtutil.cnf:fmtutil.in]) AC_OUTPUT diff --git a/Build/source/texk/web2c/dvitomp.ch b/Build/source/texk/web2c/dvitomp.ch index aff411c0edd..99e2127f9e2 100644 --- a/Build/source/texk/web2c/dvitomp.ch +++ b/Build/source/texk/web2c/dvitomp.ch @@ -1,18 +1,7 @@ -% dvitomp.ch for C compilation with web2c. +% $Id: dvitomp.ch,v 1.7 2005/04/28 06:45:21 taco Exp $ +% dvitomp.ch for C compilation with web2c. Public domain. % -% Copyright 1990 - 1995 by AT&T Bell Laboratories. -% -% Permission to use, copy, modify, and distribute this software -% and its documentation for any purpose and without fee is hereby -% granted, provided that the above copyright notice appear in all -% copies and that both that the copyright notice and this -% permission notice and warranty disclaimer appear in supporting -% documentation, and that the names of AT&T Bell Laboratories or -% any of its entities not be used in advertising or publicity -% pertaining to distribution of the software without specific, -% written prior permission. -% -% Change file for the DVItype processor, for use with WEB to C +% Change file for the DVItoMP processor, for use with WEB to C % This file was created by John Hobby. It is loosely based on the % change file for the WEB to C version of dvitype (due to Howard % Trickey and Pavel Curtis). @@ -37,12 +26,12 @@ @z @x [1] Duplicate banner line for use in |print_version_and_exit|. -@d banner=='% Written by DVItoMP, Version 0.64' +@d banner=='% Written by DVItoMP, Version 0.99' {the first line of the output file} @y -@d banner=='% Written by DVItoMP, Version 0.64/color' +@d banner=='% Written by DVItoMP, Version 0.99/color' {the first line of the output file} -@d term_banner=='This is DVItoMP, Version 0.64/color' +@d term_banner=='This is DVItoMP, Version 0.99/color' {the same in the usual format, as it would be shown on a terminal} @z @@ -257,12 +246,6 @@ round(dvi_scale*font_scaled_size[cur_font]*char_width(cur_font)(p)-0.5) floor(dvi_scale*font_scaled_size[cur_font]*char_width(cur_font)(p)) @z -@x [57] Off-by-one error in virtual font handling. -info_ptr:=info_base[f]+font_ec[f] -@y -info_ptr:=info_base[f]+font_ec[f]+1 -@z - % [61] Don't set default_directory_name. @x @d default_directory_name=='TeXfonts:' {change this to the correct name} diff --git a/Build/source/texk/web2c/dvitomp.web b/Build/source/texk/web2c/dvitomp.web index c850ceb7f8f..4bb39349828 100644 --- a/Build/source/texk/web2c/dvitomp.web +++ b/Build/source/texk/web2c/dvitomp.web @@ -1,23 +1,5 @@ -% Copyright 1990 - 1995 by AT&T Bell Laboratories. - -% Permission to use, copy, modify, and distribute this software -% and its documentation for any purpose and without fee is hereby -% granted, provided that the above copyright notice appear in all -% copies and that both that the copyright notice and this -% permission notice and warranty disclaimer appear in supporting -% documentation, and that the names of AT&T Bell Laboratories or -% any of its entities not be used in advertising or publicity -% pertaining to distribution of the software without specific, -% written prior permission. - -% AT&T disclaims all warranties with regard to this software, -% including all implied warranties of merchantability and fitness. -% In no event shall AT&T be liable for any special, indirect or -% consequential damages or any damages whatsoever resulting from -% loss of use, data or profits, whether in an action of contract, -% negligence or other tortious action, arising out of or in -% connection with the use or performance of this software. - +% $Id: dvitomp.web,v 1.3 2005/04/28 06:45:21 taco Exp $ +% DVItoMP, by John Hobby. Public domain. % Version 0 was prepared (March 1990). % Version 0.1 implemented virtual fonts. (May 1990) @@ -83,7 +65,7 @@ an ``\.{MPX}'' file. The |banner| string defined here should be changed whenever \.{DVItoMP} gets modified. -@d banner=='% Written by DVItoMP, Version 0.64' +@d banner=='% Written by DVItoMP, Version 0.99' {the first line of the output file} @ This program is written in standard \PASCAL, except where it is necessary @@ -733,7 +715,7 @@ begin for k:=font_name[f] to font_name[f+1]-1 do end; @ When we encounter a font definition, we save the name, checksum, and size -information, but we don't actaully read the \.{TFM} or \.{VF} file until we +information, but we don't actually read the \.{TFM} or \.{VF} file until we are about to use the font. If a matching font is not already defined, we then allocate a new internal font number. @@ -780,7 +762,7 @@ if font_name[nf]+n>name_size then font_name[nf+1]:=font_name[nf]+n; for k:=font_name[nf] to font_name[nf+1]-1 do names[k]:=get_byte -@ The scaled size and design size are stored in \.{DVI} units divided by $2^20$. +@ The scaled size and design size are stored in \.{DVI} units divided by $2^{20}$. The units for scaled size are a little different if we are reading a virtual font, but this will be corrected when the scaled size is used. The scaled size also needs to be truncated to at most 23 significant bits in order to make @@ -819,7 +801,7 @@ while f<nf do begin @<Compare the names of fonts |f| and |ff|; |goto 99| if they differ@>; if exact then begin if abs(font_scaled_size[f]-font_scaled_size[ff]) - <= font_tolerance then + <= font_tolerance then begin if not vf_reading then if local_only[f] then begin font_num[f]:=font_num[ff]; local_only[f]:=false; @@ -1044,7 +1026,7 @@ worthwhile to slide everything down just to save a little space. @<Finish setting up the data structures for the new virtual font@>= fbase[f]:=vf_ptr+1; -info_ptr:=info_base[f]+font_ec[f] +info_ptr:=info_base[f]+font_ec[f]+1 @* Loading fonts. diff --git a/Build/source/texk/web2c/lib/texmfmp.c b/Build/source/texk/web2c/lib/texmfmp.c index 412d01f5cab..8d464a9a582 100644 --- a/Build/source/texk/web2c/lib/texmfmp.c +++ b/Build/source/texk/web2c/lib/texmfmp.c @@ -88,7 +88,7 @@ #define edit_var "MFEDIT" #endif /* MF */ #ifdef MP -#define BANNER "This is MetaPost, Version 0.901" +#define BANNER "This is MetaPost, Version 0.99" #define COPYRIGHT_HOLDER "AT&T Bell Laboratories" #define AUTHOR "John Hobby" #define PROGRAM_HELP MPHELP @@ -686,7 +686,7 @@ readtcxfile P1H(void) string line; unsigned line_count = 0; FILE *translate_file = xfopen (translate_filename, FOPEN_R_MODE); - while (line = read_line (translate_file)) { + while ((line = read_line (translate_file))) { int first; string start2; string comment_loc = strchr (line, '%'); diff --git a/Build/source/texk/web2c/metapost.mk b/Build/source/texk/web2c/metapost.mk index 1ea6157b228..0f3b9f164f1 100644 --- a/Build/source/texk/web2c/metapost.mk +++ b/Build/source/texk/web2c/metapost.mk @@ -7,7 +7,8 @@ Makefile: metapost.mk -mpost = mpost +metapost = mpost dvitomp +mpostdir = mpdir # mpware is the subdirectory. mpware = mpware @@ -17,10 +18,16 @@ mpware_sources = mpware/dmp.c mpware/makempx.in mpware/mpto.c mpware/newer.c # mpost mp_c = mpini.c mp0.c mp1.c mp2.c -mp_o = mpini.o mp0.o mp1.o mp2.o mpextra.o -mpost: $(mp_o) - $(kpathsea_link) $(mp_o) $(LOADLIBES) -$(mp_c) mpcoerce.h mpd.h: mp.p $(web2c_texmf) web2c/cvtmf1.sed web2c/cvtmf2.sed +mp_o = mpini.o mp0.o mp1.o mp2.o mpextra.o loadpool.o + +# this will break cross-compiles, but i dont know how to fix. +# -- Taco +loadpool.c: mp.pool $(mpostdir)/makecpool + ./$(mpostdir)/makecpool mp.pool mpdir/mplib.h > loadpool.c + +mpost: $(mp_o) $(mpostlibsdep) + $(kpathsea_link) $(mp_o) $(mpostlibs) $(LOADLIBES) +$(mp_c) mpcoerce.h mpd.h: mp.p $(web2c_texmf) $(srcdir)/$(mpostdir)/mp.defines web2c/cvtmf1.sed web2c/cvtmf2.sed $(web2c) mp mpextra.c: lib/texmfmp.c sed s/TEX-OR-MF-OR-MP/mp/ $(srcdir)/lib/texmfmp.c >$@ diff --git a/Build/source/texk/web2c/mp.ch b/Build/source/texk/web2c/mp.ch index dd4a9ce9a49..42efe2ba5db 100644 --- a/Build/source/texk/web2c/mp.ch +++ b/Build/source/texk/web2c/mp.ch @@ -1,4 +1,4 @@ -% $Id: mp.ch,v 1.50 2005/06/22 17:06:13 olaf Exp $ +% $Id: mp.ch,v 1.8 2005/03/18 19:49:05 taco Exp $ % mp.ch for C compilation with web2c. Public domain. % % Derived from mf.ch and John Hobby's mp.ch (the change file for the C @@ -551,51 +551,6 @@ end; not xprn[k] @z -% [4.66] Open the pool file using a path, and can't do string -% assignments directly. (`strcpy' and `strlen' work here because -% `pool_name' is a constant string, and thus ends in a null and doesn't -% start with a space.) -@x -name_of_file:=pool_name; {we needn't set |name_length|} -if a_open_in(pool_file) then -@y -name_length := strlen (pool_name); -name_of_file := xmalloc_array (ASCII_code, 1 + name_length); -strcpy (stringcast(name_of_file+1), pool_name); {copy the string} -if a_open_in (pool_file, kpse_mppool_format) then -@z - -@x [4.66,67,68] Make `MP.POOL' lowercase in messages. -else bad_pool('! I can''t read MP.POOL.') -@y -else bad_pool('! I can''t read ', pool_name, '; bad path?') -@z -@x -begin if eof(pool_file) then bad_pool('! MP.POOL has no check sum.'); -@.MP.POOL has no check sum@> -read(pool_file,m,n); {read two digits of string length} -@y -begin if eof(pool_file) then bad_pool('! ', pool_name, ' has no check sum.'); -@.MP.POOL has no check sum@> -read(pool_file,m); read(pool_file,n); {read two digits of string length} -@z -@x - bad_pool('! MP.POOL line doesn''t begin with two digits.'); -@y - bad_pool('! ', pool_name, ' line doesn''t begin with two digits.'); -@z -@x - bad_pool('! MP.POOL check sum doesn''t have nine digits.'); -@y - bad_pool('! ', pool_name, ' check sum doesn''t have nine digits.'); -@z -@x -done: if a<>@$ then bad_pool('! MP.POOL doesn''t match; TANGLE me again.'); -@y -done: if a<>@$ then - bad_pool('! ', pool_name, ' doesn''t match; tangle me again (or fix the path).'); -@z - @x [5.69] error_line is a variable, so can't be a subrange array bound @!trick_buf:array[0..error_line] of ASCII_code; {circular buffer for @y @@ -1819,12 +1774,13 @@ dump_int(@"57324D50); {Web2C \MP's magic constant: "W2MP"} {Align engine to 4 bytes with one or more trailing NUL} x:=strlen(engine_name); base_engine:=xmalloc_array(text_char,x+4); -strcpy(base_engine, engine_name); +strcpy(stringcast(base_engine), engine_name); for k:=x to x+3 do base_engine[k]:=0; x:=x+4-(x mod 4); dump_int(x);dump_things(base_engine[0], x); libc_free(base_engine);@/ dump_int(@$);@/ +dump_int(main_memory);@/ @<Dump |xord|, |xchr|, and |xprn|@>; @z @@ -1843,7 +1799,7 @@ if (x<0) or (x>256) then goto off_base; {corrupted base file} base_engine:=xmalloc_array(text_char, x); undump_things(base_engine[0], x); base_engine[x-1]:=0; {force string termination, just in case} -if strcmp(engine_name, base_engine) then +if strcmp(engine_name, stringcast(base_engine)) then begin wake_up_terminal; wterm_ln('---! ', stringcast(name_of_file+1), ' was written by ', base_engine); libc_free(base_engine); @@ -1853,9 +1809,11 @@ libc_free(base_engine); undump_int(x); if x<>@$ then begin {check that strings are the same} wake_up_terminal; - wterm_ln('---! ', stringcast(name_of_file+1), ' doesn''t match ', pool_name); + wterm_ln('---! ', stringcast(name_of_file+1), ' doesn''t match pool strings'); goto off_base; end; +undump_int(x); +if x<>main_memory then goto off_base; @<Undump |xord|, |xchr|, and |xprn|@>; undump_int(x); if x<>mem_min then goto off_base; @@ -2003,7 +1961,10 @@ end; history:=spotless; {ready to go!} @y history:=spotless; {ready to go!} -if troff_mode then @+internal[prologues]:=unity; +if troff_mode then begin + internal[troffmode]:=unity; + internal[prologues]:=unity; +end; @z @x [46.1298] Call do_final_end. diff --git a/Build/source/texk/web2c/mp.web b/Build/source/texk/web2c/mp.web index 93481bc1598..1b159920d05 100644 --- a/Build/source/texk/web2c/mp.web +++ b/Build/source/texk/web2c/mp.web @@ -1,4 +1,4 @@ -% $Id: mp.web,v 1.5 2005/06/22 17:06:28 olaf Exp $ +% $Id: mp.web,v 1.8 2005/08/24 10:54:02 taco Exp $ % MetaPost, by John Hobby. Public domain. % Much of this program was copied with permission from MF.web Version 1.9 @@ -97,8 +97,8 @@ undergoes any modifications, so that it will be clear which version of @^extensions to \MP@> @^system dependencies@> -@d banner=='This is MetaPost, Version 0.901' {printed when \MP\ starts} -@d metapost_version=="0.901" +@d banner=='This is MetaPost, Version 0.980' {printed when \MP\ starts} +@d metapost_version=="0.980" @ Different \PASCAL s have slightly different conventions, and the present @!@:PASCAL H}{\ph@> @@ -401,6 +401,7 @@ because some fussy \PASCAL\ compilers will complain about redundant labels. @d found=40 {go here when you've found it} @d found1=41 {like |found|, when there's more than one per routine} @d found2=42 {like |found|, when there's more than two per routine} +@d found3=43 {like |found|, when there's more than three per routine} @d not_found=45 {go here when you've found nothing} @d common_ending=50 {go here when you want to merge with another branch} @@ -1423,63 +1424,21 @@ length followed by the string itself, and the information is recorded in @!init @!pool_file:alpha_file; {the string-pool file output by \.{TANGLE}} tini -@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#); - a_close(pool_file); get_strings_started:=false; return; - end -@<Read the other strings...@>= -name_of_file:=pool_name; {we needn't set |name_length|} -if a_open_in(pool_file) then - begin c:=false; - repeat @<Read one string, but return |false| if the - string memory space is getting too tight for comfort@>; - until c; - a_close(pool_file); get_strings_started:=true; - end -else bad_pool('! I can''t read MP.POOL.') -@.I can't read MP.POOL@> - -@ @<Read one string...@>= -begin if eof(pool_file) then bad_pool('! MP.POOL has no check sum.'); -@.MP.POOL has no check sum@> -read(pool_file,m,n); {read two digits of string length} -if m='*' then @<Check the pool check sum@> -else begin if (xord[m]<"0")or(xord[m]>"9")or@| - (xord[n]<"0")or(xord[n]>"9") then - bad_pool('! MP.POOL line doesn''t begin with two digits.'); -@.MP.POOL line doesn't...@> - l:=xord[m]*10+xord[n]-"0"*11; {compute the length} - if pool_ptr+l+string_vacancies>pool_size then - bad_pool('! You have to increase POOLSIZE.'); -@.You have to increase POOLSIZE@> - if str_ptr+strings_vacant>=max_strings then - bad_pool('! You have to increase MAXSTRINGS.'); -@.You have to increase MAXSTRINGS@> - for k:=1 to l do - begin if eoln(pool_file) then m:=' '@+else read(pool_file,m); - append_char(xord[m]); - end; - read_ln(pool_file); g:=make_string; str_ref[g]:=max_str_ref; +@ @<Read the other strings...@>= + g := loadpoolstrings((pool_size-string_vacancies)); + if g=0 then begin + wake_up_terminal; write_ln(term_out,'! You have to increase POOLSIZE.'); + get_strings_started:=false; + return; end; -end + get_strings_started:=true; + @ The \.{WEB} operation \.{@@\$} denotes the value that should be at the end of this \.{MP.POOL} file; any other value means that the wrong pool file has been loaded. @^check sum@> -@<Check the pool check sum@>= -begin a:=0; k:=1; -loop@+ begin if (xord[n]<"0")or(xord[n]>"9") then - bad_pool('! MP.POOL check sum doesn''t have nine digits.'); -@.MP.POOL check sum...@> - a:=10*a+xord[n]-"0"; - if k=9 then goto done; - incr(k); read(pool_file,n); - end; -done: if a<>@$ then bad_pool('! MP.POOL doesn''t match; TANGLE me again.'); -@.MP.POOL doesn't match@> -c:=true; -end @* \[5] On-line and off-line printing. Messages that are sent to a user's terminal and to the transcript-log file @@ -1626,8 +1585,13 @@ log_only: begin wlog(xchr[s]); incr(file_offset); term_only: begin wterm(xchr[s]); incr(term_offset); if term_offset=max_print_line then print_ln; end; -ps_file_only: begin wps(xchr[s]); incr(ps_offset); - end; +ps_file_only: if s=13 then begin + wps_cr; ps_offset:=0; + end + else + begin + wps(xchr[s]); incr(ps_offset); + end; no_print: do_nothing; pseudo: if tally<trick_count then trick_buf[tally mod error_line]:=s; new_string: begin if pool_ptr>=max_pool_ptr then @@ -1907,9 +1871,10 @@ in reverse order, i.e., with |help_line[0]| appearing last. @!help_ptr:0..6; {the number of help lines present} @!use_err_help:boolean; {should the |err_help| string be shown?} @!err_help:str_number; {a string set up by \&{errhelp}} +@!filename_template:str_number; {a string set up by \&{filenametemplate}} @ @<Set init...@>= -help_ptr:=0; use_err_help:=false; err_help:=0; +help_ptr:=0; use_err_help:=false; err_help:=0; filename_template:=0; @ The |jump_out| procedure just cuts across all active procedure levels and goes to |end_of_MP|. This is the only nonlocal |@!goto| statement in the @@ -3982,7 +3947,8 @@ At any rate, here is the list, for future reference. @d message_command=27 {communicate to user (\&{message}, \&{errmessage})} @d every_job_command=28 {designate a starting token (\&{everyjob})} @d delimiters=29 {define a pair of delimiters (\&{delimiters})} -@d special_command=30 {output special info (\&{special})} +@d special_command=30 {output special info (\&{special}) + or font map info (\&{fontmapfile}, \&{fontmapline})} @d write_command=31 {write text to a file (\&{write})} @d type_name=32 {declare a type (\&{numeric}, \&{pair}, etc.} @d max_statement_command=type_name @@ -4083,16 +4049,17 @@ and |string_type| in that order. @d unknown_picture=picture_type+unknown_tag @d transform_type=12 {\&{transform} variable or capsule} @d color_type=13 {\&{color} variable or capsule} -@d pair_type=14 {\&{pair} variable or capsule} -@d numeric_type=15 {variable that has been declared \&{numeric} but not used} -@d known=16 {\&{numeric} with a known value} -@d dependent=17 {a linear combination with |fraction| coefficients} -@d proto_dependent=18 {a linear combination with |scaled| coefficients} -@d independent=19 {\&{numeric} with unknown value} -@d token_list=20 {variable name or suffix argument or text argument} -@d structured=21 {variable with subscripts and attributes} -@d unsuffixed_macro=22 {variable defined with \&{vardef} but no \.{\AT!\#}} -@d suffixed_macro=23 {variable defined with \&{vardef} and \.{\AT!\#}} +@d cmykcolor_type=14 {\&{cmykcolor} variable or capsule} +@d pair_type=15 {\&{pair} variable or capsule} +@d numeric_type=16 {variable that has been declared \&{numeric} but not used} +@d known=17 {\&{numeric} with a known value} +@d dependent=18 {a linear combination with |fraction| coefficients} +@d proto_dependent=19 {a linear combination with |scaled| coefficients} +@d independent=20 {\&{numeric} with unknown value} +@d token_list=21 {variable name or suffix argument or text argument} +@d structured=22 {variable with subscripts and attributes} +@d unsuffixed_macro=23 {variable defined with \&{vardef} but no \.{\AT!\#}} +@d suffixed_macro=24 {variable defined with \&{vardef} and \.{\AT!\#}} @# @d unknown_types==unknown_boolean,unknown_string, unknown_pen,unknown_picture,unknown_path @@ -4113,6 +4080,7 @@ picture_type:print("picture"); unknown_picture:print("unknown picture"); transform_type:print("transform"); color_type:print("color"); +cmykcolor_type:print("cmykcolor"); pair_type:print("pair"); known:print("known numeric"); dependent:print("dependent"); @@ -4145,8 +4113,13 @@ here; they will be explained in more detail later. @d red_part_sector=11 {|name_type| in the \&{redpart} of a node} @d green_part_sector=12 {|name_type| in the \&{greenpart} of a node} @d blue_part_sector=13 {|name_type| in the \&{bluepart} of a node} -@d capsule=14 {|name_type| in stashed-away subexpressions} -@d token=15 {|name_type| in a numeric token or string token} +@d cyan_part_sector=14 {|name_type| in the \&{redpart} of a node} +@d magenta_part_sector=15 {|name_type| in the \&{greenpart} of a node} +@d yellow_part_sector=16 {|name_type| in the \&{bluepart} of a node} +@d black_part_sector=17 {|name_type| in the \&{greenpart} of a node} +@d grey_part_sector=18 {|name_type| in the \&{bluepart} of a node} +@d capsule=19 {|name_type| in stashed-away subexpressions} +@d token=20 {|name_type| in a numeric token or string token} @ Primitive operations that produce values have a secondary identification code in addition to their command code; it's something like genera and species. @@ -4185,77 +4158,83 @@ values they test for. @d char_op=51 {operation code for \.{char}} @d length_op=52 {operation code for \.{length}} @d turning_op=53 {operation code for \.{turningnumber}} -@d x_part=54 {operation code for \.{xpart}} -@d y_part=55 {operation code for \.{ypart}} -@d xx_part=56 {operation code for \.{xxpart}} -@d xy_part=57 {operation code for \.{xypart}} -@d yx_part=58 {operation code for \.{yxpart}} -@d yy_part=59 {operation code for \.{yypart}} -@d red_part=60 {operation code for \.{redpart}} -@d green_part=61 {operation code for \.{greenpart}} -@d blue_part=62 {operation code for \.{bluepart}} -@d font_part=63 {operation code for \.{fontpart}} -@d text_part=64 {operation code for \.{textpart}} -@d path_part=65 {operation code for \.{pathpart}} -@d pen_part=66 {operation code for \.{penpart}} -@d dash_part=67 {operation code for \.{dashpart}} -@d sqrt_op=68 {operation code for \.{sqrt}} -@d m_exp_op=69 {operation code for \.{mexp}} -@d m_log_op=70 {operation code for \.{mlog}} -@d sin_d_op=71 {operation code for \.{sind}} -@d cos_d_op=72 {operation code for \.{cosd}} -@d floor_op=73 {operation code for \.{floor}} -@d uniform_deviate=74 {operation code for \.{uniformdeviate}} -@d char_exists_op=75 {operation code for \.{charexists}} -@d font_size=76 {operation code for \.{fontsize}} -@d ll_corner_op=77 {operation code for \.{llcorner}} -@d lr_corner_op=78 {operation code for \.{lrcorner}} -@d ul_corner_op=79 {operation code for \.{ulcorner}} -@d ur_corner_op=80 {operation code for \.{urcorner}} -@d arc_length=81 {operation code for \.{arclength}} -@d angle_op=82 {operation code for \.{angle}} -@d cycle_op=83 {operation code for \.{cycle}} -@d filled_op=84 {operation code for \.{filled}} -@d stroked_op=85 {operation code for \.{stroked}} -@d textual_op=86 {operation code for \.{textual}} -@d clipped_op=87 {operation code for \.{clipped}} -@d bounded_op=88 {operation code for \.{bounded}} -@d plus=89 {operation code for \.+} -@d minus=90 {operation code for \.-} -@d times=91 {operation code for \.*} -@d over=92 {operation code for \./} -@d pythag_add=93 {operation code for \.{++}} -@d pythag_sub=94 {operation code for \.{+-+}} -@d or_op=95 {operation code for \.{or}} -@d and_op=96 {operation code for \.{and}} -@d less_than=97 {operation code for \.<} -@d less_or_equal=98 {operation code for \.{<=}} -@d greater_than=99 {operation code for \.>} -@d greater_or_equal=100 {operation code for \.{>=}} -@d equal_to=101 {operation code for \.=} -@d unequal_to=102 {operation code for \.{<>}} -@d concatenate=103 {operation code for \.\&} -@d rotated_by=104 {operation code for \.{rotated}} -@d slanted_by=105 {operation code for \.{slanted}} -@d scaled_by=106 {operation code for \.{scaled}} -@d shifted_by=107 {operation code for \.{shifted}} -@d transformed_by=108 {operation code for \.{transformed}} -@d x_scaled=109 {operation code for \.{xscaled}} -@d y_scaled=110 {operation code for \.{yscaled}} -@d z_scaled=111 {operation code for \.{zscaled}} -@d in_font=112 {operation code for \.{infont}} -@d intersect=113 {operation code for \.{intersectiontimes}} -@d double_dot=114 {operation code for improper \.{..}} -@d substring_of=115 {operation code for \.{substring}} +@d color_model_part=54 {operation code for \.{colormodel}} +@d x_part=55 {operation code for \.{xpart}} +@d y_part=56 {operation code for \.{ypart}} +@d xx_part=57 {operation code for \.{xxpart}} +@d xy_part=58 {operation code for \.{xypart}} +@d yx_part=59 {operation code for \.{yxpart}} +@d yy_part=60 {operation code for \.{yypart}} +@d red_part=61 {operation code for \.{redpart}} +@d green_part=62 {operation code for \.{greenpart}} +@d blue_part=63 {operation code for \.{bluepart}} +@d cyan_part=64 {operation code for \.{cyanpart}} +@d magenta_part=65 {operation code for \.{magentapart}} +@d yellow_part=66 {operation code for \.{yellowpart}} +@d black_part=67 {operation code for \.{blackpart}} +@d grey_part=68 {operation code for \.{greypart}} +@d font_part=69 {operation code for \.{fontpart}} +@d text_part=70 {operation code for \.{textpart}} +@d path_part=71 {operation code for \.{pathpart}} +@d pen_part=72 {operation code for \.{penpart}} +@d dash_part=73 {operation code for \.{dashpart}} +@d sqrt_op=74 {operation code for \.{sqrt}} +@d m_exp_op=75 {operation code for \.{mexp}} +@d m_log_op=76 {operation code for \.{mlog}} +@d sin_d_op=77 {operation code for \.{sind}} +@d cos_d_op=78 {operation code for \.{cosd}} +@d floor_op=79 {operation code for \.{floor}} +@d uniform_deviate=80 {operation code for \.{uniformdeviate}} +@d char_exists_op=81 {operation code for \.{charexists}} +@d font_size=82 {operation code for \.{fontsize}} +@d ll_corner_op=83 {operation code for \.{llcorner}} +@d lr_corner_op=84 {operation code for \.{lrcorner}} +@d ul_corner_op=85 {operation code for \.{ulcorner}} +@d ur_corner_op=86 {operation code for \.{urcorner}} +@d arc_length=87 {operation code for \.{arclength}} +@d angle_op=88 {operation code for \.{angle}} +@d cycle_op=89 {operation code for \.{cycle}} +@d filled_op=90 {operation code for \.{filled}} +@d stroked_op=91 {operation code for \.{stroked}} +@d textual_op=92 {operation code for \.{textual}} +@d clipped_op=93 {operation code for \.{clipped}} +@d bounded_op=94 {operation code for \.{bounded}} +@d plus=95 {operation code for \.+} +@d minus=96 {operation code for \.-} +@d times=97 {operation code for \.*} +@d over=98 {operation code for \./} +@d pythag_add=99 {operation code for \.{++}} +@d pythag_sub=100 {operation code for \.{+-+}} +@d or_op=101 {operation code for \.{or}} +@d and_op=102 {operation code for \.{and}} +@d less_than=103 {operation code for \.<} +@d less_or_equal=104 {operation code for \.{<=}} +@d greater_than=105 {operation code for \.>} +@d greater_or_equal=106 {operation code for \.{>=}} +@d equal_to=107 {operation code for \.=} +@d unequal_to=108 {operation code for \.{<>}} +@d concatenate=109 {operation code for \.\&} +@d rotated_by=110 {operation code for \.{rotated}} +@d slanted_by=111 {operation code for \.{slanted}} +@d scaled_by=112 {operation code for \.{scaled}} +@d shifted_by=113 {operation code for \.{shifted}} +@d transformed_by=114 {operation code for \.{transformed}} +@d x_scaled=115 {operation code for \.{xscaled}} +@d y_scaled=116 {operation code for \.{yscaled}} +@d z_scaled=117 {operation code for \.{zscaled}} +@d in_font=118 {operation code for \.{infont}} +@d intersect=119 {operation code for \.{intersectiontimes}} +@d double_dot=120 {operation code for improper \.{..}} +@d substring_of=121 {operation code for \.{substring}} @d min_of=substring_of -@d subpath_of=116 {operation code for \.{subpath}} -@d direction_time_of=117 {operation code for \.{directiontime}} -@d point_of=118 {operation code for \.{point}} -@d precontrol_of=119 {operation code for \.{precontrol}} -@d postcontrol_of=120 {operation code for \.{postcontrol}} -@d pen_offset_of=121 {operation code for \.{penoffset}} -@d arc_time_of=122 {operation code for \.{arctime}} -@d mp_version=123 {operation code for \.{mpversion}} +@d subpath_of=122 {operation code for \.{subpath}} +@d direction_time_of=123 {operation code for \.{directiontime}} +@d point_of=124 {operation code for \.{point}} +@d precontrol_of=125 {operation code for \.{precontrol}} +@d postcontrol_of=126 {operation code for \.{postcontrol}} +@d pen_offset_of=127 {operation code for \.{penoffset}} +@d arc_time_of=128 {operation code for \.{arctime}} +@d mp_version=129 {operation code for \.{mpversion}} @p procedure print_op(@!c:quarterword); begin if c<=numeric_type then print_type(c) @@ -4293,6 +4272,12 @@ yy_part:print("yypart"); red_part:print("redpart"); green_part:print("greenpart"); blue_part:print("bluepart"); +cyan_part:print("cyanpart"); +magenta_part:print("magentapart"); +yellow_part:print("yellowpart"); +black_part:print("blackpart"); +grey_part:print("greypart"); +color_model_part:print("colormodel"); font_part:print("fontpart"); text_part:print("textpart"); path_part:print("pathpart"); @@ -4393,7 +4378,10 @@ fuss with. Every such parameter has an identifying code number, defined here. @d boundary_char=31 {the right boundary character for ligatures} @d prologues=32 {positive to output conforming PostScript using built-in fonts} @d true_corners=33 {positive to make \&{llcorner} etc. ignore \&{setbounds}} -@d max_given_internal=33 +@d default_color_model=34 {the default color model for unspecified items} +@d restore_clip_color=35 +@d mpprocset=36 {wether or not create PostScript command shortcuts} +@d max_given_internal=36 @<Glob...@>= @!internal:array[1..max_internal] of scaled; @@ -4479,6 +4467,34 @@ primitive("prologues",internal_quantity,prologues);@/ @!@:prologues_}{\&{prologues} primitive@> primitive("truecorners",internal_quantity,true_corners);@/ @!@:true_corners_}{\&{truecorners} primitive@> +primitive("mpprocset",internal_quantity,mpprocset);@/ +@!@:mpprocset_}{\&{mpprocset} primitive@> +primitive("defaultcolormodel",internal_quantity,default_color_model);@/ +@!@:default_color_model_}{\&{defaultcolormodel} primitive@> +primitive("restoreclipcolor",internal_quantity,restore_clip_color);@/ +@!@:restore_clip_color_}{\&{restoreclipcolor} primitive@> + +@ Colors can be specified in four color models. In the special +case of |no_model|, MetaPost does not output any color operator to +the postscript output. + +Note: these values are passed directly on to |with_option|. This only +works because the other possible values passed to |with_option| are +8 and 10 respectively (from |with_pen| and |with_picture|). + +There is a first state, that is only used for |gs_colormodel|. It flags +the fact that there has not been any kind of color specification by +the user so far in the game. + +@d no_model=1 +@d grey_model=3 +@d rgb_model=5 +@d cmyk_model=7 +@d uninitialized_model=9 + +@<Initialize table entries (done by \.{INIMP} only)@>= +internal[default_color_model]:=(rgb_model*unity); +internal[restore_clip_color]:=unity; @ Well, we do have to list the names one more time, for use in symbolic printouts. @@ -4517,6 +4533,9 @@ int_name[warning_check]:="warningcheck"; int_name[boundary_char]:="boundarychar"; int_name[prologues]:="prologues"; int_name[true_corners]:="truecorners"; +int_name[default_color_model]:="defaultcolormodel"; +int_name[mpprocset]:="mpprocset"; +int_name[restore_clip_color]:="restoreclipcolor"; @ The following procedure, which is called just before \MP\ initializes its input and output, establishes the initial values of the date and time. @@ -4891,6 +4910,10 @@ primitive("skipto",skip_to,0);@/ @!@:skip_to_}{\&{skipto} primitive@> primitive("special",special_command,0); @!@:special}{\&{special} primitive@> +primitive("fontmapfile",special_command,1); +@!@:fontmapfile}{\&{fontmapfile} primitive@> +primitive("fontmapline",special_command,2); +@!@:fontmapline}{\&{fontmapline} primitive@> primitive("step",step_token,0);@/ @!@:step_}{\&{step} primitive@> primitive("str",str_op,0);@/ @@ -4944,7 +4967,9 @@ scan_tokens:print("scantokens"); semicolon:print(";"); ship_out_command:print("shipout"); skip_to:print("skipto"); -special_command: print("special"); +special_command: if m=2 then print("fontmapline") else + if m=1 then print("fontmapfile") else + print("special"); step_token:print("step"); str_op:print("str"); tension:print("tension"); @@ -5031,7 +5056,7 @@ begin while p<>null do vacuous,boolean_type,known:do_nothing; string_type:delete_str_ref(value(q)); unknown_types,pen_type,path_type,picture_type,pair_type,color_type, - transform_type,dependent,proto_dependent,independent: + cmykcolor_type,transform_type,dependent,proto_dependent,independent: begin g_pointer:=q; token_recycle; end; othercases confusion("token") @@ -5411,15 +5436,21 @@ while expressions are being evaluated. We call them {\sl capsules}. @d red_part_loc(#)==# {where the \&{redpart} is found in a color node} @d green_part_loc(#)==#+2 {where the \&{greenpart} is found in a color node} @d blue_part_loc(#)==#+4 {where the \&{bluepart} is found in a color node} +@d cyan_part_loc(#)==# {where the \&{cyanpart} is found in a color node} +@d magenta_part_loc(#)==#+2 {where the \&{magentapart} is found in a color node} +@d yellow_part_loc(#)==#+4 {where the \&{yellowpart} is found in a color node} +@d black_part_loc(#)==#+6 {where the \&{blackpart} is found in a color node} +@d grey_part_loc(#)==# {where the \&{greypart} is found in a color node} @# @d pair_node_size=4 {the number of words in a pair node} @d transform_node_size=12 {the number of words in a transform node} @d color_node_size=6 {the number of words in a color node} +@d cmykcolor_node_size=8 {the number of words in a color node} @<Glob...@>= @!big_node_size:array[transform_type..pair_type] of small_number; @!sector0:array[transform_type..pair_type] of small_number; -@!sector_offset:array[x_part_sector..blue_part_sector] of small_number; +@!sector_offset:array[x_part_sector..black_part_sector] of small_number; @ The |sector0| array gives for each big node type, |name_type| values for its first subfield; the |sector_offset| array gives for each @@ -5431,13 +5462,17 @@ big node. big_node_size[transform_type]:=transform_node_size; big_node_size[pair_type]:=pair_node_size; big_node_size[color_type]:=color_node_size; +big_node_size[cmykcolor_type]:=cmykcolor_node_size; sector0[transform_type]:=x_part_sector; sector0[pair_type]:=x_part_sector; sector0[color_type]:=red_part_sector; +sector0[cmykcolor_type]:=cyan_part_sector; for k:=x_part_sector to yy_part_sector do sector_offset[k]:=2*(k-x_part_sector); for k:=red_part_sector to blue_part_sector do sector_offset[k]:=2*(k-red_part_sector); +for k:=cyan_part_sector to black_part_sector do + sector_offset[k]:=2*(k-cyan_part_sector); @ If |type(p)=pair_type| or |transform_type| and if |value(p)=null|, the procedure call |init_big_node(p)| will allocate a pair or transform node @@ -5528,6 +5563,11 @@ yy_part_sector: print("yy"); red_part_sector: print("red"); green_part_sector: print("green"); blue_part_sector: print("blue"); +cyan_part_sector: print("cyan"); +magenta_part_sector: print("magenta"); +yellow_part_sector: print("yellow"); +black_part_sector: print("black"); +grey_part_sector: print("grey"); capsule: begin print("%CAPSULE"); print_int(p-null); return; @.CAPSULE@> end; @@ -5796,7 +5836,8 @@ string_type,unknown_string:und_type:=unknown_string; pen_type,unknown_pen:und_type:=unknown_pen; path_type,unknown_path:und_type:=unknown_path; picture_type,unknown_picture:und_type:=unknown_picture; -transform_type,color_type,pair_type,numeric_type:und_type:=type(p); +transform_type,color_type,cmykcolor_type, +pair_type,numeric_type:und_type:=type(p); known,dependent,proto_dependent,independent:und_type:=numeric_type; end; {there are no other cases} end; @@ -8001,8 +8042,8 @@ two such objects overlap, but it suffices to draw the first one first and let the second one overwrite it if necessary. @ Let's consider the types of graphical objects one at a time. -First of all, a filled contour is represented by a six-word node. The first -word contains |type| and |link| fields, and the next four words contain a +First of all, a filled contour is represented by a eight-word node. The first +word contains |type| and |link| fields, and the next six words contain a pointer to a cyclic path and the value to use for \ps' \&{currentrgbcolor} parameter. If a pen is used for filling |pen_p|, |ljoin_val| and |miterlim_val| give the relevant information. @@ -8011,20 +8052,31 @@ give the relevant information. {a pointer to the path that needs filling} @d pen_p(#)==info(#+1) {a pointer to the pen to fill or stroke with} -@d obj_red_loc(#)==#+2 {the first of three locations for the color} -@d red_val(#)==mem[#+2].sc +@d color_model(#)==type(#+2) { the color model } +@d obj_red_loc(#)==#+3 {the first of three locations for the color} +@d obj_cyan_loc==obj_red_loc {the first of four locations for the color} +@d obj_grey_loc==obj_red_loc {the location for the color} +@d red_val(#)==mem[#+3].sc {the red component of the color in the range $0\ldots1$} -@d green_val(#)==mem[#+3].sc +@d cyan_val==red_val +@d grey_val==red_val +@d green_val(#)==mem[#+4].sc {the green component of the color in the range $0\ldots1$} -@d blue_val(#)==mem[#+4].sc +@d magenta_val==green_val +@d blue_val(#)==mem[#+5].sc + {the blue component of the color in the range $0\ldots1$} +@d yellow_val==blue_val +@d black_val(#)==mem[#+6].sc {the blue component of the color in the range $0\ldots1$} @d ljoin_val(#)==name_type(#) {the value of \&{linejoin}} @:linejoin_}{\&{linejoin} primitive@> -@d miterlim_val(#)==mem[#+5].sc {the value of \&{miterlimit}} +@d miterlim_val(#)==mem[#+7].sc {the value of \&{miterlimit}} @:miterlimit_}{\&{miterlimit} primitive@> -@d obj_color_part(#)==mem[#+2-red_part].sc +@d obj_color_part(#)==mem[#+3-red_part].sc {interpret an object pointer that has been offset by |red_part..blue_part|} -@d fill_node_size=6 +@d pre_script(#)==mem[#+8].hh.lh +@d post_script(#)==mem[#+8].hh.rh +@d fill_node_size=9 @d fill_code=1 @p function new_fill_node(@!p: pointer): pointer; @@ -8037,6 +8089,10 @@ begin t:=get_node(fill_node_size); red_val(t):=0; green_val(t):=0; blue_val(t):=0; + black_val(t):=0; + color_model(t):=uninitialized_model; + pre_script(t):=null; + post_script(t):=null; @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>; new_fill_node:=t; end; @@ -8055,13 +8111,13 @@ factor for the dash pattern, and a pointer that is non-null if the stroke is to be dashed. The purpose of the scale factor is to allow a picture to be transformed without touching the picture that |dash_p| points to. -@d dash_p(#)==link(#+6) +@d dash_p(#)==link(#+9) {a pointer to the edge structure that gives the dash pattern} -@d lcap_val(#)==type(#+6) +@d lcap_val(#)==type(#+9) {the value of \&{linecap}} @:linecap_}{\&{linecap} primitive@> -@d dash_scale(#)==mem[#+7].sc {dash lengths are scaled by this factor} -@d stroked_node_size=8 +@d dash_scale(#)==mem[#+10].sc {dash lengths are scaled by this factor} +@d stroked_node_size=11 @d stroked_code=2 @p function new_stroked_node(@!p:pointer): pointer; @@ -8075,6 +8131,10 @@ begin t:=get_node(stroked_node_size); red_val(t):=0; green_val(t):=0; blue_val(t):=0; + black_val(t):=0; + color_model(t):=uninitialized_model; + pre_script(t):=null; + post_script(t):=null; @<Set the |ljoin_val| and |miterlim_val| fields in object |t|@>; if internal[linecap]>unity then lcap_val(t):=2 else if internal[linecap]>0 then lcap_val(t):=1 @@ -8129,20 +8189,20 @@ black with its reference point at the origin. @d text_p(#)==link(#+1) {a string pointer for the text to display} @d font_n(#)==info(#+1) {the font number} -@d width_val(#)==mem[#+5].sc {unscaled width of the text} -@d height_val(#)==mem[#+6].sc {unscaled height of the text} -@d depth_val(#)==mem[#+7].sc {unscaled depth of the text} -@d text_tx_loc(#)==#+8 +@d width_val(#)==mem[#+7].sc {unscaled width of the text} +@d height_val(#)==mem[#+9].sc {unscaled height of the text} +@d depth_val(#)==mem[#+10].sc {unscaled depth of the text} +@d text_tx_loc(#)==#+11 {the first of six locations for transformation parameters} -@d tx_val(#)==mem[#+8].sc {$x$ shift amount} -@d ty_val(#)==mem[#+9].sc {$y$ shift amount} -@d txx_val(#)==mem[#+10].sc {|txx| transformation parameter} -@d txy_val(#)==mem[#+11].sc {|txy| transformation parameter} -@d tyx_val(#)==mem[#+12].sc {|tyx| transformation parameter} -@d tyy_val(#)==mem[#+13].sc {|tyy| transformation parameter} -@d text_trans_part(#)==mem[#+8-x_part].sc +@d tx_val(#)==mem[#+11].sc {$x$ shift amount} +@d ty_val(#)==mem[#+12].sc {$y$ shift amount} +@d txx_val(#)==mem[#+13].sc {|txx| transformation parameter} +@d txy_val(#)==mem[#+14].sc {|txy| transformation parameter} +@d tyx_val(#)==mem[#+15].sc {|tyx| transformation parameter} +@d tyy_val(#)==mem[#+16].sc {|tyy| transformation parameter} +@d text_trans_part(#)==mem[#+11-x_part].sc {interpret a text node ponter that has been offset by |x_part..yy_part|} -@d text_node_size=14 +@d text_node_size=17 @d text_code=3 @p @<Declare text measuring subroutines@>@; @@ -8156,6 +8216,10 @@ begin t:=get_node(text_node_size); red_val(t):=0; green_val(t):=0; blue_val(t):=0; + black_val(t):=0; + color_model(t):=uninitialized_model; + pre_script(t):=null; + post_script(t):=null; tx_val(t):=0; ty_val(t):=0; txx_val(t):=unity; txy_val(t):=0; tyx_val(t):=0; tyy_val(t):=unity; @@ -8348,12 +8412,20 @@ end; case type(p) of fill_code: begin toss_knot_list(path_p(p)); if pen_p(p)<>null then toss_knot_list(pen_p(p)); + if pre_script(p)<>null then delete_str_ref(pre_script(p)); + if post_script(p)<>null then delete_str_ref(post_script(p)); end; stroked_code: begin toss_knot_list(path_p(p)); if pen_p(p)<>null then toss_knot_list(pen_p(p)); + if pre_script(p)<>null then delete_str_ref(pre_script(p)); + if post_script(p)<>null then delete_str_ref(post_script(p)); e:=dash_p(p); end; -text_code: delete_str_ref(text_p(p)); +text_code: begin + delete_str_ref(text_p(p)); + if pre_script(p)<>null then delete_str_ref(pre_script(p)); + if post_script(p)<>null then delete_str_ref(post_script(p)); + end; start_clip_code,start_bounds_code: toss_knot_list(path_p(p)); stop_clip_code,stop_bounds_code: do_nothing; end; {there are no other cases} @@ -8545,10 +8617,21 @@ black (the default color). @<Declare subroutines needed by |print_edges|@>= @<Declare a procedure called |print_compact_node|@>@; procedure print_obj_color(@!p:pointer); -begin if (red_val(p)>0) or (green_val(p)>0) or (blue_val(p)>0) then - begin print("colored "); - print_compact_node(obj_red_loc(p),3); - end; +begin if color_model(p)=grey_model then + if grey_val(p)>0 then + begin print("greyed "); + print_compact_node(obj_grey_loc(p),1); + end + else if color_model(p)=cmyk_model then + if (cyan_val(p)>0) or (magenta_val(p)>0) or (yellow_val(p)>0) or (black_val(p)>0) then + begin print("colored "); + print_compact_node(obj_cyan_loc(p),4); + end + else if color_model(p)=rgb_model then + if (red_val(p)>0) or (green_val(p)>0) or (blue_val(p)>0) then + begin print("processcolored "); + print_compact_node(obj_red_loc(p),3); + end; end; @ We also need a procedure for printing consecutive scaled values as if they @@ -8751,7 +8834,7 @@ if (x_coord(pp)>x0) or (x0>x3) then @!x0,@!x1,@!x2,@!x3:scaled; {$x$ coordinates of the segment from |qq| to |rr|} @ @<Make sure |p| and |p0| are the same color and |goto not_found|...@>= -if (red_val(p)<>red_val(p0)) or@| +if (red_val(p)<>red_val(p0)) or (black_val(p)<>black_val(p0)) or@| (green_val(p)<>green_val(p0)) or (blue_val(p)<>blue_val(p0)) then begin print_err("Picture is too complicated to use as a dash pattern"); help3("When you say `dashed p', everything in picture p should")@/ @@ -9895,9 +9978,9 @@ link(spec_p2):=link(spec_p1); link(spec_p1):=c;@/ remove_cubic(spec_p1); c:=spec_p1; -if c<>link(c) then begin -originator(spec_p2):=program_code; -remove_cubic(spec_p2); +if c<>link(c) then begin +originator(spec_p2):=program_code; +remove_cubic(spec_p2); end else @<Make |c| look like a cycle of length one@>; end @@ -14687,6 +14770,12 @@ points to a color node that contains three numeric values, each of which is |independent|, |dependent|, |proto_dependent|, or |known|. \smallskip\hang +|cur_type=cmykcolor_type| means that |cur_exp| points to a |cmykcolor_type| +capsule node. The |value| part of this capsule +points to a color node that contains four numeric values, +each of which is |independent|, |dependent|, |proto_dependent|, or |known|. + +\smallskip\hang |cur_type=pair_type| means that |cur_exp| points to a capsule node whose type is |pair_type|. The |value| part of this capsule points to a pair node that contains two numeric values, @@ -14763,7 +14852,7 @@ function stash_cur_exp:pointer; var @!p:pointer; {the capsule that will be returned} begin case cur_type of unknown_types,transform_type,color_type,pair_type,dependent,proto_dependent, - independent:p:=cur_exp; + independent,cmykcolor_type:p:=cur_exp; othercases begin p:=get_node(value_node_size); name_type(p):=capsule; type(p):=cur_type; value(p):=cur_exp; end @@ -14796,7 +14885,7 @@ procedure unstash_cur_exp(@!p:pointer); begin cur_type:=type(p); case cur_type of unknown_types,transform_type,color_type,pair_type,dependent,proto_dependent, - independent: cur_exp:=p; + independent,cmykcolor_type: cur_exp:=p; othercases begin cur_exp:=value(p); free_node(p,value_node_size); end @@ -14838,7 +14927,7 @@ unknown_types,numeric_type:@<Display a variable string_type:begin print_char(""""); print(v); print_char(""""); end; pen_type,path_type,picture_type:@<Display a complex type@>; -transform_type,color_type,pair_type:if v=null then print_type(t) +transform_type,color_type,pair_type,cmykcolor_type:if v=null then print_type(t) else @<Display a big node@>; known:print_scaled(v); dependent,proto_dependent:print_dp(t,v,verbosity); @@ -14925,7 +15014,7 @@ because |cur_exp| will not contain a pointer value. procedure flush_cur_exp(@!v:scaled); begin case cur_type of unknown_types,transform_type,color_type,pair_type,@| - dependent,proto_dependent,independent: + dependent,proto_dependent,independent,cmykcolor_type: begin recycle_value(cur_exp); free_node(cur_exp,value_node_size); end; string_type:delete_str_ref(cur_exp); @@ -14954,7 +15043,7 @@ unknown_types:ring_delete(p); string_type:delete_str_ref(v); path_type,pen_type:toss_knot_list(v); picture_type:delete_edge_ref(v); -pair_type,color_type,transform_type:@<Recycle a big node@>; +cmykcolor_type,pair_type,color_type,transform_type:@<Recycle a big node@>; dependent,proto_dependent:@<Recycle a dependency list@>; independent:@<Recycle an independent variable@>; token_list,structured:confusion("recycle"); @@ -15255,7 +15344,7 @@ if interrupt<>0 then if OK_to_interrupt then @ @<Scan a delimited primary@>= begin l_delim:=cur_sym; r_delim:=cur_mod; get_x_next; scan_expression; if (cur_cmd=comma) and (cur_type>=known) then - @<Scan the rest of a pair or triplet of numerics@> + @<Scan the rest of a delimited set of numerics@> else check_delimiter(l_delim,r_delim); end @@ -15295,7 +15384,7 @@ end @ This code uses the fact that |red_part_loc| and |green_part_loc| are synonymous with |x_part_loc| and |y_part_loc|. -@<Scan the rest of a pair or triplet of numerics@>= +@<Scan the rest of a delimited set of numerics@>= begin p:=stash_cur_exp; get_x_next; scan_expression; @<Make sure the second part of a pair or color has a numeric type@>; @@ -15307,6 +15396,19 @@ stash_in(y_part_loc(r)); unstash_cur_exp(p); stash_in(x_part_loc(r)); if cur_cmd=comma then @<Scan the last of a triplet of numerics@>; +if cur_cmd=comma then begin + type(q):=cmykcolor_type; + init_big_node(q); t:=value(q); + mem[cyan_part_loc(t)]:=mem[red_part_loc(r)]; + value(cyan_part_loc(t)):=value(red_part_loc(r)); + mem[magenta_part_loc(t)]:=mem[green_part_loc(r)]; + value(magenta_part_loc(t)):=value(green_part_loc(r)); + mem[yellow_part_loc(t)]:=mem[blue_part_loc(r)]; + value(yellow_part_loc(t)):=value(blue_part_loc(r)); + recycle_value(r); + r:=t; + @<Scan the last of a quartet of numerics@>; + end; check_delimiter(l_delim,r_delim); cur_type:=type(q); cur_exp:=q; @@ -15326,16 +15428,29 @@ if cur_type<known then @ @<Scan the last of a triplet of numerics@>= begin get_x_next; scan_expression; if cur_type<known then - begin exp_err("Nonnumeric bluepart has been replaced by 0"); + begin exp_err("Nonnumeric third part has been replaced by 0"); @.Nonnumeric...replaced by 0@> - help3("I've just scanned a color `(r,g,b)'; but the `b' isn't")@/ + help3("I've just scanned a color `(a,b,c)' or cmykcolor(a,b,c,d); but the `c' isn't")@/ ("of numeric type. So I've changed that part to zero.")@/ - ("(The b that I didn't like appears above the error message.)");@/ + ("(The c that I didn't like appears above the error message.)");@/ put_get_flush_error(0); end; stash_in(blue_part_loc(r)); end +@ @<Scan the last of a quartet of numerics@>= +begin get_x_next; scan_expression; +if cur_type<known then + begin exp_err("Nonnumeric blackpart has been replaced by 0"); +@.Nonnumeric...replaced by 0@> + help3("I've just scanned a cmykcolor `(c,m,y,k)'; but the `k' isn't")@/ + ("of numeric type. So I've changed that part to zero.")@/ + ("(The k that I didn't like appears above the error message.)");@/ + put_get_flush_error(0); + end; +stash_in(black_part_loc(r)); +end + @ The local variable |group_line| keeps track of the line where a \&{begingroup} command occurred; this will be useful in an error message if the group doesn't actually end. @@ -15674,7 +15789,7 @@ picture_type:begin cur_exp:=value(p);add_edge_ref(cur_exp); end; pen_type:cur_exp:=copy_pen(value(p)); path_type:cur_exp:=copy_path(value(p)); -transform_type,color_type,pair_type:@<Copy the big node |p|@>; +transform_type,color_type,cmykcolor_type,pair_type:@<Copy the big node |p|@>; dependent,proto_dependent:encapsulate(copy_dep_list(dep_list(p))); numeric_type:begin new_indep(p); goto restart; end; @@ -16369,6 +16484,18 @@ primitive("greenpart",unary,green_part);@/ @!@:green_part_}{\&{greenpart} primitive@> primitive("bluepart",unary,blue_part);@/ @!@:blue_part_}{\&{bluepart} primitive@> +primitive("cyanpart",unary,cyan_part);@/ +@!@:cyan_part_}{\&{cyanpart} primitive@> +primitive("magentapart",unary,magenta_part);@/ +@!@:magenta_part_}{\&{magentapart} primitive@> +primitive("yellowpart",unary,yellow_part);@/ +@!@:yellow_part_}{\&{yellowpart} primitive@> +primitive("blackpart",unary,black_part);@/ +@!@:black_part_}{\&{blackpart} primitive@> +primitive("greypart",unary,grey_part);@/ +@!@:grey_part_}{\&{greypart} primitive@> +primitive("colormodel",unary,color_model_part);@/ +@!@:color_model_part_}{\&{colormodel} primitive@> primitive("fontpart",unary,font_part);@/ @!@:font_part_}{\&{fontpart} primitive@> primitive("textpart",unary,text_part);@/ @@ -16580,7 +16707,7 @@ fully known colors. function nice_color_or_pair(@!p:integer;@!t:quarterword):boolean; label exit; var @!q,@!r:pointer; {for scanning the big node} -begin if (t<>pair_type)and(t<>color_type) then +begin if (t<>pair_type)and(t<>color_type)and(t<>cmykcolor_type) then nice_color_or_pair:=false else begin q:=value(p); r:=q+big_node_size[type(p)]; @@ -16597,7 +16724,7 @@ exit:end; procedure print_known_or_unknown_type(@!t:small_number;@!v:integer); begin print_char("("); if t>known then print("unknown numeric") -else begin if (t=pair_type)or(t=color_type) then +else begin if (t=pair_type)or(t=color_type)or(t=cmykcolor_type) then if not nice_color_or_pair(v,t) then print("unknown "); print_type(t); end; @@ -16636,7 +16763,8 @@ and recycling it afterwards (cf.~the |stash_in| routine). @<Negate the current expression@>= case cur_type of -color_type,pair_type,independent: begin q:=cur_exp; make_exp_copy(q); +color_type,cmykcolor_type,pair_type,independent: begin + q:=cur_exp; make_exp_copy(q); if cur_type=dependent then negate_dep_list(dep_list(cur_exp)) else if cur_type<=pair_type then {|color_type| or |pair_type|} begin p:=value(cur_exp); @@ -16717,6 +16845,14 @@ xx_part,xy_part,yx_part,yy_part: if cur_type=transform_type then take_part(c) red_part,green_part,blue_part: if cur_type=color_type then take_part(c) else if cur_type=picture_type then take_pict_part(c) else bad_unary(c); +cyan_part,magenta_part,yellow_part,black_part: if cur_type=cmykcolor_type + then take_part(c) else if cur_type=picture_type then take_pict_part(c) + else bad_unary(c); +grey_part: if cur_type=known then cur_exp:=value(c) + else if cur_type=picture_type then take_pict_part(c) + else bad_unary(c); +color_model_part: if cur_type=picture_type then take_pict_part(c) + else bad_unary(c); @ In the following procedure, |cur_exp| points to a capsule, which points to a big node. We want to delete all but one part of the big node. @@ -16752,6 +16888,24 @@ if p<>null then red_part,green_part,blue_part: if has_color(p) then flush_cur_exp(obj_color_part(p+c)) else goto not_found; + cyan_part,magenta_part,yellow_part,black_part: + if has_color(p) then + if color_model(p)=uninitialized_model then + flush_cur_exp(unity) + else + flush_cur_exp(obj_color_part(p+c+(red_part-cyan_part))) + else goto not_found; + grey_part: + if has_color(p) then + flush_cur_exp(obj_color_part(p+c+(red_part-grey_part))) + else goto not_found; + color_model_part: + if has_color(p) then + if color_model(p)=uninitialized_model then + flush_cur_exp(internal[default_color_model]) + else + flush_cur_exp(color_model(p)*unity) + else goto not_found; @<Handle other cases in |take_pict_part| or |goto not_found|@>@; end; {all cases have been enumerated} return; @@ -16930,10 +17084,7 @@ if p<>null then found:pict_length:=n; end; -@ The turning number is computed only with respect to a triangular pen whose -@:turning_number_}{\&{turningnumber} primitive@> -vertices are $(0,1)$ and $(\pm{1\over2},0)$. The choice of pen isn't supposed -to matter but rounding error could make a difference if the path has a cusp. +@ Implement |turningnumber| @<Additional cases of unary...@>= turning_op:if cur_type=pair_type then flush_cur_exp(0) @@ -16944,36 +17095,8 @@ turning_op:if cur_type=pair_type then flush_cur_exp(0) flush_cur_exp(turn_cycles(cur_exp)); end; - -@ This code is based on Bogus\l{}av Jackowski's -|emergency_turningnumber| macro, with some minor changes by Taco -Hoekwater. The macro code looked more like this: -{\obeylines -vardef turning\_number primary p = -~~save res, ang, turns; -~~res := 0; -~~if length p <= 2: -~~~~if Angle ((point 0 of p) - (postcontrol 0 of p)) >= 0: 1 else: -1 fi -~~else: -~~~~for t = 0 upto length p-1 : -~~~~~~angc := Angle ((point t+1 of p) - (point t of p)) -~~~~~~~~- Angle ((point t of p) - (point t-1 of p)); -~~~~~~if angc > 180: angc := angc - 360; fi; -~~~~~~if angc < -180: angc := angc + 360; fi; -~~~~~~res := res + angc; -~~~~endfor; -~~res/360 -~~fi -enddef;} -The general idea is to calculate only the sum of the angles of straight lines between -the points, of a path, not worrying about cusps or self-intersections in the segments -at all. If the segment is not well-behaved, the result is not necesarily correct. But -the old code was not always correct either, and worse, it sometimes failed for well-behaved -paths as well. All known bugs that were triggered by the original code no longer occur -with this code, and it runs roughly 3 times as fast because the algorithm is much simpler. - -@ The macro |Angle()| returns the value of the |angle| primitive, or $0$ if the argument is -|origin|. Converting that calling convention to web code gives the |an_angle| function. +@ The function |an_angle| returns the value of the |angle| primitive, or $0$ if the +argument is |origin|. @<Declare unary action...@>= function an_angle (@!xpar,@!ypar:scaled):angle; @@ -16985,42 +17108,63 @@ begin end; -@ It is possible to overflow the return value of the |turn_cycles| -function when the path is sufficiently long and winding, but I am not -going to bother testing for that. In any case, it would only return -the looped result value, which is not a big problem. +@ The actual turning number is (for the moment) computed in a C function +that receives eight integers corresponding to the four controlling points, +and returns a single angle. Besides those, we have to account for discrete +moves at the actual points. -The macro code for the repeat loop was a bit nicer to look -at than the pascal code, because it could use |point -1 of p|. In -pascal, the fastest way to loop around the path is not to look -backward once, but forward twice. These defines help hide the trick. +@d p_nextnext==link(link(p)) +@d p_next==link(p) -@d p_to==link(link(p)) -@d p_here==link(p) -@d p_from==p +@d seven_twenty_deg==@'5500000000 {$720\cdot2^{20}$, represents $720^\circ$} @<Declare unary action...@>= function turn_cycles (@!c:pointer):scaled; +label exit; var @!res,ang:angle; { the angles of intermediate results } @!turns:scaled; { the turn counter } @!p:pointer; { for running around the path } -begin res:=0; turns:= 0; p:=c; -if ((link(p) = p) or (link(link(p)) = p)) then +@!xp,yp:integer; { coordinates of next point } +@!x,y:integer; { helper coordinates } +@!in_angle,out_angle:angle; { helper angles} +begin +res:=0; +turns:= 0; +p:=c; +if (p_next=p)or(p_nextnext=p) then if an_angle (x_coord(p) - right_x(p), y_coord(p) - right_y(p)) >= 0 then turn_cycles := unity else turn_cycles := -unity else begin repeat - ang := an_angle (x_coord(p_to) - x_coord(p_here), y_coord(p_to) - y_coord(p_here)) - - an_angle (x_coord(p_here) - x_coord(p_from), y_coord(p_here) - y_coord(p_from)); - reduce_angle(ang); + xp := x_coord(p_next); yp := y_coord(p_next); + ang := bezier_slope(x_coord(p), y_coord(p), right_x(p), right_y(p), + left_x(p_next), left_y(p_next), xp, yp); + if ang>seven_twenty_deg then begin + print_err("Strange path"); + error; + turn_cycles := 0; + return; + end; + res := res + ang; + { incoming angle at next point } + x := left_x(p_next); y := left_y(p_next); + if (xp=x)and(yp=y) then begin x := right_x(p); y := right_y(p); end; + if (xp=x)and(yp=y) then begin x := x_coord(p); y := y_coord(p); end; + in_angle := an_angle(xp - x, yp - y); + { outgoing angle at next point } + x := right_x(p_next); y := right_y(p_next); + if (xp=x)and(yp=y) then begin x := left_x(p_nextnext); y := left_y(p_nextnext); end; + if (xp=x)and(yp=y) then begin x := x_coord(p_nextnext); y := y_coord(p_nextnext); end; + out_angle := an_angle(x - xp, y- yp); + ang := (out_angle - in_angle); res := res + ang; - if res >= three_sixty_deg then begin + while res >= three_sixty_deg do begin res := res - three_sixty_deg; turns := turns + unity; end; - if res <= -three_sixty_deg then begin + while res <= -three_sixty_deg do begin res := res + three_sixty_deg; turns := turns - unity; end; @@ -17028,17 +17172,7 @@ else begin until p=c; turn_cycles := turns; end; -end; - -@ @<Declare unary action...@>= -function count_turns(@!c:pointer):scaled; -var @!p:pointer; {a knot in envelope spec |c|} -@!t:integer; {total pen offset changes counted} -begin t:=0; p:=c; -repeat t:=t+info(p)-zero_off; -p:=link(p); -until p=c; -count_turns:=(t div 3)*unity; +exit: end; @ @d type_test_end== flush_cur_exp(true_code) @@ -17055,7 +17189,7 @@ string_type: type_range(string_type)(unknown_string); pen_type: type_range(pen_type)(unknown_pen); path_type: type_range(path_type)(unknown_path); picture_type: type_range(picture_type)(unknown_picture); -transform_type,color_type,pair_type: type_test(c); +transform_type,color_type,cmykcolor_type,pair_type: type_test(c); numeric_type: type_range(known)(independent); known_op,unknown_op: test_known(c); @@ -17068,7 +17202,7 @@ begin b:=false_code; case cur_type of vacuous,boolean_type,string_type,pen_type,path_type,picture_type, known: b:=true_code; -transform_type,color_type,pair_type:begin p:=value(cur_exp); +transform_type,color_type,cmykcolor_type,pair_type:begin p:=value(cur_exp); q:=p+big_node_size[cur_type]; repeat q:=q-2; if type(q)<>known then goto done; @@ -17322,7 +17456,7 @@ that returns |null| if and only if its argument is not tarnished. @<Sidestep |independent| cases in capsule |p|@>= case type(p) of -transform_type,color_type,pair_type: old_p:=tarnished(p); +transform_type,color_type,cmykcolor_type,pair_type: old_p:=tarnished(p); independent: old_p:=void; othercases old_p:=null endcases; @@ -17333,7 +17467,8 @@ if old_p<>null then @ @<Sidestep |independent| cases in the current expression@>= case cur_type of -transform_type,color_type,pair_type:old_exp:=tarnished(cur_exp); +transform_type,color_type,cmykcolor_type, +pair_type:old_exp:=tarnished(cur_exp); independent:old_exp:=void; othercases old_exp:=null endcases; @@ -17561,7 +17696,8 @@ begin if type(p)=known then else begin v:=cur_exp; unstash_cur_exp(p); end; if cur_type=known then cur_exp:=take_scaled(cur_exp,v) -else if (cur_type=pair_type)or(cur_type=color_type) then +else if (cur_type=pair_type)or(cur_type=color_type)or + (cur_type=cmykcolor_type) then begin p:=value(cur_exp)+big_node_size[cur_type]; repeat p:=p-2; dep_mult(p,v,true); @@ -17599,7 +17735,7 @@ var @!p:pointer; {a pair node} begin if internal[tracing_commands]>two then @<Trace the fraction multiplication@>; case cur_type of -transform_type,color_type,pair_type:old_exp:=tarnished(cur_exp); +transform_type,color_type,cmykcolor_type,pair_type:old_exp:=tarnished(cur_exp); independent:old_exp:=void; othercases old_exp:=null endcases; @@ -18646,7 +18782,8 @@ unknown_types:if cur_type=t-unknown_tag then else if cur_type=pair_type then if t=unknown_path then begin pair_to_path; goto restart; end; -transform_type,color_type,pair_type:if cur_type=t then +transform_type,color_type,cmykcolor_type, +pair_type:if cur_type=t then @<Do multiple equations and |goto done|@>; known,dependent,proto_dependent,independent:if cur_type>=known then begin try_eq(lhs,null); goto done; @@ -18833,6 +18970,10 @@ primitive("transform",type_name,transform_type);@/ @!@:transform_}{\&{transform} primitive@> primitive("color",type_name,color_type);@/ @!@:color_}{\&{color} primitive@> +primitive("rgbcolor",type_name,color_type);@/ +@!@:color_}{\&{rgbcolor} primitive@> +primitive("cmykcolor",type_name,cmykcolor_type);@/ +@!@:color_}{\&{cmykcolor} primitive@> primitive("pair",type_name,pair_type);@/ @!@:pair_}{\&{pair} primitive@> @@ -19323,6 +19464,11 @@ end; @d contour_code=1 {command modifier for `\&{contour}'} @d also_code=2 {command modifier for `\&{also}'} +@ Pre and postscripts need two new identifiers: + +@d with_pre_script=11 +@d with_post_script=13 + @<Put each...@>= primitive("doublepath",thing_to_add,double_path_code);@/ @!@:double_path_}{\&{doublepath} primitive@> @@ -19334,15 +19480,34 @@ primitive("withpen",with_option,pen_type);@/ @!@:with_pen_}{\&{withpen} primitive@> primitive("dashed",with_option,picture_type);@/ @!@:dashed_}{\&{dashed} primitive@> -primitive("withcolor",with_option,color_type);@/ +primitive("withprescript",with_option,with_pre_script);@/ +@!@:with_pre_script_}{\&{withprescript} primitive@> +primitive("withpostscript",with_option,with_post_script);@/ +@!@:with_post_script_}{\&{withpostscript} primitive@> +primitive("withoutcolor",with_option,no_model);@/ +@!@:with_color_}{\&{withoutcolor} primitive@> +primitive("withgreyscale",with_option,grey_model);@/ +@!@:with_color_}{\&{withgreyscale} primitive@> +primitive("withcolor",with_option,uninitialized_model);@/ @!@:with_color_}{\&{withcolor} primitive@> +{ \&{withrgbcolor} is an alias for \&{withcolor}} +primitive("withrgbcolor",with_option,rgb_model);@/ +@!@:with_color_}{\&{withrgbcolor} primitive@> +primitive("withcmykcolor",with_option,cmyk_model);@/ +@!@:with_color_}{\&{withcmykcolor} primitive@> @ @<Cases of |print_cmd...@>= thing_to_add:if m=contour_code then print("contour") else if m=double_path_code then print("doublepath") else print("also"); with_option:if m=pen_type then print("withpen") - else if m=color_type then print("withcolor") + else if m=with_pre_script then print("withprescript") + else if m=with_post_script then print("withpostscript") + else if m=no_model then print("withoutcolor") + else if m=rgb_model then print("withrgbcolor") + else if m=uninitialized_model then print("withcolor") + else if m=cmyk_model then print("withcmykcolor") + else if m=grey_model then print("withgreyscale") else print("dashed"); @ The |scan_with_list| procedure parses a $\langle$with list$\rangle$ and @@ -19355,18 +19520,55 @@ procedure scan_with_list(@!p:pointer); label done, done1, done2; var @!t:small_number; {|cur_mod| of the |with_option| (should match |cur_type|)} @!q:pointer; {for list manipulation} -@!cp,@!pp,@!dp:pointer; +@!old_setting:0..max_selector; {saved |selector| setting} +@!k:pointer; {for finding the near-last item in a list } +@!s:str_number; {for string cleanup after combining } +@!cp,@!pp,@!dp,@!ap,@!bp:pointer; {objects being updated; |void| initially; |null| to suppress update} -begin cp:=void; pp:=void; dp:=void; +begin cp:=void; pp:=void; dp:=void; ap:=void; bp:=void; while cur_cmd=with_option do - begin t:=cur_mod; get_x_next; scan_expression; - if cur_type<>t then @<Complain about improper type@> - else if t=color_type then + begin t:=cur_mod; + get_x_next; + if t<>no_model then scan_expression; + if ((t=with_pre_script)and(cur_type<>string_type))or + ((t=with_post_script)and(cur_type<>string_type))or + ((t=uninitialized_model)and + ((cur_type<>cmykcolor_type)and(cur_type<>color_type) + and(cur_type<>known)and(cur_type<>boolean_type)))or + ((t=cmyk_model)and(cur_type<>cmykcolor_type))or + ((t=rgb_model)and(cur_type<>color_type))or + ((t=grey_model)and(cur_type<>known))or + ((t=pen_type)and(cur_type<>t))or + ((t=picture_type)and(cur_type<>t)) then @<Complain about improper type@> + else if t=uninitialized_model then begin if cp=void then @<Make |cp| a colored object in object list~|p|@>; if cp<>null then @<Transfer a color from the current expression to object~|cp|@>; flush_cur_exp(0); end + else if t=rgb_model then + begin if cp=void then @<Make |cp| a rgb colored object in object list~|p|@>; + if cp<>null then + @<Transfer a rgbcolor from the current expression to object~|cp|@>; + flush_cur_exp(0); + end + else if t=cmyk_model then + begin if cp=void then @<Make |cp| a cmyk colored object in object list~|p|@>; + if cp<>null then + @<Transfer a cmykcolor from the current expression to object~|cp|@>; + flush_cur_exp(0); + end + else if t=grey_model then + begin if cp=void then @<Make |cp| a grey colored object in object list~|p|@>; + if cp<>null then + @<Transfer a greyscale from the current expression to object~|cp|@>; + flush_cur_exp(0); + end + else if t=no_model then + begin if cp=void then @<Make |cp| a no colored object in object list~|p|@>; + if cp<>null then + @<Transfer a noncolor from the current expression to object~|cp|@>; + end else if t=pen_type then begin if pp=void then @<Make |pp| an object in list~|p| that needs a pen@>; @@ -19375,6 +19577,54 @@ while cur_cmd=with_option do pen_p(pp):=cur_exp; cur_type:=vacuous; end; end + else if t=with_pre_script then + begin if ap=void then + ap:=p; + while (ap<>null)and(not has_color(ap)) do + ap:=link(ap); + if ap<>null then + begin if pre_script(ap)<>null then begin { build a new,combined string } + s:=pre_script(ap); + old_setting:=selector; + selector:=new_string; + str_room(length(pre_script(ap))+length(cur_exp)+2); + print(cur_exp); + append_char(13); {a forced \ps\ newline } + print(pre_script(ap)); + pre_script(ap):=make_string; + delete_str_ref(s); + selector:=old_setting; + end + else + pre_script(ap):=cur_exp; + cur_type:=vacuous; + end; + end + else if t=with_post_script then + begin if bp=void then + k:=p; bp:=k; + while link(k)<>null do begin + k:=link(k); + if has_color(k) then bp:=k; + end; + if bp<>null then + begin if post_script(bp)<>null then begin + s:=post_script(bp); + old_setting:=selector; + selector:=new_string; + str_room(length(post_script(bp))+length(cur_exp)+2); + print(post_script(bp)); + append_char(13); {a forced \ps\ newline } + print(cur_exp); + post_script(bp):=make_string; + delete_str_ref(s); + selector:=old_setting; + end + else + post_script(bp):=cur_exp; + cur_type:=vacuous; + end; + end else begin if dp=void then @<Make |dp| a stroked node in list~|p|@>; if dp<>null then begin if dash_p(dp)<>null then delete_edge_ref(dash_p(dp)); @@ -19393,10 +19643,20 @@ begin exp_err("Improper type"); @.Improper type@> help2("Next time say `withpen <known pen expression>';")@/ ("I'll ignore the bad `with' clause and look for another."); -if t=picture_type then +if t=with_pre_script then + help_line[1]:="Next time say `withprescript <known string expression>';" +else if t=with_post_script then + help_line[1]:="Next time say `withpostscript <known string expression>';" +else if t=picture_type then help_line[1]:="Next time say `dashed <known picture expression>';" -else if t=color_type then - help_line[1]:="Next time say `withcolor <known color expression>';"; +else if t=uninitialized_model then + help_line[1]:="Next time say `withcolor <known color expression>';" +else if t=rgb_model then + help_line[1]:="Next time say `withrgbcolor <known color expression>';" +else if t=cmyk_model then + help_line[1]:="Next time say `withcmykcolor <known cmykcolor expression>';" +else if t=grey_model then + help_line[1]:="Next time say `withgreyscale <known numeric expression>';"; put_get_flush_error(0); end @@ -19404,10 +19664,26 @@ end picture will ever contain a color outside the legal range for \ps\ graphics. @<Transfer a color from the current expression to object~|cp|@>= +begin if cur_type=color_type then + @<Transfer a rgbcolor from the current expression to object~|cp|@> +else if cur_type=cmykcolor_type then + @<Transfer a cmykcolor from the current expression to object~|cp|@> +else if cur_type=known then + @<Transfer a greyscale from the current expression to object~|cp|@> +else if cur_exp=false_code then + @<Transfer a noncolor from the current expression to object~|cp|@>; +end + +@ @<Transfer a rgbcolor from the current expression to object~|cp|@>= begin q:=value(cur_exp); +cyan_val(cp):=0; +magenta_val(cp):=0; +yellow_val(cp):=0; +black_val(cp):=0; red_val(cp):=value(red_part_loc(q)); green_val(cp):=value(green_part_loc(q)); blue_val(cp):=value(blue_part_loc(q));@/ +color_model(cp):=rgb_model; if red_val(cp)<0 then red_val(cp):=0; if green_val(cp)<0 then green_val(cp):=0; if blue_val(cp)<0 then blue_val(cp):=0; @@ -19416,7 +19692,49 @@ if green_val(cp)>unity then green_val(cp):=unity; if blue_val(cp)>unity then blue_val(cp):=unity; end -@ @<Make |cp| a colored object in object list~|p|@>= +@ @<Transfer a cmykcolor from the current expression to object~|cp|@>= +begin q:=value(cur_exp); +cyan_val(cp):=value(cyan_part_loc(q)); +magenta_val(cp):=value(magenta_part_loc(q)); +yellow_val(cp):=value(yellow_part_loc(q));@/ +black_val(cp):=value(black_part_loc(q));@/ +color_model(cp):=cmyk_model; +if cyan_val(cp)<0 then cyan_val(cp):=0; +if magenta_val(cp)<0 then magenta_val(cp):=0; +if yellow_val(cp)<0 then yellow_val(cp):=0; +if black_val(cp)<0 then black_val(cp):=0; +if cyan_val(cp)>unity then cyan_val(cp):=unity; +if magenta_val(cp)>unity then magenta_val(cp):=unity; +if yellow_val(cp)>unity then yellow_val(cp):=unity; +if black_val(cp)>unity then black_val(cp):=unity; +end + +@ @<Transfer a greyscale from the current expression to object~|cp|@>= +begin q:=cur_exp; +cyan_val(cp):=0; +magenta_val(cp):=0; +yellow_val(cp):=0; +black_val(cp):=0; +grey_val(cp):=q; +color_model(cp):=grey_model; +if grey_val(cp)<0 then grey_val(cp):=0; +if grey_val(cp)>unity then grey_val(cp):=unity; +end + +@ @<Transfer a noncolor from the current expression to object~|cp|@>= +begin +cyan_val(cp):=0; +magenta_val(cp):=0; +yellow_val(cp):=0; +black_val(cp):=0; +grey_val(cp):=0; +color_model(cp):=no_model; +end + +@ It is a bit silly to repeat this action in five different +forms with the only difference being the label. Ah well. + +@<Make |cp| a colored object in object list~|p|@>= begin cp:=p; while cp<>null do begin if has_color(cp) then goto done; @@ -19425,6 +19743,42 @@ while cp<>null do done:do_nothing; end +@ @<Make |cp| a rgb colored object in object list~|p|@>= +begin cp:=p; +while cp<>null do + begin if has_color(cp) then goto done6; + cp:=link(cp); + end; +done6:do_nothing; +end + +@ @<Make |cp| a cmyk colored object in object list~|p|@>= +begin cp:=p; +while cp<>null do + begin if has_color(cp) then goto done5; + cp:=link(cp); + end; +done5:do_nothing; +end + +@ @<Make |cp| a grey colored object in object list~|p|@>= +begin cp:=p; +while cp<>null do + begin if has_color(cp) then goto done4; + cp:=link(cp); + end; +done4:do_nothing; +end + +@ @<Make |cp| a no colored object in object list~|p|@>= +begin cp:=p; +while cp<>null do + begin if has_color(cp) then goto done3; + cp:=link(cp); + end; +done3:do_nothing; +end + @ @<Make |pp| an object in list~|p| that needs a pen@>= begin pp:=p; while pp<>null do @@ -19444,7 +19798,7 @@ done2:do_nothing; end @ @<Copy the information from objects |cp|, |pp|, and |dp| into...@>= -if cp>void then @<Copy |cp|'s color into the colored objects linked to~|cp|@>; +@<Copy |cp|'s color into the colored objects linked to~|cp|@>; if pp>void then @<Copy |pen_p(pp)| into stroked and filled nodes linked to |pp|@>; if dp>void then @<Make stroked nodes linked to |dp| refer to |dash_p(dp)|@> @@ -19456,6 +19810,8 @@ while q<>null do begin red_val(q):=red_val(cp); green_val(q):=green_val(cp); blue_val(q):=blue_val(cp);@/ + black_val(q):=black_val(cp);@/ + color_model(q):=color_model(cp);@/ end; q:=link(q); end; @@ -19735,6 +20091,18 @@ start_sym:=0; @d message_code=0 @d err_message_code=1 @d err_help_code=2 +@d filename_template_code=3 +@d print_with_leading_zeroes(#)== g := pool_ptr; + print_int(#); g := pool_ptr-g; + if f>g then begin + pool_ptr := pool_ptr - g; + while f>g do begin + print_char("0"); + decr(f); + end; + print_int(#); + end; + f := 0 @<Put each...@>= primitive("message",message_command,message_code);@/ @@ -19743,10 +20111,13 @@ primitive("errmessage",message_command,err_message_code);@/ @!@:err_message_}{\&{errmessage} primitive@> primitive("errhelp",message_command,err_help_code);@/ @!@:err_help_}{\&{errhelp} primitive@> +primitive("filenametemplate",message_command,filename_template_code);@/ +@!@:filename_template_}{\&{filenametemplate} primitive@> @ @<Cases of |print_cmd...@>= message_command: if m<err_message_code then print("message") else if m=err_message_code then print("errmessage") + else if m=filename_template_code then print("filenametemplate") else print("errhelp"); @ @<Cases of |do_statement|...@>= @@ -19764,6 +20135,7 @@ else case m of end; err_message_code:@<Print string |cur_exp| as an error message@>; err_help_code:@<Save string |cur_exp| as the |err_help|@>; + filename_template_code:@<Save the filename template@>; end; {there are no other cases} flush_cur_exp(0); end; @@ -20980,6 +21352,11 @@ font_number=0..font_max; @ @<Glob...@>= font_info:array[0..font_mem_size] of memory_word; {height, width, and depth data} +@!font_enc_name:array[font_number] of str_number; + {encoding names, if any} +@!font_ps_name_fixed:array[font_number] of boolean; + {are the postscript names fixed already? } +@!mp_font_map: ^fm_entry_ptr; {pointer into AVL tree of font mappings} next_fmem:0..font_mem_size; {next unused entry in |font_info|} last_fnum:font_number; {last font number used so far} font_dsize:array[font_number] of scaled; @@ -21302,6 +21679,203 @@ if height_val(p)<-depth_val(p) then depth_val(p):=0; end +@ The new primitives fontmapfile and fontmapline. + +@<Declare action procedures for use by |do_statement|@>= +procedure do_mapfile; +begin get_x_next; scan_expression; +if cur_type<>string_type then @<Complain about improper map operation@> +else mpmapfile(cur_exp); +end; +procedure do_mapline; +begin get_x_next; scan_expression; +if cur_type<>string_type then @<Complain about improper map operation@> +else begin mpmapline(cur_exp); + end; +end; + +@ @<Complain about improper map operation@>= +begin exp_err("Unsuitable expression"); +help1("Only known strings can be map files or map lines."); +put_get_error; +end + +@ the C code needs to know how to get at the null font, how remove +a string from memory, etc. + +@d is_valid_char(#)==((font_bc[f] <= #) and (# <= font_ec[f]) and + ichar_exists(char_info(f)(#))) + +@p function get_nullfont: font_number; +begin + get_nullfont := null_font; +end; +@# +procedure flush_str(s: str_number); {flush a string if possible} +begin + flush_string(s); +end; +@# +function get_nullstr: str_number; +begin + get_nullstr := ""; +end; +@# +function get_termandlogid: integer; +begin + get_termandlogid:=term_and_log; +end; +@# +function get_charwidth(f: font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_charwidth := char_width(f)(char_info(f)(c)) + else + get_charwidth := 0; +end; +@# +function tfm_lookup(s: str_number; fs: scaled): font_number; +{looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s|} +var k: font_number; +begin + if fs <> 0 then begin { should not be used! } + for k := null_font + 1 to last_fnum do + if str_vs_str(font_name[k], s) and (font_sizes[k] = fs) then begin + flush_str(s); + tfm_lookup := k; + return; + end; + end + else begin + for k := null_font + 1 to last_fnum do + if str_vs_str(font_name[k], s) then begin + flush_str(s); + tfm_lookup := k; + return; + end; + end; + tfm_lookup := null_font; + exit: +end; +@# +function new_dummy_font: font_number; +begin + new_dummy_font := read_font_info("dummy"); +end; + +@x +function round_xn_over_d(@!x:scaled; @!n,@!d:integer):scaled; +var positive:boolean; {was |x>=0|?} +@!t,@!u,@!v:nonnegative_integer; {intermediate quantities} +begin if x>=0 then positive:=true +else begin negate(x); positive:=false; + end; +t:=(x mod @'100000)*n; +u:=(x div @'100000)*n+(t div @'100000); +v:=(u mod d)*@'100000 + (t mod @'100000); +if u div d>=@'100000 then arith_error:=true +else u:=@'100000*(u div d) + (v div d); +v := v mod d; +if 2*v >= d then + incr(u); +if positive then + round_xn_over_d := u +else + round_xn_over_d := -u; +end; + + +@ +@<Declare the \ps\ output procedures@>= +procedure ps_print_cmd(@!l:str_number;@!s:str_number); +begin +if internal[mpprocset]>0 then begin ps_room(length(s)); print(s); end +else begin ps_room(length(l)); print(l); end; +end; +@# +procedure print_cmd(@!l:str_number;@!s:str_number); +begin +if internal[mpprocset]>0 then print(s) else print(l); +end; +@# +function mp_char_marked(@!f:font_number;@!c: eight_bits): boolean; +var @!b:integer; {|char_base[f]|} +begin b:=char_base[f]; + if (c>=font_bc[f])and(c<=font_ec[f])and(font_info[b+c].qqqq.b3<>0) then + mp_char_marked:=true + else + mp_char_marked:=false; +end; + +@ The fontmap entries need a typedef + +@<Types...@>= +fm_entry_ptr = ^integer; +@!nonnegative_integer=0..@'17777777777; {$0\L x<2^{31}$} + +@ To print |scaled| value to PDF output we need some subroutines to ensure +accurary. + +@d max_integer == @"7FFFFFFF {$2^{31}-1$} +@d call_func(#) == begin if # <> 0 then do_nothing end + +@<Glob...@>= +@!one_bp: scaled; {scaled value corresponds to 1bp} +@!one_hundred_bp: scaled; {scaled value corresponds to 100bp} +@!one_hundred_inch: scaled; {scaled value corresponds to 100in} +@!ten_pow: array[0..9] of integer; {$10^0..10^9$} +@!scaled_out: integer; {amount of |scaled| that was taken out in +|divide_scaled|} + +@ @<Set init...@>= +one_bp := 65782; {65781.76} +one_hundred_bp := 6578176; +one_hundred_inch := 473628672; +ten_pow[0] := 1; +for i := 1 to 9 do + ten_pow[i] := 10*ten_pow[i - 1]; +mp_font_map:=xmalloc_array(fm_entry_ptr,font_max); +for i := null_font to font_max do begin + font_enc_name[i] := 0; + font_ps_name_fixed[i] := false; + mp_font_map[i] := 0; + end; + + + +@ The following function divides |s| by |m|. |dd| is number of decimal digits. + +@p function divide_scaled(s, m: scaled; dd: integer): scaled; +var q, r: scaled; + sign, i: integer; +begin + sign := 1; + if s < 0 then begin + sign := -sign; + s := -s; + end; + if m < 0 then begin + sign := -sign; + m := -m; + end; + if m = 0 then + confusion("arithmetic: divided by zero") + else if m >= (max_integer div 10) then + confusion("arithmetic: number too big"); + q := s div m; + r := s mod m; + for i := 1 to dd do begin + q := 10*q + (10*r) div m; + r := (10*r) mod m; + end; + if 2*r >= m then begin + incr(q); + r := r - m; + end; + scaled_out := sign*(s - (r div ten_pow[dd])); + divide_scaled := sign*q; +end; + @ The file |ps_tab_file| gives a table of \TeX\ font names and corresponding PostScript names for fonts that do not have to be downloaded, i.e., fonts that can be used when |internal[prologues]>0|. Each line consists of a \TeX\ name, @@ -21392,16 +21966,91 @@ file named according to the current \&{charcode}. @<Declare the \ps\ output procedures@>= procedure open_output_file; +label @!continue; { after a digit is seen} var @!c:integer; {\&{charcode} rounded to the nearest integer} @!old_setting:0..max_selector; {previous |selector| setting} -@!s:str_number; {a file extension derived from |c|} +@!s,n:str_number; {a file extension derived from |c|} +@!i:pool_pointer; { indexes into |filename_template| } +@!cc:integer; {a temporary integer for template building } +@!f,g:integer; {field widths} begin if job_name=0 then open_log_file; c:=round_unscaled(internal[char_code]); -if c<0 then s:=".ps" -else @<Use |c| to compute the file extension |s|@>; -pack_job_name(s); -while not a_open_out(ps_file) do - prompt_file_name("file name for output",s); +if filename_template=0 then begin + if c<0 then s:=".ps" + else @<Use |c| to compute the file extension |s|@>; + pack_job_name(s); + while not a_open_out(ps_file) do + prompt_file_name("file name for output",s); + end +else begin + {initializations} + s := ""; + n := ""; + old_setting:=selector; selector:=new_string; + f := 0; + i := str_start[filename_template]; + while i<str_stop(filename_template) do begin + if so(str_pool[i])="%" then begin + continue: + incr(i); + if i<str_stop(filename_template) then + begin + if so(str_pool[i])="j" then + print(job_name) + else if so(str_pool[i])="d" then begin + cc:= round_unscaled(internal[day]); + print_with_leading_zeroes(cc); + end + else if so(str_pool[i])="m" then begin + cc:= round_unscaled(internal[month]); + print_with_leading_zeroes(cc); + end + else if so(str_pool[i])="y" then begin + cc:= round_unscaled(internal[year]); + print_with_leading_zeroes(cc); + end + else if so(str_pool[i])="H" then begin + cc:= round_unscaled(internal[time]) div 60; + print_with_leading_zeroes(cc); + end + else if so(str_pool[i])="M" then begin + cc:= round_unscaled(internal[time]) mod 60; + print_with_leading_zeroes(cc); + end + else if so(str_pool[i])="c" then begin + if c<0 then print("ps") + else begin + print_with_leading_zeroes(c); + end; + end + else if (so(str_pool[i])>="0") and (so(str_pool[i])<="9") then begin + if (f<10) then + f := (f*10) + so(str_pool[i])-"0"; + goto continue; + end + else + print(str_pool[i]) + end + end + else begin + if so(str_pool[i])="." then + if n="" then + n := make_string; + print(str_pool[i]); + end; + incr(i); + end; + s := make_string; + selector:= old_setting; + if n="" then begin + n:=s; + s:=""; + end; + pack_file_name(n,"",s); + while not a_open_out(ps_file) do + prompt_file_name("file name for output",s); + delete_str_ref(n); + end; delete_str_ref(s); @<Store the true output file name if appropriate@>; @<Begin the progress report for the ouput of picture~|c|@>; @@ -21504,13 +22153,13 @@ var @!p,@!q:pointer; {for scanning the path} @!d:scaled; {a temporary value} @!curved:boolean; {|true| unless the cubic is almost straight} begin ps_room(40); -if need_newpath then print("newpath "); +if need_newpath then print_cmd("newpath ","n "); need_newpath:=true; ps_pair_out(x_coord(h),y_coord(h)); -print("moveto");@/ +print_cmd("moveto","m");@/ p:=h; repeat if right_type(p)=endpoint then - begin if p=h then ps_print(" 0 0 rlineto"); + begin if p=h then ps_print_cmd(" 0 0 rlineto"," 0 0 r"); return; end; q:=link(p); @@ -21518,7 +22167,7 @@ q:=link(p); |p| to~|q|@>; p:=q; until p=h; -ps_print(" closepath"); +ps_print_cmd(" closepath"," p"); exit:end; @ @<Glob...@>= @@ -21534,11 +22183,11 @@ if curved then begin ps_pair_out(right_x(p),right_y(p)); ps_pair_out(left_x(q),left_y(q)); ps_pair_out(x_coord(q),y_coord(q)); - ps_print("curveto"); + ps_print_cmd("curveto","c"); end else if q<>h then begin ps_pair_out(x_coord(q),y_coord(q)); - ps_print("lineto"); + ps_print_cmd("lineto","l"); end @ Two types of straight lines come up often in \MP\ paths: @@ -21566,23 +22215,35 @@ if abs(right_x(p)-x_coord(p)-d)<=bend_tolerance then This allows us to be sure that \ps\ has the correct values when they are needed without wasting time and space setting them unnecessarily. +@d gs_node_size=10 +@d gs_red ==mem[gs_state+1].sc +@d gs_green ==mem[gs_state+2].sc +@d gs_blue ==mem[gs_state+3].sc +@d gs_black ==mem[gs_state+4].sc + {color from the last \&{setcmykcolor} or \&{setrgbcolor} or \&{setgray} command} +@d gs_colormodel==mem[gs_state+5].qqqq.b0 + {the current colormodel} +@d gs_ljoin ==mem[gs_state+5].qqqq.b1 +@d gs_lcap ==mem[gs_state+5].qqqq.b2 + {values from the last \&{setlinejoin} and \&{setlinecap} commands} +@d gs_adj_wx ==mem[gs_state+5].qqqq.b3 + {what resolution-dependent adjustment applies to the width} +@d gs_miterlim ==mem[gs_state+6].sc + {the value from the last \&{setmiterlimit} command} +@d gs_dash_p ==mem[gs_state+7].hh.lh + {edge structure for last \&{setdash} command} +@d gs_previous ==mem[gs_state+7].hh.rh + {backlink to the previous |gs_state| structure} +@d gs_dash_sc ==mem[gs_state+8].sc + {scale factor used with |gs_dash_p|} +@d gs_width ==mem[gs_state+9].sc + {width setting or $-1$ if no \&{setlinewidth} command so far} + @<Glob...@>= -@!gs_red,@!gs_green,@!gs_blue:scaled; - {color from the last \&{setrgbcolor} or \&{setgray} command} -@:setrgbcolor}{\&{setrgbcolor} command@> -@:setgray}{\&{setgray} command@> -@!gs_ljoin,@!gs_lcap:quarterword; - {values from the last \&{setlinejoin} and \&{setlinecap} commands} -@:setlinejoin}{\&{setlinejoin} command@> -@:setlinecap}{\&{setlinecap} command@> -@!gs_miterlim:scaled; {the value from the last \&{setmiterlimit} command} -@:setmiterlimit}{\&{setmiterlimit} command@> -@!gs_dash_p:pointer; {edge structure for last \&{setdash} command} -@:setdash}{\&{setdash} command@> -@!gs_dash_sc:scaled; {scale factor used with |gs_dash_p|} -@!gs_width:scaled; {width setting or $-1$ if no \&{setlinewidth} command so far} -@!gs_adj_wx:boolean; {what resolution-dependent adjustment applies to the width} -@:setlinewidth}{\&{setlinewidth} command@> +gs_state:pointer; + +@ @<Set init...@>= +gs_state:=null; @ To avoid making undue assumptions about the initial graphics state, these parameters are given special values that are guaranteed not to match anything @@ -21594,13 +22255,41 @@ to recover from a situation where we have lost track of the graphics state. @<Declare the \ps\ output procedures@>= procedure unknown_graphics_state(c:scaled); -begin gs_red:=c; gs_green:=c; gs_blue:=c;@/ -gs_ljoin:=3; -gs_lcap:=3; -gs_miterlim:=0;@/ -gs_dash_p:=void; -gs_dash_sc:=0; -gs_width:=-1; +var @!p:pointer; {to shift graphic states around} + @!k:quarterword; {a loop index for copying the |gs_state|} +begin if (c=0)or(c=-1) then begin + if gs_state=null then begin + gs_state := get_node(gs_node_size); + gs_previous:=null; + end + else begin + while gs_previous<>null do begin + p := gs_previous; + free_node(gs_state,gs_node_size); + gs_state:=p; + end; + end; + gs_red:=c; gs_green:=c; gs_blue:=c; gs_black:=c;@/ + gs_colormodel:=uninitialized_model; + gs_ljoin:=3; + gs_lcap:=3; + gs_miterlim:=0;@/ + gs_dash_p:=void; + gs_dash_sc:=0; + gs_width:=-1; + end +else if c=1 then begin + p:= gs_state; + gs_state := get_node(gs_node_size); + for k:=1 to gs_node_size-1 do + mem[gs_state+k]:=mem[p+k]; + gs_previous := p; + end +else if c=2 then begin + p := gs_previous; + free_node(gs_state,gs_node_size); + gs_state:=p; + end; end; @ When it is time to output a graphical object, |fix_graphics_state| ensures @@ -21635,7 +22324,7 @@ if type(p)=stroked_code then if gs_lcap<>lcap_val(p) then begin ps_room(13); print_char(" "); - print_char("0"+lcap_val(p)); print(" setlinecap"); + print_char("0"+lcap_val(p)); print_cmd(" setlinecap"," lc"); gs_lcap:=lcap_val(p); end @@ -21643,36 +22332,86 @@ if type(p)=stroked_code then if gs_ljoin<>ljoin_val(p) then begin ps_room(14); print_char(" "); - print_char("0"+ljoin_val(p)); print(" setlinejoin"); + print_char("0"+ljoin_val(p)); print_cmd(" setlinejoin"," lj"); gs_ljoin:=ljoin_val(p); end; if gs_miterlim<>miterlim_val(p) then begin ps_room(27); print_char(" "); - print_scaled(miterlim_val(p)); print(" setmiterlimit"); + print_scaled(miterlim_val(p)); print_cmd(" setmiterlimit"," ml"); gs_miterlim:=miterlim_val(p); end @ @<Make sure \ps\ will use the right color for object~|p|@>= -if (gs_red<>red_val(p))or(gs_green<>green_val(p))or@| - (gs_blue<>blue_val(p)) then - begin gs_red:=red_val(p); - gs_green:=green_val(p); - gs_blue:=blue_val(p);@/ - if (gs_red=gs_green)and(gs_green=gs_blue) then - begin ps_room(16); - print_char(" "); - print_scaled(gs_red); - print(" setgray"); +begin + if (color_model(p)=rgb_model)or@| + ((color_model(p)=uninitialized_model)and + ((internal[default_color_model] div unity)=rgb_model)) then + begin if (gs_colormodel<>rgb_model)or(gs_red<>red_val(p))or@| + (gs_green<>green_val(p))or(gs_blue<>blue_val(p)) then + begin gs_red:=red_val(p); + gs_green:=green_val(p); + gs_blue:=blue_val(p); + gs_black:= -1;@/ + gs_colormodel:=rgb_model; + begin ps_room(36); + print_char(" "); + print_scaled(gs_red); print_char(" "); + print_scaled(gs_green); print_char(" "); + print_scaled(gs_blue); + print_cmd(" setrgbcolor", " R"); + end; + end; end - else begin ps_room(36); - print_char(" "); - print_scaled(gs_red); print_char(" "); - print_scaled(gs_green); print_char(" "); - print_scaled(gs_blue); - print(" setrgbcolor"); + else if (color_model(p)=cmyk_model)or@| + ((color_model(p)=uninitialized_model)and + ((internal[default_color_model] div unity)=cmyk_model)) then + begin if (gs_red<>cyan_val(p))or(gs_green<>magenta_val(p))or@| + (gs_blue<>yellow_val(p))or(gs_black<>black_val(p))or@| + (gs_colormodel<>cmyk_model) then + begin + if color_model(p)=uninitialized_model then begin + gs_red:=unity; + gs_green:=unity; + gs_blue:=unity; + gs_black:=unity;@/ + end + else begin + gs_red:=cyan_val(p); + gs_green:=magenta_val(p); + gs_blue:=yellow_val(p); + gs_black:=black_val(p);@/ + end; + gs_colormodel:=cmyk_model; + begin ps_room(45); + print_char(" "); + print_scaled(gs_red); print_char(" "); + print_scaled(gs_green); print_char(" "); + print_scaled(gs_blue); print_char(" "); + print_scaled(gs_black); + print_cmd(" setcmykcolor"," C"); + end; + end; + end + else if (color_model(p)=grey_model)or@| + ((color_model(p)=uninitialized_model)and + ((internal[default_color_model] div unity)=grey_model)) then + begin if (gs_red<>grey_val(p))or(gs_colormodel<>grey_model) then + begin gs_red := grey_val(p); + gs_green:= -1; + gs_blue:= -1; + gs_black:= -1;@/ + gs_colormodel:=grey_model; + begin ps_room(16); + print_char(" "); + print_scaled(gs_red); + print_cmd(" setgray"," G"); + end; + end; end; - end; + if color_model(p)=no_model then + gs_colormodel:=no_model; +end @ In order to get consistent widths for horizontal and vertical pen strokes, we want \ps\ to use an integer number of pixels for the \&{setwidth} parameter. @@ -21700,11 +22439,19 @@ if (ww<>gs_width) or (adj_wx<>gs_adj_wx) then begin if adj_wx then begin ps_room(13); print_char(" "); print_scaled(ww); - ps_print(" 0 dtransform exch truncate exch idtransform pop setlinewidth"); + ps_print_cmd(" 0 dtransform exch truncate exch idtransform pop setlinewidth"," hlw"); end - else begin ps_room(15); - print(" 0 "); print_scaled(ww); - ps_print(" dtransform truncate idtransform setlinewidth pop"); + else begin + if internal[mpprocset]>0 then begin + ps_room(13); + print_char(" "); + print_scaled(ww); + ps_print(" vlw"); + end + else begin ps_room(15); + print(" 0 "); print_scaled(ww); + ps_print(" dtransform truncate idtransform setlinewidth pop"); + end; end; gs_width := ww; gs_adj_wx := adj_wx; @@ -21792,7 +22539,7 @@ else begin hh:=dash_p(p); end; if hh=null then begin if gs_dash_p<>null then - begin ps_print(" [] 0 setdash"); + begin ps_print_cmd(" [] 0 setdash"," rd"); gs_dash_p:=null; end; end @@ -21808,7 +22555,7 @@ cannot be printed without overflow. begin gs_dash_p:=hh; gs_dash_sc:=scf; if (dash_y(hh)=0) or (abs(dash_y(hh)) div unity >= el_gordo div scf) then - ps_print(" [] 0 setdash") + ps_print_cmd(" [] 0 setdash"," rd") else begin pp:=dash_list(hh); start_x(null_dash):=start_x(pp)+dash_y(hh);@/ ps_room(28); @@ -21821,7 +22568,7 @@ else begin pp:=dash_list(hh); ps_room(22); print("] "); print_scaled(take_scaled(dash_offset(hh),scf)); - print(" setdash"); + print_cmd(" setdash"," sd"); end; end @@ -21869,10 +22616,29 @@ begin transformed:=false;@/ translation@>; @<Tweak the transformation parameters so the transformation is nonsingular@>; ps_path_out(path_p(h));@/ -if fill_also then print_nl("gsave fill grestore"); -@<Issue \ps\ commands to transform the coordinate system@>; -ps_print(" stroke"); -if transformed then ps_print(" grestore"); +if internal[mpprocset]=0 then begin + if fill_also then print_nl("gsave fill grestore"); + @<Issue \ps\ commands to transform the coordinate system@>; + ps_print(" stroke"); + if transformed then ps_print(" grestore"); + end +else begin + if fill_also then print_nl("B") else print_ln; + if (txy<>0)or(tyx<>0) then + begin {print_ln;} + print(" ["); + ps_pair_out(txx,tyx); + ps_pair_out(txy,tyy);@/ + ps_print("0 0] t"); + end + else if (txx<>unity)or(tyy<>unity) then + begin {print_ln;} + ps_pair_out(txx,tyy); + print(" s"); + end; + ps_print(" S"); + if transformed then ps_print(" Q"); +end; print_ln; end; @@ -21883,7 +22649,7 @@ tyx:=left_y(p);@/ txy:=right_x(p); tyy:=right_y(p); if (x_coord(p)<>0)or(y_coord(p)<>0) then - begin print_nl("gsave "); + begin print_ln; print_cmd("gsave ","q "); ps_pair_out(x_coord(p),y_coord(p)); ps_print("translate ");@/ txx:=txx-x_coord(p); @@ -21908,7 +22674,7 @@ if gs_width<>unity then end; if (txy<>0)or(tyx<>0)or(txx<>unity)or(tyy<>unity) then if (not transformed) then - begin ps_print("gsave "); + begin ps_print_cmd("gsave ","q "); transformed:=true; end @@ -21956,7 +22722,7 @@ if abs(det)<d1 then @<Declare the \ps\ output procedures@>= procedure ps_fill_out(@!p:pointer); {fill cyclic path~|p|} begin ps_path_out(p); -ps_print(" fill"); +ps_print_cmd(" fill"," F"); print_ln; end; @@ -22235,7 +23001,7 @@ end; last_pending:=spec_head; @ @<Cases of |do_statement|...@>= -special_command:do_special; +special_command: if cur_mod=0 then do_special else if cur_mod=1 then do_mapfile else do_mapline; @ @<Declare action procedures for use by |do_statement|@>= procedure do_special; @@ -22271,7 +23037,7 @@ setting is saved in a global variable so that |begin_diagnostic| can access it. @<Declare the \ps\ output procedures@>= procedure ship_out(@!h:pointer); {output edge structure |h|} -label done,found; +label done,done2,found,found2,found3; var @!p:pointer; {the current graphical object} @!q:pointer; {something that |p| points to} @!t:integer; {a temporary value} @@ -22283,12 +23049,42 @@ var @!p:pointer; {the current graphical object} @!ds,@!scf:scaled; {design size and scale factor for a text node} @!transformed:boolean; {is the coordinate system being transformed?} begin open_output_file; -if (internal[prologues]>0) and (last_ps_fnum<last_fnum) then - read_psname_table; non_ps_setting:=selector; selector:=ps_file_only;@/ +if (internal[prologues]=two)or(internal[prologues]=three) then begin + @<Print improved initial comment and bounding box for edge structure~|h|@>; + @<Scan all the text nodes and mark the used characters@>; + mploadencodings(last_fnum); + @<Update encoding names@>; + @<Print the improved prologue and setup@>; + @<Print any pending specials@>; + unknown_graphics_state(0); + need_newpath:=true; + p:=link(dummy_loc(h)); + while p<>null do + begin if has_color(p) then + if (pre_script(p))<>null then begin + print_nl (pre_script(p)); print_ln; + end; + fix_graphics_state(p); + case type(p) of + @<Cases for translating graphical object~|p| into \ps@>@; + start_bounds_code,stop_bounds_code: do_nothing; + end; {all cases are enumerated} + p:=link(p); + end; + print_cmd("showpage","P"); print_ln; + print("%%EOF"); print_ln; + a_close(ps_file); + selector:=non_ps_setting; + if internal[prologues]<=0 then clear_sizes; + @<End progress report@>; + end +else begin @<Print the initial comment and give the bounding box for edge structure~|h|@>; +if (internal[prologues]>0) and (last_ps_fnum<last_fnum) then + read_psname_table; print("%%BeginProlog"); print_ln; -if internal[prologues]>0 then @<Print the prologue@>; +if (internal[prologues]>0)or(internal[mpprocset]>0) then @<Print the prologue@>; print("%%EndProlog"); print_nl("%%Page: 1 1"); print_ln; @<Print any pending specials@>; @@ -22296,22 +23092,397 @@ unknown_graphics_state(0); need_newpath:=true; p:=link(dummy_loc(h)); while p<>null do - begin fix_graphics_state(p); + begin if has_color(p) then + if (pre_script(p))<>null then begin + print_nl (pre_script(p)); print_ln; + end; + fix_graphics_state(p); case type(p) of @<Cases for translating graphical object~|p| into \ps@>@; start_bounds_code,stop_bounds_code: do_nothing; end; {all cases are enumerated} p:=link(p); end; -print("showpage"); print_ln; +print_cmd("showpage","P"); print_ln; print("%%EOF"); print_ln; a_close(ps_file); selector:=non_ps_setting; if internal[prologues]<=0 then clear_sizes; @<End progress report@>; +end; if internal[tracing_output]>0 then print_edges(h," (just shipped out)",true); end; +@ @<Print the procset@>= + begin + print_nl("/hlw{0 dtransform exch truncate exch idtransform pop setlinewidth}bd"); + print_nl("/vlw{0 exch dtransform truncate idtransform setlinewidth pop}bd"); + print_nl("/l{lineto}bd/r{rlineto}bd/c{curveto}bd/m{moveto}bd/p{closepath}bd/n{newpath}bd"); + print_nl("/C{setcmykcolor}bd/G{setgray}bd/R{setrgbcolor}bd/lj{setlinejoin}bd/ml{setmiterlimit}bd"); + print_nl("/lc{setlinecap}bd/S{stroke}bd/F{fill}bd/q{gsave}bd/Q{grestore}bd/s{scale}bd/t{concat}bd"); + print_nl("/sd{setdash}bd/rd{[] 0 setdash}bd/P{showpage}bd/B{q F Q}bd/W{clip}bd"); + end + + +@ +@d applied_reencoding(#)==((font_is_reencoded(#))and + ((not font_is_subsetted(#))or(internal[prologues]=two))) + +@d ps_print_defined_name(#)==ps_print(" /"); + if (font_is_subsetted(#))and(font_is_included(#))and(internal[prologues]=three) + then print(fm_font_subset_name(#)) + else print(font_ps_name[#]); + if applied_reencoding(#) then begin ps_print("-"); + ps_print(font_enc_name[#]); end; + if fm_font_slant(#)<>0 then begin + ps_print("-Slant_"); print_int(fm_font_slant(#)) end; + if fm_font_extend(#)<>0 then begin + ps_print("-Extend_"); print_int(fm_font_extend(#)) end + +@<Print the improved prologue and setup@>= +begin + list_used_resources; + list_supplied_resources; + list_needed_resources; + print_nl("%%EndComments"); + print_nl("%%BeginProlog"); + if internal[mpprocset]>0 then + print_nl("%%BeginResource: procset mpost") + else + print_nl("%%BeginResource: procset mpost-minimal"); + print_nl("/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd"); + if internal[mpprocset]>0 then @<Print the procset@>; + print_nl("/fcp{findfont dup length dict begin{1 index/FID ne{def}{pop pop}ifelse}forall}bd"); + print_nl("/fmc{FontMatrix dup length array copy dup dup}bd/fmd{/FontMatrix exch def}bd"); + print_nl("/Amul{4 -1 roll exch mul 1000 div}bd/ExtendFont{fmc 0 get Amul 0 exch put fmd}bd"); + print_nl("/SlantFont{fmc 2 get dup 0 eq{pop 1}if Amul FontMatrix 0 get mul 2 exch put fmd}bd"); + print_nl("%%EndResource"); + @<Include encodings and fonts for edge structure~|h|@>; + print_nl("%%EndProlog"); + print_nl("%%BeginSetup"); + print_ln; + for f:=null_font+1 to last_fnum do begin + if font_sizes[f]<>null then begin + if hasfmentry(f) then begin + @<Write font definition@>; + ps_name_out(font_name[f],true); + ps_print_defined_name(f); + ps_print(" def"); + end + else begin + begin_diagnostic; + {selector:=term_and_log;} + print_err("Warning: font "); + print(font_name[f]); + print(" cannot be found in any fontmapfile!"); + end_diagnostic(true); + ps_name_out(font_name[f],true); + ps_name_out(font_name[f],true); + ps_print(" def"); + end; + print_ln; + end; + end; + print_nl("%%EndSetup"); + print_nl("%%Page: 1 1"); + print_ln; +end + +@ @<Write font definition@>= +if (applied_reencoding(f))or(fm_font_slant(f)<>0)or(fm_font_extend(f)<>0) then begin + if (font_is_subsetted(f))and(font_is_included(f))and(internal[prologues]=three) + then ps_name_out(fm_font_subset_name(f),true) + else ps_name_out(font_ps_name[f],true); + ps_print(" fcp"); + print_ln; + if applied_reencoding(f) then begin + ps_print("/Encoding "); + ps_print(font_enc_name[f]); + ps_print(" def "); + end; + if fm_font_slant(f)<>0 then begin + print_int(fm_font_slant(f)); + ps_print(" SlantFont "); + end; + if fm_font_extend(f)<>0 then begin + print_int(fm_font_extend(f)); + ps_print(" ExtendFont "); + end; + ps_print("currentdict end"); + print_ln; + ps_print_defined_name(f); + ps_print(" exch definefont pop"); + print_ln; +end + +@ Included subset fonts do not need and encoding vector, make +sure we skip that case. + +@p procedure list_used_resources; +label found,found2; +var @!f,ff:font_number; {fonts used in a text node or as loop counters} +@!ldf:font_number; {the last \.{DocumentFont} listed (otherwise |null_font|)} +firstitem:boolean; +begin +if internal[mpprocset]>0 then + print_nl("%%DocumentResources: procset mpost") +else + print_nl("%%DocumentResources: procset mpost-minimal"); +ldf:=null_font; +firstitem:=true; +for f:=null_font+1 to last_fnum do + if (font_sizes[f]<>null)and(font_is_reencoded(f)) then + begin + for ff:=ldf downto null_font do + if font_sizes[ff]<>null then + if str_vs_str(font_enc_name[f],font_enc_name[ff])=0 then + goto found; + if font_is_subsetted(f) then + goto found; + if ps_offset+1+length(font_enc_name[f])>max_print_line then + print_nl("%%+ encoding"); + if firstitem then begin + firstitem:=false; + print_nl("%%+ encoding"); + end; + print_char(" "); + print(font_enc_name[f]); + ldf:=f; + found: + end; +ldf:=null_font; +firstitem:=true; +for f:=null_font+1 to last_fnum do + if font_sizes[f]<>null then + begin + for ff:=ldf downto null_font do + if font_sizes[ff]<>null then + if str_vs_str(font_name[f],font_name[ff])=0 then + goto found2; + if ps_offset+1+length(font_ps_name[f])>max_print_line then + print_nl("%%+ font"); + if firstitem then begin + firstitem:=false; + print_nl("%%+ font"); + end; + print_char(" "); + if (internal[prologues]=three)and(font_is_subsetted(f)) then + print(fm_font_subset_name(f)) + else + print(font_ps_name[f]); + ldf:=f; + found2: + end; +print_ln; +end; + +@ +@p procedure list_supplied_resources; +label found,found2; +var @!f,ff:font_number; {fonts used in a text node or as loop counters} +@!ldf:font_number; {the last \.{DocumentFont} listed (otherwise |null_font|)} +firstitem:boolean; +begin +if internal[mpprocset]>0 then + print_nl("%%DocumentSuppliedResources: procset mpost") +else + print_nl("%%DocumentSuppliedResources: procset mpost-minimal"); +ldf:=null_font; +firstitem:=true; +for f:=null_font+1 to last_fnum do + if (font_sizes[f]<>null)and(font_is_reencoded(f)) then + begin + for ff:=ldf downto null_font do + if font_sizes[ff]<>null then + if str_vs_str(font_enc_name[f],font_enc_name[ff])=0 then + goto found; + if (internal[prologues]=three)and(font_is_subsetted(f))then + goto found; + if ps_offset+1+length(font_enc_name[f])>max_print_line then + print_nl("%%+ encoding"); + if firstitem then begin + firstitem:=false; + print_nl("%%+ encoding"); + end; + print_char(" "); + print(font_enc_name[f]); + ldf:=f; + found: + end; +ldf:=null_font; +firstitem:=true; +if internal[prologues]=three then begin + for f:=null_font+1 to last_fnum do + if font_sizes[f]<>null then + begin + for ff:=ldf downto null_font do + if font_sizes[ff]<>null then + if str_vs_str(font_name[f],font_name[ff])=0 then + goto found2; + if not font_is_included(f) then + goto found2; + if ps_offset+1+length(font_ps_name[f])>max_print_line then + print_nl("%%+ font"); + if firstitem then begin + firstitem:=false; + print_nl("%%+ font"); + end; + print_char(" "); + if font_is_subsetted(f) then + print(fm_font_subset_name(f)) + else + print(font_ps_name[f]); + ldf:=f; + found2: + end; + print_ln; +end; +end; + + +@ +@p procedure list_needed_resources; +label found,found2; +var @!f,ff:font_number; {fonts used in a text node or as loop counters} +@!ldf:font_number; {the last \.{DocumentFont} listed (otherwise |null_font|)} +firstitem:boolean; +begin +ldf:=null_font; +firstitem:=true; +for f:=null_font+1 to last_fnum do + if font_sizes[f]<>null then + begin + for ff:=ldf downto null_font do + if font_sizes[ff]<>null then + if str_vs_str(font_name[f],font_name[ff])=0 then + goto found; + if(internal[prologues]=three)and(font_is_included(f)) then + goto found; + if ps_offset+1+length(font_ps_name[f])>max_print_line then + print_nl("%%+ font"); + if firstitem then begin + firstitem:=false; + print_nl("%%DocumentNeededResources: font"); + end; + print_char(" "); + print(font_ps_name[f]); + ldf:=f; + found: + end; +if not firstitem then begin + print_ln; + ldf:=null_font; + firstitem:=true; + for f:=null_font+1 to last_fnum do + if font_sizes[f]<>null then + begin + for ff:=ldf downto null_font do + if font_sizes[ff]<>null then + if str_vs_str(font_name[f],font_name[ff])=0 then + goto found2; + if(internal[prologues]=three)and(font_is_included(f)) then + goto found2; + print("%%IncludeResource: font "); + print(font_ps_name[f]); + print_ln; + ldf:=f; + found2: + end; +end; +end; + +@ +@<Print improved initial comment and bounding box for edge...@>= +print("%!PS-Adobe-3.0 EPSF-3.0"); +print_nl("%%BoundingBox: "); +set_bbox(h,true); +if minx_val(h)>maxx_val(h) then print("0 0 0 0") +else begin ps_pair_out(floor_scaled(minx_val(h)),floor_scaled(miny_val(h))); + ps_pair_out(-floor_scaled(-maxx_val(h)),-floor_scaled(-maxy_val(h))); + end; +print_nl("%%HiResBoundingBox: "); +if minx_val(h)>maxx_val(h) then print("0 0 0 0") +else begin + ps_pair_out(minx_val(h),miny_val(h)); + ps_pair_out(maxx_val(h),maxy_val(h)); + end; +print_nl("%%Creator: MetaPost "); +print(metapost_version); +print_nl("%%CreationDate: "); +print_int(round_unscaled(internal[year])); print_char("."); +print_dd(round_unscaled(internal[month])); print_char("."); +print_dd(round_unscaled(internal[day])); print_char(":");@/ +t:=round_unscaled(internal[time]); +print_dd(t div 60); print_dd(t mod 60);@/ +print_nl("%%Pages: 1");@/ + +@ + +@ @<Include encodings and fonts for edge structure~|h|@>= +mpfontencodings(last_fnum,(internal[prologues]=two)); +@<Embed fonts that are available@> + +@ @<Scan all the text nodes and mark the used ...@>= +for f:=null_font+1 to last_fnum do begin + if font_sizes[f]<>null then begin + unmark_font(f); + font_sizes[f]:=null; + end; + if font_enc_name[f]<>0 then + delete_str_ref(font_enc_name[f]); + font_enc_name[f] := 0; +end; +for f:=null_font+1 to last_fnum do begin + p:=link(dummy_loc(h)); + while p<>null do + begin if type(p)=text_code then + if font_n(p)<>null_font then begin + font_sizes[font_n(p)] := void; + mark_string_chars(font_n(p),text_p(p)); + if hasfmentry(font_n(p)) then + font_ps_name[font_n(p)] := fm_font_name(font_n(p)); + end; + p:=link(p); + end; +end + +@ @<Update encoding names@>= +for f:=null_font+1 to last_fnum do begin + p:=link(dummy_loc(h)); + while p<>null do + begin if type(p)=text_code then + if font_n(p)<>null_font then + if hasfmentry(font_n(p)) then + if font_enc_name[font_n(p)]=0 then + font_enc_name[font_n(p)] := fm_encoding_name(font_n(p)); + p:=link(p); + end; +end + +@ @<Embed fonts that are available@>= +begin next_size:=0; +@<Make |cur_fsize| a copy of the |font_sizes| array@>; +repeat done_fonts:=true; +for f:=null_font+1 to last_fnum do + begin if cur_fsize[f]<>null then begin + if internal[prologues]=three then + if not dopsfont(f) then + if hasfmentry(f) then begin + print_err("Font embedding failed"); + error; + end; + cur_fsize[f]:=link(cur_fsize[f]); + if cur_fsize[f]<>null then + begin unmark_font(f); done_fonts:=false; @+end + end; + end; + if not done_fonts then + @<Increment |next_size| and apply |mark_string_chars| to all text nodes with + that size index@>; + until done_fonts; +end + + @ These special comments described in the {\sl PostScript Language Reference Manual}, 2nd.~edition are understood by some \ps-reading programs. We can't normally output ``conforming'' \ps\ because @@ -22466,41 +23637,61 @@ trouble. @:prologues_}{\&{prologues} primitive@> @<Print the prologue@>= -begin if ldf<>null_font then - begin for f:=null_font+1 to last_fnum do +begin +if ldf<>null_font then begin + if internal[prologues]>0 then begin + for f:=null_font+1 to last_fnum do if font_sizes[f]<>null then begin ps_name_out(font_name[f],true); ps_name_out(font_ps_name[f],true); ps_print(" def"); print_ln; end; - print("/fshow {exch findfont exch scalefont setfont show}bind def"); + if internal[mpprocset]=0 then begin + print("/fshow {exch findfont exch scalefont setfont show}bind def"); + print_ln; + end; + end; + end; +if internal[mpprocset]>0 then begin + if (internal[prologues]>0)and(ldf<>null_font) then + print("/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd") + else + print_nl("/bd{bind def}bind def"); + @<Print the procset@>; print_ln; end; end -@ Since we do not have a stack for the graphics state, it is considered -completely unknown after the \.{grestore} from a stop clip object. Procedure -|unknown_graphics_state| needs a negative argument in this case. - -@<Cases for translating graphical object~|p| into \ps@>= -start_clip_code:begin print_nl("gsave "); +@ @<Cases for translating graphical object~|p| into \ps@>= +start_clip_code:begin print_nl(""); print_cmd("gsave ","q "); ps_path_out(path_p(p)); - ps_print(" clip"); + ps_print_cmd(" clip"," W"); print_ln; + if internal[restore_clip_color]>0 then + unknown_graphics_state(1); end; -stop_clip_code:begin print_nl("grestore"); +stop_clip_code:begin print_nl(""); print_cmd("grestore","Q"); print_ln; - unknown_graphics_state(-1); + if internal[restore_clip_color]>0 then + unknown_graphics_state(2) + else + unknown_graphics_state(-1); end; @ @<Cases for translating graphical object~|p| into \ps@>= -fill_code: if pen_p(p)=null then ps_fill_out(path_p(p)) +fill_code: begin + if pen_p(p)=null then ps_fill_out(path_p(p)) else if pen_is_elliptical(pen_p(p)) then stroke_ellipse(p,true) else begin do_outer_envelope(copy_path(path_p(p)), p); do_outer_envelope(htap_ypoc(path_p(p)), p); end; -stroked_code: if pen_is_elliptical(pen_p(p)) then stroke_ellipse(p,false) + if (post_script(p))<>null then begin + print_nl (post_script(p)); print_ln; + end; + end; +stroked_code: begin + if pen_is_elliptical(pen_p(p)) then stroke_ellipse(p,false) else begin q:=copy_path(path_p(p)); t:=lcap_val(p); @<Break the cycle and set |t:=1| if path |q| is cyclic@>; @@ -22508,6 +23699,10 @@ stroked_code: if pen_is_elliptical(pen_p(p)) then stroke_ellipse(p,false) ps_fill_out(q); toss_knot_list(q); end; + if (post_script(p))<>null then begin + print_nl (post_script(p)); print_ln; + end; + end; @ The envelope of a cyclic path~|q| could be computed by calling |make_envelope| once for |q| and once for its reversal. We don't do this @@ -22523,7 +23718,8 @@ if left_type(q)<>endpoint then end @ @<Cases for translating graphical object~|p| into \ps@>= -text_code: if (font_n(p)<>null_font) and (length(text_p(p))>0) then +text_code: begin + if (font_n(p)<>null_font) and (length(text_p(p))>0) then begin if internal[prologues]>0 then scf:=choose_scale(p) else scf:=indexed_size(font_n(p), name_type(p)); @@ -22535,6 +23731,10 @@ text_code: if (font_n(p)<>null_font) and (length(text_p(p))>0) then @<Print the size information and \ps\ commands for text node~|p|@>; print_ln; end; + if (post_script(p))<>null then begin + print_nl (post_script(p)); print_ln; + end; + end; @ @<Print the size information and \ps\ commands for text node~|p|@>= ps_room(18); @@ -22548,15 +23748,15 @@ if transformed then ps_print(" grestore") transformed:=(txx_val(p)<>scf)or(tyy_val(p)<>scf)or@| (txy_val(p)<>0)or(tyx_val(p)<>0); if transformed then - begin print("gsave ["); + begin print_cmd("gsave [", "q ["); ps_pair_out(make_scaled(txx_val(p),scf),@|make_scaled(tyx_val(p),scf)); ps_pair_out(make_scaled(txy_val(p),scf),@|make_scaled(tyy_val(p),scf)); ps_pair_out(tx_val(p),ty_val(p));@/ - ps_print("] concat 0 0 moveto"); + ps_print_cmd("] concat 0 0 ","] t 0 0"); end else begin ps_pair_out(tx_val(p),ty_val(p)); - ps_print("moveto"); end; +ps_print_cmd("moveto","m"); print_ln @ Now that we've finished |ship_out|, let's look at the other commands @@ -22961,6 +24161,8 @@ tini@/ ready_already:=314159; start_of_MP: @<Initialize the output routines@>; @<Get the first line of input and prepare to start@>; +mp_init_map_file; +setjobid(internal[year],internal[month],internal[day],internal[time]); history:=spotless; {ready to go!} if start_sym>0 then {insert the `\&{everyjob}' symbol} begin cur_sym:=start_sym; back_input; @@ -23219,6 +24421,14 @@ for postprocessing. @<Character |k| is not allowed in PostScript output@>= (k<=" ")or(k>"~") +@ Saving the filename template + +@<Save the filename template@>= +begin if filename_template<>0 then delete_str_ref(filename_template); +if length(cur_exp)=0 then filename_template:=0 +else begin filename_template:=cur_exp; add_str_ref(filename_template); + end; +end @* \[48] System-dependent changes. This section should be replaced, if necessary, by any special modification of the program diff --git a/Build/source/texk/web2c/mpdir/Makefile.in b/Build/source/texk/web2c/mpdir/Makefile.in new file mode 100644 index 00000000000..c6abb102f2d --- /dev/null +++ b/Build/source/texk/web2c/mpdir/Makefile.in @@ -0,0 +1,40 @@ +# Makefile for libmpost - taco@elvenkind.com, but +# mostly ripped off from Makefile.in from pdftex +# $Id $ + +kpse_include ../make/common.mk +kpse_include ../make/programs.mk +kpse_include ../make/library.mk + +kpathsea_srcdir_parent = $(srcdir)/../.. +kpathsea_dir_parent = ../.. + +ALL_CXXFLAGS = @CXXFLAGS@ @DEFS@ $(XXCFLAGS) -I. -I$(srcdir) -I$(kpathsea_dir_parent) -I$(kpathsea_srcdir_parent) +CXX = @CXX@ + +XCPPFLAGS=-I.. -I$(srcdir)/.. -I../.. -I$(srcdir)/../.. + +OBJS = mapfile.o avl.o avlstuff.o utils.o writeenc.o writet1.o writefont.o + +all: libmpost.a makecpool + +libmpost.a: $(OBJS) + rm -f $@ + $(AR) $(ARFLAGS) $@ $(OBJS) + $(RANLIB) $@ + +makecpool: makecpool.o + $(link_command) makecpool.o + +kpse_include ../make/clean.mk + +clean:: + rm -f libmpost.a makecpool + +depend: + rm -f $(OBJS) + XXCFLAGS=-MM XCFLAGS=-MM $(MAKE) -k $(OBJS) | \ + grep -v "^$(CC)\|$(CXX)\|$(AR)\|make\|klibtool" | \ + sed 's: [^ ]*/\.\./libs/[^ ]*::g' > $(srcdir)/depend.mk + +kpse_include mpdir/depend.mk diff --git a/Build/source/texk/web2c/mpdir/avl.c b/Build/source/texk/web2c/mpdir/avl.c new file mode 100644 index 00000000000..703c4b2e72d --- /dev/null +++ b/Build/source/texk/web2c/mpdir/avl.c @@ -0,0 +1,792 @@ +/* Produced by texiweb from libavl.w on 2003/01/06 at 18:07. */ + +/* libavl - library for manipulation of binary trees. + Copyright (C) 1998-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + The author may be contacted at <blp@gnu.org> on the Internet, or + write to Ben Pfaff, Stanford University, Computer Science Dept., 353 + Serra Mall, Stanford CA 94305, USA. +*/ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "avl.h" + +/* Creates and returns a new table + with comparison function |compare| using parameter |param| + and memory allocator |allocator|. + Returns |NULL| if memory allocation failed. */ +struct avl_table *avl_create (avl_comparison_func * compare, void *param, + struct libavl_allocator *allocator) +{ + struct avl_table *tree; + + assert (compare != NULL); + + if (allocator == NULL) + allocator = &avl_allocator_default; + + tree = allocator->libavl_malloc (allocator, sizeof *tree); + if (tree == NULL) + return NULL; + + tree->avl_root = NULL; + tree->avl_compare = compare; + tree->avl_param = param; + tree->avl_alloc = allocator; + tree->avl_count = 0; + tree->avl_generation = 0; + + return tree; +} + +/* Search |tree| for an item matching |item|, and return it if found. + Otherwise return |NULL|. */ +void *avl_find (const struct avl_table *tree, const void *item) +{ + const struct avl_node *p; + + assert (tree != NULL && item != NULL); + for (p = tree->avl_root; p != NULL;) { + int cmp = tree->avl_compare (item, p->avl_data, tree->avl_param); + + if (cmp < 0) + p = p->avl_link[0]; + else if (cmp > 0) + p = p->avl_link[1]; + else /* |cmp == 0| */ + return p->avl_data; + } + + return NULL; +} + +/* Inserts |item| into |tree| and returns a pointer to |item|'s address. + If a duplicate item is found in the tree, + returns a pointer to the duplicate without inserting |item|. + Returns |NULL| in case of memory allocation failure. */ +void **avl_probe (struct avl_table *tree, void *item) +{ + struct avl_node *y, *z; /* Top node to update balance factor, and parent. */ + struct avl_node *p, *q; /* Iterator, and parent. */ + struct avl_node *n; /* Newly inserted node. */ + struct avl_node *w; /* New root of rebalanced subtree. */ + int dir; /* Direction to descend. */ + + unsigned char da[AVL_MAX_HEIGHT]; /* Cached comparison results. */ + int k = 0; /* Number of cached results. */ + + assert (tree != NULL && item != NULL); + + z = (struct avl_node *) &tree->avl_root; + y = tree->avl_root; + dir = 0; + for (q = z, p = y; p != NULL; q = p, p = p->avl_link[dir]) { + int cmp = tree->avl_compare (item, p->avl_data, tree->avl_param); + if (cmp == 0) + return &p->avl_data; + + if (p->avl_balance != 0) + z = q, y = p, k = 0; + da[k++] = dir = cmp > 0; + } + + n = q->avl_link[dir] = + tree->avl_alloc->libavl_malloc (tree->avl_alloc, sizeof *n); + if (n == NULL) + return NULL; + + tree->avl_count++; + n->avl_data = item; + n->avl_link[0] = n->avl_link[1] = NULL; + n->avl_balance = 0; + if (y == NULL) + return &n->avl_data; + + for (p = y, k = 0; p != n; p = p->avl_link[da[k]], k++) + if (da[k] == 0) + p->avl_balance--; + else + p->avl_balance++; + + if (y->avl_balance == -2) { + struct avl_node *x = y->avl_link[0]; + if (x->avl_balance == -1) { + w = x; + y->avl_link[0] = x->avl_link[1]; + x->avl_link[1] = y; + x->avl_balance = y->avl_balance = 0; + } else { + assert (x->avl_balance == +1); + w = x->avl_link[1]; + x->avl_link[1] = w->avl_link[0]; + w->avl_link[0] = x; + y->avl_link[0] = w->avl_link[1]; + w->avl_link[1] = y; + if (w->avl_balance == -1) + x->avl_balance = 0, y->avl_balance = +1; + else if (w->avl_balance == 0) + x->avl_balance = y->avl_balance = 0; + else /* |w->avl_balance == +1| */ + x->avl_balance = -1, y->avl_balance = 0; + w->avl_balance = 0; + } + } else if (y->avl_balance == +2) { + struct avl_node *x = y->avl_link[1]; + if (x->avl_balance == +1) { + w = x; + y->avl_link[1] = x->avl_link[0]; + x->avl_link[0] = y; + x->avl_balance = y->avl_balance = 0; + } else { + assert (x->avl_balance == -1); + w = x->avl_link[0]; + x->avl_link[0] = w->avl_link[1]; + w->avl_link[1] = x; + y->avl_link[1] = w->avl_link[0]; + w->avl_link[0] = y; + if (w->avl_balance == +1) + x->avl_balance = 0, y->avl_balance = -1; + else if (w->avl_balance == 0) + x->avl_balance = y->avl_balance = 0; + else /* |w->avl_balance == -1| */ + x->avl_balance = +1, y->avl_balance = 0; + w->avl_balance = 0; + } + } else + return &n->avl_data; + z->avl_link[y != z->avl_link[0]] = w; + + tree->avl_generation++; + return &n->avl_data; +} + +/* Inserts |item| into |table|. + Returns |NULL| if |item| was successfully inserted + or if a memory allocation error occurred. + Otherwise, returns the duplicate item. */ +void *avl_insert (struct avl_table *table, void *item) +{ + void **p = avl_probe (table, item); + return p == NULL || *p == item ? NULL : *p; +} + +/* Inserts |item| into |table|, replacing any duplicate item. + Returns |NULL| if |item| was inserted without replacing a duplicate, + or if a memory allocation error occurred. + Otherwise, returns the item that was replaced. */ +void *avl_replace (struct avl_table *table, void *item) +{ + void **p = avl_probe (table, item); + if (p == NULL || *p == item) + return NULL; + else { + void *r = *p; + *p = item; + return r; + } +} + +/* Deletes from |tree| and returns an item matching |item|. + Returns a null pointer if no matching item found. */ +void *avl_delete (struct avl_table *tree, const void *item) +{ + /* Stack of nodes. */ + struct avl_node *pa[AVL_MAX_HEIGHT]; /* Nodes. */ + unsigned char da[AVL_MAX_HEIGHT]; /* |avl_link[]| indexes. */ + int k; /* Stack pointer. */ + + struct avl_node *p; /* Traverses tree to find node to delete. */ + int cmp; /* Result of comparison between |item| and |p|. */ + + assert (tree != NULL && item != NULL); + + k = 0; + p = (struct avl_node *) &tree->avl_root; + for (cmp = -1; cmp != 0; + cmp = tree->avl_compare (item, p->avl_data, tree->avl_param)) { + int dir = cmp > 0; + + pa[k] = p; + da[k++] = dir; + + p = p->avl_link[dir]; + if (p == NULL) + return NULL; + } + item = p->avl_data; + + if (p->avl_link[1] == NULL) + pa[k - 1]->avl_link[da[k - 1]] = p->avl_link[0]; + else { + struct avl_node *r = p->avl_link[1]; + if (r->avl_link[0] == NULL) { + r->avl_link[0] = p->avl_link[0]; + r->avl_balance = p->avl_balance; + pa[k - 1]->avl_link[da[k - 1]] = r; + da[k] = 1; + pa[k++] = r; + } else { + struct avl_node *s; + int j = k++; + + for (;;) { + da[k] = 0; + pa[k++] = r; + s = r->avl_link[0]; + if (s->avl_link[0] == NULL) + break; + + r = s; + } + + s->avl_link[0] = p->avl_link[0]; + r->avl_link[0] = s->avl_link[1]; + s->avl_link[1] = p->avl_link[1]; + s->avl_balance = p->avl_balance; + + pa[j - 1]->avl_link[da[j - 1]] = s; + da[j] = 1; + pa[j] = s; + } + } + + tree->avl_alloc->libavl_free (tree->avl_alloc, p); + + assert (k > 0); + while (--k > 0) { + struct avl_node *y = pa[k]; + + if (da[k] == 0) { + y->avl_balance++; + if (y->avl_balance == +1) + break; + else if (y->avl_balance == +2) { + struct avl_node *x = y->avl_link[1]; + if (x->avl_balance == -1) { + struct avl_node *w; + assert (x->avl_balance == -1); + w = x->avl_link[0]; + x->avl_link[0] = w->avl_link[1]; + w->avl_link[1] = x; + y->avl_link[1] = w->avl_link[0]; + w->avl_link[0] = y; + if (w->avl_balance == +1) + x->avl_balance = 0, y->avl_balance = -1; + else if (w->avl_balance == 0) + x->avl_balance = y->avl_balance = 0; + else /* |w->avl_balance == -1| */ + x->avl_balance = +1, y->avl_balance = 0; + w->avl_balance = 0; + pa[k - 1]->avl_link[da[k - 1]] = w; + } else { + y->avl_link[1] = x->avl_link[0]; + x->avl_link[0] = y; + pa[k - 1]->avl_link[da[k - 1]] = x; + if (x->avl_balance == 0) { + x->avl_balance = -1; + y->avl_balance = +1; + break; + } else + x->avl_balance = y->avl_balance = 0; + } + } + } else { + y->avl_balance--; + if (y->avl_balance == -1) + break; + else if (y->avl_balance == -2) { + struct avl_node *x = y->avl_link[0]; + if (x->avl_balance == +1) { + struct avl_node *w; + assert (x->avl_balance == +1); + w = x->avl_link[1]; + x->avl_link[1] = w->avl_link[0]; + w->avl_link[0] = x; + y->avl_link[0] = w->avl_link[1]; + w->avl_link[1] = y; + if (w->avl_balance == -1) + x->avl_balance = 0, y->avl_balance = +1; + else if (w->avl_balance == 0) + x->avl_balance = y->avl_balance = 0; + else /* |w->avl_balance == +1| */ + x->avl_balance = -1, y->avl_balance = 0; + w->avl_balance = 0; + pa[k - 1]->avl_link[da[k - 1]] = w; + } else { + y->avl_link[0] = x->avl_link[1]; + x->avl_link[1] = y; + pa[k - 1]->avl_link[da[k - 1]] = x; + if (x->avl_balance == 0) { + x->avl_balance = +1; + y->avl_balance = -1; + break; + } else + x->avl_balance = y->avl_balance = 0; + } + } + } + } + + tree->avl_count--; + tree->avl_generation++; + return (void *) item; +} + +/* Refreshes the stack of parent pointers in |trav| + and updates its generation number. */ +static void trav_refresh (struct avl_traverser *trav) +{ + assert (trav != NULL); + + trav->avl_generation = trav->avl_table->avl_generation; + + if (trav->avl_node != NULL) { + avl_comparison_func *cmp = trav->avl_table->avl_compare; + void *param = trav->avl_table->avl_param; + struct avl_node *node = trav->avl_node; + struct avl_node *i; + + trav->avl_height = 0; + for (i = trav->avl_table->avl_root; i != node;) { + assert (trav->avl_height < AVL_MAX_HEIGHT); + assert (i != NULL); + + trav->avl_stack[trav->avl_height++] = i; + i = i->avl_link[cmp (node->avl_data, i->avl_data, param) > 0]; + } + } +} + +/* Initializes |trav| for use with |tree| + and selects the null node. */ +void avl_t_init (struct avl_traverser *trav, struct avl_table *tree) +{ + trav->avl_table = tree; + trav->avl_node = NULL; + trav->avl_height = 0; + trav->avl_generation = tree->avl_generation; +} + +/* Initializes |trav| for |tree| + and selects and returns a pointer to its least-valued item. + Returns |NULL| if |tree| contains no nodes. */ +void *avl_t_first (struct avl_traverser *trav, struct avl_table *tree) +{ + struct avl_node *x; + + assert (tree != NULL && trav != NULL); + + trav->avl_table = tree; + trav->avl_height = 0; + trav->avl_generation = tree->avl_generation; + + x = tree->avl_root; + if (x != NULL) + while (x->avl_link[0] != NULL) { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[0]; + } + trav->avl_node = x; + + return x != NULL ? x->avl_data : NULL; +} + +/* Initializes |trav| for |tree| + and selects and returns a pointer to its greatest-valued item. + Returns |NULL| if |tree| contains no nodes. */ +void *avl_t_last (struct avl_traverser *trav, struct avl_table *tree) +{ + struct avl_node *x; + + assert (tree != NULL && trav != NULL); + + trav->avl_table = tree; + trav->avl_height = 0; + trav->avl_generation = tree->avl_generation; + + x = tree->avl_root; + if (x != NULL) + while (x->avl_link[1] != NULL) { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[1]; + } + trav->avl_node = x; + + return x != NULL ? x->avl_data : NULL; +} + +/* Searches for |item| in |tree|. + If found, initializes |trav| to the item found and returns the item + as well. + If there is no matching item, initializes |trav| to the null item + and returns |NULL|. */ +void *avl_t_find (struct avl_traverser *trav, struct avl_table *tree, + void *item) +{ + struct avl_node *p, *q; + + assert (trav != NULL && tree != NULL && item != NULL); + trav->avl_table = tree; + trav->avl_height = 0; + trav->avl_generation = tree->avl_generation; + for (p = tree->avl_root; p != NULL; p = q) { + int cmp = tree->avl_compare (item, p->avl_data, tree->avl_param); + + if (cmp < 0) + q = p->avl_link[0]; + else if (cmp > 0) + q = p->avl_link[1]; + else { /* |cmp == 0| */ + + trav->avl_node = p; + return p->avl_data; + } + + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = p; + } + + trav->avl_height = 0; + trav->avl_node = NULL; + return NULL; +} + +/* Attempts to insert |item| into |tree|. + If |item| is inserted successfully, it is returned and |trav| is + initialized to its location. + If a duplicate is found, it is returned and |trav| is initialized to + its location. No replacement of the item occurs. + If a memory allocation failure occurs, |NULL| is returned and |trav| + is initialized to the null item. */ +void *avl_t_insert (struct avl_traverser *trav, struct avl_table *tree, + void *item) +{ + void **p; + + assert (trav != NULL && tree != NULL && item != NULL); + + p = avl_probe (tree, item); + if (p != NULL) { + trav->avl_table = tree; + trav->avl_node = ((struct avl_node *) + ((char *) p - offsetof (struct avl_node, avl_data))); + trav->avl_generation = tree->avl_generation - 1; + return *p; + } else { + avl_t_init (trav, tree); + return NULL; + } +} + +/* Initializes |trav| to have the same current node as |src|. */ +void *avl_t_copy (struct avl_traverser *trav, const struct avl_traverser *src) +{ + assert (trav != NULL && src != NULL); + + if (trav != src) { + trav->avl_table = src->avl_table; + trav->avl_node = src->avl_node; + trav->avl_generation = src->avl_generation; + if (trav->avl_generation == trav->avl_table->avl_generation) { + trav->avl_height = src->avl_height; + memcpy (trav->avl_stack, (const void *) src->avl_stack, + sizeof *trav->avl_stack * trav->avl_height); + } + } + + return trav->avl_node != NULL ? trav->avl_node->avl_data : NULL; +} + +/* Returns the next data item in inorder + within the tree being traversed with |trav|, + or if there are no more data items returns |NULL|. */ +void *avl_t_next (struct avl_traverser *trav) +{ + struct avl_node *x; + + assert (trav != NULL); + + if (trav->avl_generation != trav->avl_table->avl_generation) + trav_refresh (trav); + + x = trav->avl_node; + if (x == NULL) { + return avl_t_first (trav, trav->avl_table); + } else if (x->avl_link[1] != NULL) { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[1]; + + while (x->avl_link[0] != NULL) { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[0]; + } + } else { + struct avl_node *y; + + do { + if (trav->avl_height == 0) { + trav->avl_node = NULL; + return NULL; + } + + y = x; + x = trav->avl_stack[--trav->avl_height]; + } + while (y == x->avl_link[1]); + } + trav->avl_node = x; + + return x->avl_data; +} + +/* Returns the previous data item in inorder + within the tree being traversed with |trav|, + or if there are no more data items returns |NULL|. */ +void *avl_t_prev (struct avl_traverser *trav) +{ + struct avl_node *x; + + assert (trav != NULL); + + if (trav->avl_generation != trav->avl_table->avl_generation) + trav_refresh (trav); + + x = trav->avl_node; + if (x == NULL) { + return avl_t_last (trav, trav->avl_table); + } else if (x->avl_link[0] != NULL) { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[0]; + + while (x->avl_link[1] != NULL) { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[1]; + } + } else { + struct avl_node *y; + + do { + if (trav->avl_height == 0) { + trav->avl_node = NULL; + return NULL; + } + + y = x; + x = trav->avl_stack[--trav->avl_height]; + } + while (y == x->avl_link[0]); + } + trav->avl_node = x; + + return x->avl_data; +} + +/* Returns |trav|'s current item. */ +void *avl_t_cur (struct avl_traverser *trav) +{ + assert (trav != NULL); + + return trav->avl_node != NULL ? trav->avl_node->avl_data : NULL; +} + +/* Replaces the current item in |trav| by |new| and returns the item replaced. + |trav| must not have the null item selected. + The new item must not upset the ordering of the tree. */ +void *avl_t_replace (struct avl_traverser *trav, void *new) +{ + void *old; + + assert (trav != NULL && trav->avl_node != NULL && new != NULL); + old = trav->avl_node->avl_data; + trav->avl_node->avl_data = new; + return old; +} + +static void +copy_error_recovery (struct avl_node **stack, int height, + struct avl_table *new, avl_item_func * destroy) +{ + assert (stack != NULL && height >= 0 && new != NULL); + + for (; height > 2; height -= 2) + stack[height - 1]->avl_link[1] = NULL; + avl_destroy (new, destroy); +} + +/* Copies |org| to a newly created tree, which is returned. + If |copy != NULL|, each data item in |org| is first passed to |copy|, + and the return values are inserted into the tree, + with |NULL| return values taken as indications of failure. + On failure, destroys the partially created new tree, + applying |destroy|, if non-null, to each item in the new tree so far, + and returns |NULL|. + If |allocator != NULL|, it is used for allocation in the new tree. + Otherwise, the same allocator used for |org| is used. */ +struct avl_table *avl_copy (const struct avl_table *org, avl_copy_func * copy, + avl_item_func * destroy, + struct libavl_allocator *allocator) +{ + struct avl_node *stack[2 * (AVL_MAX_HEIGHT + 1)]; + int height = 0; + + struct avl_table *new; + const struct avl_node *x; + struct avl_node *y; + + assert (org != NULL); + new = avl_create (org->avl_compare, org->avl_param, + allocator != NULL ? allocator : org->avl_alloc); + if (new == NULL) + return NULL; + new->avl_count = org->avl_count; + if (new->avl_count == 0) + return new; + + x = (const struct avl_node *) &org->avl_root; + y = (struct avl_node *) &new->avl_root; + for (;;) { + while (x->avl_link[0] != NULL) { + assert (height < 2 * (AVL_MAX_HEIGHT + 1)); + + y->avl_link[0] = + new->avl_alloc->libavl_malloc (new->avl_alloc, + sizeof *y->avl_link[0]); + if (y->avl_link[0] == NULL) { + if (y != (struct avl_node *) &new->avl_root) { + y->avl_data = NULL; + y->avl_link[1] = NULL; + } + + copy_error_recovery (stack, height, new, destroy); + return NULL; + } + + stack[height++] = (struct avl_node *) x; + stack[height++] = y; + x = x->avl_link[0]; + y = y->avl_link[0]; + } + y->avl_link[0] = NULL; + + for (;;) { + y->avl_balance = x->avl_balance; + if (copy == NULL) + y->avl_data = x->avl_data; + else { + y->avl_data = copy (x->avl_data, org->avl_param); + if (y->avl_data == NULL) { + y->avl_link[1] = NULL; + copy_error_recovery (stack, height, new, destroy); + return NULL; + } + } + + if (x->avl_link[1] != NULL) { + y->avl_link[1] = + new->avl_alloc->libavl_malloc (new->avl_alloc, + sizeof *y->avl_link[1]); + if (y->avl_link[1] == NULL) { + copy_error_recovery (stack, height, new, destroy); + return NULL; + } + + x = x->avl_link[1]; + y = y->avl_link[1]; + break; + } else + y->avl_link[1] = NULL; + + if (height <= 2) + return new; + + y = stack[--height]; + x = stack[--height]; + } + } +} + +/* Frees storage allocated for |tree|. + If |destroy != NULL|, applies it to each data item in inorder. */ +void avl_destroy (struct avl_table *tree, avl_item_func * destroy) +{ + struct avl_node *p, *q; + + assert (tree != NULL); + + for (p = tree->avl_root; p != NULL; p = q) + if (p->avl_link[0] == NULL) { + q = p->avl_link[1]; + if (destroy != NULL && p->avl_data != NULL) + destroy (p->avl_data, tree->avl_param); + tree->avl_alloc->libavl_free (tree->avl_alloc, p); + } else { + q = p->avl_link[0]; + p->avl_link[0] = q->avl_link[1]; + q->avl_link[1] = p; + } + + tree->avl_alloc->libavl_free (tree->avl_alloc, tree); +} + +/* Allocates |size| bytes of space using |malloc()|. + Returns a null pointer if allocation fails. */ +void *avl_malloc (struct libavl_allocator *allocator, size_t size) +{ + assert (allocator != NULL && size > 0); + return malloc (size); +} + +/* Frees |block|. */ +void avl_free (struct libavl_allocator *allocator, void *block) +{ + assert (allocator != NULL && block != NULL); + free (block); +} + +/* Default memory allocator that uses |malloc()| and |free()|. */ +struct libavl_allocator avl_allocator_default = { + avl_malloc, + avl_free +}; + +#undef NDEBUG +#include <assert.h> + +/* Asserts that |avl_insert()| succeeds at inserting |item| into |table|. */ +void + (avl_assert_insert) (struct avl_table * table, void *item) { + void **p = avl_probe (table, item); + assert (p != NULL && *p == item); +} + +/* Asserts that |avl_delete()| really removes |item| from |table|, + and returns the removed item. */ +void *(avl_assert_delete) (struct avl_table * table, void *item) { + void *p = avl_delete (table, item); + assert (p != NULL); + return p; +} diff --git a/Build/source/texk/web2c/mpdir/avl.h b/Build/source/texk/web2c/mpdir/avl.h new file mode 100644 index 00000000000..acdf8bacc53 --- /dev/null +++ b/Build/source/texk/web2c/mpdir/avl.h @@ -0,0 +1,118 @@ +/* Produced by texiweb from libavl.w on 2003/01/06 at 18:07. */ + +/* libavl - library for manipulation of binary trees. + Copyright (C) 1998-2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + The author may be contacted at <blp@gnu.org> on the Internet, or + write to Ben Pfaff, Stanford University, Computer Science Dept., 353 + Serra Mall, Stanford CA 94305, USA. +*/ + +#ifndef AVL_H +# define AVL_H 1 + +# include <stddef.h> +# if defined(__cplusplus) +extern "C" { +# endif + + +/* Function types. */ + typedef int avl_comparison_func (const void *avl_a, const void *avl_b, + void *avl_param); + typedef void avl_item_func (void *avl_item, void *avl_param); + typedef void *avl_copy_func (void *avl_item, void *avl_param); + +# ifndef LIBAVL_ALLOCATOR +# define LIBAVL_ALLOCATOR +/* Memory allocator. */ + struct libavl_allocator { + void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size); + void (*libavl_free) (struct libavl_allocator *, void *libavl_block); + }; +# endif + +/* Default memory allocator. */ + extern struct libavl_allocator avl_allocator_default; + void *avl_malloc (struct libavl_allocator *, size_t); + void avl_free (struct libavl_allocator *, void *); + +/* Maximum AVL height. */ +# ifndef AVL_MAX_HEIGHT +# define AVL_MAX_HEIGHT 32 +# endif + +/* Tree data structure. */ + struct avl_table { + struct avl_node *avl_root; /* Tree's root. */ + avl_comparison_func *avl_compare; /* Comparison function. */ + void *avl_param; /* Extra argument to |avl_compare|. */ + struct libavl_allocator *avl_alloc; /* Memory allocator. */ + size_t avl_count; /* Number of items in tree. */ + unsigned long avl_generation; /* Generation number. */ + }; + +/* An AVL tree node. */ + struct avl_node { + struct avl_node *avl_link[2]; /* Subtrees. */ + void *avl_data; /* Pointer to data. */ + signed char avl_balance; /* Balance factor. */ + }; + +/* AVL traverser structure. */ + struct avl_traverser { + struct avl_table *avl_table; /* Tree being traversed. */ + struct avl_node *avl_node; /* Current node in tree. */ + struct avl_node *avl_stack[AVL_MAX_HEIGHT]; + /* All the nodes above |avl_node|. */ + size_t avl_height; /* Number of nodes in |avl_parent|. */ + unsigned long avl_generation; /* Generation number. */ + }; + +/* Table functions. */ + struct avl_table *avl_create (avl_comparison_func *, void *, + struct libavl_allocator *); + struct avl_table *avl_copy (const struct avl_table *, avl_copy_func *, + avl_item_func *, struct libavl_allocator *); + void avl_destroy (struct avl_table *, avl_item_func *); + void **avl_probe (struct avl_table *, void *); + void *avl_insert (struct avl_table *, void *); + void *avl_replace (struct avl_table *, void *); + void *avl_delete (struct avl_table *, const void *); + void *avl_find (const struct avl_table *, const void *); + void avl_assert_insert (struct avl_table *, void *); + void *avl_assert_delete (struct avl_table *, void *); + +# define avl_count(table) ((size_t) (table)->avl_count) + +/* Table traverser functions. */ + void avl_t_init (struct avl_traverser *, struct avl_table *); + void *avl_t_first (struct avl_traverser *, struct avl_table *); + void *avl_t_last (struct avl_traverser *, struct avl_table *); + void *avl_t_find (struct avl_traverser *, struct avl_table *, void *); + void *avl_t_insert (struct avl_traverser *, struct avl_table *, void *); + void *avl_t_copy (struct avl_traverser *, const struct avl_traverser *); + void *avl_t_next (struct avl_traverser *); + void *avl_t_prev (struct avl_traverser *); + void *avl_t_cur (struct avl_traverser *); + void *avl_t_replace (struct avl_traverser *, void *); + +# if defined(__cplusplus) +} +# endif +#endif /* avl.h */ diff --git a/Build/source/texk/web2c/mpdir/avlstuff.c b/Build/source/texk/web2c/mpdir/avlstuff.c new file mode 100644 index 00000000000..300cd2c5218 --- /dev/null +++ b/Build/source/texk/web2c/mpdir/avlstuff.c @@ -0,0 +1,50 @@ +/* +Copyright (c) 2004-2005 Han The Thanh, <thanh@pdftex.org> + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + +This file is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this file; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: avlstuff.c,v 1.12 2005/07/11 20:27:39 hahe Exp hahe $ + +*/ + +#include "mplib.h" +#include <kpathsea/c-vararg.h> +#include <kpathsea/c-proto.h> +#include "avl.h" + +static const char perforce_id[] = + "$Id: avlstuff.c,v 1.12 2005/07/11 20:27:39 hahe Exp hahe $"; + +/* memory management functions for avl */ + +void *avl_xmalloc (struct libavl_allocator *allocator, size_t size) +{ + assert (allocator != NULL && size > 0); + return xmalloc (size); +} + +void avl_xfree (struct libavl_allocator *allocator, void *block) +{ + assert (allocator != NULL && block != NULL); + xfree (block); +} + +struct libavl_allocator avl_xallocator = { + avl_xmalloc, + avl_xfree +}; + + +/**********************************************************************/ diff --git a/Build/source/texk/web2c/mpdir/avlstuff.h b/Build/source/texk/web2c/mpdir/avlstuff.h new file mode 100644 index 00000000000..2ffa57b627d --- /dev/null +++ b/Build/source/texk/web2c/mpdir/avlstuff.h @@ -0,0 +1,29 @@ +/* +Copyright (c) 2004 Han The Thanh, <thanh@pdftex.org> + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + +This file is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this file; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/avlstuff.h#5 $ + +formatted by indent -kr +*/ + +#include "avl.h" + +/* memory management functions for avl */ + +extern struct libavl_allocator avl_xallocator; + +/* end of file avlstuff.h */ diff --git a/Build/source/texk/web2c/mpdir/makecpool.c b/Build/source/texk/web2c/mpdir/makecpool.c new file mode 100644 index 00000000000..02ce0f94bea --- /dev/null +++ b/Build/source/texk/web2c/mpdir/makecpool.c @@ -0,0 +1,58 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) { + if (argc!=3) { + puts("Need exactly two arguments: pool_name and header_name"); + exit(1); + } + char *filename = argv[1]; + char *headername = argv[2]; + FILE *fh = fopen(filename,"r"); + char data[1024]; + printf( + "/* This file is auto-generated by makecpool */\n" + "\n" + "#include <stdio.h>\n" + "#include \"%s\"\n" + "\n" + "static char *poolfilearr[] = {\n",headername); + while (fgets(data,1024,fh)) { + int len = strlen(data); + int o = 0; // skip first o characters + int i; + if (data[len-1]=='\n') { // chomp; + data[len-1] = 0; + len--; + } + if (data[0]=='*') break; // last if /^\*/; + if (data[0]>='0' && data[0]<='9' && data[1]>='0' && data[1]<='9') { + o=2; // $data =~ s/^\d\d//; + } + printf(" \""); + for (i=o; i<len; i++) { + if (data[i]=='"' || data[i]=='\\') putchar('\\'); + if (data[i]=='?') printf("\" \""); /* suppress trigraphs */ + putchar(data[i]); + } // $data =~ s/(["\\])/\\$1/g; + printf("\",\n"); + } + fclose(fh); + printf(" NULL };\n" + "int loadpoolstrings (integer spare_size) {\n" + " strnumber g=0;\n" + " int i=0,j=0;\n" + " char *s;\n" + " while ((s = poolfilearr[j++])) {\n" + " int l = strlen (s);\n" + " i += l;\n" + " if (i>=spare_size) return 0;\n" + " while (l-- > 0) strpool[poolptr++] = *s++;\n" + " g = makestring();\n" + " strref[g]= 127;\n" + " }\n" + " return g;\n" + "}\n"); + return 0; +} diff --git a/Build/source/texk/web2c/mpdir/mapfile.c b/Build/source/texk/web2c/mpdir/mapfile.c new file mode 100644 index 00000000000..25d5818f5c0 --- /dev/null +++ b/Build/source/texk/web2c/mpdir/mapfile.c @@ -0,0 +1,993 @@ +/* Copyright (c) 2006 Taco Hoekwater <taco@elvenkind.com> + +This file is part of MetaPost. + +MetaPost is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +MetaPost is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with MetaPost; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: mapfile.c,v 1.20 2005/10/16 17:41:51 hahe Exp hahe $ + +*/ + +#include <math.h> +#include "mplib.h" +#include <kpathsea/c-auto.h> +#include <kpathsea/c-memstr.h> +#include <string.h> + +static const char perforce_id[] = + "$Id: mapfile.c,v 1.20 2005/10/16 17:41:51 hahe Exp hahe $"; + +#define FM_BUF_SIZE 1024 + +static FILE *fm_file; + +#define fm_open() \ + open_input (&fm_file, kpse_fontmap_format, FOPEN_RBIN_MODE) +#define fm_close() xfclose(fm_file, cur_file_name) +#define fm_getchar() xgetc(fm_file) +#define fm_eof() feof(fm_file) + +enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE }; +enum _ltype { MAPFILE, MAPLINE }; +enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND }; + +typedef struct mitem { + int mode; /* FM_DUPIGNORE or FM_REPLACE or FM_DELETE */ + int type; /* map file or map line */ + char *line; /* pointer to map file name or map line */ + int lineno; /* line number in map file */ +} mapitem; +mapitem *mitem = NULL; + +fm_entry *fm_cur; +static const char nontfm[] = "<nontfm>"; +static fm_entry *loaded_tfm_found; +static fm_entry *avail_tfm_found; +static fm_entry *non_tfm_found; +static fm_entry *not_avail_tfm_found; + +#define read_field(r, q, buf) do { \ + q = buf; \ + while (*r != ' ' && *r != '\0') \ + *q++ = *r++; \ + *q = '\0'; \ + skip (r, ' '); \ +} while (0) + +#define set_field(F) do { \ + if (q > buf) \ + fm->F = xstrdup(buf); \ + if (*r == '\0') \ + goto done; \ +} while (0) + +#define cmp_return(a, b) \ + if (a > b) \ + return 1; \ + if (a < b) \ + return -1 + +fm_entry *new_fm_entry (void) +{ + fm_entry *fm; + fm = xtalloc (1, fm_entry); + fm->tfm_name = NULL; + fm->ps_name = NULL; + fm->flags = 4; + fm->ff_name = NULL; + fm->subset_tag = NULL; + fm->encoding = NULL; + fm->tfm_num = getnullfont (); + fm->tfm_avail = TFM_UNCHECKED; + fm->type = 0; + fm->slant = 0; + fm->extend = 0; + fm->ff_objnum = 0; + fm->fn_objnum = 0; + fm->fd_objnum = 0; + fm->charset = NULL; + fm->all_glyphs = false; + fm->links = 0; + fm->pid = -1; + fm->eid = -1; + fm->subfont = NULL; + return fm; +} + +void delete_fm_entry (fm_entry * fm) +{ + xfree (fm->tfm_name); + xfree (fm->ps_name); + xfree (fm->ff_name); + xfree (fm->subset_tag); + xfree (fm->charset); + xfree (fm); +} + +static ff_entry *new_ff_entry (void) +{ + ff_entry *ff; + ff = xtalloc (1, ff_entry); + ff->ff_name = NULL; + ff->ff_path = NULL; + return ff; +} + +static void delete_ff_entry (ff_entry * ff) +{ + xfree (ff->ff_name); + xfree (ff->ff_path); + xfree (ff); +} + +static fm_entry *dummy_fm_entry () +{ + static const fm_entry const_fm_entry; + return (fm_entry *) & const_fm_entry; +} + +char *mk_base_tfm (char *tfmname, int *i) +{ + static char buf[SMALL_BUF_SIZE]; + char *p = tfmname, *r = strend (p) - 1, *q = r; + while (q > p && isdigit (*q)) + --q; + if (!(q > p) || q == r || (*q != '+' && *q != '-')) + return NULL; + check_buf (q - p + 1, SMALL_BUF_SIZE); + strncpy (buf, p, (size_t) (q - p)); + buf[q - p] = '\0'; + *i = atoi (q); + return buf; +} + +static fmentryptr fmlookup (fontnumber); + +boolean hasfmentry (fontnumber f) +{ + if (mpfontmap[f] == NULL) + mpfontmap[f] = fmlookup (f); + assert (mpfontmap[f] != NULL); + return mpfontmap[f] != (fmentryptr) dummy_fm_entry (); +} + +/**********************************************************************/ + +struct avl_table *tfm_tree = NULL; +struct avl_table *ps_tree = NULL; +struct avl_table *ff_tree = NULL; + +/* AVL sort fm_entry into tfm_tree by tfm_name */ + +static int comp_fm_entry_tfm (const void *pa, const void *pb, void *p) +{ + return strcmp (((const fm_entry *) pa)->tfm_name, + ((const fm_entry *) pb)->tfm_name); +} + +/* AVL sort fm_entry into ps_tree by ps_name, slant, and extend */ + +static int comp_fm_entry_ps (const void *pa, const void *pb, void *p) +{ + const fm_entry *p1 = (const fm_entry *) pa, *p2 = (const fm_entry *) pb; + int i; + assert (p1->ps_name != NULL && p2->ps_name != NULL); + if ((i = strcmp (p1->ps_name, p2->ps_name))) + return i; + cmp_return (p1->slant, p2->slant); + cmp_return (p1->extend, p2->extend); + if (p1->tfm_name != NULL && p2->tfm_name != NULL && + (i = strcmp (p1->tfm_name, p2->tfm_name))) + return i; + return 0; +} + +/* AVL sort ff_entry into ff_tree by ff_name */ + +static int comp_ff_entry (const void *pa, const void *pb, void *p) +{ + return strcmp (((const ff_entry *) pa)->ff_name, + ((const ff_entry *) pb)->ff_name); +} + +static void create_avl_trees () +{ + if (tfm_tree == NULL) { + tfm_tree = avl_create (comp_fm_entry_tfm, NULL, &avl_xallocator); + assert (tfm_tree != NULL); + } + if (ps_tree == NULL) { + ps_tree = avl_create (comp_fm_entry_ps, NULL, &avl_xallocator); + assert (ps_tree != NULL); + } + if (ff_tree == NULL) { + ff_tree = avl_create (comp_ff_entry, NULL, &avl_xallocator); + assert (ff_tree != NULL); + } +} + +/* +The function avl_do_entry() is not completely symmetrical with regards +to tfm_name and ps_name handling, e. g. a duplicate tfm_name gives a +"goto exit", and no ps_name link is tried. This is to keep it compatible +with the original version. +*/ + +int avl_do_entry (fm_entry * fp, int mode) +{ + fm_entry *p; + void *a; + void **aa; + + /* handle tfm_name link */ + + if (strcmp (fp->tfm_name, nontfm)) { + p = (fm_entry *) avl_find (tfm_tree, fp); + if (p != NULL) { + if (mode == FM_DUPIGNORE) { + pdftex_warn + ("fontmap entry for `%s' already exists, duplicates ignored", + fp->tfm_name); + goto exit; + } else { /* mode == FM_REPLACE / FM_DELETE */ + if (fontsizes[p->tfm_num]!=0) { + pdftex_warn + ("fontmap entry for `%s' has been used, replace/delete not allowed", + fp->tfm_name); + goto exit; + } + a = avl_delete (tfm_tree, p); + assert (a != NULL); + unset_tfmlink (p); + if (!has_pslink (p)) + delete_fm_entry (p); + } + } + if (mode != FM_DELETE) { + aa = avl_probe (tfm_tree, fp); + assert (aa != NULL); + set_tfmlink (fp); + } + } + + /* handle ps_name link */ + + if (fp->ps_name != NULL) { + assert (fp->tfm_name != NULL); + p = (fm_entry *) avl_find (ps_tree, fp); + if (p != NULL) { + if (mode == FM_DUPIGNORE) { + pdftex_warn + ("ps_name entry for `%s' already exists, duplicates ignored", + fp->ps_name); + goto exit; + } else { /* mode == FM_REPLACE / FM_DELETE */ + if (fontsizes[p->tfm_num]!=0) { + /* REPLACE/DELETE not allowed */ + pdftex_warn + ("fontmap entry for `%s' has been used, replace/delete not allowed", + p->tfm_name); + goto exit; + } + a = avl_delete (ps_tree, p); + assert (a != NULL); + unset_pslink (p); + if (!has_tfmlink (p)) + delete_fm_entry (p); + } + } + if (mode != FM_DELETE) { + aa = avl_probe (ps_tree, fp); + assert (aa != NULL); + set_pslink (fp); + } + } + exit: + if (!has_tfmlink (fp) && !has_pslink (fp)) /* e. g. after FM_DELETE */ + return 1; /* deallocation of fm_entry structure required */ + else + return 0; +} + +/**********************************************************************/ +/* consistency check for map entry, with warn flag */ + +int check_fm_entry (fm_entry * fm, boolean warn) +{ + int a = 0; + assert (fm != NULL); + if (fm->ps_name != NULL) { + if (is_basefont (fm)) { + if (is_fontfile (fm) && !is_included (fm)) { + if (warn) + pdftex_warn + ("invalid entry for `%s': font file must be included or omitted for base fonts", + fm->tfm_name); + a += 1; + } + } else { /* not a base font */ + /* if no font file given, drop this entry */ + /* if (!is_fontfile (fm)) { + if (warn) + pdftex_warn + ("invalid entry for `%s': font file missing", + fm->tfm_name); + a += 2; + } + */ + } + } + if (is_truetype (fm) && is_reencoded (fm) && !is_subsetted (fm)) { + if (warn) + pdftex_warn + ("invalid entry for `%s': only subsetted TrueType font can be reencoded", + fm->tfm_name); + a += 4; + } + if ((fm->slant != 0 || fm->extend != 0) && + (is_truetype (fm))) { + if (warn) + pdftex_warn + ("invalid entry for `%s': SlantFont/ExtendFont can be used only with embedded T1 fonts", + fm->tfm_name); + a += 8; + } + if (abs (fm->slant) > 1000) { + if (warn) + pdftex_warn + ("invalid entry for `%s': too big value of SlantFont (%g)", + fm->tfm_name, fm->slant / 1000.0); + a += 16; + } + if (abs (fm->extend) > 2000) { + if (warn) + pdftex_warn + ("invalid entry for `%s': too big value of ExtendFont (%g)", + fm->tfm_name, fm->extend / 1000.0); + a += 32; + } + if (fm->pid != -1 && + !(is_truetype (fm) && is_included (fm) && + is_subsetted (fm) && !is_reencoded (fm))) { + if (warn) + pdftex_warn + ("invalid entry for `%s': PidEid can be used only with subsetted non-reencoded TrueType fonts", + fm->tfm_name); + a += 64; + } + return a; +} + +/**********************************************************************/ +/* returns true if s is one of the 14 std. font names; speed-trimmed. */ + +boolean check_basefont (char *s) +{ + static const char *basefont_names[] = { + "Courier", /* 0:7 */ + "Courier-Bold", /* 1:12 */ + "Courier-Oblique", /* 2:15 */ + "Courier-BoldOblique", /* 3:19 */ + "Helvetica", /* 4:9 */ + "Helvetica-Bold", /* 5:14 */ + "Helvetica-Oblique", /* 6:17 */ + "Helvetica-BoldOblique", /* 7:21 */ + "Symbol", /* 8:6 */ + "Times-Roman", /* 9:11 */ + "Times-Bold", /* 10:10 */ + "Times-Italic", /* 11:12 */ + "Times-BoldItalic", /* 12:16 */ + "ZapfDingbats" /* 13:12 */ + }; + static const int index[] = + { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6, + -1, 3, -1, 7 + }; + const size_t n = strlen (s); + int k = -1; + if (n > 21) + return false; + if (n == 12) { /* three names have length 12 */ + switch (*s) { + case 'C': + k = 1; /* Courier-Bold */ + break; + case 'T': + k = 11; /* Times-Italic */ + break; + case 'Z': + k = 13; /* ZapfDingbats */ + break; + default: + return false; + } + } else + k = index[n]; + if (k > -1 && !strcmp (basefont_names[k], s)) + return true; + return false; +}; + +/**********************************************************************/ + +static void fm_scan_line () +{ + int a, b, c, j, u = 0, v = 0; + float d; + fm_entry *fm; + char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE]; + char *p, *q, *r, *s; + switch (mitem->type) { + case MAPFILE: + p = fm_line; + do { + c = fm_getchar (); + append_char_to_buf (c, p, fm_line, FM_BUF_SIZE); + } + while (c != 10); + *(--p) = '\0'; + r = fm_line; + break; + case MAPLINE: + r = mitem->line; /* work on string from makecstring() */ + break; + default: + assert (0); + } + if (*r == '\0' || is_cfg_comment (*r)) + return; + fm = new_fm_entry (); + read_field (r, q, buf); + set_field (tfm_name); + p = r; + read_field (r, q, buf); + if (*buf != '<' && *buf != '"') + set_field (ps_name); + else + r = p; /* unget the field */ + if (isdigit (*r)) { /* font flags given */ + fm->flags = atoi (r); + while (isdigit (*r)) + r++; + } + while (1) { /* loop through "specials", encoding, font file */ + skip (r, ' '); + switch (*r) { + case '\0': + goto done; + case '"': /* opening quote */ + r++; + u = v = 0; + do { + skip (r, ' '); + if (sscanf (r, "%f %n", &d, &j) > 0) { + s = r + j; /* jump behind number, eat also blanks, if any */ + if (*(s - 1) == 'E' || *(s - 1) == 'e') + s--; /* e. g. 0.5ExtendFont: %f = 0.5E */ + if (str_prefix (s, "SlantFont")) { + d *= 1000.0; /* correct rounding also for neg. numbers */ + fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5); + r = s + strlen ("SlantFont"); + } else if (str_prefix (s, "ExtendFont")) { + d *= 1000.0; + fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5); + if (fm->extend == 1000) + fm->extend = 0; + r = s + strlen ("ExtendFont"); + } else { /* unknown name */ + for (r = s; *r != ' ' && *r != '"' && *r != '\0'; r++); /* jump over name */ + c = *r; /* remember char for temporary end of string */ + *r = '\0'; + pdftex_warn + ("invalid entry for `%s': unknown name `%s' ignored", + fm->tfm_name, s); + *r = c; + } + } else + for (; *r != ' ' && *r != '"' && *r != '\0'; r++); + } + while (*r == ' '); + if (*r == '"') /* closing quote */ + r++; + else { + pdftex_warn + ("invalid entry for `%s': closing quote missing", + fm->tfm_name); + goto bad_line; + } + break; + case 'P': /* handle cases for subfonts like 'PidEid=3,1' */ + if (sscanf (r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) { + fm->pid = a; + fm->eid = b; + r += c; + break; + } + default: /* encoding or font file specification */ + a = b = 0; + if (*r == '<') { + a = *r++; + if (*r == '<' || *r == '[') + b = *r++; + } + read_field (r, q, buf); + /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */ + if (strlen (buf) > 4 && strcasecmp (strend (buf) - 4, ".enc") == 0) { + fm->encoding = add_enc (buf); + u = v = 0; /* u, v used if intervening blank: "<< foo" */ + } else if (strlen (buf) > 0) { /* file name given */ + /* font file, formats: + * subsetting: '<cmr10.pfa' + * no subsetting: '<<cmr10.pfa' + * no embedding: 'cmr10.pfa' + */ + if (a == '<' || u == '<') { + set_included (fm); + if ((a == '<' && b == 0) || (a == 0 && v == 0)) + set_subsetted (fm); + /* otherwise b == '<' (or '[') => no subsetting */ + } + set_field (ff_name); + u = v = 0; + } else { + u = a; + v = b; + } + } + } + done: + if (fm->ps_name != NULL && check_basefont (fm->ps_name)) + set_basefont (fm); + if (is_fontfile (fm) + && strcasecmp (strend (fm_fontfile (fm)) - 4, ".ttf") == 0) + set_truetype (fm); + if (check_fm_entry (fm, true) != 0) + goto bad_line; + /* + Until here the map line has been completely scanned without errors; + fm points to a valid, freshly filled-out fm_entry structure. + Now follows the actual work of registering/deleting. + */ + // if (handle_subfont_fm (fm, mitem->mode)) /* is this a subfont? */ + // return; + if (avl_do_entry (fm, mitem->mode) == 0) /* if success */ + return; + bad_line: + delete_fm_entry (fm); +} + +/**********************************************************************/ + +void fm_read_info () +{ + if (tfm_tree == NULL) + create_avl_trees (); + if (mitem->line == NULL) /* nothing to do */ + return; + mitem->lineno = 1; + switch (mitem->type) { + case MAPFILE: + set_cur_file_name (mitem->line); + if (!fm_open ()) { + pdftex_warn ("cannot open font map file"); + } else { + cur_file_name = (char *) nameoffile + 1; + mp_printf ("{%s", cur_file_name); + while (!fm_eof ()) { + fm_scan_line (); + mitem->lineno++; + } + fm_close (); + mp_printf ("}"); + fm_file = NULL; + } + break; + case MAPLINE: + cur_file_name = NULL; /* makes pdftex_warn() shorter */ + fm_scan_line (); + break; + default: + assert (0); + } + mitem->line = NULL; /* done with this line */ + cur_file_name = NULL; + return; +} + +/**********************************************************************/ + +fontnumber tfmoffm (fmentryptr fm_pt) +{ + return ((fm_entry *) fm_pt)->tfm_num; +} + +static fm_entry *mk_ex_fm (fontnumber f, fm_entry * basefm, int ex) +{ + fm_entry *fm; + integer e = basefm->extend; + if (e == 0) + e = 1000; + fm = new_fm_entry (); + fm->flags = basefm->flags; + fm->encoding = basefm->encoding; + fm->type = basefm->type; + fm->slant = basefm->slant; + fm->extend = roundxnoverd (e, 1000 + ex, 1000); /* modify ExtentFont to simulate expansion */ + if (fm->extend == 1000) + fm->extend = 0; + fm->tfm_name = xstrdup (makecstring (fontname[f])); + if (basefm->ps_name != NULL) + fm->ps_name = xstrdup (basefm->ps_name); + fm->ff_name = xstrdup (basefm->ff_name); + fm->ff_objnum = 0; + fm->tfm_num = f; + fm->tfm_avail = TFM_FOUND; + assert (strcmp (fm->tfm_name, nontfm)); + return fm; +} + +static void init_fm (fm_entry * fm, fontnumber f) +{ + // if (fm->fd_objnum == 0 && !no_font_desc (fm)) + // fm->fd_objnum = pdfnewobjnum (); + // if (fm->ff_objnum == 0 && is_included (fm)) + // fm->ff_objnum = pdfnewobjnum (); + if (fm->tfm_num == getnullfont ()) { + fm->tfm_num = f; + fm->tfm_avail = TFM_FOUND; + } +} + +static fmentryptr fmlookup (fontnumber f) +{ + char *tfm; + fm_entry *fm, *exfm; + fm_entry tmp; + int ai, e; + if (tfm_tree == NULL) + fm_read_info (); /* only to read default map file */ + tfm = makecstring (fontname[f]); + assert (strcmp (tfm, nontfm)); + + /* Look up for full <tfmname>[+-]<expand> */ + tmp.tfm_name = tfm; + fm = (fm_entry *) avl_find (tfm_tree, &tmp); + if (fm != NULL) { + init_fm (fm, f); + return (fmentryptr) fm; + } + tfm = mk_base_tfm (makecstring (fontname[f]), &e); + if (tfm == NULL) /* not an expanded font, nothing to do */ + return (fmentryptr) dummy_fm_entry (); + + tmp.tfm_name = tfm; + fm = (fm_entry *) avl_find (tfm_tree, &tmp); + if (fm != NULL) { /* found an entry with the base tfm name, e.g. cmr10 */ + return (fmentryptr) fm; /* font expansion uses the base font */ + /* the following code would be obsolete, as would be mk_ex_fm() */ + if (!is_t1fontfile (fm) || !is_included (fm)) { + pdftex_warn + ("font %s cannot be expanded (not an included Type1 font)", + tfm); + return (fmentryptr) dummy_fm_entry (); + } + exfm = mk_ex_fm (f, fm, e); /* copies all fields from fm except tfm name */ + init_fm (exfm, f); + ai = avl_do_entry (exfm, FM_DUPIGNORE); + assert (ai == 0); + return (fmentryptr) exfm; + } + return (fmentryptr) dummy_fm_entry (); +} + +/* + Early check whether a font file exists. Used e. g. for replacing fonts + of embedded PDF files: Without font file, the font within the embedded + PDF-file is used. Search tree ff_tree is used in 1st instance, as it + may be faster than the kpse_find_file(), and kpse_find_file() is called + only once per font file name + expansion parameter. This might help + keeping speed, if many PDF pages with same fonts are to be embedded. + + The ff_tree contains only font files, which are actually needed, + so this tree typically is much smaller than the tfm_tree or ps_tree. +*/ + +ff_entry *check_ff_exist (fm_entry * fm) +{ + ff_entry *ff; + ff_entry tmp; + void **aa; + + assert (fm->ff_name != NULL); + tmp.ff_name = fm->ff_name; + ff = (ff_entry *) avl_find (ff_tree, &tmp); + if (ff == NULL) { /* not yet in database */ + ff = new_ff_entry (); + ff->ff_name = xstrdup (fm->ff_name); + if (is_truetype (fm)) + ff->ff_path = kpse_find_file (fm->ff_name, kpse_truetype_format, 0); + else + ff->ff_path = kpse_find_file (fm->ff_name, kpse_type1_format, 0); + aa = avl_probe (ff_tree, ff); + assert (aa != NULL); + } + return ff; +} + +/**********************************************************************/ + +static boolean used_tfm (fm_entry * p) +{ + fontnumber f; + strnumber s; + ff_entry *ff; + + /* check if the font file is not a TrueType font */ + /* font replacement makes sense only for included Type1 files */ + if (is_truetype (p) || !is_included (p)) + return false; + + /* check if the font file is available */ + ff = check_ff_exist (p); + if (ff->ff_path == NULL) + return false; + + /* check whether this font has been used */ + if (fontsizes[p->tfm_num]!=0) + return true; + assert (p->tfm_name != NULL); + + /* check whether we didn't find a loaded font yet, + * and this font has been loaded */ + if (loaded_tfm_found == NULL && strcmp (p->tfm_name, nontfm)) { + s = maketexstring (p->tfm_name); + if ((f = tfmlookup (s, 0)) != getnullfont ()) { + loaded_tfm_found = p; + if (mpfontmap[f] == NULL) + mpfontmap[f] = (fmentryptr) p; + if (p->tfm_num == getnullfont ()) + p->tfm_num = f; + assert (p->tfm_num == f); + /* don't call flushstr() here as it has been called by tfmlookup() */ + } else + flushstr (s); + } + + /* check whether we didn't find either a loaded or a loadable font yet, + * and this font is loadable */ + if (avail_tfm_found == NULL && loaded_tfm_found == NULL && + strcmp (p->tfm_name, nontfm)) { + if (p->tfm_avail == TFM_UNCHECKED) { + if (kpse_find_file (p->tfm_name, kpse_tfm_format, 0) != NULL) { + avail_tfm_found = p; + p->tfm_avail = TFM_FOUND; + } else { + p->tfm_avail = TFM_NOTFOUND; + if (not_avail_tfm_found == NULL) + not_avail_tfm_found = p; + } + } + } + + /* check whether the current entry is a <nontfm> entry */ + if (non_tfm_found == NULL && !strcmp (p->tfm_name, nontfm)) + non_tfm_found = p; + + return false; +} + +/* lookup_ps_name looks for an entry with a given ps name + slant + extend; + * return NULL if not found. + * + * As there may exist several such entries, we need to select the `right' + * one. We do so by checking all such entries and return the first one that + * fulfils the following criteria (in descending priority): + * + * - the tfm has been used (some char from this font has been typeset) + * - the tfm has been loaded (but not used yet) + * - the tfm can be loaded (but not loaded yet) + * - the tfm is present in map files, but cannot be loaded. In this case a + * dummy tfm can be loaded instead, and a warning should be written out + */ + +static fm_entry *lookup_ps_name (fm_entry * fm) +{ + fm_entry *p, *p2; + struct avl_traverser t, t2; + int a; + + loaded_tfm_found = NULL; + avail_tfm_found = NULL; + non_tfm_found = NULL; + not_avail_tfm_found = NULL; + + assert (fm->tfm_name == NULL); + p = (fm_entry *) avl_t_find (&t, ps_tree, fm); + if (p == NULL) + return NULL; + t2 = t; + p2 = (fm_entry *) avl_t_prev (&t2); + + /* search forward */ + do { + if (used_tfm (p)) + return p; + p = (fm_entry *) avl_t_next (&t); + } + while (p != NULL && comp_fm_entry_ps (fm, p, NULL) == 0); + + /* search backward */ + while (p2 != NULL && comp_fm_entry_ps (fm, p2, NULL) == 0) { + if (used_tfm (p2)) + return p2; + p2 = (fm_entry *) avl_t_prev (&t2); + } + + if (loaded_tfm_found != NULL) + p = loaded_tfm_found; + else if (avail_tfm_found != NULL) { + /* TH: do not do this for metapost, there is no embedding anyway */ + /* p = avail_tfm_found; + * p->tfm_num = readfontinfo (getnullcs (), maketexstring (p->tfm_name), + * getnullstr (), -1000); + * p->tfm_avail = TFM_FOUND; + */ + } else if (non_tfm_found != NULL) { + p = non_tfm_found; + p->tfm_num = newdummyfont (); + p->tfm_avail = TFM_FOUND; + } else if (not_avail_tfm_found != NULL) { + p = not_avail_tfm_found; + pdftex_warn ("`%s' not loadable, use a dummy tfm instead", p->tfm_name); + p2 = new_fm_entry (); + p2->flags = p->flags; + p2->encoding = p->encoding; + p2->type = p->type; + p2->slant = p->slant; + p2->extend = p->extend; + p2->tfm_name = xstrdup (nontfm); + p2->ps_name = xstrdup (p->ps_name); + if (p->ff_name != NULL) + p2->ff_name = xstrdup (p->ff_name); + p2->tfm_num = newdummyfont (); + p2->tfm_avail = TFM_FOUND; + a = avl_do_entry (p2, FM_DUPIGNORE); + assert (a == 0); + p = p2; + } else + return NULL; + assert (p->tfm_num != getnullfont ()); + return p; +} + + +/**********************************************************************/ +/* +Process map file given by its name or map line contents. Items not +beginning with [+-=] flush default map file, if it has not yet been +read. Leading blanks and blanks immediately following [+-=] are ignored. +*/ + +void process_map_item (char *s, int type) +{ + char *p; + int mode; + if (*s == ' ') + s++; /* ignore leading blank */ + switch (*s) { + case '+': /* +mapfile.map, +mapline */ + mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */ + s++; + break; + case '=': /* =mapfile.map, =mapline */ + mode = FM_REPLACE; /* try to replace earlier entry */ + s++; + break; + case '-': /* -mapfile.map, -mapline */ + mode = FM_DELETE; /* try to delete entry */ + s++; + break; + default: + mode = FM_DUPIGNORE; /* like +, but also: */ + mitem->line = NULL; /* flush default map file name */ + } + if (*s == ' ') + s++; /* ignore blank after [+-=] */ + p = s; /* map item starts here */ + switch (type) { + case MAPFILE: /* remove blank at end */ + while (*p != '\0' && *p != ' ') + p++; + *p = '\0'; + break; + case MAPLINE: /* blank at end allowed */ + break; + default: + assert (0); + } + if (mitem->line != NULL) /* read default map file first */ + fm_read_info (); + if (*s != '\0') { /* only if real item to process */ + mitem->mode = mode; + mitem->type = type; + mitem->line = s; + fm_read_info (); + } +} + +void mpmapfile (strnumber t) +{ + char *s = xstrdup(makecstring (t)); + process_map_item (s, MAPFILE); + xfree (s); +} + +void mpmapline (strnumber t) +{ + char *s = xstrdup(makecstring (t)); + process_map_item (s, MAPLINE); + xfree (s); +} + +void mpinitmapfile (void) +{ + assert (mitem == NULL); + mitem = xtalloc (1, mapitem); + mitem->mode = FM_DUPIGNORE; + mitem->type = MAPFILE; + if (kpse_find_file("mpost.map", kpse_fontmap_format,0)) + mitem->line = xstrdup ("mpost.map"); + else + mitem->line = xstrdup ("pdftex.map"); +} + +/**********************************************************************/ +/* cleaning up... */ + +static void destroy_fm_entry_tfm (void *pa, void *pb) +{ + fm_entry *fm; + fm = (fm_entry *) pa; + if (!has_pslink (fm)) + delete_fm_entry (fm); + else + unset_tfmlink (fm); +} +static void destroy_fm_entry_ps (void *pa, void *pb) +{ + fm_entry *fm; + fm = (fm_entry *) pa; + if (!has_tfmlink (fm)) + delete_fm_entry (fm); + else + unset_pslink (fm); +} +static void destroy_ff_entry (void *pa, void *pb) +{ + ff_entry *ff; + ff = (ff_entry *) pa; + delete_ff_entry (ff); +} void fm_free (void) +{ + if (tfm_tree != NULL) + avl_destroy (tfm_tree, destroy_fm_entry_tfm); + if (ps_tree != NULL) + avl_destroy (ps_tree, destroy_fm_entry_ps); + if (ff_tree != NULL) + avl_destroy (ff_tree, destroy_ff_entry); +} + +/**********************************************************************/ +/* end of mapfile.c */ diff --git a/Build/source/texk/web2c/mpdir/mp.defines b/Build/source/texk/web2c/mpdir/mp.defines new file mode 100644 index 00000000000..bdd51f83332 --- /dev/null +++ b/Build/source/texk/web2c/mpdir/mp.defines @@ -0,0 +1,54 @@ +{ +Copyright (c) 2006 Taco Hoekwater <taco@elvenkind.com> + +This file is part of MetaPost. + +MetaPost is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +MetaPost is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with MetaPost; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id$ +} + +{ functions from loadpool.c } + +@define function loadpoolstrings(); + +{ functions from mapfile.c } + +@define function hasfmentry(); +@define function tfmoffm(); +@define procedure mpmapfile(); +@define procedure mpmapline(); +@define procedure mpinitmapfile; + +{ functions from writefont.c } + +@define procedure mploadencodings(); +@define procedure mpfontencodings(); +@define function fontisreencoded(); +@define function fontisincluded(); +@define function fontissubsetted(); + +@define function fmencodingname(); +@define function fmfontname(); +@define function fmfontsubsetname(); +@define function fmfontslant(); +@define function fmfontextend(); + +@define function dopsfont(); + +{ functions from utils.c } + +@define procedure setjobid(); + diff --git a/Build/source/texk/web2c/mpdir/mplib.h b/Build/source/texk/web2c/mpdir/mplib.h new file mode 100644 index 00000000000..363836a994d --- /dev/null +++ b/Build/source/texk/web2c/mpdir/mplib.h @@ -0,0 +1,300 @@ +/* +Copyright (c) 2006 Taco Hoekwater <taco@elvenkind.com> + +This file is part of pdfTeX. + +pdfTeX is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +pdfTeX is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id$ +*/ + +#ifndef MPOSTLIB +# define MPOSTLIB + +/* WEB2C macros and prototypes */ +# if !defined(MPOSTCOERCE) +# define EXTERN extern +# include "mpd.h" +# endif + +/* pdftexlib macros */ +# include "mpmac.h" + +# include "avlstuff.h" + + +/* pdftexlib type declarations */ +typedef struct { + const char *pdfname; + const char *t1name; + float value; + boolean valid; +} key_entry; + +typedef struct { + boolean loaded; /* the encoding has been loaded? */ + char *name; /* encoding file name */ + char *encname; /* encoding true name */ + integer objnum; /* object number */ + char **glyph_names; + integer tounicode; /* object number of associated ToUnicode entry */ +} enc_entry; + +struct _subfont_entry; +typedef struct _subfont_entry subfont_entry; + +struct _subfont_entry { + char *infix; /* infix for this subfont, eg "01" */ + long charcodes[256]; /* the mapping for this subfont as read from sfd */ + subfont_entry *next; +}; + +typedef struct { + char *name; /* sfd name, eg "Unicode" */ + subfont_entry *subfont; /* linked list of subfonts */ +} sfd_entry; + +typedef struct { + char *name; /* glyph name */ + long code; /* -1 = undefined; -2 = multiple codes, stored + as string in unicode_seq; otherwise unicode value */ + char *unicode_seq; /* multiple unicode sequence */ +} glyph_unicode_entry; + +typedef struct { + char *tfm_name; /* TFM file name */ + char *ps_name; /* PostScript name */ + integer flags; /* font flags */ + char *ff_name; /* font file name */ + char *subset_tag; /* pseudoUniqueTag for subsetted font */ + enc_entry *encoding; /* pointer to corresponding encoding */ + fontnumber tfm_num; /* number of the TFM refering this entry */ + unsigned short type; /* font type (T1/TTF/...) */ + short slant; /* SlantFont */ + short extend; /* ExtendFont */ + integer ff_objnum; /* FontFile object number */ + integer fn_objnum; /* FontName/BaseName object number */ + integer fd_objnum; /* FontDescriptor object number */ + char *charset; /* string containing used glyphs */ + boolean all_glyphs; /* embed all glyphs? */ + unsigned short links; /* link flags from tfm_tree and ps_tree */ + short tfm_avail; /* flags whether a tfm is available */ + short pid; /* Pid for truetype fonts */ + short eid; /* Eid for truetype fonts */ + subfont_entry *subfont; /* subfont mapping */ +} fm_entry; + +typedef struct { + char *ff_name; /* base name of font file */ + char *ff_path; /* full path to font file */ +} ff_entry; + +typedef short shalfword; +typedef struct { + integer charcode, cwidth, cheight, xoff, yoff, xescape, rastersize; + halfword *raster; +} chardesc; + +/* pdftexlib variable declarations */ +extern boolean fontfile_found; +extern boolean is_otf_font; +extern boolean true_dimen; +extern boolean write_ttf_glyph_names; +extern char **t1_glyph_names, *t1_builtin_glyph_names[]; +extern char *cur_file_name; +extern const char notdef[]; +extern integer t1_length1, t1_length2, t1_length3; +extern integer ttf_length; +extern key_entry font_keys[]; +extern strnumber last_tex_string; +extern size_t last_ptr_index; +extern char fontname_buf[]; + +/* pdftexlib function prototypes */ + +/* epdf.c */ +extern integer get_fontfile_num (int); +extern integer get_fontname_num (int); +extern void epdf_free (void); +extern int is_type1 (fm_entry *); + +/* mapfile.c */ +extern char *mk_basename (char *); +extern char *mk_exname (char *, int); +extern fm_entry *lookup_fontmap (char *); +extern boolean hasfmentry (fontnumber); +extern fontnumber tfmoffm (fmentryptr); +extern void checkextfm (strnumber, integer); +extern void fm_free (void); +extern void fm_read_info (void); +extern ff_entry *check_ff_exist (fm_entry *); +extern void pdfmapfile (integer); +extern void pdfmapline (integer); +extern void pdfinitmapfile (string map_name); +extern fm_entry *new_fm_entry (void); +extern void delete_fm_entry (fm_entry *); +extern int avl_do_entry (fm_entry *, int); + +/* papersiz.c */ +extern integer myatodim (char **); +extern integer myatol (char **); + +/* pkin.c */ +extern int readchar (boolean, chardesc *); + +/* subfont.c */ +extern void sfd_free (void); +extern boolean handle_subfont_fm (fm_entry *, int); + +/* tounicode.c */ +extern void glyph_unicode_free (void); +extern void deftounicode (strnumber, strnumber); +extern integer write_tounicode (char **, char *); + +/* utils.c */ +extern boolean str_eq_cstr (strnumber, char *); +extern char *makecstring (integer); +extern int xfflush (FILE *); +extern int xgetc (FILE *); +extern int xputc (int, FILE *); +extern scaled extxnoverd (scaled, scaled, scaled); +extern size_t xfwrite (void *, size_t size, size_t nmemb, FILE *); +extern strnumber getresnameprefix (void); +extern strnumber maketexstring (const char *); +extern integer fb_offset (void); +extern void fb_flush (void); +extern void fb_putchar (eightbits b); +extern void fb_seek (integer); +extern void libpdffinish (void); +extern char *makecfilename (strnumber s); +extern void make_subset_tag (fm_entry *, char **, int); +extern void pdf_printf (const char *, ...); +extern void pdf_puts (const char *); +extern void pdftex_fail (const char *, ...); +extern void pdftex_warn (const char *, ...); +extern void setjobid (int, int, int, int); +extern void mp_printf (const char *, ...); +extern void writestreamlength (integer, integer); +extern char *convertStringToPDFString (const char *in, int len); +extern void printID (strnumber); +extern void printcreationdate (); +extern void printmoddate (); +extern void escapename (poolpointer in); +extern void escapestring (poolpointer in); +extern void escapehex (poolpointer in); +extern void unescapehex (poolpointer in); +extern void getcreationdate (); +extern void getfilemoddate (strnumber s); +extern void getfilesize (strnumber s); +extern void getmd5sum (strnumber s, boolean file); +extern void getfiledump (strnumber s, int offset, int length); +extern void matchstrings (strnumber s, strnumber t, int subcount, + boolean icase); +extern void getmatch (int i); +extern void makepdftexbanner (void); +extern void initstarttime (); +extern void removepdffile (void); +extern void garbagewarning (void); +extern void stripspaces (char *p); +extern void initversionstring (char **versions); +extern int newcolorstack (integer s, integer literal_mode, boolean pagestart); +extern int colorstackused (); +extern integer colorstackset (int colstack_no, integer s); +extern integer colorstackpush (int colstack_no, integer s); +extern integer colorstackpop (int colstack_no); +extern integer colorstackcurrent (int colstack_no); +extern integer colorstackskippagestart (int colstack_no); +extern void checkpdfsave (int cur_h, int cur_v); +extern void checkpdfrestore (int cur_h, int cur_v); +extern void pdfshipoutbegin (boolean shipping_page); +extern void pdfshipoutend (boolean shipping_page); +extern void pdfsetmatrix (poolpointer in, scaled cur_h, scaled cur_v); +extern void matrixtransformpoint (scaled x, scaled y); +extern void matrixtransformrect (scaled llx, scaled lly, scaled urx, + scaled ury); +extern boolean matrixused (); +extern void matrixrecalculate (scaled urx); +extern scaled getllx (); +extern scaled getlly (); +extern scaled geturx (); +extern scaled getury (); + +/* vfpacket.c */ +extern eightbits packetbyte (void); +extern integer newvfpacket (fontnumber); +extern void poppacketstate (void); +extern void pushpacketstate (void); +extern void startpacket (fontnumber, integer); +extern void storepacket (integer, integer, integer); +extern void vf_free (void); + +/* writeenc.c */ +extern boolean indexed_enc (fm_entry *); +extern enc_entry *add_enc (char *); +extern void enc_free (void); +extern void read_enc (enc_entry *); +extern void write_enc (char **, enc_entry *, integer); + +/* writefont.c */ +extern boolean dopsfont (fontnumber); + +/* writeimg.c */ +extern boolean checkimageb (integer); +extern boolean checkimagec (integer); +extern boolean checkimagei (integer); +extern boolean ispdfimage (integer); +extern integer epdforigx (integer); +extern integer epdforigy (integer); +extern integer imageheight (integer); +extern integer imagepages (integer); +extern integer imagewidth (integer); +extern integer imagexres (integer); +extern integer imageyres (integer); +extern integer readimage (strnumber, integer, strnumber, integer, integer, + integer, integer); +extern void deleteimage (integer); +extern void img_free (void); +extern void updateimageprocset (integer); +extern void writeimage (integer); +extern integer imagecolordepth (integer img); + +/* writejbig2.c */ +extern void flushjbig2page0objects (); + +/* writet1.c */ +extern boolean t1_subset (char *, char *, unsigned char *); +extern void load_enc (char *, char **, char **); +extern void writet1 (int, fm_entry *); +extern void t1_free (void); + +#define bitfile psfile + +/* writet3.c */ +extern void writet3 (int, fontnumber); +extern scaled getpkcharwidth (fontnumber, scaled); + +/* writettf.c */ +extern void writettf (void); +extern void writeotf (void); +extern void ttf_free (void); + +/* writezip.c */ +extern void writezip (boolean); + +/* avlstuff.c */ +extern void avlputobj (integer, integer); +extern integer avlfindobj (integer, integer, integer); + +#endif /* MPOSTLIB */ diff --git a/Build/source/texk/web2c/mpdir/mpmac.h b/Build/source/texk/web2c/mpdir/mpmac.h new file mode 100644 index 00000000000..bc9e6a79640 --- /dev/null +++ b/Build/source/texk/web2c/mpdir/mpmac.h @@ -0,0 +1,218 @@ +/* +Copyright (c) 2006 Taco Hoekwater <taco@elvenkind.com> + +This file is part of MetaPost. + +MetaPost is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +MetaPost is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with MetaPost; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id $ +*/ + +#ifndef MPOSTMAC +# define MPOSTMAC + +/* Not all systems define it. */ +# ifndef M_PI +# define M_PI 3.14159265358979323846 + /* pi */ +# define M_PI_2 1.5707963267948966192E0 + /*Hex 2^ 0 * 1.921FB54442D18 */ +# define M_PI_4 7.8539816339744830962E-1 + /*Hex 2^-1 * 1.921FB54442D18 */ +# endif + +# ifdef WIN32 +// Why relying on gmalloc() ??? +# define gmalloc(n) xmalloc(n) +# define gfree(p) free(p) +# define inline __inline +# define srandom(n) srand(n) +# define random() rand() +# endif + +/* Pascal WEB macros */ +# define maxinteger 0x7FFFFFFF +# define maxdimen 0x3FFFFFFF + +# define objinfo(n) objtab[n].int0 + +# define pdfroom(n) do { \ + if ((unsigned)(n + pdfptr) > (unsigned)pdfbufsize) { \ + if (pdfosmode) \ + zpdfosgetosbuf(n); \ + else { \ + if ((unsigned)(n) > (unsigned)pdfbufsize) \ + pdftex_fail("PDF output buffer overflowed"); \ + else \ + pdfflush(); \ + } \ + } \ +} while (0) + +# define pdfout(c) do { \ + pdfroom(1); \ + pdfbuf[pdfptr++] = c; \ +} while (0) + +# define pdfoffset() (pdfgone + pdfptr) +# define pdfinitfont(f) {tmpf = f; pdfcreatefontobj();} + +# define MAX_CHAR_CODE 255 +# define PRINTF_BUF_SIZE 1024 +# define MAX_CSTRING_LEN 1024 * 1024 +# define MAX_PSTRING_LEN 1024 +# define SMALL_BUF_SIZE 256 +# define SMALL_ARRAY_SIZE 256 +# define FONTNAME_BUF_SIZE 128 + /* a PDF name can be maximum 127 chars long */ + +# define pdftex_debug tex_printf + +# define check_buf(size, buf_size) \ + if ((unsigned)(size) > (unsigned)(buf_size)) \ + pdftex_fail("buffer overflow: (%d,%d) at file %s, line %d",size,buf_size, __FILE__, __LINE__ ) + +# define append_char_to_buf(c, p, buf, buf_size) do { \ + if (c == 9) \ + c = 32; \ + if (c == 13 || c == EOF) \ + c = 10; \ + if (c != ' ' || (p > buf && p[-1] != 32)) { \ + check_buf(p - buf + 1, (buf_size)); \ + *p++ = c; \ + } \ +} while (0) + +# define append_eol(p, buf, buf_size) do { \ + check_buf(p - buf + 2, (buf_size)); \ + if (p - buf > 1 && p[-1] != 10) \ + *p++ = 10; \ + if (p - buf > 2 && p[-2] == 32) { \ + p[-2] = 10; \ + p--; \ + } \ + *p = 0; \ +} while (0) + +# define remove_eol(p, buf) do { \ + p = strend(buf) - 1; \ + if (*p == 10) \ + *p = 0; \ +} while (0) + +# define skip(p, c) if (*p == c) p++ + +# define alloc_array(T, n, s) do { \ + if (T##_array == NULL) { \ + T##_limit = (s); \ + if ((unsigned)(n) > T##_limit) \ + T##_limit = (n); \ + T##_array = xtalloc(T##_limit, T##_entry); \ + T##_ptr = T##_array; \ + } \ + else if ((unsigned)(T##_ptr - T##_array + (n)) > T##_limit) { \ + last_ptr_index = T##_ptr - T##_array; \ + T##_limit *= 2; \ + if ((unsigned)(T##_ptr - T##_array + (n)) > T##_limit) \ + T##_limit = T##_ptr - T##_array + (n); \ + xretalloc(T##_array, T##_limit, T##_entry); \ + T##_ptr = T##_array + last_ptr_index; \ + } \ +} while (0) + +# define is_cfg_comment(c) \ + (c == 10 || c == '*' || c == '#' || c == ';' || c == '%') + +# define define_array(T) \ +T##_entry *T##_ptr, *T##_array = NULL; \ +size_t T##_limit + +# define xfree(p) do { if (p != NULL) free(p); p = NULL; } while (0) +# define strend(s) strchr(s, 0) +# define xtalloc XTALLOC +# define xretalloc XRETALLOC + +# define ASCENT_CODE 0 +# define CAPHEIGHT_CODE 1 +# define DESCENT_CODE 2 +# define FONTNAME_CODE 3 +# define ITALIC_ANGLE_CODE 4 +# define STEMV_CODE 5 +# define XHEIGHT_CODE 6 +# define FONTBBOX1_CODE 7 +# define FONTBBOX2_CODE 8 +# define FONTBBOX3_CODE 9 +# define FONTBBOX4_CODE 10 +# define MAX_KEY_CODE (FONTBBOX1_CODE + 1) +# define FONT_KEYS_NUM (FONTBBOX4_CODE + 1) + +# define F_INCLUDED 0x01 +# define F_SUBSETTED 0x02 +# define F_TRUETYPE 0x04 +# define F_BASEFONT 0x08 +# define F_SUBFONT 0x10 + +# define set_included(fm) ((fm)->type |= F_INCLUDED) +# define set_subsetted(fm) ((fm)->type |= F_SUBSETTED) +# define set_truetype(fm) ((fm)->type |= F_TRUETYPE) +# define set_basefont(fm) ((fm)->type |= F_BASEFONT) +# define set_subfont(fm) ((fm)->type |= F_SUBFONT) + +# define unset_included(fm) ((fm)->type &= ~F_INCLUDED) +# define unset_subsetted(fm) ((fm)->type &= ~F_SUBSETTED) +# define unset_truetype(fm) ((fm)->type &= ~F_TRUETYPE) +# define unset_basefont(fm) ((fm)->type &= ~F_BASEFONT) +# define unset_subfont(fm) ((fm)->type &= ~F_SUBFONT) + +# define unset_fontfile(fm) xfree((fm)->ff_name) + +# define is_included(fm) ((fm)->type & F_INCLUDED) +# define is_subsetted(fm) ((fm)->type & F_SUBSETTED) +# define is_truetype(fm) ((fm)->type & F_TRUETYPE) +# define is_basefont(fm) ((fm)->type & F_BASEFONT) +# define is_subfont(fm) ((fm)->type & F_SUBFONT) +# define no_font_desc(fm) (is_basefont(fm) && !is_included(fm)) + +# define fm_slant(fm) (fm)->slant +# define fm_extend(fm) (fm)->extend +# define fm_fontfile(fm) (fm)->ff_name + +# define is_reencoded(fm) ((fm)->encoding != NULL) +# define is_fontfile(fm) (fm_fontfile(fm) != NULL) +# define is_t1fontfile(fm) (is_fontfile(fm) && !is_truetype(fm)) + +# define LINK_TFM 0x01 +# define LINK_PS 0x02 +# define set_tfmlink(fm) ((fm)->links |= LINK_TFM) +# define set_pslink(fm) ((fm)->links |= LINK_PS) +# define unset_tfmlink(fm) ((fm)->links &= ~LINK_TFM) +# define unset_pslink(fm) ((fm)->links &= ~LINK_PS) +# define has_tfmlink(fm) ((fm)->links & LINK_TFM) +# define has_pslink(fm) ((fm)->links & LINK_PS) + + +# define set_cur_file_name(s) \ + cur_file_name = s; \ + packfilename(maketexstring(cur_file_name), getnullstr(), getnullstr()) + +# define cmp_return(a, b) \ + if (a > b) \ + return 1; \ + if (a < b) \ + return -1 + +# define str_prefix(s1, s2) (strncmp((s1), (s2), strlen(s2)) == 0) + +#endif /* MPOSTMAC */ diff --git a/Build/source/texk/web2c/mpdir/mpostlib.mk b/Build/source/texk/web2c/mpdir/mpostlib.mk new file mode 100644 index 00000000000..01d798b60bb --- /dev/null +++ b/Build/source/texk/web2c/mpdir/mpostlib.mk @@ -0,0 +1,29 @@ +## mpostlib.mk - Makefile fragment for libraries used by mpost +# Public domain. + +# Include dependencies to get the built if we don't do make +# from the top-level directory. + +Makefile: mpdir/mpostlib.mk + +# libmpost +mpostlib = mpdir/libmpost.a +mpostlib_sources = $(srcdir)/mpdir/*.c $(srcdir)/mpdir/*.h + +mpdir/libmpost.a: $(mpostlib_sources) + cd mpdir && $(MAKE) $(common_makeargs) libmpost.a + +# makecpool + +makecpool = mpdir/makecpool + +mpdir/makecpool: mpdir/makecpool.c + cd mpdir && $(MAKE) $(common_makeargs) makecpool + +# Convenience variables. + +mpostlibs = $(mpostlib) +mpostlibsdep = $(mpostlib) $(makecpool) + +## end of mpostlib.mk - Makefile fragment for libraries used by mpost + diff --git a/Build/source/texk/web2c/mpdir/utils.c b/Build/source/texk/web2c/mpdir/utils.c new file mode 100644 index 00000000000..16de3f5a8d3 --- /dev/null +++ b/Build/source/texk/web2c/mpdir/utils.c @@ -0,0 +1,719 @@ +/* Copyright (c) 2006 Taco Hoekwater <taco@elvenkind.com> + +This file is part of MetaPost. + +MetaPost is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +MetaPost is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with MetaPost; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id $ +*/ + +#ifdef HAVE_ASPRINTF /* asprintf is not defined in openbsd-compat.h, but in stdio.h */ +# include <stdio.h> +#endif +#include <sys/types.h> + +#include <kpathsea/c-proto.h> +#include <kpathsea/c-stat.h> +#include <kpathsea/c-fopen.h> +#include <string.h> +#include <time.h> +#include <float.h> /* for DBL_EPSILON */ +#include "mplib.h" + +/* define char_ptr, char_array & char_limit */ +typedef char char_entry; +define_array (char); + +#define Z_NULL 0 + +typedef unsigned char Byte; +typedef Byte Bytef; + +#define check_nprintf(size_get, size_want) \ + if ((unsigned)(size_get) >= (unsigned)(size_want)) \ + pdftex_fail ("snprintf failed: file %s, line %d", __FILE__, __LINE__); + +/*@unused@*/ +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#24 $"; + +char *cur_file_name = NULL; +strnumber last_tex_string; +static char print_buf[PRINTF_BUF_SIZE]; +static char *jobname_cstr = NULL; +static char *job_id_string = NULL; +extern string ptexbanner; /* from web2c/lib/texmfmp.c */ +extern string versionstring; /* from web2c/lib/version.c */ +extern KPSEDLL string kpathsea_version_string; /* from kpathsea/version.c */ + +size_t last_ptr_index; /* for use with alloc_array */ + + + +void pdf_puts (const char *s) +{ + while (*s) + fputc(*s++,psfile); +} + +void pdf_printf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + vsnprintf (print_buf, PRINTF_BUF_SIZE, fmt, args); + pdf_puts (print_buf); + va_end (args); +} + +strnumber maketexstring (const char *s) +{ + size_t l; + if (s == NULL || *s == 0) + return getnullstr (); + l = strlen (s); + check_buf (poolptr + l, poolsize); + while (l-- > 0) + strpool[poolptr++] = *s++; + last_tex_string = makestring (); + return last_tex_string; +} + +void mp_printf (const char *fmt, ...) +{ + va_list args; + int saved_selector; + saved_selector = selector; + va_start (args, fmt); + vsnprintf (print_buf, PRINTF_BUF_SIZE, fmt, args); + selector = gettermandlogid(); + print (maketexstring (print_buf)); + flushstr (last_tex_string); + xfflush (stdout); + va_end (args); + selector = saved_selector; /* ps_file_only, probably */ +} + +/* Helper for pdftex_fail. */ +static void safe_print (const char *str) +{ + const char *c; + for (c = str; *c; ++c) + print (*c); +} + +/* pdftex_fail may be called when a buffer overflow has happened/is + happening, therefore may not call mktexstring. However, with the + current implementation it appears that error messages are misleading, + possibly because pool overflows are detected too late. + + The output format of this fuction must be the same as pdf_error in + pdftex.web! */ + +void pdftex_fail (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + fputs ("\nError: module writet1", stderr); + if (cur_file_name) + fprintf (stderr, " (file %s)", cur_file_name); + fputs (": ", stderr); + vsprintf (print_buf, fmt, args); + fputs (print_buf, stderr); + fputs + ("\n ==> Fatal error occurred, the output PS file is not finished!\n", + stderr); + va_end (args); + exit (1); +} + +/* The output format of this fuction must be the same as pdf_warn in + pdftex.web! */ +void pdftex_warn (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + fputs ("\nWarning: module writet1", stderr); + if (cur_file_name) + fprintf (stderr, " (file %s)", cur_file_name); + fputs (": ", stderr); + vsprintf (print_buf, fmt, args); + fputs (print_buf, stderr); + fputs ("\n", stderr); + va_end (args); +} + + +static char *cstrbuf = NULL; + +char *makecstring (integer s) +{ + char *p; + static int allocsize; + int allocgrow, i, l ; + if (s==0) + return ""; + l = strstart[nextstr[s]] - strstart[s]; + if (l==0) + return ""; + check_buf (l + 1, MAX_CSTRING_LEN); + if (cstrbuf == NULL) { + allocsize = l + 1; + cstrbuf = xmallocarray (char, allocsize); + } else if (l + 1 > allocsize) { + allocgrow = allocsize * 0.2; + if (l + 1 - allocgrow > allocsize) + allocsize = l + 1; + else if (allocsize < MAX_CSTRING_LEN - allocgrow) + allocsize += allocgrow; + else + allocsize = MAX_CSTRING_LEN; + cstrbuf = xrealloc (cstrbuf, sizeof (char) * allocsize); + } + p = cstrbuf; + for (i = 0; i < l; i++) + *p++ = strpool[i + strstart[s]]; + *p = 0; + return cstrbuf; +} + +size_t xfwrite (void *ptr, size_t size, size_t nmemb, FILE * stream) +{ + if (fwrite (ptr, size, nmemb, stream) != nmemb) + pdftex_fail ("fwrite() failed"); + return nmemb; +} + +int xfflush (FILE * stream) +{ + if (fflush (stream) != 0) + pdftex_fail ("fflush() failed"); + return 0; +} + +int xgetc (FILE * stream) +{ + int c = getc (stream); + if (c < 0 && c != EOF) + pdftex_fail ("getc() failed"); + return c; +} + +int xputc (int c, FILE * stream) +{ + int i = putc (c, stream); + if (i < 0) + pdftex_fail ("putc() failed"); + return i; +} + + +scaled extxnoverd (scaled x, scaled n, scaled d) +{ + double r = (((double) x) * ((double) n)) / ((double) d); + if (r > DBL_EPSILON) + r += 0.5; + else + r -= 0.5; + if (r >= (double) maxinteger || r <= -(double) maxinteger) + pdftex_warn ("arithmetic: number too big"); + return (scaled) r; +} + +/* Converts any string given in in in an allowed PDF string which can be + * handled by printf et.al.: \ is escaped to \\, parenthesis are escaped and + * control characters are octal encoded. + * This assumes that the string does not contain any already escaped + * characters! + */ +char *convertStringToPDFString (const char *in, int len) +{ + static char pstrbuf[MAX_PSTRING_LEN]; + char *out = pstrbuf; + int i, j = 0, k; + char buf[5]; + for (i = 0; i < len; i++) { + check_buf (j + sizeof (buf), MAX_PSTRING_LEN); + if (((unsigned char) in[i] < '!') || ((unsigned char) in[i] > '~')) { + /* convert control characters into oct */ + k = snprintf (buf, sizeof (buf), + "\\%03o", (unsigned int) (unsigned char) in[i]); + check_nprintf (k, sizeof (buf)); + out[j++] = buf[0]; + out[j++] = buf[1]; + out[j++] = buf[2]; + out[j++] = buf[3]; + } else if ((in[i] == '(') || (in[i] == ')')) { + /* escape paranthesis */ + out[j++] = '\\'; + out[j++] = in[i]; + } else if (in[i] == '\\') { + /* escape backslash */ + out[j++] = '\\'; + out[j++] = '\\'; + } else { + /* copy char :-) */ + out[j++] = in[i]; + } + } + out[j] = '\0'; + return pstrbuf; +} + + +/* Converts any string given in in in an allowed PDF string which can be + * handled by printf et.al.: \ is escaped to \\, parenthesis are escaped and + * control characters are octal encoded. + * This assumes that the string does not contain any already escaped + * characters! + * + * See escapename for parameter description. + */ +void escapestring (poolpointer in) +{ + const poolpointer out = poolptr; + unsigned char ch; + while (in < out) { + if (poolptr + 4 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char) strpool[in++]; + + if ((ch < '!') || (ch > '~')) { + /* convert control characters into oct */ + int i = snprintf ((char *) &strpool[poolptr], 5, + "\\%.3o", (unsigned int) ch); + check_nprintf (i, 5); + poolptr += i; + continue; + } + if ((ch == '(') || (ch == ')') || (ch == '\\')) { + /* escape parenthesis and backslash */ + strpool[poolptr++] = '\\'; + } + /* copy char :-) */ + strpool[poolptr++] = ch; + } +} + +/* Convert any given string in a PDF name using escaping mechanism + of PDF 1.2. The result does not include the leading slash. + + PDF specification 1.6, section 3.2.6 "Name Objects" explains: + <blockquote> + Beginning with PDF 1.2, any character except null (character code 0) may + be included in a name by writing its 2-digit hexadecimal code, preceded + by the number sign character (#); see implementation notes 3 and 4 in + Appendix H. This syntax is required to represent any of the delimiter or + white-space characters or the number sign character itself; it is + recommended but not required for characters whose codes are outside the + range 33 (!) to 126 (~). + </blockquote> + The following table shows the conversion that are done by this + function: + code result reason + ----------------------------------- + 0 ignored not allowed + 1..32 escaped must for white-space: + 9 (tab), 10 (lf), 12 (ff), 13 (cr), 32 (space) + recommended for the other control characters + 35 escaped escape char "#" + 37 escaped delimiter "%" + 40..41 escaped delimiters "(" and ")" + 47 escaped delimiter "/" + 60 escaped delimiter "<" + 62 escaped delimiter ">" + 91 escaped delimiter "[" + 93 escaped delimiter "]" + 123 escaped delimiter "{" + 125 escaped delimiter "}" + 127..255 escaped recommended + else copy regular characters + + Parameter "in" is a pointer into the string pool where + the input string is located. The output string is written + as temporary string right after the input string. + Thus at the begin of the procedure the global variable + "poolptr" points to the start of the output string and + after the end when the procedure returns. +*/ +void escapename (poolpointer in) +{ + const poolpointer out = poolptr; + unsigned char ch; + int i; + + while (in < out) { + if (poolptr + 3 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char) strpool[in++]; + + if ((ch >= 1 && ch <= 32) || ch >= 127) { + /* escape */ + i = snprintf ((char *) &strpool[poolptr], 4, + "#%.2X", (unsigned int) ch); + check_nprintf (i, 4); + poolptr += i; + continue; + } + switch (ch) { + case 0: + /* ignore */ + break; + case 35: + case 37: + case 40: + case 41: + case 47: + case 60: + case 62: + case 91: + case 93: + case 123: + case 125: + /* escape */ + i = snprintf ((char *) &strpool[poolptr], 4, + "#%.2X", (unsigned int) ch); + check_nprintf (i, 4); + poolptr += i; + break; + default: + /* copy */ + strpool[poolptr++] = ch; + } + } +} + +/* Convert any given string in a PDF hexadecimal string. The + result does not include the angle brackets. + + This procedure uses uppercase hexadecimal letters. + + See escapename for description of parameters. +*/ +void escapehex (poolpointer in) +{ + const poolpointer out = poolptr; + unsigned char ch; + int i; + + while (in < out) { + if (poolptr + 2 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char) strpool[in++]; + + i = snprintf ((char *) &strpool[poolptr], 3, "%.2X", (unsigned int) ch); + check_nprintf (i, 3); + poolptr += 2; + } +} + +/* Unescape any given hexadecimal string. + + Last hex digit can be omitted, it is replaced by zero, see + PDF specification. + + Invalid digits are silently ignored. + + See escapename for description of parameters. +*/ +void unescapehex (poolpointer in) +{ + const poolpointer out = poolptr; + unsigned char ch; + unsigned char a = 0; /* to avoid warning about uninitialized use of a */ + boolean first = true; + + while (in < out) { + if (poolptr + 1 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char) strpool[in++]; + + if ((ch >= '0') && (ch <= '9')) { + ch -= '0'; + } else if ((ch >= 'A') && (ch <= 'F')) { + ch -= 'A' - 10; + } else if ((ch >= 'a') && (ch <= 'f')) { + ch -= 'a' - 10; + } else { + continue; /* ignore wrong character */ + } + + if (first) { + a = ch << 4; + first = false; + continue; + } + + strpool[poolptr++] = a + ch; + first = true; + } + if (!first) { /* last hex digit is omitted */ + strpool[poolptr++] = ch << 4; + } +} + + +/* Converts any string given in in in an allowed PDF string which is + * hexadecimal encoded; + * sizeof(out) should be at least lin*2+1. + */ +static void convertStringToHexString (const char *in, char *out, int lin) +{ + int i, j, k; + char buf[3]; + j = 0; + for (i = 0; i < lin; i++) { + k = snprintf (buf, sizeof (buf), + "%02X", (unsigned int) (unsigned char) in[i]); + check_nprintf (k, sizeof (buf)); + out[j++] = buf[0]; + out[j++] = buf[1]; + } + out[j] = '\0'; +} + + + +/* makecfilename + input/ouput same as makecstring: + input: string number + output: C string with quotes removed. + That means, file names that are legal on some operation systems + cannot any more be used since pdfTeX version 1.30.4. +*/ +char *makecfilename (strnumber s) +{ + char *name = makecstring (s); + char *p = name; + char *q = name; + + while (*p) { + if (*p != '"') + *q++ = *p; + p++; + } + *q = '\0'; + return name; +} + +/* function strips trailing zeros in string with numbers; */ +/* leading zeros are not stripped (as in real life) */ +char *stripzeros (char *a) +{ + enum { NONUM, DOTNONUM, INT, DOT, LEADDOT, FRAC } s = NONUM, t = NONUM; + char *p, *q, *r; + for (p = q = r = a; *p != '\0';) { + switch (s) { + case NONUM: + if (*p >= '0' && *p <= '9') + s = INT; + else if (*p == '.') + s = LEADDOT; + break; + case DOTNONUM: + if (*p != '.' && (*p < '0' || *p > '9')) + s = NONUM; + break; + case INT: + if (*p == '.') + s = DOT; + else if (*p < '0' || *p > '9') + s = NONUM; + break; + case DOT: + case LEADDOT: + if (*p >= '0' && *p <= '9') + s = FRAC; + else if (*p == '.') + s = DOTNONUM; + else + s = NONUM; + break; + case FRAC: + if (*p == '.') + s = DOTNONUM; + else if (*p < '0' || *p > '9') + s = NONUM; + break; + default:; + } + switch (s) { + case DOT: + r = q; + break; + case LEADDOT: + r = q + 1; + break; + case FRAC: + if (*p > '0') + r = q + 1; + break; + case NONUM: + if ((t == FRAC || t == DOT) && r != a) { + q = r--; + if (*r == '.') /* was a LEADDOT */ + *r = '0'; + r = a; + } + break; + default:; + } + *q++ = *p++; + t = s; + } + *q = '\0'; + return a; +} + +void stripspaces (char *p) +{ + char *q; + for (q = p; *p != '\0'; p++) { + if (*p != ' ') + *q++ = *p; + } + *q = '\0'; +} + +void initversionstring (char **versions) +{ +} + +void setjobid (int year, int month, int day, int time) +{ + char *name_string, *format_string, *s; + size_t slen; + int i; + + if (job_id_string != NULL) + return; + + name_string = xstrdup (makecstring (jobname)); + format_string = xstrdup (makecstring (memident)); + + slen = SMALL_BUF_SIZE + + strlen (name_string) + + strlen (format_string) + + //strlen (banner) + + strlen (versionstring) + strlen (kpathsea_version_string); + s = xtalloc (slen, char); + /* The Web2c version string starts with a space. */ + i = snprintf (s, slen, + "%.4d/%.2d/%.2d %.2d:%.2d %s %s%s %s", + (year>>16), (month>>16), (day>>16), (time>>16) / 60, (time>>16) % 60, + name_string, format_string, //ptexbanner, + versionstring, kpathsea_version_string); + check_nprintf (i, slen); + job_id_string = xstrdup (s); + xfree (s); + xfree (name_string); + xfree (format_string); +} + + + +static void fnstr_append (const char *s) +{ + size_t l = strlen (s) + 1; + alloc_array (char, l, SMALL_ARRAY_SIZE); + strcat (char_ptr, s); + char_ptr = strend (char_ptr); +} + +/* this is not really a true crc32, but it should be just enough to keep + subsets prefixes somewhat disjunct */ +unsigned long crc32 (int oldcrc, const Byte *buf, int len) { + unsigned long ret; + int i; + if (oldcrc==0) + ret = (23<<24)+(45<<16)+(67<<8)+89; + else + for (i=0;i<len;i++) + ret = (ret<<2)+buf[i]; + return ret; +} + +void make_subset_tag (fm_entry * fm_cur, char **glyph_names, int tex_font) +{ + char tag[7]; + unsigned long crc; + int i; + size_t l ; + if (job_id_string ==NULL) + exit; + l = strlen (job_id_string) + 1; + + alloc_array (char, l, SMALL_ARRAY_SIZE); + strcpy (char_array, job_id_string); + char_ptr = strend (char_array); + if (fm_cur->tfm_name != NULL) { + fnstr_append (" TFM name: "); + fnstr_append (fm_cur->tfm_name); + } + fnstr_append (" PS name: "); + //if (font_keys[FONTNAME_CODE].valid) + // fnstr_append (fontname_buf); + //else + if (fm_cur->ps_name != NULL) + fnstr_append (fm_cur->ps_name); + fnstr_append (" Encoding: "); + if (fm_cur->encoding != NULL && (fm_cur->encoding)->name != NULL) + fnstr_append ((fm_cur->encoding)->name); + else + fnstr_append ("built-in"); + fnstr_append (" CharSet: "); + assert (glyph_names != NULL); + for (i = 0; i < 256; i++) + if (mpcharmarked (tex_font, i) && glyph_names[i] != notdef) { + if (glyph_names[i]!=NULL) { + fnstr_append ("/"); + fnstr_append (glyph_names[i]); + } + } + if (fm_cur->charset != NULL) { + fnstr_append (" Extra CharSet: "); + fnstr_append (fm_cur->charset); + } + crc = crc32 (0L, Z_NULL, 0); + crc = crc32 (crc, (Bytef *) char_array, strlen (char_array)); + /* we need to fit a 32-bit number into a string of 6 uppercase chars long; + * there are 26 uppercase chars ==> each char represents a number in range + * 0..25. The maximal number that can be represented by the tag is + * 26^6 - 1, which is a number between 2^28 and 2^29. Thus the bits 29..31 + * of the CRC must be dropped out. + */ + for (i = 0; i < 6; i++) { + tag[i] = 'A' + crc % 26; + crc /= 26; + } + tag[6] = 0; + fm_cur->subset_tag = xstrdup (tag); +} + diff --git a/Build/source/texk/web2c/mpdir/writeenc.c b/Build/source/texk/web2c/mpdir/writeenc.c new file mode 100644 index 00000000000..30673cd6aa3 --- /dev/null +++ b/Build/source/texk/web2c/mpdir/writeenc.c @@ -0,0 +1,142 @@ +/* Copyright (c) 2006 Taco Hoekwater <taco@elvenkind.com> + +This file is part of MetaPost. + +MetaPost is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +MetaPost is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with MetaPost; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id $ +*/ + +#include "mplib.h" + +/*@unused@*/ +static const char perforce_id[] = + "$Id: writeenc.c,v 1.3 2005/12/26 14:20:13 hahe Exp hahe $"; + +void read_enc (enc_entry * e) +{ + assert (e != NULL); + if (e->loaded) + return; + e->encname = NULL; + load_enc (e->name, &e->encname, e->glyph_names); + e->loaded = true; +} + +/* write_enc is used to write either external encoding (given in map file) or + * internal encoding (read from the font file); when glyph_names is NULL + * the 2nd argument is a pointer to the encoding entry; otherwise the 3rd is + * the object number of the Encoding object + */ +void write_enc (char **glyph_names, enc_entry * e, integer eobjnum) +{ + boolean is_notdef; + int i; + int s; + int foffset; + char **g; + if (glyph_names == NULL) { + assert (e != NULL); + if (e->objnum != 0) /* the encoding has been written already */ + return; + e->objnum = 1; + g = e->glyph_names; + } else { + g = glyph_names; + } + pdf_printf("\n%%%%BeginResource: encoding %s",e->encname); + pdf_printf ("\n/%s [ ", e->encname); + foffset = strlen(e->name)+3; + for (i = 0; i < 256; i++) { + s = strlen(g[i]); + if (s+1+foffset>=80) { + pdf_printf ("\n"); + foffset = 0; + } + foffset += s+2; + pdf_printf ("/%s ", g[i]); + } + if (foffset>75) + pdf_printf ("\n"); + pdf_puts ("] def\n"); + pdf_printf("%%%%EndResource"); +} + +/**********************************************************************/ +/* All encoding entries go into AVL tree for fast search by name. */ + +struct avl_table *enc_tree = NULL; + +/* AVL sort enc_entry into enc_tree by name */ + +static int comp_enc_entry (const void *pa, const void *pb, void *p) +{ + return strcmp (((const enc_entry *) pa)->name, + ((const enc_entry *) pb)->name); +} + +enc_entry *add_enc (char *s) +{ + int i; + enc_entry tmp, *p; + void **aa; + + assert (s != NULL); + if (enc_tree == NULL) { + enc_tree = avl_create (comp_enc_entry, NULL, &avl_xallocator); + assert (enc_tree != NULL); + } + tmp.name = s; + p = (enc_entry *) avl_find (enc_tree, &tmp); + if (p != NULL) /* encoding already registered */ + return p; + p = xtalloc (1, enc_entry); + p->loaded = false; + p->name = xstrdup (s); + p->objnum = 0; + p->tounicode = 0; + p->glyph_names = xtalloc (256, char *); + for (i = 0; i < 256; i++) + p->glyph_names[i] = (char *) notdef; + aa = avl_probe (enc_tree, p); + assert (aa != NULL); + return p; +} + +/**********************************************************************/ +/* cleaning up... */ + +static void destroy_enc_entry (void *pa, void *pb) +{ + enc_entry *p; + int i; + + p = (enc_entry *) pa; + xfree (p->name); + if (p->glyph_names != NULL) + for (i = 0; i < 256; i++) + if (p->glyph_names[i] != notdef) + xfree (p->glyph_names[i]); + xfree (p->glyph_names); + xfree (p); +} + +void enc_free () +{ + if (enc_tree != NULL) + avl_destroy (enc_tree, destroy_enc_entry); +} + +/**********************************************************************/ diff --git a/Build/source/texk/web2c/mpdir/writefont.c b/Build/source/texk/web2c/mpdir/writefont.c new file mode 100644 index 00000000000..e88b4dbab7d --- /dev/null +++ b/Build/source/texk/web2c/mpdir/writefont.c @@ -0,0 +1,244 @@ +/* +Copyright (c) 1996-2006 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +pdfTeX is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: writefont.c,v 1.3 2005/12/27 19:04:42 hahe Exp $ +*/ + +#include "mplib.h" + +static const char perforce_id[] = + "$Id: writefont.c,v 1.3 2005/12/27 19:04:42 hahe Exp $"; + +boolean fontfile_found; +boolean is_otf_font; +char fontname_buf[FONTNAME_BUF_SIZE]; + +boolean fontisreencoded (int f) { + fm_entry *fm; + if (fontsizes[f]!=0 && hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL + && (fm->ps_name != NULL) + && is_reencoded (fm)) + return 1; + } + return 0; +} + +boolean fontisincluded (int f) { + fm_entry *fm; + if (fontsizes[f]!=0 && hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL + && (fm->ps_name != NULL && fm->ff_name != NULL) + && is_included (fm)) + return 1; + } + return 0; +} + +boolean fontissubsetted (int f) { + fm_entry *fm; + if (fontsizes[f]!=0 && hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL + && (fm->ps_name != NULL && fm->ff_name != NULL) + && is_included (fm) && is_subsetted (fm)) + return 1; + } + return 0; +} + + +strnumber fmencodingname (int f) { + enc_entry *e; + fm_entry *fm; + if (hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL && (fm->ps_name != NULL)) { + if (is_reencoded (fm)) { + e = fm->encoding; + if (e->encname!=NULL) { + return maketexstring(e->encname); + } + } else { + return 0; + } + } + } + pdftex_fail ("fontmap encoding problems for font %s",makecstring (fontname[f])); + return 0; +} + +strnumber fmfontname (int f) { + fm_entry *fm; + if (hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL && (fm->ps_name != NULL)) { + if (fontisincluded(f) && !fontpsnamefixed[f]) { + /* find the real fontname, and update ps_name and subset_tag if needed */ + if(t1_updatefm(f,fm)) { + fontpsnamefixed[f] = true; + } else { + pdftex_fail ("font loading problems for font %s",makecstring (fontname[f])); + } + } + return maketexstring(fm->ps_name); + } + } + pdftex_fail ("fontmap name problems for font %s",makecstring (fontname[f])); + return 0; +} + +strnumber fmfontsubsetname (int f) { + fm_entry *fm; + char *s; + if (hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL && (fm->ps_name != NULL)) { + if (is_subsetted(fm)) { + s = xmalloc(strlen(fm->ps_name)+8); + snprintf(s,strlen(fm->ps_name)+8,"%s-%s",fm->subset_tag,fm->ps_name); + return maketexstring(s); + } else { + return maketexstring(fm->ps_name); + } + } + } + pdftex_fail ("fontmap name problems for font %s",makecstring (fontname[f])); + return 0; +} + + + +integer fmfontslant (int f) { + fm_entry *fm; + if (hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL && (fm->ps_name != NULL)) { + return fm->slant; + } + } + return 0; +} + +integer fmfontextend (int f) { + fm_entry *fm; + if (hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL && (fm->ps_name != NULL)) { + return fm->extend; + } + } + return 0; +} + + + +void mploadencodings (int lastfnum) { + int nullfont; + int f; + enc_entry *e; + fm_entry *fm_cur; + nullfont = getnullfont(); + for (f=nullfont+1;f<=lastfnum;f++) { + if (fontsizes[f]!=0 && hasfmentry (f)) { + fm_cur = (fm_entry *) mpfontmap[f]; + if (fm_cur != NULL && + fm_cur->ps_name != NULL && + is_reencoded (fm_cur)) { + e = fm_cur->encoding; + read_enc (e); + } + } + } +} + +void mpfontencodings (int lastfnum, int encodings_only) { + int nullfont; + int f,ff; + enc_entry *e; + fm_entry *fm; + nullfont = getnullfont(); + for (f=nullfont+1;f<=lastfnum;f++) { + if (fontsizes[f]!=0 && hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL && (fm->ps_name != NULL)) { + if (is_reencoded (fm)) { + if (encodings_only || (!is_subsetted (fm))) { + e = fm->encoding; + write_enc (NULL, e, 0); + } + } + } + } + } + for (f=nullfont+1;f<=lastfnum;f++) { + if (fontsizes[f]!=0 && hasfmentry (f)) { + fm = (fm_entry *) mpfontmap[f]; + if (fm != NULL && (fm->ps_name != NULL)) { + if (is_reencoded (fm)) { + if (encodings_only || (!is_subsetted (fm))) { + /* clear for next run */ + e->objnum = 0; + } + } + } + } + } +} + +boolean dopsfont (fontnumber f) +{ + int i; + fm_entry *fm_cur; + if (mpfontmap[f] == NULL) + pdftex_fail ("pdffontmap not initialized for font %s", + makecstring (fontname[f])); + if (hasfmentry (f)) + fm_cur = (fm_entry *) mpfontmap[f]; + else + fm_cur = NULL; + if (fm_cur == NULL) + return 1; + if (is_truetype(fm_cur) || + (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) { + return 0; + } + + if (is_included(fm_cur)) { + printnl(maketexstring("%%BeginResource: font ")); + flushstr (last_tex_string); + if (is_subsetted(fm_cur)) { + print(maketexstring(fm_cur->subset_tag)); + flushstr (last_tex_string); + print(maketexstring("-")); + flushstr (last_tex_string); + } + print(maketexstring(fm_cur->ps_name)); + flushstr (last_tex_string); + println(); + writet1 (f,fm_cur); + printnl(maketexstring("%%EndResource")); + flushstr (last_tex_string); + println(); + } + return 1; +} + diff --git a/Build/source/texk/web2c/mpdir/writet1.c b/Build/source/texk/web2c/mpdir/writet1.c new file mode 100644 index 00000000000..bbfd398aa3b --- /dev/null +++ b/Build/source/texk/web2c/mpdir/writet1.c @@ -0,0 +1,1736 @@ +/* Copyright (c) 2006 Taco Hoekwater <taco@elvenkind.com> + +This file is part of MetaPost. + +MetaPost is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +MetaPost is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with MetaPost; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id$ + +*/ + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writet1.c#25 $"; + +# include "mplib.h" +# define t1_open() \ + open_input(&t1_file, kpse_type1_format, FOPEN_RBIN_MODE) +# define enc_open() \ + open_input(&enc_file, kpse_enc_format, FOPEN_RBIN_MODE) +# define external_enc() (fm_cur->encoding)->glyph_names + +# define full_file_name() cur_file_name +# define get_length1() +# define get_length2() +# define get_length3() +# define is_used_char(c) mpcharmarked(tex_font, c) +# define out_eexec_char t1_outhex +# define save_offset() +# define end_last_eexec_line() \ + hexline_length = HEXLINE_WIDTH; \ + end_hexline(); \ + t1_eexec_encrypt = false +# define t1_log(s) mp_printf(s) +# define t1_putchar(c) fputc(c, bitfile) +# define embed_all_glyphs(tex_font) false +# undef pdfmovechars +# ifdef SHIFTLOWCHARS +extern char errbuf[]; +extern Boolean shiftlowchars; +# define pdfmovechars shiftlowchars +# define t1_char(c) T1Char(c) +# else /* SHIFTLOWCHARS */ +# define t1_char(c) c +# define pdfmovechars 0 +# endif /* SHIFTLOWCHARS */ +# define extra_charset() dvips_extra_charset +# define update_subset_tag() + +# define fixedcontent true + +static char *dvips_extra_charset; +static char *cur_enc_name; +static unsigned char *grid; +static char *ext_glyph_names[256]; +static char print_buf[PRINTF_BUF_SIZE]; +static int hexline_length; +const char notdef[] = ".notdef"; +/* static size_t last_ptr_index; */ + +#include <kpathsea/c-vararg.h> +#include <kpathsea/c-proto.h> +#include <string.h> + +#define t1_getchar() getc(t1_file) +#define t1_ungetchar(c) ungetc(c, t1_file) +#define t1_eof() feof(t1_file) +#define t1_close() xfclose(t1_file, cur_file_name) + +#define enc_getchar() getc(enc_file) +#define enc_eof() feof(enc_file) +#define enc_close() xfclose(enc_file, cur_file_name) + +#define valid_code(c) (c >= 0 && c < 256) + +static const char *standard_glyph_names[256] = + { notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, + notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, + notdef, notdef, notdef, notdef, notdef, notdef, + notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, + "space", "exclam", "quotedbl", "numbersign", + "dollar", "percent", "ampersand", "quoteright", "parenleft", + "parenright", "asterisk", "plus", "comma", "hyphen", "period", + "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", + "eight", "nine", "colon", "semicolon", "less", + "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", + "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", + "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", + "backslash", "bracketright", "asciicircum", "underscore", + "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", + "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", + "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", + notdef, notdef, notdef, notdef, notdef, notdef, notdef, + notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, + notdef, notdef, notdef, notdef, notdef, notdef, + notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, + notdef, notdef, notdef, "exclamdown", "cent", + "sterling", "fraction", "yen", "florin", "section", "currency", + "quotesingle", "quotedblleft", "guillemotleft", + "guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash", + "dagger", "daggerdbl", "periodcentered", notdef, + "paragraph", "bullet", "quotesinglbase", "quotedblbase", + "quotedblright", "guillemotright", "ellipsis", "perthousand", + notdef, "questiondown", notdef, "grave", "acute", "circumflex", + "tilde", "macron", "breve", "dotaccent", "dieresis", notdef, + "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash", + notdef, notdef, notdef, notdef, notdef, notdef, + notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, + notdef, "AE", notdef, "ordfeminine", notdef, notdef, + notdef, notdef, "Lslash", "Oslash", "OE", "ordmasculine", notdef, + notdef, notdef, notdef, notdef, "ae", notdef, notdef, + notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe", + "germandbls", notdef, notdef, notdef, notdef +}; + +static char charstringname[] = "/CharStrings"; + +char **t1_glyph_names; +char *t1_builtin_glyph_names[256]; +char charsetstr[0x4000]; +static boolean read_encoding_only; +static int t1_encoding; + +#define T1_BUF_SIZE 0x10 +#define ENC_BUF_SIZE 0x1000 + +#define ENC_STANDARD 0 +#define ENC_BUILTIN 1 + +#define CS_HSTEM 1 +#define CS_VSTEM 3 +#define CS_VMOVETO 4 +#define CS_RLINETO 5 +#define CS_HLINETO 6 +#define CS_VLINETO 7 +#define CS_RRCURVETO 8 +#define CS_CLOSEPATH 9 +#define CS_CALLSUBR 10 +#define CS_RETURN 11 +#define CS_ESCAPE 12 +#define CS_HSBW 13 +#define CS_ENDCHAR 14 +#define CS_RMOVETO 21 +#define CS_HMOVETO 22 +#define CS_VHCURVETO 30 +#define CS_HVCURVETO 31 +#define CS_1BYTE_MAX (CS_HVCURVETO + 1) + +#define CS_DOTSECTION CS_1BYTE_MAX + 0 +#define CS_VSTEM3 CS_1BYTE_MAX + 1 +#define CS_HSTEM3 CS_1BYTE_MAX + 2 +#define CS_SEAC CS_1BYTE_MAX + 6 +#define CS_SBW CS_1BYTE_MAX + 7 +#define CS_DIV CS_1BYTE_MAX + 12 +#define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16 +#define CS_POP CS_1BYTE_MAX + 17 +#define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33 +#define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1) +#define CS_MAX CS_2BYTE_MAX + +typedef unsigned char byte; + +typedef struct { + byte nargs; /* number of arguments */ + boolean bottom; /* take arguments from bottom of stack? */ + boolean clear; /* clear stack? */ + boolean valid; +} cc_entry; /* CharString Command */ + +typedef struct { + char *name; /* glyph name (or notdef for Subrs entry) */ + byte *data; + unsigned short len; /* length of the whole string */ + unsigned short cslen; /* length of the encoded part of the string */ + boolean used; + boolean valid; +} cs_entry; + +static unsigned short t1_dr, t1_er; +static const unsigned short t1_c1 = 52845, t1_c2 = 22719; +static unsigned short t1_cslen; +static short t1_lenIV; +static char enc_line[ENC_BUF_SIZE]; + +/* define t1_line_ptr, t1_line_array & t1_line_limit */ +typedef char t1_line_entry; +define_array (t1_line); + +/* define t1_buf_ptr, t1_buf_array & t1_buf_limit */ +typedef char t1_buf_entry; +define_array (t1_buf); + +static int cs_start; + +static cs_entry *cs_tab, *cs_ptr, *cs_notdef; +static char *cs_dict_start, *cs_dict_end; +static int cs_count, cs_size, cs_size_pos; + +static cs_entry *subr_tab; +static char *subr_array_start, *subr_array_end; +static int subr_max, subr_size, subr_size_pos; + +/* This list contains the begin/end tokens commonly used in the */ +/* /Subrs array of a Type 1 font. */ +static const char *cs_token_pairs_list[][2] = { + {" RD", "NP"}, + {" -|", "|"}, + {" RD", "noaccess put"}, + {" -|", "noaccess put"}, + {NULL, NULL} +}; +static const char **cs_token_pair; + +static boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic; +static int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */ +static long t1_block_length; +static int last_hexbyte; +static FILE *t1_file; +static FILE *enc_file; + +#define t1_prefix(s) str_prefix(t1_line_array, s) +#define t1_buf_prefix(s) str_prefix(t1_buf_array, s) +#define t1_suffix(s) str_suffix(t1_line_array, t1_line_ptr, s) +#define t1_buf_suffix(s) str_suffix(t1_buf_array, t1_buf_ptr, s) +#define t1_charstrings() strstr(t1_line_array, charstringname) +#define t1_subrs() t1_prefix("/Subrs") +#define t1_end_eexec() t1_suffix("mark currentfile closefile") +#define t1_cleartomark() t1_prefix("cleartomark") + + +#ifndef pdfTeX +# define HEXLINE_WIDTH 64 + +static void end_hexline () +{ + if (hexline_length == HEXLINE_WIDTH) { + fputs ("\n", bitfile); + hexline_length = 0; + } +} + +static void t1_outhex (byte b) +{ + static char *hexdigits = "0123456789ABCDEF"; + t1_putchar (hexdigits[b / 16]); + t1_putchar (hexdigits[b % 16]); + hexline_length += 2; + end_hexline (); +} +#endif /* pdfTeX */ + + +static void enc_getline (void) +{ + char *p; + int c; + restart: + if (enc_eof ()) + pdftex_fail ("unexpected end of file"); + p = enc_line; + do { + c = enc_getchar (); + append_char_to_buf (c, p, enc_line, ENC_BUF_SIZE); + } + while (c != 10); + append_eol (p, enc_line, ENC_BUF_SIZE); + if (p - enc_line < 2 || *enc_line == '%') + goto restart; +} + +void load_enc (char *enc_name, char **enc_encname, char **glyph_names) +{ + char buf[ENC_BUF_SIZE], *p, *r; + int names_count; + char *myname; + set_cur_file_name (enc_name); + if (!enc_open ()) { + pdftex_warn ("cannot open encoding file for reading"); + cur_file_name = NULL; + return; + } + t1_log ("{"); + t1_log (cur_file_name = full_file_name ()); + enc_getline (); + if (*enc_line != '/' || (r = strchr (enc_line, '[')) == NULL) { + remove_eol (r, enc_line); + pdftex_fail + ("invalid encoding vector (a name or `[' missing): `%s'", enc_line); + } + while (*(r-1)==' ') r--; /* strip trailing spaces from encoding name */ + myname = xmalloc(r-enc_line); + memcpy(myname,enc_line+1,(r-enc_line)-1); + *(myname+(r-enc_line-1))=0; + *enc_encname = myname; + while (*r!='[') r++; + r++; /* skip '[' */ + names_count = 0; + skip (r, ' '); + for (;;) { + while (*r == '/') { + for (p = buf, r++; + *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++); + *p = 0; + skip (r, ' '); + if (names_count > 256) + pdftex_fail ("encoding vector contains more than 256 names"); + if (strcmp (buf, notdef) != 0) + glyph_names[names_count] = xstrdup (buf); + names_count++; + } + if (*r != 10 && *r != '%') { + if (str_prefix (r, "] def")) + goto done; + else { + remove_eol (r, enc_line); + pdftex_fail + ("invalid encoding vector: a name or `] def' expected: `%s'", + enc_line); + } + } + enc_getline (); + r = enc_line; + } + done: + enc_close (); + t1_log ("}"); + cur_file_name = NULL; +} + +static void t1_check_pfa (void) +{ + const int c = t1_getchar (); + t1_pfa = (c != 128) ? true : false; + t1_ungetchar (c); +} + +static int t1_getbyte (void) +{ + int c = t1_getchar (); + if (t1_pfa) + return c; + if (t1_block_length == 0) { + if (c != 128) + pdftex_fail ("invalid marker"); + c = t1_getchar (); + if (c == 3) { + while (!t1_eof ()) + t1_getchar (); + return EOF; + } + t1_block_length = t1_getchar () & 0xff; + t1_block_length |= (t1_getchar () & 0xff) << 8; + t1_block_length |= (t1_getchar () & 0xff) << 16; + t1_block_length |= (t1_getchar () & 0xff) << 24; + c = t1_getchar (); + } + t1_block_length--; + return c; +} + +static int hexval (int c) +{ + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= '0' && c <= '9') + return c - '0'; + else + return -1; +} + +static byte edecrypt (byte cipher) +{ + byte plain; + if (t1_pfa) { + while (cipher == 10 || cipher == 13) + cipher = t1_getbyte (); + last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte ()); + } + plain = (cipher ^ (t1_dr >> 8)); + t1_dr = (cipher + t1_dr) * t1_c1 + t1_c2; + return plain; +} + +static byte cdecrypt (byte cipher, unsigned short *cr) +{ + const byte plain = (cipher ^ (*cr >> 8)); + *cr = (cipher + *cr) * t1_c1 + t1_c2; + return plain; +} + +static byte eencrypt (byte plain) +{ + const byte cipher = (plain ^ (t1_er >> 8)); + t1_er = (cipher + t1_er) * t1_c1 + t1_c2; + return cipher; +} + +static byte cencrypt (byte plain, unsigned short *cr) +{ + const byte cipher = (plain ^ (*cr >> 8)); + *cr = (cipher + *cr) * t1_c1 + t1_c2; + return cipher; +} + +static char *eol (char *s) +{ + char *p = strend (s); + if (p - s > 1 && p[-1] != 10) { + *p++ = 10; + *p = 0; + } + return p; +} + +static float t1_scan_num (char *p, char **r) +{ + float f; + skip (p, ' '); + if (sscanf (p, "%g", &f) != 1) { + remove_eol (p, t1_line_array); + pdftex_fail ("a number expected: `%s'", t1_line_array); + } + if (r != NULL) { + for (; isdigit (*p) || *p == '.' || + *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++); + *r = p; + } + return f; +} + +static boolean str_suffix (const char *begin_buf, const char *end_buf, + const char *s) +{ + const char *s1 = end_buf - 1, *s2 = strend (s) - 1; + if (*s1 == 10) + s1--; + while (s1 >= begin_buf && s2 >= s) { + if (*s1-- != *s2--) + return false; + } + return s2 < s; +} + +static void t1_getline (void) +{ + int c, l, eexec_scan; + char *p; + static const char eexec_str[] = "currentfile eexec"; + static int eexec_len = 17; /* strlen(eexec_str) */ + restart: + if (t1_eof ()) + pdftex_fail ("unexpected end of file"); + t1_line_ptr = t1_line_array; + alloc_array (t1_line, 1, T1_BUF_SIZE); + t1_cslen = 0; + eexec_scan = 0; + c = t1_getbyte (); + if (c == EOF) + goto exit; + while (!t1_eof ()) { + if (t1_in_eexec == 1) + c = edecrypt (c); + alloc_array (t1_line, 1, T1_BUF_SIZE); + append_char_to_buf (c, t1_line_ptr, t1_line_array, t1_line_limit); + if (t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) { + if (t1_line_array[eexec_scan] == eexec_str[eexec_scan]) + eexec_scan++; + else + eexec_scan = -1; + } + if (c == 10 || (t1_pfa && eexec_scan == eexec_len && c == 32)) + break; + if (t1_cs && t1_cslen == 0 && (t1_line_ptr - t1_line_array > 4) && + (t1_suffix (" RD ") || t1_suffix (" -| "))) { + p = t1_line_ptr - 5; + while (*p != ' ') + p--; + t1_cslen = l = t1_scan_num (p + 1, 0); + cs_start = t1_line_ptr - t1_line_array; /* cs_start is an index now */ + alloc_array (t1_line, l, T1_BUF_SIZE); + while (l-- > 0) + *t1_line_ptr++ = edecrypt (t1_getbyte ()); + } + c = t1_getbyte (); + } + alloc_array (t1_line, 2, T1_BUF_SIZE); /* append_eol can append 2 chars */ + append_eol (t1_line_ptr, t1_line_array, t1_line_limit); + if (t1_line_ptr - t1_line_array < 2) + goto restart; + if (eexec_scan == eexec_len) + t1_in_eexec = 1; + exit: + /* ensure that t1_buf_array has as much room as t1_line_array */ + t1_buf_ptr = t1_buf_array; + alloc_array (t1_buf, t1_line_limit, t1_line_limit); +} + +static void t1_putline (void) +{ + char *p = t1_line_array; + if (t1_line_ptr - t1_line_array <= 1) + return; + if (t1_eexec_encrypt) { + while (p < t1_line_ptr) + out_eexec_char (eencrypt (*p++)); + } else { + while (p < t1_line_ptr) + t1_putchar (*p++); + } +} + +static void t1_puts (const char *s) +{ + if (s != t1_line_array) + strcpy (t1_line_array, s); + t1_line_ptr = strend (t1_line_array); + t1_putline (); +} + +static void t1_printf (const char *fmt, ...) +{ + va_list args; + va_start (args, fmt); + vsprintf (t1_line_array, fmt, args); + t1_puts (t1_line_array); + va_end (args); +} + +static void t1_init_params (const char *open_name_prefix) +{ + if ((open_name_prefix != NULL) && strlen(open_name_prefix)) { + t1_log (open_name_prefix); + t1_log (cur_file_name); + } + t1_lenIV = 4; + t1_dr = 55665; + t1_er = 55665; + t1_in_eexec = 0; + t1_cs = false; + t1_scan = true; + t1_synthetic = false; + t1_eexec_encrypt = false; + t1_block_length = 0; + t1_check_pfa (); +} + +static void t1_close_font_file (const char *close_name_suffix) +{ + if ((close_name_suffix != NULL) && strlen(close_name_suffix)) { + t1_log (close_name_suffix); + } + t1_close (); + cur_file_name = NULL; +} + +static void t1_check_block_len (boolean decrypt) +{ + int l, c; + if (t1_block_length == 0) + return; + c = t1_getbyte (); + if (decrypt) + c = edecrypt (c); + l = t1_block_length; + if (!(l == 0 && (c == 10 || c == 13))) { + pdftex_warn ("%i bytes more than expected were ignored", l + 1); + while (l-- > 0) + t1_getbyte (); + } +} + +static void t1_start_eexec (fm_entry *fm_cur) +{ + int i; + if (is_included (fm_cur)) { + get_length1 (); + save_offset (); + } + if (!t1_pfa) + t1_check_block_len (false); + for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) { + edecrypt (t1_getbyte ()); + *t1_line_ptr++ = 0; + } + t1_eexec_encrypt = true; + if (!read_encoding_only) + if (is_included (fm_cur)) + t1_putline (); /* to put the first four bytes */ +} + +static void t1_stop_eexec (fm_entry *fm_cur) +{ + int c; + if (is_included (fm_cur)) { + get_length2 (); + save_offset (); + } + end_last_eexec_line (); + if (!t1_pfa) + t1_check_block_len (true); + else { + c = edecrypt (t1_getbyte ()); + if (!(c == 10 || c == 13)) { + if (last_hexbyte == 0) + t1_puts ("00"); + else + pdftex_warn ("unexpected data after eexec"); + } + } + t1_cs = false; + t1_in_eexec = 2; +} + +#ifdef pdfTeX +/* macros for various transforms; currently only slant and extend are used */ +# define do_xshift(x,a) {x[4]+=a;} +# define do_yshift(x,a) {x[5]+=a;} +# define do_xscale(x,a) {x[0]*=a; x[2]*=a; x[4]*=a;} +# define do_yscale(x,a) {x[1]*=a; x[3]*=a; x[5]*=a;} +# define do_extend(x,a) {do_xscale(x,a);} +# define do_scale(x,a) {do_xscale(x,a); do_yscale(x,a);} +# define do_slant(x,a) {x[0]+=x[1]*(a); x[2]+=x[3]*(a); x[4]+=x[5]*(a);} +# define do_shear(x,a) {x[1]+=x[0]*(a); x[3]+=x[2]*(a); x[5]+=x[4]*(a);} +# define do_rotate(x,a) \ + {float t, u=cos(a), v=sin(a); \ + t =x[0]*u+x[1]*-v; \ + x[1] =x[0]*v+x[1]* u; x[0]=t; \ + t =x[2]*u+x[3]*-v; \ + x[3] =x[2]*v+x[3]* u; x[2]=t; \ + t =x[4]*u+x[5]*-v; \ + x[5] =x[4]*v+x[5]* u; x[4]=t;} + +static void t1_modify_fm (void) +{ + /* + * font matrix is given as six numbers a0..a5, which stands for the matrix + * + * a0 a1 0 + * M = a2 a3 0 + * a4 a5 1 + * + * ExtendFont is given as + * + * e 0 0 + * E = 0 1 0 + * 0 0 1 + * + * SlantFont is given as + * + * 1 0 0 + * S = s 1 0 + * 0 0 1 + * + * The slant transform must be done _before_ the extend transform + * for compatibility! + */ + float a[6]; + int i, c; + char *p, *q, *r; + if ((p = strchr (t1_line_array, '[')) == 0) + if ((p = strchr (t1_line_array, '{')) == 0) { + remove_eol (p, t1_line_array); + pdftex_fail ("FontMatrix: an array expected: `%s'", t1_line_array); + } + c = *p++; /* save the character '[' resp. '{' */ + strncpy (t1_buf_array, t1_line_array, (size_t) (p - t1_line_array)); + r = t1_buf_array + (p - t1_line_array); + for (i = 0; i < 6; i++) { + a[i] = t1_scan_num (p, &q); + p = q; + } + if (fm_slant (fm_cur) != 0) + do_slant (a, fm_slant (fm_cur) * 1E-3); + if (fm_extend (fm_cur) != 0) + do_extend (a, fm_extend (fm_cur) * 1E-3); + for (i = 0; i < 6; i++) { + sprintf (r, "%g ", a[i]); + r = strend (r); + } + if (c == '[') { + while (*p != ']' && *p != 0) + p++; + } else { + while (*p != '}' && *p != 0) + p++; + } + if (*p == 0) { + remove_eol (p, t1_line_array); + pdftex_fail + ("FontMatrix: cannot find the corresponding character to '%c': `%s'", + c, t1_line_array); + } + strcpy (r, p); + strcpy (t1_line_array, t1_buf_array); + t1_line_ptr = eol (t1_line_array); +} + +static void t1_modify_italic (void) +{ + float a; + char *p, *r; + if (fm_slant (fm_cur) == 0) + return; + p = strchr (t1_line_array, ' '); + strncpy (t1_buf_array, t1_line_array, (size_t) (p - t1_line_array + 1)); + a = t1_scan_num (p + 1, &r); + a -= atan (fm_slant (fm_cur) * 1E-3) * (180 / M_PI); + sprintf (t1_buf_array + (p - t1_line_array + 1), "%g", a); + strcpy (strend (t1_buf_array), r); + strcpy (t1_line_array, t1_buf_array); + t1_line_ptr = eol (t1_line_array); + font_keys[ITALIC_ANGLE_CODE].value = round (a); + font_keys[ITALIC_ANGLE_CODE].valid = true; +} + +#else + +static void t1_modify_fm (void) +{ + // t1_line_ptr = eol (t1_line_array); +} + +static void t1_modify_italic (void) +{ + // t1_line_ptr = eol (t1_line_array); +} + +#endif /* pdfTeX */ + +key_entry font_keys[FONT_KEYS_NUM] = { + {"Ascent", "Ascender", 0, false}, + {"CapHeight", "CapHeight", 0, false}, + {"Descent", "Descender", 0, false}, + {"FontName", "FontName", 0, false}, + {"ItalicAngle", "ItalicAngle", 0, false}, + {"StemV", "StdVW", 0, false}, + {"XHeight", "XHeight", 0, false}, + {"FontBBox", "FontBBox", 0, false}, + {"", "", 0, false}, + {"", "", 0, false}, + {"", "", 0, false} +}; + + +static void t1_scan_keys (int tex_font,fm_entry *fm_cur) +{ + int i, k; + char *p, *q, *r; + key_entry *key; + if (fm_extend (fm_cur) != 0 || fm_slant (fm_cur) != 0) { + if (t1_prefix ("/FontMatrix")) { + t1_modify_fm (); + return; + } + if (t1_prefix ("/ItalicAngle")) { + t1_modify_italic (); + return; + } + } + if (t1_prefix ("/FontType")) { + p = t1_line_array + strlen ("FontType") + 1; + if ((i = t1_scan_num (p, 0)) != 1) + pdftex_fail ("Type%d fonts unsupported by metapost", i); + return; + } + for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++) + if (str_prefix (t1_line_array + 1, key->t1name)) + break; + if (key - font_keys == MAX_KEY_CODE) + return; + key->valid = true; + p = t1_line_array + strlen (key->t1name) + 1; + skip (p, ' '); + if ((k = key - font_keys) == FONTNAME_CODE) { + if (*p != '/') { + remove_eol (p, t1_line_array); + pdftex_fail ("a name expected: `%s'", t1_line_array); + } + r = ++p; /* skip the slash */ + if (is_included (fm_cur)) { + /* save the fontname */ + strncpy (fontname_buf, p, FONTNAME_BUF_SIZE); + for (i=0; fontname_buf[i] != 10; i++); + fontname_buf[i]=0; + + if(is_subsetted (fm_cur)) { + if (fm_cur->encoding!=NULL && fm_cur->encoding->glyph_names!=NULL) + make_subset_tag (fm_cur, fm_cur->encoding->glyph_names, tex_font); + else + make_subset_tag (fm_cur, t1_builtin_glyph_names, tex_font); + + alloc_array (t1_line, (r-t1_line_array+6+1+strlen(fontname_buf)+1), T1_BUF_SIZE); + strncpy (r, fm_cur->subset_tag , 6); + *(r+6) = '-'; + strncpy (r+7, fontname_buf, strlen(fontname_buf)+1); + t1_line_ptr = eol (r); + } else { + /* for (q = p; *q != ' ' && *q != 10; *q++);*/ + /**q = 0;*/ + t1_line_ptr = eol (r); + } + } + return; + } + if ((k == STEMV_CODE || k == FONTBBOX1_CODE) + && (*p == '[' || *p == '{')) + p++; + if (k == FONTBBOX1_CODE) { + for (i = 0; i < 4; i++) { + key[i].value = t1_scan_num (p, &r); + p = r; + } + return; + } + key->value = t1_scan_num (p, 0); +} + +static void t1_scan_param (int tex_font,fm_entry *fm_cur) +{ + static const char *lenIV = "/lenIV"; + if (!t1_scan || *t1_line_array != '/') + return; + if (t1_prefix (lenIV)) { + t1_lenIV = t1_scan_num (t1_line_array + strlen (lenIV), 0); + return; + } + t1_scan_keys (tex_font,fm_cur); +} + +static void copy_glyph_names (char **glyph_names, int a, int b) +{ + if (glyph_names[b] != notdef) { + free (glyph_names[b]); + glyph_names[b] = (char *) notdef; + } + if (glyph_names[a] != notdef) { + glyph_names[b] = xstrdup (glyph_names[a]); + } +} + +static void t1_builtin_enc (void) +{ + int i, a, b, c, counter = 0; + char *r, *p; + /* + * At this moment "/Encoding" is the prefix of t1_line_array + */ + if (t1_suffix ("def")) { /* predefined encoding */ + sscanf (t1_line_array + strlen ("/Encoding"), "%256s", t1_buf_array); + if (strcmp (t1_buf_array, "StandardEncoding") == 0) { + for (i = 0; i < 256; i++) + if (standard_glyph_names[i] == notdef) + t1_builtin_glyph_names[i] = (char *) notdef; + else + t1_builtin_glyph_names[i] = + xstrdup (standard_glyph_names[i]); + t1_encoding = ENC_STANDARD; + } else + pdftex_fail + ("cannot subset font (unknown predefined encoding `%s')", + t1_buf_array); + return; + } else + t1_encoding = ENC_BUILTIN; + /* + * At this moment "/Encoding" is the prefix of t1_line_array, and the encoding is + * not a predefined encoding + * + * We have two possible forms of Encoding vector. The first case is + * + * /Encoding [/a /b /c...] readonly def + * + * and the second case can look like + * + * /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for + * dup 0 /x put + * dup 1 /y put + * ... + * readonly def + */ + for (i = 0; i < 256; i++) + t1_builtin_glyph_names[i] = (char *) notdef; + if (t1_prefix ("/Encoding [") || t1_prefix ("/Encoding[")) { /* the first case */ + r = strchr (t1_line_array, '[') + 1; + skip (r, ' '); + for (;;) { + while (*r == '/') { + for (p = t1_buf_array, r++; + *r != 32 && *r != 10 && *r != ']' && *r != '/'; + *p++ = *r++); + *p = 0; + skip (r, ' '); + if (counter > 255) + pdftex_fail + ("encoding vector contains more than 256 names"); + if (strcmp (t1_buf_array, notdef) != 0) + t1_builtin_glyph_names[counter] = xstrdup (t1_buf_array); + counter++; + } + if (*r != 10 && *r != '%') { + if (str_prefix (r, "] def") + || str_prefix (r, "] readonly def")) + break; + else { + remove_eol (r, t1_line_array); + pdftex_fail + ("a name or `] def' or `] readonly def' expected: `%s'", + t1_line_array); + } + } + t1_getline (); + r = t1_line_array; + } + } else { /* the second case */ + p = strchr (t1_line_array, 10); + for (;;) { + if (*p == 10) { + t1_getline (); + p = t1_line_array; + } + /* + check for `dup <index> <glyph> put' + */ + if (sscanf (p, "dup %i%256s put", &i, t1_buf_array) == 2 && + *t1_buf_array == '/' && valid_code (i)) { + if (strcmp (t1_buf_array + 1, notdef) != 0) + t1_builtin_glyph_names[i] = xstrdup (t1_buf_array + 1); + p = strstr (p, " put") + strlen (" put"); + skip (p, ' '); + } + /* + check for `dup dup <to> exch <from> get put' + */ + else if (sscanf (p, "dup dup %i exch %i get put", &b, &a) == 2 + && valid_code (a) && valid_code (b)) { + copy_glyph_names (t1_builtin_glyph_names, a, b); + p = strstr (p, " get put") + strlen (" get put"); + skip (p, ' '); + } + /* + check for `dup dup <from> <size> getinterval <to> exch putinterval' + */ + else if (sscanf + (p, "dup dup %i %i getinterval %i exch putinterval", + &a, &c, &b) == 3 && valid_code (a) && valid_code (b) + && valid_code (c)) { + for (i = 0; i < c; i++) + copy_glyph_names (t1_builtin_glyph_names, a + i, b + i); + p = strstr (p, " putinterval") + strlen (" putinterval"); + skip (p, ' '); + } + /* + check for `def' or `readonly def' + */ + else if ((p == t1_line_array || (p > t1_line_array && p[-1] == ' ')) + && strcmp (p, "def\n") == 0) + return; + /* + skip an unrecognizable word + */ + else { + while (*p != ' ' && *p != 10) + p++; + skip (p, ' '); + } + } + } +} + +static void t1_check_end (void) +{ + if (t1_eof ()) + return; + t1_getline (); + if (t1_prefix ("{restore}")) + t1_putline (); +} + +static boolean t1_open_fontfile (fm_entry *fm_cur,const char *open_name_prefix) +{ + ff_entry *ff; + ff = check_ff_exist (fm_cur); + if (ff->ff_path != NULL) + t1_file = xfopen (cur_file_name = ff->ff_path, FOPEN_RBIN_MODE); + else { + set_cur_file_name (fm_cur->ff_name); + pdftex_warn ("cannot open Type 1 font file for reading"); + return false; + } + t1_init_params (open_name_prefix); + fontfile_found = true; + return true; +} + +static void t1_scan_only (int tex_font, fm_entry *fm_cur) +{ + do { + t1_getline (); + t1_scan_param (tex_font, fm_cur); + } + while (t1_in_eexec == 0); + t1_start_eexec (fm_cur); + do { + t1_getline (); + t1_scan_param (tex_font, fm_cur); + } + while (!(t1_charstrings () || t1_subrs ())); +} + +static void t1_include (int tex_font, fm_entry *fm_cur) +{ + do { + t1_getline (); + t1_scan_param (tex_font, fm_cur); + t1_putline (); + } + while (t1_in_eexec == 0); + t1_start_eexec (fm_cur); + do { + t1_getline (); + t1_scan_param (tex_font, fm_cur); + t1_putline (); + } + while (!(t1_charstrings () || t1_subrs ())); + t1_cs = true; + do { + t1_getline (); + t1_putline (); + } + while (!t1_end_eexec ()); + t1_stop_eexec (fm_cur); + if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */ + do { + t1_getline (); + t1_putline (); + } + while (!t1_cleartomark ()); + t1_check_end (); /* write "{restore}if" if found */ + } + get_length3 (); +} + +#define check_subr(subr) \ + if (subr >= subr_size || subr < 0) \ + pdftex_fail("Subrs array: entry index out of range (%i)", subr); + +static const char **check_cs_token_pair () +{ + const char **p = (const char **) cs_token_pairs_list; + for (; p[0] != NULL; ++p) + if (t1_buf_prefix (p[0]) && t1_buf_suffix (p[1])) + return p; + return NULL; +} + +static void cs_store (boolean is_subr) +{ + char *p; + cs_entry *ptr; + int subr; + for (p = t1_line_array, t1_buf_ptr = t1_buf_array; *p != ' '; + *t1_buf_ptr++ = *p++); + *t1_buf_ptr = 0; + if (is_subr) { + subr = t1_scan_num (p + 1, 0); + check_subr (subr); + ptr = subr_tab + subr; + } else { + ptr = cs_ptr++; + if (cs_ptr - cs_tab > cs_size) + pdftex_fail + ("CharStrings dict: more entries than dict size (%i)", cs_size); + if (strcmp (t1_buf_array + 1, notdef) == 0) /* skip the slash */ + ptr->name = (char *) notdef; + else + ptr->name = xstrdup (t1_buf_array + 1); + } + /* copy " RD " + cs data to t1_buf_array */ + memcpy (t1_buf_array, t1_line_array + cs_start - 4, + (unsigned) (t1_cslen + 4)); + /* copy the end of cs data to t1_buf_array */ + for (p = t1_line_array + cs_start + t1_cslen, t1_buf_ptr = + t1_buf_array + t1_cslen + 4; *p != 10; *t1_buf_ptr++ = *p++); + *t1_buf_ptr++ = 10; + if (is_subr && cs_token_pair == NULL) + cs_token_pair = check_cs_token_pair (); + ptr->len = t1_buf_ptr - t1_buf_array; + ptr->cslen = t1_cslen; + ptr->data = xtalloc (ptr->len, byte); + memcpy (ptr->data, t1_buf_array, ptr->len); + ptr->valid = true; +} + +#define store_subr() cs_store(true) +#define store_cs() cs_store(false) + +#define CC_STACK_SIZE 24 + +static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack; +static cc_entry cc_tab[CS_MAX]; +static boolean is_cc_init = false; + + +#define cc_pop(N) \ + if (stack_ptr - cc_stack < (N)) \ + stack_error(N); \ + stack_ptr -= N + +#define stack_error(N) { \ + pdftex_warn("CharString: invalid access (%i) to stack (%i entries)", \ + (int) N, (int)(stack_ptr - cc_stack)); \ + goto cs_error; \ +} + +/* +static integer cc_get(integer index) +{ + if (index < 0) { + if (stack_ptr + index < cc_stack ) + stack_error(stack_ptr - cc_stack + index); + return *(stack_ptr + index); + } + else { + if (cc_stack + index >= stack_ptr) + stack_error(index); + return cc_stack[index]; + } +} +*/ + +#define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N))) + +#define cc_push(V) *stack_ptr++ = V +#define cc_clear() stack_ptr = cc_stack + +#define set_cc(N, B, A, C) \ + cc_tab[N].nargs = A; \ + cc_tab[N].bottom = B; \ + cc_tab[N].clear = C; \ + cc_tab[N].valid = true + +static void cc_init (void) +{ + int i; + if (is_cc_init) + return; + for (i = 0; i < CS_MAX; i++) + cc_tab[i].valid = false; + set_cc (CS_HSTEM, true, 2, true); + set_cc (CS_VSTEM, true, 2, true); + set_cc (CS_VMOVETO, true, 1, true); + set_cc (CS_RLINETO, true, 2, true); + set_cc (CS_HLINETO, true, 1, true); + set_cc (CS_VLINETO, true, 1, true); + set_cc (CS_RRCURVETO, true, 6, true); + set_cc (CS_CLOSEPATH, false, 0, true); + set_cc (CS_CALLSUBR, false, 1, false); + set_cc (CS_RETURN, false, 0, false); + /* + set_cc(CS_ESCAPE, false, 0, false); + */ + set_cc (CS_HSBW, true, 2, true); + set_cc (CS_ENDCHAR, false, 0, true); + set_cc (CS_RMOVETO, true, 2, true); + set_cc (CS_HMOVETO, true, 1, true); + set_cc (CS_VHCURVETO, true, 4, true); + set_cc (CS_HVCURVETO, true, 4, true); + set_cc (CS_DOTSECTION, false, 0, true); + set_cc (CS_VSTEM3, true, 6, true); + set_cc (CS_HSTEM3, true, 6, true); + set_cc (CS_SEAC, true, 5, true); + set_cc (CS_SBW, true, 4, true); + set_cc (CS_DIV, false, 2, false); + set_cc (CS_CALLOTHERSUBR, false, 0, false); + set_cc (CS_POP, false, 0, false); + set_cc (CS_SETCURRENTPOINT, true, 2, true); + is_cc_init = true; +} + +#define cs_getchar() cdecrypt(*data++, &cr) + +#define mark_subr(n) cs_mark(0, n) +#define mark_cs(s) cs_mark(s, 0) + +static void cs_warn (const char *cs_name, int subr, const char *fmt, ...) +{ + char buf[SMALL_BUF_SIZE]; + va_list args; + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + if (cs_name == NULL) + pdftex_warn ("Subr (%i): %s", (int) subr, buf); + else + pdftex_warn ("CharString (/%s): %s", cs_name, buf); +} + +static void cs_mark (const char *cs_name, int subr) +{ + byte *data; + int i, b, cs_len; + integer a, a1, a2; + unsigned short cr; + static integer lastargOtherSubr3 = 3; /* the argument of last call to + OtherSubrs[3] */ + cs_entry *ptr; + cc_entry *cc; + if (cs_name == NULL) { + check_subr (subr); + ptr = subr_tab + subr; + if (!ptr->valid) + return; + } else { + if (cs_notdef != NULL && + (cs_name == notdef || strcmp (cs_name, notdef) == 0)) + ptr = cs_notdef; + else { + for (ptr = cs_tab; ptr < cs_ptr; ptr++) + if (strcmp (ptr->name, cs_name) == 0) + break; + if (ptr == cs_ptr) { + pdftex_warn ("glyph `%s' undefined", cs_name); + return; + } + if (ptr->name == notdef) + cs_notdef = ptr; + } + } + /* only marked CharString entries and invalid entries can be skipped; + valid marked subrs must be parsed to keep the stack in sync */ + if (!ptr->valid || (ptr->used && cs_name != NULL)) + return; + ptr->used = true; + cr = 4330; + cs_len = ptr->cslen; + data = ptr->data + 4; + for (i = 0; i < t1_lenIV; i++, cs_len--) + cs_getchar (); + while (cs_len > 0) { + --cs_len; + b = cs_getchar (); + if (b >= 32) { + if (b <= 246) + a = b - 139; + else if (b <= 250) { + --cs_len; + a = ((b - 247) << 8) + 108 + cs_getchar (); + } else if (b <= 254) { + --cs_len; + a = -((b - 251) << 8) - 108 - cs_getchar (); + } else { + cs_len -= 4; + a = (cs_getchar () & 0xff) << 24; + a |= (cs_getchar () & 0xff) << 16; + a |= (cs_getchar () & 0xff) << 8; + a |= (cs_getchar () & 0xff) << 0; + if (sizeof (integer) > 4 && (a & 0x80000000)) + a |= ~0x7FFFFFFF; + } + cc_push (a); + } else { + if (b == CS_ESCAPE) { + b = cs_getchar () + CS_1BYTE_MAX; + cs_len--; + } + if (b >= CS_MAX) { + cs_warn (cs_name, subr, "command value out of range: %i", + (int) b); + goto cs_error; + } + cc = cc_tab + b; + if (!cc->valid) { + cs_warn (cs_name, subr, "command not valid: %i", (int) b); + goto cs_error; + } + if (cc->bottom) { + if (stack_ptr - cc_stack < cc->nargs) + cs_warn (cs_name, subr, + "less arguments on stack (%i) than required (%i)", + (int) (stack_ptr - cc_stack), (int) cc->nargs); + else if (stack_ptr - cc_stack > cc->nargs) + cs_warn (cs_name, subr, + "more arguments on stack (%i) than required (%i)", + (int) (stack_ptr - cc_stack), (int) cc->nargs); + } + switch (cc - cc_tab) { + case CS_CALLSUBR: + a1 = cc_get (-1); + cc_pop (1); + mark_subr (a1); + if (!subr_tab[a1].valid) { + cs_warn (cs_name, subr, "cannot call subr (%i)", (int) a1); + goto cs_error; + } + break; + case CS_DIV: + cc_pop (2); + cc_push (0); + break; + case CS_CALLOTHERSUBR: + if (cc_get (-1) == 3) + lastargOtherSubr3 = cc_get (-3); + a1 = cc_get (-2) + 2; + cc_pop (a1); + break; + case CS_POP: + cc_push (lastargOtherSubr3); + /* the only case when we care about the value being pushed onto + stack is when POP follows CALLOTHERSUBR (changing hints by + OtherSubrs[3]) + */ + break; + case CS_SEAC: + a1 = cc_get (3); + a2 = cc_get (4); + cc_clear (); + mark_cs (standard_glyph_names[a1]); + mark_cs (standard_glyph_names[a2]); + break; + default: + if (cc->clear) + cc_clear (); + } + } + } + return; + cs_error: /* an error occured during parsing */ + cc_clear (); + ptr->valid = false; + ptr->used = false; +} + +static void t1_subset_ascii_part (int tex_font, fm_entry *fm_cur) +{ + int i, j; + t1_getline (); + while (!t1_prefix ("/Encoding")) { + t1_scan_param (tex_font, fm_cur); + t1_putline (); + t1_getline (); + } + t1_builtin_enc (); + if (is_reencoded (fm_cur)) + t1_glyph_names = external_enc (); + else + t1_glyph_names = t1_builtin_glyph_names; + /* + if (is_included (fm_cur) && is_subsetted (fm_cur)) { + make_subset_tag (fm_cur, t1_glyph_names, tex_font); + update_subset_tag (); + } + */ + if ((!is_subsetted (fm_cur)) && t1_encoding == ENC_STANDARD) + t1_puts ("/Encoding StandardEncoding def\n"); + else { + t1_puts + ("/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"); + for (i = 0, j = 0; i < 256; i++) { + if (is_used_char (i) && t1_glyph_names[i] != notdef) { + j++; + t1_printf ("dup %i /%s put\n", (int) t1_char (i), + t1_glyph_names[i]); + } + } + /* We didn't mark anything for the Encoding array. */ + /* We add "dup 0 /.notdef put" for compatibility */ + /* with Acrobat 5.0. */ + if (j == 0) + t1_puts ("dup 0 /.notdef put\n"); + t1_puts ("readonly def\n"); + } + do { + t1_getline (); + t1_scan_param (tex_font, fm_cur); + if (!t1_prefix ("/UniqueID")) /* ignore UniqueID for subsetted fonts */ + t1_putline (); + } + while (t1_in_eexec == 0); +} + +#define t1_subr_flush() t1_flush_cs(true) +#define t1_cs_flush() t1_flush_cs(false) + +static void t1_flush_cs (boolean); + +static void cs_init (void) +{ + cs_ptr = cs_tab = NULL; + cs_dict_start = cs_dict_end = NULL; + cs_count = cs_size = cs_size_pos = 0; + cs_token_pair = NULL; + subr_tab = NULL; + subr_array_start = subr_array_end = NULL; + subr_max = subr_size = subr_size_pos = 0; +} + +static void init_cs_entry (cs_entry * cs) +{ + cs->data = NULL; + cs->name = NULL; + cs->len = 0; + cs->cslen = 0; + cs->used = false; + cs->valid = false; +} + +static void t1_mark_glyphs (int tex_font); + +static void t1_read_subrs (int tex_font, fm_entry *fm_cur) +{ + int i, s; + cs_entry *ptr; + t1_getline (); + while (!(t1_charstrings () || t1_subrs ())) { + t1_scan_param (tex_font, fm_cur); + t1_putline (); + t1_getline (); + } + found: + t1_cs = true; + t1_scan = false; + if (!t1_subrs ()) + return; + subr_size_pos = strlen ("/Subrs") + 1; + /* subr_size_pos points to the number indicating dict size after "/Subrs" */ + subr_size = t1_scan_num (t1_line_array + subr_size_pos, 0); + if (subr_size == 0) { + while (!t1_charstrings ()) + t1_getline (); + return; + } + // subr_tab = xtalloc (subr_size, cs_entry); + subr_tab = (cs_entry *)malloc (subr_size*sizeof (cs_entry)); + for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) + init_cs_entry (ptr); + subr_array_start = xstrdup (t1_line_array); + t1_getline (); + while (t1_cslen) { + store_subr (); + t1_getline (); + } + /* mark the first four entries without parsing */ + for (i = 0; i < subr_size && i < 4; i++) + subr_tab[i].used = true; + /* the end of the Subrs array might have more than one line so we need to + concatnate them to subr_array_end. Unfortunately some fonts don't have + the Subrs array followed by the CharStrings dict immediately (synthetic + fonts). If we cannot find CharStrings in next POST_SUBRS_SCAN lines then + we will treat the font as synthetic and ignore everything until next + Subrs is found + */ +#define POST_SUBRS_SCAN 5 + s = 0; + *t1_buf_array = 0; + for (i = 0; i < POST_SUBRS_SCAN; i++) { + if (t1_charstrings ()) + break; + s += t1_line_ptr - t1_line_array; + alloc_array (t1_buf, s, T1_BUF_SIZE); + strcat (t1_buf_array, t1_line_array); + t1_getline (); + } + subr_array_end = xstrdup (t1_buf_array); + if (i == POST_SUBRS_SCAN) { /* CharStrings not found; + suppose synthetic font */ + for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) + if (ptr->valid) + xfree (ptr->data); + xfree (subr_tab); + xfree (subr_array_start); + xfree (subr_array_end); + cs_init (); + t1_cs = false; + t1_synthetic = true; + while (!(t1_charstrings () || t1_subrs ())) + t1_getline (); + goto found; + } +} + +static void t1_flush_cs (boolean is_subr) +{ + char *p; + byte *r, *return_cs = NULL; + cs_entry *tab, *end_tab, *ptr; + char *start_line, *line_end; + int count, size_pos; + unsigned short cr, cs_len = 0; /* to avoid warning about uninitialized use of cs_len */ + if (is_subr) { + start_line = subr_array_start; + line_end = subr_array_end; + size_pos = subr_size_pos; + tab = subr_tab; + count = subr_max + 1; + end_tab = subr_tab + count; + } else { + start_line = cs_dict_start; + line_end = cs_dict_end; + size_pos = cs_size_pos; + tab = cs_tab; + end_tab = cs_ptr; + count = cs_count; + } + t1_line_ptr = t1_line_array; + for (p = start_line; p - start_line < size_pos;) + *t1_line_ptr++ = *p++; + while (isdigit (*p)) + p++; + sprintf (t1_line_ptr, "%u", count); + strcat (t1_line_ptr, p); + t1_line_ptr = eol (t1_line_array); + t1_putline (); + + /* create return_cs to replace unsused subr's */ + if (is_subr) { + cr = 4330; + cs_len = 0; + return_cs = xtalloc (t1_lenIV + 1, byte); + if (t1_lenIV > 0) { + for (cs_len = 0, r = return_cs; cs_len < t1_lenIV; cs_len++, r++) + *r = cencrypt (0x00, &cr); + *r = cencrypt (CS_RETURN, &cr); + } else { + *return_cs = CS_RETURN; + } + cs_len++; + } + + for (ptr = tab; ptr < end_tab; ptr++) { + if (ptr->used) { + if (is_subr) + sprintf (t1_line_array, "dup %i %u", (int) (ptr - tab), + ptr->cslen); + else + sprintf (t1_line_array, "/%s %u", ptr->name, ptr->cslen); + p = strend (t1_line_array); + memcpy (p, ptr->data, ptr->len); + t1_line_ptr = p + ptr->len; + t1_putline (); + } else { + /* replace unsused subr's by return_cs */ + if (is_subr) { + sprintf (t1_line_array, "dup %i %u%s ", (int) (ptr - tab), + cs_len, cs_token_pair[0]); + p = strend (t1_line_array); + memcpy (p, return_cs, cs_len); + t1_line_ptr = p + cs_len; + t1_putline (); + sprintf (t1_line_array, " %s", cs_token_pair[1]); + t1_line_ptr = eol (t1_line_array); + t1_putline (); + } + } + xfree (ptr->data); + if (ptr->name != notdef) + xfree (ptr->name); + } + sprintf (t1_line_array, "%s", line_end); + t1_line_ptr = eol (t1_line_array); + t1_putline (); + if (is_subr) + xfree (return_cs); + xfree (tab); + xfree (start_line); + xfree (line_end); +} + +static void t1_mark_glyphs (int tex_font) +{ + int i; + char *charset = extra_charset (); + char *g, *s, *r; + cs_entry *ptr; + if (t1_synthetic || embed_all_glyphs (tex_font)) { /* mark everything */ + if (cs_tab != NULL) + for (ptr = cs_tab; ptr < cs_ptr; ptr++) + if (ptr->valid) + ptr->used = true; + if (subr_tab != NULL) { + for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) + if (ptr->valid) + ptr->used = true; + subr_max = subr_size - 1; + } + return; + } + mark_cs (notdef); + for (i = 0; i < 256; i++) + if (is_used_char (i)) { + if (t1_glyph_names[i] == notdef) + pdftex_warn ("character %i is mapped to %s", i, notdef); + else + mark_cs (t1_glyph_names[i]); + } + if (charset == NULL) + goto set_subr_max; + g = s = charset + 1; /* skip the first '/' */ + r = strend (g); + while (g < r) { + while (*s != '/' && s < r) + s++; + *s = 0; /* terminate g by rewriting '/' to 0 */ + mark_cs (g); + g = s + 1; + } + set_subr_max: + if (subr_tab != NULL) + for (subr_max = -1, ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) + if (ptr->used && ptr - subr_tab > subr_max) + subr_max = ptr - subr_tab; +} + +static void t1_subset_charstrings (int tex_font) +{ + cs_entry *ptr; + cs_size_pos = + strstr (t1_line_array, charstringname) + strlen (charstringname) + - t1_line_array + 1; + /* cs_size_pos points to the number indicating + dict size after "/CharStrings" */ + cs_size = t1_scan_num (t1_line_array + cs_size_pos, 0); + cs_ptr = cs_tab = xtalloc (cs_size, cs_entry); + for (ptr = cs_tab; ptr - cs_tab < cs_size; ptr++) + init_cs_entry (ptr); + cs_notdef = NULL; + cs_dict_start = xstrdup (t1_line_array); + t1_getline (); + while (t1_cslen) { + store_cs (); + t1_getline (); + } + cs_dict_end = xstrdup (t1_line_array); + t1_mark_glyphs (tex_font); + if (subr_tab != NULL) { + if (cs_token_pair == NULL) + pdftex_fail + ("This Type 1 font uses mismatched subroutine begin/end token pairs."); + t1_subr_flush (); + } + for (cs_count = 0, ptr = cs_tab; ptr < cs_ptr; ptr++) + if (ptr->used) + cs_count++; + t1_cs_flush (); +} + +static void t1_subset_end (fm_entry *fm_cur) +{ + if (t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */ + while (!strstr (t1_line_array, "definefont")) { + t1_getline (); + t1_putline (); + } + while (!t1_end_eexec ()) + t1_getline (); /* ignore the rest */ + t1_putline (); /* write "mark currentfile closefile" */ + } else + while (!t1_end_eexec ()) { /* copy to "mark currentfile closefile" */ + t1_getline (); + t1_putline (); + } + t1_stop_eexec (fm_cur); + if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */ + while (!t1_cleartomark ()) { + t1_getline (); + t1_putline (); + } + if (!t1_synthetic) /* don't check "{restore}if" for synthetic fonts */ + t1_check_end (); /* write "{restore}if" if found */ + } + get_length3 (); +} + +int t1_updatefm (int f, fm_entry *fm) +{ + char *s, *p; + read_encoding_only = true; + if (!t1_open_fontfile (fm,NULL)) { + return 0; + } + t1_scan_only (f, fm); + s = xstrdup(fontname_buf); + for (p=s; *p != ' ' && *p != 0; *p++); + *p=0; + fm->ps_name = s; + t1_close_font_file (""); + return 1; +} + + +void writet1 (int tex_font, fm_entry *fm_cur) +{ + read_encoding_only = false; + if (!is_included (fm_cur)) { /* scan parameters from font file */ + if (!t1_open_fontfile (fm_cur,"{")) + return; + t1_scan_only (tex_font, fm_cur); + t1_close_font_file ("}"); + return; + } + if (!is_subsetted (fm_cur)) { /* include entire font */ + if (!t1_open_fontfile (fm_cur,"<<")) + return; + t1_include (tex_font,fm_cur); + t1_close_font_file (">>"); + return; + } + /* partial downloading */ + if (!t1_open_fontfile (fm_cur,"<")) + return; + t1_subset_ascii_part (tex_font,fm_cur); + t1_start_eexec (fm_cur); + cc_init (); + cs_init (); + t1_read_subrs (tex_font, fm_cur); + t1_subset_charstrings (tex_font); + t1_subset_end (fm_cur); + t1_close_font_file (">"); +} + +void t1_free () +{ + xfree (t1_line_array); + xfree (t1_buf_array); +} diff --git a/Build/source/texk/web2c/mpware/makempx.in b/Build/source/texk/web2c/mpware/makempx.in index 8aaa9bac1dc..0f1c660ca40 100644 --- a/Build/source/texk/web2c/mpware/makempx.in +++ b/Build/source/texk/web2c/mpware/makempx.in @@ -1,12 +1,12 @@ #!/bin/sh -# $Id: makempx.in,v 1.18 2005/06/22 17:33:26 olaf Exp $ +# $Id: makempx.in,v 1.7 2005/04/28 06:45:21 taco Exp $ # Make an MPX file from the labels in a MetaPost source file, # using mpto and either dvitomp (TeX) or dmp (troff). # From John Hobby's original (though there's not much of it left by now). # Public domain. # -# -version=0.9 +# +version=0.99 : ${DMP=dmp} : ${DVITOMP=dvitomp} @@ -17,7 +17,7 @@ version=0.9 : ${NEWER=newer} # This is oriented towards GNU roff: old value was # 'eqn -Tpost -d\$\$ | troff -Tpost' -: ${TROFF='eqn -Tps -d\$\$ | troff -Tps'} +: ${TROFF='soelim -k | eqn -Tps -d\$\$ | troff -Tps'} # convert relative path to absolute in $MAKEMPX_BINDIR: case "$MAKEMPX_BINDIR" in diff --git a/Build/source/texk/web2c/mpware/mpto.c b/Build/source/texk/web2c/mpware/mpto.c index 0bc29fc259b..99678221e4b 100644 --- a/Build/source/texk/web2c/mpware/mpto.c +++ b/Build/source/texk/web2c/mpware/mpto.c @@ -1,4 +1,4 @@ -/* $Id: mpto.c,v 1.21 2005/08/28 09:17:25 olaf Exp $ +/* $Id: mpto.c,v 1.15 2005/08/28 11:42:55 taco Exp $ * Public domain. * * Previous versions of mpto were copyright 1990 - 1995 by AT&T Bell @@ -280,7 +280,7 @@ main(int argc, char **argv) exit (0); } else if (argc > 1 && (strcmp (argv[1], "--version") == 0 || strcmp (argv[1], "-version") == 0)) { - printf ("mpto 0.902\n\ + printf ("mpto 0.99\n\ This program is in the public domain.\n\ Primary author of mpto: John Hobby.\n"); exit (0); diff --git a/Build/source/texk/web2c/mpware/newer.c b/Build/source/texk/web2c/mpware/newer.c index 69ab23aeb67..55e9fb4958a 100644 --- a/Build/source/texk/web2c/mpware/newer.c +++ b/Build/source/texk/web2c/mpware/newer.c @@ -1,4 +1,5 @@ -/* newer - true if any source file is newer than the target file. +/* $Id: newer.c,v 1.10 2005/11/30 08:49:55 taco Exp $ + * newer - true if any source file is newer than the target file. * * Public domain. * @@ -13,7 +14,7 @@ #endif #include <stdio.h> #include <stdlib.h> -#ifndef WIN32 +#if !defined(WIN32) || defined(__MINGW32__) #include <sys/types.h> #include <sys/stat.h> #endif @@ -32,7 +33,8 @@ #endif int i; -int verbose = 1; +int verbose = 0; +int quiet = 0; int missing_source = 0; int missing_target = 0; int result = exit_false; @@ -63,7 +65,7 @@ main(int argc, char **argv) strcmp(argv[1], "-quiet") == 0 || strcmp(argv[1], "--quiet") == 0) { - verbose = 0; + quiet = 1; argv++; argc--; @@ -75,17 +77,17 @@ main(int argc, char **argv) one of them is not older than `target'.\n\ Also exit successfully if `target' doesn't exist.\n\ \n\ ---help display this help and exit\n\ ---quiet do not print anything\n\ ---verbose list missing input files (default)\n\ ---version output version information and exit\n\n", stdout); +--help Display this help and exit\n\ +--quiet Do not print anything\n\ +--verbose List missing files, including missing target files\n\ +--version Output version information and exit\n\n", stdout); fputs ("Email bug reports to metapost@tug.org.\n", stdout); exit(0); } else if (strcmp(argv[1], "-version") == 0 || strcmp(argv[1], "--version") == 0) { - fputs("newer 0.901\n\ + fputs("newer 0.99\n\ This program is in the public domain.\n\ Primary author of newer: John Hobby.\n", stdout); exit(0); @@ -108,7 +110,7 @@ Try `newer --help' for more information.\n", stderr); /* check the target file */ if (stat(argv[argc-1], &target_stat) < 0) { - if (verbose) { + if (verbose && !quiet) { fprintf(stderr, "newer: target file `%s' doesn't exist.\n", argv[argc-1]); } @@ -118,7 +120,7 @@ Try `newer --help' for more information.\n", stderr); /* check the source files */ for (i = 1; i < (argc-1); i++) { if (stat(argv[i], &source_stat) < 0) { - if (verbose) { + if (!quiet) { fprintf (stderr, "newer: source file `%s' doesn't exist.\n", argv[i]); } diff --git a/Build/source/texk/web2c/web2c/convert b/Build/source/texk/web2c/web2c/convert index 3c5b72f617b..05b85430072 100755 --- a/Build/source/texk/web2c/web2c/convert +++ b/Build/source/texk/web2c/web2c/convert @@ -48,7 +48,7 @@ output_files="$cfile $basefile.h" case $basefile in bibtex) midcmd="| sed -f $srcdir/web2c/cvtbib.sed";; - mf|mp) # MF and MP are almost the same. + mf) # MF and MP are almost the same. more_defines="$srcdir/web2c/texmf.defines $srcdir/web2c/mfmp.defines" precmd="| sed -f $srcdir/web2c/cvtmf1.sed" web2c_options="-m -c${basefile}coerce" @@ -60,6 +60,22 @@ case $basefile in output_files="$basefile[0-9].c ${basefile}ini.c ${basefile}d.h \ ${basefile}coerce.h" ;; + mp) # MP now needs mp.defines for font inclusion library + more_defines="$srcdir/web2c/texmf.defines $srcdir/web2c/mfmp.defines" + prog_defines="$srcdir/${basefile}dir/$basefile.defines" + if test -f $prog_defines; then + more_defines="$more_defines $prog_defines" + fi + precmd="| sed -f $srcdir/web2c/cvtmf1.sed" + web2c_options="-m -c${basefile}coerce" + hfile=texmfmp.h + midcmd="| sed -f $srcdir/web2c/cvtmf2.sed" + postcmd="| ./web2c/splitup $splitup_options $basefile" + cfile=${basefile}2.c # last output file, or thereabouts + output= + output_files="$basefile[0-9].c ${basefile}ini.c ${basefile}d.h \ +${basefile}coerce.h" + ;; tex|eomega|etex|pdftex|pdfetex|omega|aleph|xetex) more_defines="$srcdir/web2c/texmf.defines" prog_defines="$srcdir/${basefile}dir/$basefile.defines" |