summaryrefslogtreecommitdiff
path: root/dviware/crudetype/version3/hpgf.ch
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/crudetype/version3/hpgf.ch')
-rw-r--r--dviware/crudetype/version3/hpgf.ch832
1 files changed, 832 insertions, 0 deletions
diff --git a/dviware/crudetype/version3/hpgf.ch b/dviware/crudetype/version3/hpgf.ch
new file mode 100644
index 0000000000..c1a5734d2c
--- /dev/null
+++ b/dviware/crudetype/version3/hpgf.ch
@@ -0,0 +1,832 @@
+% hpgf.ch -*-mode: change; webfile: crudetype.web version 3.01;-*-
+% HPGF.CH Provisional change file for the HP Laserjet...
+% NOTE the system change file must normally be inserted above this point.
+% SEE HPGF.DOC for users document--which must be rewritten for any new
+% system.
+% BUGFIX 19-dec-1990 Bug spoilt Landscape mode.
+%
+
+@x Module 41; Lines 822 -- 839
+When this module starts, the \.{DVI} file should be positioned at or before a
+BOP.
+
+@<For each page...@>=
+ read_BOP;
+ if (counter[0] >= first_page) then start := true ;
+ if start and (count_pages > 0 )
+ then begin
+ @<Maybe a formfeed@>
+ decr(count_pages);
+ if not quiet then display('[', counter[0]:1 ); {Progress report}
+ Read_one_page ;
+ @<Sort the page@>
+ Send_page ;
+ if not quiet then display( ']' );
+ end
+ else if ( count_pages > 0) then Skip_page
+ else time_to_stop := true;
+@y
+When this module starts, the \.{DVI} file should be positioned at or before a
+BOP.
+
+This is where the printer change file proper begins. This change file goes
+with \.{Crudetype} version 2. First, it should be explained that the HP is not
+at all a "crude" printer, and the mechanisms of \.{Crudetype} are not really
+suitable for it. It is really stretching the program a very long way from its
+intended purpose. In particular, some changes have to be spliced into the
+middle of the program, instead of going at the end as printer changes ought
+to. It seems that the only reasonable way to drive a HP is by downloading all
+the required characters. As stated in \.{Crudetype}, the problems of
+downloading are extremely difficult and I have not solved them in any
+satisfactory manner. The code given below manages downloading in the simplest
+and crudest way possible.
+
+First, I have added flags to print either even or odd pages only. In
+principle, this will allow double sided printing. Also, we do not sort the
+page as the HP can jump about.
+
+@<For each page...@>=
+ read_BOP;
+ if (counter[0] >= first_page) then start := true ;
+ if start and (count_pages > 0 ) and (
+ ( odd( counter[0]) = odds) or (( not evens) and ( not odds)) )
+ then begin
+ decr(count_pages);
+ if not quiet then display('[', counter[0]:1 ); {Progress report}
+ Read_one_page ;
+ @<Dont sort the page but |reset| it @>
+ Send_page ;
+ @<Maybe a formfeed@>
+ if not quiet then display( ']' );
+ end
+ else if ( count_pages > 0) then Skip_page
+ else time_to_stop := true;
+@z
+
+% Next, the HP has its own rule-setting commands.
+@x Module 57; Lines 1126 -- 1136
+ procedure set_rule;
+ var D_p,D_q: integer;
+ begin
+ D_p:=get_integer(dvi) (-4);
+ D_q:=get_integer(dvi)(-4);
+ if (D_p<=0)or(D_q<=0) then
+ {an invisible rule! Dont ask me why \TeX\ wants to do this}
+ else if (D_p*v_conv <= post_height/2)
+ then do_rail(D_p, D_q)
+ else do_post(D_p, D_q);
+ end;
+@y
+ procedure set_rule;
+ var D_p,D_q: integer;
+ rule_h, rule_v, rule_ht, rule_wid: integer ; {all in pixels}
+ begin
+ D_p:=get_integer(dvi) (-4);
+ D_q:=get_integer(dvi)(-4);
+ if (D_p<=0)or(D_q<=0) then
+ {an invisible rule! Dont ask me why \TeX\ wants to do this}
+ else begin @<Find the pixel sizes and reference point@>
+ @<Send it to the printer@>
+ end;
+ end;
+@z
+
+% Dont shunt on a fine printer
+@x Module 154; Lines 2678 -- 2679
+ if H_shunt > (Set_h - 3)
+ then H_shunt := (Set_h - 3) ;
+@y
+ do_nothing ;
+@z
+
+@x Module 174; Lines 2958 -- 2959
+@d out_of_sequence ==
+ ( ( Old_v > Set_v) or ( ( Old_v = Set_v) and ( Old_h > Set_h)))
+@y
+Since we do not sort, we will not separate the characters into runs.
+
+@d out_of_sequence == false
+@z
+
+% Again, shunting is only appropriate for line printers.
+@x Module 186; Lines 3157 -- 3157
+ PR_h_next := hpos - H_shunt ;
+@y
+ PR_h_next := hpos ;
+@z
+
+@x Module 207; Lines 3467 -- 3484
+@ So here are their default values. We believe they are all appropriate for
+lineprinters on VMS machines. Note that the program makes no attempt to check
+these values for consistency.
+
+@<Set init...@>=
+ device_ID := 'Lineprinter '; {Pad to 12 chars}
+ list := false ;
+ fortran := false ;
+ b_feed_absolute := false ;
+ b_feed_by_string := false ;
+ feed_absolute := false ;
+ b_feed_scream := true ;
+ b_space_absolute := false ;
+ b_space_by_string := false ;
+ space_absolute := false ;
+ abs_is_incr := false ;
+ wl_does_cr := false ;
+ want_split := true ;
+@y
+@ The first lot of data describes the HP's overall style of carriage
+control. Many of them are completely irrelevant to the HP, but still needed in
+order for the program to compile.
+
+@<Set init...@>=
+ device_ID := 'Laserjet + ';
+ list := false ;
+ fortran := false ;
+ b_feed_absolute := true ;
+ b_feed_by_string := false ;
+ feed_absolute := true ;
+ b_feed_scream := true ;
+ b_space_absolute := true ;
+ b_space_by_string :=false ;
+ space_absolute := true ;
+ abs_is_incr := false ;
+ wl_does_cr := false ;
+ want_split := true ;
+ is_header := false ; {each page needs a header}
+@z
+
+@x Module 208; Lines 3518 -- 3527
+@ The general run of \TeX\ characters are narrower than line-printer chars. So
+we spread them out to make them fit.
+
+@<Set init...@>=
+ l_margin := 1.0 ; {Normal left margin, in inches}
+ top_margin := 1.0 ; {Top ditto}
+ h_fudge := 7.227 {number of points per |h_step|}
+ / 5.25 ; {A typical design width}
+ v_fudge := 2.0 ;
+ { Force double-spacing, in hope that suffixes will come out right}
+@y
+@ The general run of \TeX\ characters are narrower than line-printer chars.
+But the HP prints them at their proper widths.
+
+@<Set init...@>=
+ l_margin := 1.0 ; {Normal left margin, in inches}
+ top_margin := 1.0 ; {Top ditto}
+ h_fudge := 1.0 ;
+ v_fudge := 1.0 ;
+@z
+
+@x Module 213; Lines 3584 -- 3594
+@ This batch is concerned with distances and resolutions.
+
+@<Const...@>=
+ h_resolution = 10 ; {|h_steps| per inch}
+ v_resolution = 6 ; {|v_steps| per inch}
+ fixed_width = true ; {printers characters are fixed width}
+ char_width = 1 ;
+ {all printer characters are this width, in units of |h_step|. Normally,
+ |space_dist| will be equal to this, but some printers are not normal!}
+ gap_width = 1 ; {Intended minimum space between words}
+ char_ht = 1 ;
+@y
+@ This batch is concerned with distances and resolutions.
+
+@<Const...@>=
+ h_resolution = 300 ; {|h_steps| per inch}
+ v_resolution = 300 ; {|v_steps| per inch}
+ fixed_width = false ;
+ char_width = 30 ; {default char. sizes in |h_steps| -- a guess}
+ gap_width = 5 ; {Intended minimum space between words}
+ char_ht = 42 ;
+@z
+
+@x Module 216; Lines 3616 -- 3620
+ max_font = 1 ;
+ only_one_font = true ;
+ can_dl_font = false ;
+ min_dl_font = 0 ;
+ max_dl_font = 0 ; {printers down-loadable fonts}
+@y
+ max_font = 40 ;
+ only_one_font = false ;
+ can_dl_font = true ;
+ min_dl_font = 8 ;
+ max_dl_font = 40 ; {printers down-loadable fonts. The HP allows up to 32}
+@z
+
+@x Module 234; Lines 4022 -- 4024
+@<Assign char...@>=
+ @<Define Lineprinter codes@>
+ @<Set rule characters@>
+@y
+ @<Assign char...@>= do_nothing
+@z
+
+@x Module 235; Lines 4028 -- 4028
+*** Attach printer change file here ***
+@y
+
+@ The remaining changes can all go at the end of the program. Before getting
+onto the hardest task (namely, downloading) lets clear up the loose ends that
+were left lying about in the body of the program. First, there are a number of
+extra command options:
+
+@<If the |key|...@>=
+ else if ( key = "O") then odds := true {Print odd-numbered pages only}
+ else if ( key = "E") then evens := true {Even ditto}
+ else if ( key = "L") then begin
+ land := true ; {Print Landscape}
+ start_stuff.data[ 8] := '1' ; {bugfix, 19-dec-1990, previously 6}
+ end
+
+@ @<Glob...@>=
+ land, odds, evens: boolean ;
+
+@ @<Set init...@>=
+ land := false ;
+ odds := false ;
+ evens := false ;
+
+@ Where will the printed file go to?
+
+@<Set init...@>=
+ be_string( '.HPL') ; print_ex := buffer ;
+
+@ @<Dont sort the page but |reset| it @>=
+ L_reset( run) ;
+ Add_run ;
+ L_reset( mid) ;
+ cur_pge_ptr := son( next( mid) ) ;
+
+@ Now lets dispose of rule-setting. \TeX\ puts the reference point of a rule
+at bottom left, the HP at top left. Sizes must be rounded up.
+
+@<Find the pixel sizes and reference point@>=
+ rule_ht := round(v_conv*D_p + 0.5) ;
+ rule_wid := round(h_conv*D_q + 0.5) ;
+ D_dis := D_q ;
+ IM_dis := rule_wid ;
+ round_IM_h ( 0);
+ rule_h := IM_h ;
+ rule_v := IM_v - rule_ht ;
+
+@ @<Send it to the printer@>=
+ set_v_abs(rule_v) ;
+ set_h_abs(rule_h) ;
+ print(chr(27), '*c', rule_ht:1, 'B') ;
+ print(chr(27), '*c', rule_wid:1, 'A') ;
+ print(chr(27), '*c0P') ;
+ print_ln;
+
+@ Consider command strings.
+
+@<Set init...@>=
+ be_string ( '^[E^[&l0O' ) ; start_stuff := buffer ;
+ {Reset everything to default state}
+ be_string ( '^[(&DX' ) ; font_command := buffer ;
+ be_string ( '^[*p&DY' ) ; v_abs_com := buffer ;
+ be_string ( '^[*p&DX ' ) ; h_abs_com := buffer ;
+ stop_stuff := start_stuff ;
+ page_top := blank ;
+ pause_after := blank ;
+
+@ On the HP, we must explicitly start a new page at a set position. Also since
+rules get set before any characters, we must then reset the position.
+
+@<Set up an empty page...@>=
+ set_v_abs(0) ;
+ set_h_abs(0) ;
+
+@ @<Pause reset@>=
+ set_v_abs(0) ;
+ set_h_abs(0) ;
+
+@* Downloading, 1: reading the font file.
+
+The simplest and crudest way this could possibly be done is: read the raster
+file and load the entire font, as soon as the |font_def| command is read from
+the \.{DVI} file. On VAX/VMS, this turned out to be unbearably slow. So it is
+here changed as follows: When a |font_def| command is read, we read the whole
+raster file into an array. Then download each character before trying to print
+it. This `lazy downloading' makes the program run much faster, at the price of
+a large use of memory.
+ @^\.{TUG}boat@>
+
+@<Download a whole font@>=
+ begin
+ @<Prepare to read the |raster_file|@>
+ repeat
+ @<Get \.{GF} command |GF_com|, and do it@>
+ until GF_com = 248;
+ close_binary( raster_file) ;
+ @<Establish the new font in memory@>
+ end
+
+@ First we have to determine the file name.
+
+@<Prepare to read...@>=
+ raster_mag := round(300 * font_mag * magnification ) ;
+ if not hunt_for_size( font_name, raster_mag)
+ then font_error('cannot load this font') ;
+ @.Error: cannot load@>
+
+@ @<Medium...@>=
+ function open_font(
+ name: var_string; mag: integer; ask: boolean ): boolean;
+ begin
+ splice( raster_name, raster_def, mag) ;
+ open_font := open_and_ask(
+ raster_file, raster_indx, name, raster_name, ask) ;
+ end;
+
+@ Frequently the {\.DVI} file calls for a font at a magnification that is
+almost but not quite one of the standard sizes. So we try a few steps up or
+down before giving up. |range| is the maximum percentage that we allow the
+magnification to vary.
+
+@<Forw...@>=
+ function hunt_for_size (
+ name: var_string; mag: integer): boolean; forward ;
+
+@ @<Medium...@>= function hunt_for_size ;
+ label exit ;
+ const range = 5 ;
+ var try_mag, n , max : integer; hh: boolean;
+ begin
+ max := round( raster_mag* range / 100);
+ n := 0 ;
+ while ( n <= max) do begin
+ try_mag := mag + n ;
+ hh := open_font( name, try_mag, false) ;
+ if hh then return
+ else if ( n>0) then n:= -n
+ else n := 1 - n ;
+ end;
+ hh := open_font( name, mag, true) ;
+ exit: hunt_for_size := hh;
+ end;
+
+@ Then read the file; a horrible mess.
+
+@<Get \.{GF} command...@>=
+ GF_com := get_byte( raster) ;
+ if GF_com <= 63 then paint( GF_com)
+ else if ( GF_com >= 74) and ( GF_com <= 238) then
+ new_row( GF_com - 74 )
+ else
+
+@ Then we have the usual messy |case| statement:
+
+@d three_cases(#)==
+ #,#+1,#+2 : begin GF_par := get_integer( raster)( GF_com - # + 1 );
+ four_case_end
+
+@<Get \.{GF} command...@>=
+ case GF_com of
+ three_cases( 64)( paint( GF_par));
+ 67, 68: boc;
+ 69: eoc;
+ 70: miss_row( 0);
+ three_cases( 71)( miss_row( GF_par));
+ three_cases( 239)( skip( raster)( GF_par));
+ 242: skip( raster)( get_integer( raster)( -4)) ;
+ 243: skip( raster)( 4);
+ 244:;
+ 247: preamble;
+ 248: postamble ;
+ 245,246,249,250,251,252,253,254,255:
+ warn( 'illegal GF command, will try to continue');
+ end;
+ @.illegal GF command@>
+
+@ Now there follow lots of procedures to deal with the commands.
+
+@<Lowest...@>=
+ procedure preamble;
+ var p: byte;
+ begin
+ p:=get_byte( raster);
+ p:=get_byte( raster);
+ skip( raster)( p) ; {the introductory comment}
+ with Font_box do begin
+ L := pixel_R ;
+ R := pixel_L ;
+ T := pixel_B ;
+ B := pixel_T ;
+ end;
+ end;
+
+@#
+ procedure postamble;
+ var GF_check: integer ;
+ begin
+ skip( raster)( 8);
+ GF_check := get_integer( raster)( -4) ;
+ if (D_check<>0)and(GF_check<>0)and(D_check<>GF_check) then
+ begin warn('check sums do not agree!');
+ @.error: check sums...@>
+ display_ln('DVI check was: ', D_check, ' GF check was: ', GF_check);
+ display(' ');
+ end;
+ end;
+
+@#
+ procedure boc;
+ var q : byte; mm, nn: i_word;
+ begin
+ if GF_com = 67 then
+ begin GF_char := get_integer( raster)( 4) mod 256 ;
+ skip( raster) ( 4);
+ Boc_box.L:=get_integer( raster)( -4);
+ Boc_box.R:=get_integer( raster)( -4);
+ Boc_box.B:=get_integer( raster)( -4);
+ Boc_box.T:=get_integer( raster)( -4);
+ end
+ else begin GF_char:=get_byte( raster);
+ q:=get_byte( raster); Boc_box.R:=get_byte( raster);
+ Boc_box.L:=Boc_box.R-q;
+ q:=get_byte( raster); Boc_box.T:=get_byte( raster);
+ Boc_box.B:=Boc_box.T-q;
+ end;
+ @<Clear the image@>
+ end;
+
+@ Now lets assign names to variables. In order to try to clear up the muddle
+of boundaries for character cells, I introduce a concept of a ``box'', not the
+same as a \TeX\ box. The fields represent the boundaries that must contain all
+the black pixels of any character.
+
+@<Const...@>=
+ pixel_L = -300; pixel_R = 700; pixel_B = -300; pixel_T = 700;
+
+@ @<Types...@>=
+ @!x_coord=pixel_L..pixel_R;
+ @!y_coord=pixel_B..pixel_T;
+ box = packed record
+ L,R: x_coord;
+ T,B: y_coord;
+ end;
+ dir_entry = packed record
+ point: integer;
+ h_offset, v_offset, wid, ht : i_word;
+ end;
+
+@ @<Glob...@>=
+ Boc_box, {Limits of char. cell declared in |BOC| command}
+ char_box, {actual boundaries of char. cell}
+ Font_box: box; {The font cell. This is the smallest cell that
+ contains the reference point and any char. cell in the font}
+ GF_com, GF_par, GF_char : byte;
+ glyphs: packed array[1..max_glyph] of byte ;
+ glyph_ptr: integer;
+ raster_mag: integer;
+ directory : array[D_font_ptr, D_char_ptr ] of dir_entry ;
+ C_width : integer;
+
+@ @<Set init...@>=
+ glyph_ptr := 1 ;
+ for in_i := 0 to max_D_fonts do
+ for in_j := 0 to max_D_char do
+ directory[ in_i, in_j].point := sentry ;
+ {Mark everything as unprintable}
+
+@ The definition of \.{GF} files refers to two registers, $(G_m,G_n)$, which
+hold row and column numbers. We also need to remember |paint_switch|, which
+is either |black| or |white|.
+
+@<Glob...@>=
+ @!pixels: packed array [y_coord,x_coord] of pixel;
+ @!G_m: x_coord;
+ @!G_n: y_coord; {current state values}
+ @!paint_switch: pixel;
+
+@ We'll need a big array of pixels to hold the character image. Each pixel
+should be represented as a single bit in order to save space. Different
+systems may prefer the following definitions, while others may do better using
+the |boolean| type and constants.
+ @^system dependencies@>
+
+@d white==false
+@d black==true
+@d swop == paint_switch:=not paint_switch
+{could also be |if paint_switch=black then paint_switch:=white
+else paint_switch:=black|}
+
+@<Types...@>=
+@!pixel=boolean ;
+ {could also be |white..black|}
+
+@ Maybe there's a faster way to do this on your system. Note that the only
+part of the |image_array| that we clear is the part that the current character
+may use. Thus, the rest of this program may not look outside the area
+delimited by |Boc_box| and expect to see anything but junk.
+@^system dependencies@>
+
+@<Clear the image@>=
+ begin
+ for nn := Boc_box.B to Boc_box.T do
+ for mm := Boc_box.L to Boc_box.R do
+ pixels[nn,mm] := white;
+ G_n := Boc_box.T ;
+ G_m := Boc_box.L ;
+ char_box.L := pixel_R ;
+ char_box.R := pixel_L ;
+ char_box.B := pixel_T ;
+ char_box.T := pixel_B ;
+ directory[ nf, GF_char].point := 0 ;
+ {Indicates a blank character}
+ end
+
+@ @<Lowest...@>=
+ procedure paint( p: integer);
+ var m, k: integer;
+ begin
+ if G_m+p> pixel_R then
+ warn('character extends too far to the right')
+ @.character extends...@>
+ else if paint_switch = white then
+ else begin
+ m := G_m + p -1 ;
+ if char_box.T < G_n then char_box.T := G_n ;
+ if char_box.B > G_n then char_box.B := G_n ;
+ if char_box.L > G_m then char_box.L := G_m ;
+ for k:= G_m to m do
+ pixels[G_n, k] := black ;
+ if char_box.R < m then char_box.R := m ;
+ end;
+ swop;
+ G_m := G_m +p ;
+ end;
+
+@#
+procedure new_row( p:integer);
+ begin
+ decr(G_n);
+ G_m:=Boc_box.L + p;
+ paint_switch:=black;
+ end;
+
+@# procedure miss_row( p: integer);
+ begin
+ G_n:=G_n - p ;
+ G_m:= Boc_box.L;
+ paint_switch:=white;
+ end;
+
+@* Downloading, 2: Transfer characters into memory.
+
+After we have read the character, we must transfer it into memory. First,
+stretch the Font box to include the current characters box.
+
+@<Lowest...@>=
+ procedure eoc;
+ var x, y : integer;
+ cur_byt: byte ;
+ q: i_word ;
+ begin
+ if char_box.R >= char_box.L {If not, the character is unprintable}
+ then begin
+ if char_box.L < Font_box.L then Font_box.L := char_box.L ;
+ if char_box.B < Font_box.B then Font_box.B := char_box.B ;
+ if char_box.R > Font_box.R then Font_box.R := char_box.R ;
+ if char_box.T > Font_box.T then Font_box.T := char_box.T ;
+ @<Transfer the dimensions of the character@>
+ @<Transfer the |pixels| into |glyphs|@>
+ end;
+ end;
+
+@ In landscape mode, the character must be rotated. The |directory| will
+contain the dimensions to be downloaded; these do depend on orientation.
+|char_box| describes the logical character which does not depend on
+orientation.
+
+@<Transfer the dimensions...@>=
+ with directory[nf, GF_char] do begin
+ point := glyph_ptr;
+ if land then begin
+ h_offset := - char_box.T ;
+ v_offset := char_box.R ;
+ ht := char_box.R - char_box.L +1 ;
+ wid := char_box.T - char_box.B +1 ;
+ end else begin
+ h_offset := char_box.L ;
+ {\TeX\ and the HP measure this in opposite directions}
+ v_offset := char_box.T ;
+ wid := char_box.R - char_box.L +1 ;
+ ht := char_box.T - char_box.B +1 ;
+ end;
+ end;
+
+@ Likewise the |glyphs| array will contain the pixels to be downloaded; these
+also depend on orientation. Looking at the logical character, |x| is the
+horizontal coordinate and |y| the vertical. In portrait mode the pixels must
+be sent starting at the top left corner and going left to right along the top
+row. In Landscape mode you must start at the top right corner and go down the
+right hand column. Each row or column must be padded to |8n| bits.
+
+@<Transfer the |pixels|...@>=
+ if land then begin
+ for x := char_box.R downto char_box.L do begin
+ cur_byt := 0 ;
+ q := 0 ;
+ for y := char_box.T downto char_box.B do begin
+ if pixels[ y, x] then cur_byt := cur_byt + powers[q] ;
+ if q < 7 then incr( q)
+ else begin
+ glyphs[glyph_ptr] := cur_byt ; incr( glyph_ptr) ; cur_byt := 0;
+ q := 0 ;
+ end;
+ end;
+ if q > 0 then
+ begin
+ glyphs[glyph_ptr] := cur_byt ; incr( glyph_ptr) ; cur_byt := 0;
+ end;
+ end;
+ end else
+
+@ @<Transfer the |pixels|...@>=
+ begin
+ for y := char_box.T downto char_box.B do begin
+ cur_byt := 0 ;
+ q := 0 ;
+ for x := char_box.L to char_box.R do begin
+ if pixels[ y, x] then cur_byt := cur_byt + powers[q] ;
+ if q < 7 then incr( q)
+ else begin
+ glyphs[glyph_ptr] := cur_byt ; incr( glyph_ptr) ; cur_byt := 0;
+ q := 0 ;
+ end;
+ end;
+ if q > 0 then
+ begin
+ glyphs[glyph_ptr] := cur_byt ; incr( glyph_ptr) ; cur_byt := 0;
+ end;
+ end;
+ end ;
+
+@ @<Set init...@>=
+ powers[0] := 128 ;
+ for in_i := 1 to 7 do powers[in_i] := powers[in_i-1] div 2 ;
+
+@ @<Glob...@>= powers: array[0..7] of byte ;
+
+@ @<Const...@>= max_glyph = 1000000 ;
+
+@ @<Clean...@>=
+ display_ln
+ ('Used ', glyph_ptr:1, ' bytes of font memory out of ', max_glyph:1);
+
+@ Finally, does the printer have enough room for the font? The HP allows 32
+fonts per job and 395 KB memory. I have not checked the restriction of only 16
+fonts per page.
+
+@<Establish...@>=
+ incr(PR_dl_font ) ;
+ if PR_dl_font > max_dl_font then
+ font_error('tried to load too many fonts') ;
+ @.Error: tried to load@>
+
+@ @<Set init...@>=
+ PR_dl_font := min_dl_font ;
+ PR_mem_used := 0 ;
+ PR_max_mem := 395000;
+ be_string( '^[*c&DD' ) ; font_start := buffer ;
+
+@ @<Glob...@>= PR_dl_font, PR_max_mem, PR_mem_used: integer ;
+ font_start: var_string ;
+
+@ If the error tests succeed, then we come here. Before we can load any
+characters, we have to send a command to the printer to declare the new font.
+This section assembles the necessary information. |dir_start[ nf]| should be
+pointing to the start of the font directory. The main task is that the printer
+must be given the size of a character cell; this must be large enough to
+contain all the characters. First we specify the font ID. This is a number by
+which the printer will refer to the font after loading it.
+
+@<Establish...@>=
+ print_command( font_start, PR_dl_font, '^') ;
+ print(chr(27), ')s26W' );
+ {A create font command}
+ prw(26);
+ prw(1) ; { 8 bit chars}
+ prw(0) ;
+ with Font_box do begin
+ if L > 0 then L := 0 ;
+ if B > 0 then B := 0 ;
+ if R < 0 then R := 0 ;
+ if T < 0 then T := 0 ; {Stretch the Font box to include the ref. point}
+ prw( T) ;
+ prw( R - L + 1) ; {width}
+ prw( T - B + 1) ; {height}
+ end;
+ if land then prw( 257) else prw(1) ; {proportional spaced}
+ prw(277) ;
+ for font_i := 1 to 5 do prw(0) ;
+ {The HP needs these parameters, but they serve no purpose known to me}
+
+@ Finally, we must establish the map from \TeX\ characters to printers
+characters in the new font.
+
+@<Establish...@>=
+ incr(top_code) ; {get a new coding scheme}
+ scheme[ nf] := top_code ;
+ alphabet(0, 33, top_code, PR_dl_font, 190);
+ alphabet(33, 95, top_code, PR_dl_font, 33);
+ for tex_chr := 0 to max_D_char do
+ codes[ top_code, tex_chr].breadth := down_loaded ;
+
+@ @<Glob...@>= top_code: integer ;
+
+@ @<|font_def| vars@>= tex_chr, font_i: integer;
+
+@ @<Set init...@>= top_code := 1 ;
+
+@* Downloading, 3: Lazy downloading.
+
+The idea is to load only those characters in each font that actually will be
+printed. It is obviously essential to ensure that each character gets loaded
+before being printed, and only once. This is done in the procedure
+|set_character|. The \TeX\ character is number |c_num| in font |D_font|,
+but the printer character is addressed by |cod|.
+
+The first job is to update the directory info. for the character, and assemble
+its size parameters.
+
+@<Enter a download...@>=
+ with directory [ D_font, c_num] do begin
+ if point < 0 then begin warn(
+ 'tried to print a non-existent character, number: ' , c_num:1) ;
+ codes[ cur_scheme, c_num].breadth := bad_char ;
+ end else begin
+ C_length := ht * (( wid + 7) div 8) ; {length of data}
+ C_width := D_width[ D_font, c_num] ;
+ C_delta := round(C_width * h_conv) ;
+ codes[ cur_scheme, c_num].breadth := C_delta ;
+ cod.breadth := C_delta ;
+ PR_mem_used := PR_mem_used + C_length + 64 ; {approximate}
+ if PR_mem_used > PR_max_mem then
+ warn('overflowed printer memory, will try to proceed regardless') ;
+ @.Error: overflowed printer memory@>
+ @.Error: tried to print...@>
+
+@ @<Clean...@>=
+ display_ln
+ ('Used ', PR_mem_used:1, ' bytes of printers memory out of ',
+ PR_max_mem:1) ;
+
+@ @<Glob...@>=
+ C_length, C_delta : integer;
+ char_start, char_head: var_string ;
+
+@ @<Set init...@>=
+ be_string( '^[*c&DE' ) ; char_start := buffer ;
+ be_string( '^[(s&DW' ) ; char_head := buffer ;
+
+@ Now we must not let the character get downloaded twice, so we put the
+correct value into its |breadth|; we must also update the current |cod|.
+
+@ Now we send the character header. First, tell the printer which character
+will be downloaded. \TeX\ fonts usually have 128 characters and HP fonts have
+either 96 or 192. The permitted values for HP characters are 33..127 and
+160..255 according to the manual but appendix B says 160 and some others are
+undefined. So we map \TeX\ characters 0..32 onto 190..222 .
+
+@<Enter a download...@>=
+ { N.B. still |with directory [ D_font, c_num]| }
+ print_command( font_start, cod.IM_font, '^') ;
+ {Specify printers font identifier}
+ print_command( char_start, cod.IM_char, '^') ;
+ print_command( char_head, (C_length + 16), '^') ;
+ {and the character}
+ prw(1024);
+ prw(14*256 + 1);
+ if land then prw( 256 ) else prw(0);
+ prw(h_offset) ;
+ prw(v_offset);
+ prw(wid) ;
+ prw(ht) ;
+ prw(4 * C_delta) ;
+
+@ And at long last we can send the pixels!!
+
+@<Enter a download...@>=
+ for d_i := point to point+C_length-1 do
+ print(chr(glyphs[ d_i] )) ;
+ print_ln ;
+end; end;
+
+@ Nearly all the HP's arguments come as signed 16-bit words, to be printed in
+two-complement notation. This procedure prints them.
+
+@<Low...@>=
+ procedure prw( n: i_word);
+ var nn: integer ;
+ begin
+ if (n>= 0) then nn := n
+ else nn := n + 65536 ;
+ print( zchr(nn div 256));
+ print( zchr(nn mod 256));
+ end ;
+@z