sources-request@mirror.UUCP (06/22/86)
Submitted by: Tor Lillqvist <talcott!seismo!mcvax!santra!tml> Mod.sources: Volume 6, Issue 14 Archive-name: texdvi2lj/Part2 [ I have split this submission into three pieces named LJ.1.3, LJ.2.3, and LJ.2.3. Unpack each piece and do "cat LJ.[123].3 >dvi2lj.web" This is not great, but is the best way I could think of to distribute a large single-file source; if you have a better way, please let me know. * * * * * * OOPS! This article went out earlier with a wrong subject line. I sent out a cancel, but in case it didn't get out, here's the "official" posting. * * * * * * --r$] Here is a DVI (TeX output) driver for the HP LaserJet+. This version is for the Pascal/1000 compiler on HP1000 machines running RTE-A (and my TeX implementation), but it should be fairly easy to convert to other TeX implementations, compilers and operating systems. DVIplus is based on the DVItype program. It downloads only those characters actually used. Pages are printed in reverse. # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # Contents: LJ.2.3 echo x - LJ.2.3 sed 's/^XX//' > "LJ.2.3" <<'@//E*O*F LJ.2.3//' XX@* Reading the font information. XXThe current number of known fonts is |nf|. Each known font has XXan internal number |f|, where |0<=f<nf|; the external number of this font, XXi.e., its font identification number in the \.{DVI} file, is XX|font_num[f]|, and the external name of this font is the string that XXoccupies positions |font_name[f]| through |font_name[f+1]-1| of the array XX|names|. The latter array consists of |ASCII_code| characters, and XX|font_name[nf]| is its first unoccupied position. A horizontal motion XXin the range |-4*font_space[f]<h<font_space[f]| XXwill be treated as a `kern'. XXA given character |c| is valid in font |f| if and only if XX|char_width(f)(c)<>invalid_width|. XXFinally, |char_width(f)(c)=width[width_base[f]+c]|, and |width_ptr| is the XXfirst unused position of the |width| array. XX XX@d char_width(#)==width[width_base[#]+char_end_width XX@d invalid_width==@'17777777777 XX XX@<Glob...@>= XX@!font_num:array [0..max_fonts] of integer; {external font numbers} XX@!font_name:array [0..max_fonts] of 0..name_size; {starting positions XX of external font names} XX@!names:array [0..name_size] of ASCII_code; {characters of names} XX@!font_check_sum:array [0..max_fonts] of integer; {check sums} XX@!font_scaled_size:array [0..max_fonts] of integer; {scale factors} XX@!font_design_size:array [0..max_fonts] of integer; {design sizes} XX@!font_mag:array [0..max_fonts] of integer; XX@!font_space:array [0..max_fonts] of integer; {boundary between ``small'' XX and ``large'' spaces} XX@!font_used_on:array[0..max_fonts] of integer; {on which page last used} XX@!width_base:array [0..max_fonts] of integer; {index into |width| table} XX@=$Ema_Var On$@> XX@!width:array [0..max_widths] of integer; {character widths, in \.{DVI} units} XX@=$Ema_Var Off$@> XX@!nf:0..max_fonts; {the number of known fonts} XX@!width_ptr:0..max_widths; {the number of known character widths} XX XX@ @<Set init...@>= XXnf:=0; width_ptr:=0; font_name[0]:=0; font_space[0]:=0; XXfont_used_on[0]:=0; XX XX@ It is, of course, a simple matter to print the name of a given font. XX XX@p procedure print_font(@!f:integer); {|f| is an internal font number} XXvar k:0..name_size; {index into |names|} XXbegin if f=nf then print('UNDEFINED!') XX@.UNDEFINED@> XXelse begin for k:=font_name[f] to font_name[f+1]-1 do XX print(xchr[names[k]]); XX end; XXend; XX XX@ The global variabls |pxl_check_sum|, XX|pxl_design_size| are set from the \.{PXL} file. XX XX@<Glob...@>= XX@!pxl_check_sum:integer; {check sum found in |pxl_file|} XX@!pxl_dptr:array [0..max_fonts] of integer; {directory pointers} XX@!pxl_design_size:integer; XX XX@ Here is a procedure that absorbs the necessary information from a XX\.{PXL} file, assuming that the file has just been successfully opened. XX(A complete description of XX\.{PXL} file format appears elsewhere and will XXnot be repeated here.) The procedure does not check the \.{PXL} file XXfor validity, nor does it give explicit information about what is XXwrong with a \.{PXL} file that proves to be invalid; \.{DVI}-reading XXprograms need not do this, since \.{PXL} files are almost always valid. XXThe procedure simply returns |false| if it XXdetects anything amiss in the \.{PXL} data. XX XXThere is a parameter, |z|, which represents the scaling factor being XXused to compute the font dimensions; it must be in the range $0<z<2^{27}$. XX XX@d read_pxl(#)==begin #:=pxl_file[nf]^.i; get(pxl_file[nf]); end XX XX@p procedure in_PXL(@!z:integer); {input \.{PXL} data} XXvar i,j,k,n:short; {indices etc.} XX@!wp:0..max_widths; {new value of |width_ptr| after successful input} XX@!raster_address:integer; XX@!alpha,@!beta:integer; {quantities used in the scaling computation} XXbegin XX if width_ptr+128>max_widths then begin XX print_nl; XX abort('Need larger width table'); XX end; XX width_base[nf]:=width_ptr; XX wp:=width_ptr; XX @<Check the header ID@>; XX @<Read the trailer@>; XX @<Read the font directory@>; XX width_ptr:=wp; XXend; XX XX@ @<Check the header ID@>= XXbegin XX seek_pxl(nf)(0); XX get(pxl_file[nf]); XX if pxl_file[nf]^.i <> pxl_id then XX bad_pxl('bad header id'); XXend XX XX@ @<Read the trailer@>= XXbegin XX seek(pxl_file[nf],s_pxl_file+1); XX get(pxl_file[nf]); XX if pxl_file[nf]^.i <> pxl_id then XX bad_pxl('bad trailer id'); XX seek(pxl_file[nf],s_pxl_file-3); XX get(pxl_file[nf]); XX read_pxl(pxl_check_sum); XX read_pxl(font_mag[nf]); XX read_pxl(pxl_design_size); XX read_pxl(pxl_dptr[nf]); XXend; XX XX@ One important part of |in_PXL| is the width computation, which XXinvolves multiplying the relative widths in the \.{PXL} file by the XXscaling factor in the \.{DVI} file. This fixed-point multiplication XXmust be done with precisely the same accuracy by all \.{DVI}-reading programs, XXin order to validate the assumptions made by \.{DVI}-writing programs XXlike \TeX82. XX XXLet us therefore summarize what needs to be done. Each width in a \.{PXL} XXfile appears as a four-byte quantity called a |fix_word|. A |fix_word| XXwhose respective bytes are $(a,b,c,d)$ represents the number XX$$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr XXb\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr XX-16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$ XX(No other choices of $a$ are allowed, since the magnitude of a \.{TFM} XXdimension must be less than 16.) We want to multiply this quantity by the XXinteger~|z|, which is known to be less than $2^{27}$. Let $\alpha=16z$. XXIf $|z|<2^{23}$, the individual multiplications $b\cdot z$, $c\cdot z$, XX$d\cdot z$ cannot overflow; otherwise we will divide |z| by 2, 4, 8, or XX16, to obtain a multiplier less than $2^{23}$, and we can compensate for XXthis later. If |z| has thereby been replaced by $|z|^\prime=|z|/2^e$, let XX$\beta=2^{4-e}$; we shall compute XX$$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$ if $a=0$, XXor the same quantity minus $\alpha$ if $a=255$. This calculation must be XXdone exactly, for the reasons stated above; the following program does the XXjob in a system-independent way, assuming that arithmetic is exact on XXnumbers less than $2^{31}$ in magnitude. XX XXThe following code computes pixel widths by simply rounding the \.{PXL} XXwidths to the nearest integer number of pixels, based on the conversion factor XX|conv| that converts \.{DVI} units to pixels. However, such a simple XXformula will not be valid for all fonts, and it will often give results that XXare off by $\pm1$ when a low-resolution font has been carefully XXhand-fitted. For example, a font designer often wants to make the letter `m' XXa pixel wider or narrower in order to make the font appear more consistent. XX\.{DVI}-to-printer programs should therefore input the correct pixel width XXinformation from font files whenever there is a chance that it may differ. XXA warning message may also be desirable in the case that at least one character XXis found whose pixel width differs from |conv*width| by more than a full pixel. XX XXThose characters that are too large to be downloadable, are marked as such, XXand will be transferred using raster graphics. We must be especially careful XXin the y dimension, as the character must fit into the 255*255 box when XXthe reference point is placed on the baseline. The baseline was set to XX$255-$|baseline| pixel rows down from the top. XX@^system dependencies@> XX XX@d pixel_round(#)==round(conv*(#)) XX XX@<Read the font dir...@>= XX@<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>; XXfor k:=0 to 127 do begin XX seek(pxl_file[nf],pxl_dptr[nf]+k*4+2); XX get(pxl_file[nf]); XX {is the charater too large ?} XX if (pxl_file[nf]^.i0 >= 128) or (pxl_file[nf]^.i1 >= 128) then XX status[wp]:=too_large XX else XX status[wp]:=not_loaded; XX get(pxl_file[nf]); XX get(pxl_file[nf]); XX if pxl_file[nf]^.i=0 then begin XX width[wp]:=invalid_width; XX pixel_width[wp]:=0 end XX else begin XX get(pxl_file[nf]); XX read_pxl_word(nf); XX width[wp]:=(((((b3*z)div@'400)+(b2*z))div@'400)+(b1*z))div beta; XX if b0>0 then if b0<255 then bad_pxl('strange width for char ', k:1) XX else width[wp]:=width[wp]-alpha; XX pixel_width[wp]:=pixel_round(width[wp]); XX end; XX incr(wp); XXend XX XX@ @<Replace |z|...@>= XXbegin alpha:=16*z; beta:=16; XXwhile z>=@'40000000 do XX begin z:=z div 2; beta:=beta div 2; XX end; XXend XX XX@* Downloading information to the printer. XXThe procedure |update_pos| is used to update the printer cursor position. XXThis is the only place where the cursor is explicitely positioned. XX XX@p procedure update_pos; XXlabel done; XXbegin if (lj_h<>hh)or(lj_v<>vv) then begin XX write_lj(@=#27'*p'@>); XX if (lj_h<>hh) then begin XX if abs(lj_h-hh) > hh div 10 then XX write_lj_f(hh:1) XX else if (lj_h<hh) then XX write_lj_f('+', hh-lj_h:1) XX else XX write_lj_f('-', lj_h-hh:1); XX if (lj_v<>vv) then XX write_lj_f('x') XX else begin XX write_lj_f('X'); XX goto done; XX end XX end; XX if abs(lj_v-vv) > vv div 10 then XX write_lj_f(vv:1) XX else if (lj_v<vv) then XX write_lj_f('+', vv-lj_v:1) XX else XX write_lj_f('-', lj_v-vv:1); XX write_lj_f('Y'); XXend; XXdone: XXlj_h:=hh; lj_v:=vv; XXend; XX XX@ This procedure downloads a single character from a \.{PXL} file. XX@^system dependencies@> XX XX@p procedure download_char(p:integer); XXvar i,j:short; XX@!pixel_wd,@!pixel_ht:integer; XX@!offsets,char_wd,char_ht,delta_x:i2c; XX@!raster_address:integer; XX XXbegin XX seek(pxl_file[cur_font],pxl_dptr[cur_font]+p*4+2); XX get(pxl_file[cur_font]); XX pixel_wd:=pxl_file[cur_font]^.i0; XX pixel_ht:=pxl_file[cur_font]^.i1; XX get(pxl_file[cur_font]); XX offsets:=pxl_file[cur_font]^; XX get(pxl_file[cur_font]); XX raster_address:=pxl_file[cur_font]^.i; XX @<Download character header@>; XX seek(pxl_file[cur_font],raster_address+2); XX for j:=1 to pixel_ht do begin XX for i:=1 to (pixel_wd-1) div 8 + 1 do begin XX if (i-1) mod 4 = 0 then XX get(pxl_file[cur_font]); XX write_lj(pxl_file[cur_font]^.c[(i-1) mod 4]); XX end; XX end XXend; XX XX@ Download a character header. XX XX@d data_bytes==(pixel_ht*(((pixel_wd-1) div 8)+1)) XX XX@<Download character header@>= XXbegin XX if pixel_ht - offsets.i1 > baseline then begin XX char_status(cur_font)(p):=pixel_ht-offsets.i1; XX offsets.i1:=pixel_ht; end XX else XX char_status(cur_font)(p):=loaded_ok; XX offsets.i0:=-offsets.i0; XX char_wd.i0:=pixel_wd; XX char_ht.i0:=pixel_ht; XX delta_x.i0:=char_pixel_width(cur_font)(p)*4; XX write_lj(@=#27'*c'@>,font_num[cur_font]:1,'d', XX ord(vis_chr(p)):1,@='E'#27'(s'@>, XX data_bytes+16:1,'W'+ XX @=#4#0#14#1#0#0@>, XX offsets.c[0], offsets.c[1], XX offsets.c[2], offsets.c[3], XX char_wd.c[0], char_wd.c[1], XX char_ht.c[0], char_ht.c[1], XX delta_x.c[0], delta_x.c[1]); XXend XX XX@ This procedure transfers a character in raster form. XXThis is used for characters which are too large to be stored in XXthe font memory of the printer. XX@^system dependencies@> XX XX@p procedure raster_char(p:integer); XXvar XXi,j,n:short; XX@!pixel_ht,@!pixel_wd,@!x_offset,@!y_offset:short; XX@!raster_address:integer; XX XXbegin XX seek(pxl_file[cur_font],pxl_dptr[cur_font]+p*4+2); XX get(pxl_file[cur_font]); XX pixel_wd:=pxl_file[cur_font]^.i0; XX pixel_ht:=pxl_file[cur_font]^.i1; XX get(pxl_file[cur_font]); XX x_offset:=pxl_file[cur_font]^.i0; XX y_offset:=pxl_file[cur_font]^.i1; XX get(pxl_file[cur_font]); XX raster_address:=pxl_file[cur_font]^.i; XX hh:=hh-x_offset; vv:=vv-y_offset; XX update_pos; XX write_lj(@=#27'*r1A'@>); XX seek(pxl_file[cur_font],raster_address+2); XX for j:=1 to pixel_ht do begin XX write_lj(#27'*b',(pixel_wd-1) div 8 + 1:1, 'W'); XX for i:=1 to (pixel_wd-1) div 8 + 1 do begin XX if (i-1) mod 4 = 0 then XX get(pxl_file[cur_font]); XX write_lj(pxl_file[cur_font]^.c[(i-1) mod 4]); XX end; XX end; XX lj_v:=lj_v+pixel_ht; XX hh:=hh+char_pixel_width(cur_font)(p); vv:=vv+y_offset; XX write_lj(@=#27'*rB'@>); XXend; XX XX@* Optional modes of output. XXThe starting page is specified by giving a sequence of 1 to 10 numbers or XXasterisks separated by dots. For example, the specification `\.{1.*.-5}' XXcan be used to refer to a page output by \TeX\ when $\.{\\count0}=1$ XXand $\.{\\count2}=-5$. (Recall that |bop| commands in a \.{DVI} file XXare followed by ten `count' values.) An asterisk matches any number, XXso the `\.*' in `\.{1.*.-5}' means that \.{\\count1} is ignored when XXspecifying the first page. If several pages match the given specification, XX\.{DVIplus} will begin with the earliest such page in the file. The XXdefault specification `\.*' (which matches all pages) therefore denotes XXthe page at the beginning of the file. XX XXAnother option is the page offset. That is the point on the physical XXprinter page where the point (0,0) in the DVI file is mapped. XX XXNormally \.{DVIplus} uses default values for the options. XXIt can be started in such a way that it engages XXthe user in a brief dialog so that the XXoptions will be specified. XX@^system dependencies@> XX XX@<Glob...@>= XX@!max_pages:integer; {at most this many |bop..eop| pages will be printed} XX@!resolution:real; {pixels per inch} XX@!new_mag:integer; {if positive, overrides the postamble's magnification} XX@!copies:integer; XX@!h_offset,@!v_offset:integer; {offset where to put (0,0) on physical page} XX XX@ The starting page specification is recorded in two global arrays called XX|start_count| and |start_there|. For example, `\.{1.*.-5}' is represented XXby |start_there[0]=true|, |start_count[0]=1|, |start_there[1]=false|, XX|start_there[2]=true|, |start_count[2]=-5|. XXWe also set |start_vals=2|, to indicate that count 2 was the last one XXmentioned. The other values of |start_count| and |start_there| are not XXimportant, in this example. XX XX@<Glob...@>= XX@!start_count:array[0..9] of integer; {count values to select starting page} XX@!start_there:array[0..9] of boolean; {is the |start_count| value relevant?} XX@!start_vals:0..9; {the last count considered significant} XX@!count:array[0..9] of integer; {the count values on the current page} XX XX@ @<Set init...@>= XXmax_pages:=100; start_vals:=0; start_there[0]:=false; copies:=1; XXresolution:=300.0; new_mag:=0; XXh_offset:=210; v_offset:=100; XX XX@ Here is a simple subroutine that tests if the current page might be the XXstarting page. XX XX@p function start_match:boolean; {does |count| match the starting spec?} XXvar k:0..9; {loop index} XX@!match:boolean; {does everything match so far?} XXbegin match:=true; XXfor k:=0 to start_vals do XX if start_there[k]and(start_count[k]<>count[k]) then match:=false; XXstart_match:=match; XXend; XX XX@ The |input_ln| routine waits for the user to type a line at his or her XXterminal; then it puts ASCII-code equivalents for the characters on that line XXinto the |buffer| array. The |term_in| file is used for terminal input, XXand |term_out| for terminal output. XX@^system dependencies@> XX XX@<Glob...@>= XX@!buffer:array[0..terminal_line_length] of ASCII_code; XX@!term_in:text_file; {the terminal, considered as an input file} XX@!term_out:text_file; {the terminal, considered as an output file} XX@!arg_index:short; {which command line argument is being processed} XX@!interactive:boolean; XX XX@ Since the terminal is being used for both input and output, some systems XXneed a special routine to make sure that the user can see a prompt message XXbefore waiting for input based on that message. (Otherwise the message XXmay just be sitting in a hidden buffer somewhere, and the user will have XXno idea what the program is waiting for.) We shall call a system-dependent XXsubroutine |update_terminal| in order to avoid this problem. XX@^system dependencies@> XX XX@d update_terminal == prompt(term_out) {empty the terminal output buffer} XX XX@ During the dialog, \.{DVIplus} will treat the first blank space in a XXline as the end of that line. Therefore |input_ln| makes sure that there XXis always at least one blank space in |buffer|. XX@^system dependencies@> XX XX@p procedure input_ln; {inputs a line from the terminal} XXvar k:0..terminal_line_length; XXbegin update_terminal; XXk:=0; XXif eoln(term_in) then read_ln(term_in) XXelse begin while (k<terminal_line_length)and not eoln(term_in) do XX begin buffer[k]:=xord[term_in^]; incr(k); get(term_in); XX end; XX read_ln(term_in); XXend; XXbuffer[k]:=" "; XXend; XX XX@ The global variable |buf_ptr| is used while scanning each line of input; XXit points to the first unread character in |buffer|. XX XX@<Glob...@>= XX@!buf_ptr:0..terminal_line_length; {the number of characters read} XX XX@ Here is a routine that scans a (possibly signed) integer and computes XXthe decimal value. If no decimal integer starts at |buf_ptr|, the XXvalue 0 is returned. The integer should be less than $2^{31}$ in XXabsolute value. XX@p function get_integer:integer; XXvar x:integer; {accumulates the value} XX@!negative:boolean; {should the value be negated?} XXbegin if buffer[buf_ptr]="-" then XX begin negative:=true; incr(buf_ptr); XX end XXelse negative:=false; XXx:=0; XXwhile (buffer[buf_ptr]>="0")and(buffer[buf_ptr]<="9") do XX begin x:=10*x+buffer[buf_ptr]-"0"; incr(buf_ptr); XX end; XXif negative then get_integer:=-x @+ else get_integer:=x; XXend; XX XX@ The selected options are put into global variables by the |dialog| XXprocedure, which is called just as \.{DVIplus} begins. XX@^system dependencies@> XX XX@p procedure dialog; XXlabel 2,3,6,7,8,9,99; XXvar i,j,k:short; XXbegin rewrite(term_out, '1', 'NOCCTL'); {prepare the terminal for output} XXreset(term_in, '1'); {and for input} XXprint_ln(banner); XX@<Get flags, check if interactive@>; XX@<Determine the desired |start_count| values@>; XX@<Determine the desired |max_pages|@>; XX@<Determine the number of copies@>; XX@<Determine the page offset@>; XX@<Print all the selected options@>; XXend; XX XX@ @<Get flags, check if interactive@>= XXarg_index:=1; interactive:=false; XXrepeat XX i:=parameters(arg_index,cur_name,name_length); XX if cur_name[1]='-' then begin XX incr(arg_index); XX if i=1 then XX interactive:=true XX else case cur_name[2] of XX 'i','I':interactive:=true; XX othercases begin end; XX endcases; XX end; XXuntil cur_name[1]<>'-'; XXif not interactive then goto 99; XX XX@ @<Determine the desired |start...@>= XX2: print('Starting page (default=*): '); XXinput_ln; buf_ptr:=0; k:=0; XXif buffer[0]<>" " then XX repeat if buffer[buf_ptr]="*" then XX begin start_there[k]:=false; incr(buf_ptr); XX end XX else begin start_there[k]:=true; start_count[k]:=get_integer; XX end; XX if (k<9)and(buffer[buf_ptr]=".") then XX begin incr(k); incr(buf_ptr); XX end XX else if buffer[buf_ptr]=" " then start_vals:=k XX else begin print('Type, e.g., 1.*.-5 to specify the '); XX print_ln('first page with \count0=1, \count2=-5.'); XX goto 2; XX end; XX until start_vals=k XX XX@ @<Determine the desired |max_pages|@>= XX3: print('Maximum number of pages (default=100): '); XXinput_ln; buf_ptr:=0; XXif buffer[0]<>" " then XX begin max_pages:=get_integer; XX if max_pages<=0 then XX begin print_ln('Please type a positive number.'); XX goto 3; XX end; XX end XX XX@ @<Determine the number of copies@>= XX6: print('Number of copies (default=1): '); XXinput_ln; buf_ptr:=0; XXif buffer[0]<>" " then XX if (buffer[0]>="0")and(buffer[0]<="9") then copies:=get_integer XX else begin print('Type a positive integer to specify '); XX print_ln('the number of copies.'); XX goto 6; XX end XX XX@ @<Determine the page offset@>= XX7: print('Page offset in dots (default=210,100): '); XXinput_ln; buf_ptr:=0; XXif buffer[0]=" " then goto 9; XXif ((buffer[0]>="0")and(buffer[0]<="9")) or (buffer[0]="-") then XX h_offset:=get_integer XXelse goto 8; XXif (buffer[buf_ptr]=",") then incr(buf_ptr); XXif (buffer[buf_ptr]=" ") then incr(buf_ptr); XXif ((buffer[buf_ptr]>="0")and(buffer[buf_ptr]<="9")) or XX (buffer[buf_ptr]="-") then begin XX v_offset:=get_integer; XX goto 9; end XXelse goto 8; XX8:print('Specify a dot coordinate pair where the (0,0) '); XX print_ln('point will be placed.'); XX goto 7; XX9: XX XX@ After the dialog is over, we print the options so that the user XXcan see what \.{DVIplus} thought was specified. XX XX@<Print all the selected options@>= XX99:print_ln('Options selected:'); XX@.Options selected@> XXprint(' Starting page = '); XXfor k:=0 to start_vals do XX begin if start_there[k] then print(start_count[k]:1) XX else print('*'); XX if k<start_vals then print('.') XX else print_nl; XX end; XXprint_ln(' Maximum number of pages = ',max_pages:1); XXprint_ln(' Page offset = (', h_offset:1, ',', v_offset:1, ')'); XX XX@* Defining fonts. XX\.{DVIplus} reads the postamble first and loads XXall of the fonts defined there; then it processes the pages. XX XX@ Approximate the desired magnification to an available one. XXThe ``magig numbers'' that the desired magnification XXis compared to are calculated as XX$1500*1.2^m$, where $m = 1/4,3/4,1.5,2.5,3.5,4.5$ XX XX@p function approx_mag(f:integer;d_mag:integer):integer; XX XXbegin XX if d_mag < 1569 then XX approx_mag := 1500 XX else if d_mag < 1720 then XX approx_mag := 1643 XX else if d_mag < 1971 then XX approx_mag := 1800 XX else if d_mag < 2366 then XX approx_mag := 2160 XX else if d_mag < 2839 then XX approx_mag := 2592 XX else if d_mag < 3407 then XX approx_mag := 3110 XX else if d_mag < 4089 then XX approx_mag := 3732 XX else XX approx_mag:= 4479; XXend; XX XX@ The following subroutine does the necessary things when a \\{fnt\_def} XXcommand is being processed. XX XX@p procedure define_font(@!e:integer); {|e| is an external font number} XXvar f:0..max_fonts; XX@!p:integer; {length of the area/directory spec} XX@!n:integer; {length of the font name proper} XX@!c,@!q,@!d:integer; {check sum, scaled size, and design size} XX@!m:integer; {|mag| corrected for 300 pixels/inch} XX@!r:0..name_length; {index into |cur_name|} XX@!j,@!k:0..name_size; {indices into |names|} XX@!mismatch:boolean; {do names disagree?} XXbegin if nf=max_fonts then abort('DVIplus capacity exceeded (max fonts=', XX max_fonts:1,')!'); XX@.DVIplus capacity exceeded...@> XXfont_num[nf]:=e; f:=0; XXwhile font_num[f]<>e do incr(f); XX@<Read the font parameters into position for font |nf|, and XX print the font name@>; XX if f<nf then print_ln('---this font was already defined!'); XX@.this font was already defined@> XX @<Load the new font, unless there are problems@> XXend; XX XX@ @<Read the font parameters into position for font |nf|...@>= XXc:=signed_quad; font_check_sum[nf]:=c;@/ XXq:=signed_quad; font_scaled_size[nf]:=q;@/ XXd:=signed_quad; font_design_size[nf]:=d;@/ XXp:=get_byte; n:=get_byte; XXif font_name[nf]+n+p>name_size then XX abort('DVIplus capacity exceeded (name size=',name_size:1,')'); XX@.DVIplus capacity exceeded...@> XXfont_name[nf+1]:=font_name[nf]+n+p; XXif n+p=0 then abort('Null font name') XX@.Null font name@> XXelse for k:=font_name[nf] to font_name[nf+1]-1 do names[k]:=get_byte; XXfont_used_on[nf+1]:=0; XXincr(nf); XXif f=nf-1 then begin XX print('Font ', e:1, ': '); print_font(nf-1); XX update_terminal; XXend; XXdecr(nf) XX XX@ @<Load the new font, unless there are problems@>= XXbegin XX@<Compute |desired_mag|@>; XX@<Move font name into the |cur_name| string@>; XXif not open_pxl_file(nf) then begin XX print_nl; XX abort('Cannot open PXL file ', cur_name); end XX@.Cannot open PXL file@> XXelse begin if (q<=0)or(q>=@'1000000000) then begin XX print_nl; XX abort('PXL file not loaded, bad scale (',q:1,')!'); end XX@.bad scale@> XX else if (d<=0)or(d>=@'1000000000) then begin XX print_nl; XX abort('PXL file not loaded, bad design size (',d:1,')!'); end XX@.bad design size@> XX else begin XX in_PXL(q); XX @<Finish loading the new font info@>; XX end XXend XXend XX XX@ @<Compute |desired_mag|@>= XXdesired_mag:=round((mag * q * (300.0/200.0))/d+0.5); XX XX@ @<Finish loading...@>= XXbegin font_space[nf]:=q div 6; {this is a 3-unit ``thin space''} XXif (c<>0)and(pxl_check_sum<>0)and(c<>pxl_check_sum) then XX begin print(' ---beware: check sums do not agree!'); XX@.beware: check sums do not agree@> XX@.check sums do not agree@> XX print(' (',c:1,' vs. ',pxl_check_sum:1,')'); XX end; XXd:=round((100.0*conv*q)/(true_conv*d)); XXif d<>100 then XX print(' (magnified ',d:1,'%)'); XX@.this font is magnified@> XXincr(nf); {now the new font is officially present} XXfont_space[nf]:=0; {for |out_space| and |out_vmove|} XXend XX XX@ If |p=0|, i.e., if no font directory has been specified, \.{DVIplus} XXuses the default font directory, which is a XXsystem-dependent place where the standard fonts are kept. XX XXIn RTE--A, the \.{PXL} files are kept in directories called XX\.{/TeX/Fonts/MagXXXX}, where \.{XXXX} is the magnification. XXThe string variable |default_prefix| contains the prefix of these names. XX@^system dependencies@> XX XX@d default_prefix_name=='/TeX/Fonts/Mag' XX@d default_prefix_length=14 {change this to the correct length} XX XX@<Glob...@>= XX@!default_prefix:packed array[1..default_prefix_length] of char; XX XX@ @<Set init...@>= XXdefault_prefix:=default_prefix_name; XX XX@ The string |cur_name| is set to the external name of the XX\.{PXL} file for the current font and magnification. XX@^system dependencies@> XX XX@<Move font name into the |cur_name| string@>= XXfor k:=1 to name_length do cur_name[k]:=' '; XXif p=0 then XX begin for k:=1 to default_prefix_length do XX cur_name[k]:=default_prefix[k]; XX r:=default_prefix_length; XX incr(r); XX best_mag:=approx_mag(font_name[nf],desired_mag); XX m:=best_mag; XX cur_name[r]:=xchr[ m div 1000 + xord['0']]; XX incr(r); XX cur_name[r]:=xchr[ (m div 100) mod 10 + xord['0']]; XX incr(r); XX cur_name[r]:=xchr[ (m div 10) mod 10 + xord['0']]; XX incr(r); XX cur_name[r]:=xchr[ m mod 10 + xord['0']]; XX incr(r); XX cur_name[r]:='/'; end XXelse XX r:=0; XX XXfor k:=font_name[nf] to font_name[nf+1]-1 do XX begin incr(r); XX if r+4>name_length then XX abort('DVIplus capacity exceeded (max font name length=', XX name_length:1,')!'); XX@.DVIplus capacity exceeded...@> XX cur_name[r]:=xchr[names[k]]; XX end; XXcur_name[r+1]:='.'; cur_name[r+2]:='P'; cur_name[r+3]:='X'; cur_name[r+4]:='L' XX @//E*O*F LJ.2.3// chmod u=rw,g=rw,o=rw LJ.2.3 exit 0