home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / texdvi2lj / part2 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  27.5 KB

  1. Subject: v06i014:  TeX DVI driver for LaserJet+ (texdvi2lj), Part2/3
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.UUCP
  4.  
  5. Submitted by: Tor Lillqvist <talcott!seismo!mcvax!santra!tml>
  6. Mod.sources: Volume 6, Issue 14
  7. Archive-name: texdvi2lj/Part2
  8.  
  9. [ I have split this submission into three pieces named LJ.1.3,
  10.   LJ.2.3, and LJ.2.3.  Unpack each piece and do
  11.       "cat LJ.[123].3 >dvi2lj.web"
  12.   This is not great, but is the best way I could think of to
  13.   distribute a large single-file source; if you have a better
  14.   way, please let me know.
  15.     *    *    *    *    *    *
  16.   OOPS!  This article went out earlier with a wrong subject
  17.   line.  I sent out a cancel, but in case it didn't get out,
  18.   here's the "official" posting.
  19.     *    *    *    *    *    *
  20.         --r$]
  21.  
  22. Here is a DVI (TeX output) driver for the HP LaserJet+.  This version
  23. is for the Pascal/1000 compiler on HP1000 machines running RTE-A (and
  24. my TeX implementation), but it should be fairly easy to convert to
  25. other TeX implementations, compilers and operating systems.
  26.  
  27. DVIplus is based on the DVItype program. It downloads only those
  28. characters actually used. Pages are printed in reverse.
  29.  
  30. # This is a shell archive.  Remove anything before this line,
  31. # then unpack it by saving it in a file and typing "sh file".
  32. # Contents:  LJ.2.3
  33.  
  34. echo x - LJ.2.3
  35. sed 's/^XX//' > "LJ.2.3" <<'@//E*O*F LJ.2.3//'
  36. XX@* Reading the font information.
  37. XXThe current number of known fonts is |nf|. Each known font has
  38. XXan internal number |f|, where |0<=f<nf|; the external number of this font,
  39. XXi.e., its font identification number in the \.{DVI} file, is
  40. XX|font_num[f]|, and the external name of this font is the string that
  41. XXoccupies positions |font_name[f]| through |font_name[f+1]-1| of the array
  42. XX|names|. The latter array consists of |ASCII_code| characters, and
  43. XX|font_name[nf]| is its first unoccupied position.  A horizontal motion
  44. XXin the range |-4*font_space[f]<h<font_space[f]|
  45. XXwill be treated as a `kern'.
  46. XXA given character |c| is valid in font |f| if and only if
  47. XX|char_width(f)(c)<>invalid_width|.
  48. XXFinally, |char_width(f)(c)=width[width_base[f]+c]|, and |width_ptr| is the
  49. XXfirst unused position of the |width| array.
  50. XX  
  51. XX@d char_width(#)==width[width_base[#]+char_end_width
  52. XX@d invalid_width==@'17777777777
  53. XX  
  54. XX@<Glob...@>=
  55. XX@!font_num:array [0..max_fonts] of integer; {external font numbers}
  56. XX@!font_name:array [0..max_fonts] of 0..name_size; {starting positions
  57. XX  of external font names}
  58. XX@!names:array [0..name_size] of ASCII_code; {characters of names}
  59. XX@!font_check_sum:array [0..max_fonts] of integer; {check sums}
  60. XX@!font_scaled_size:array [0..max_fonts] of integer; {scale factors}
  61. XX@!font_design_size:array [0..max_fonts] of integer; {design sizes}
  62. XX@!font_mag:array [0..max_fonts] of integer;
  63. XX@!font_space:array [0..max_fonts] of integer; {boundary between ``small''
  64. XX  and ``large'' spaces}
  65. XX@!font_used_on:array[0..max_fonts] of integer; {on which page last used}
  66. XX@!width_base:array [0..max_fonts] of integer; {index into |width| table}
  67. XX@=$Ema_Var On$@>
  68. XX@!width:array [0..max_widths] of integer; {character widths, in \.{DVI} units}
  69. XX@=$Ema_Var Off$@>
  70. XX@!nf:0..max_fonts; {the number of known fonts}
  71. XX@!width_ptr:0..max_widths; {the number of known character widths}
  72. XX  
  73. XX@ @<Set init...@>=
  74. XXnf:=0; width_ptr:=0; font_name[0]:=0; font_space[0]:=0;
  75. XXfont_used_on[0]:=0; 
  76. XX  
  77. XX@ It is, of course, a simple matter to print the name of a given font.
  78. XX  
  79. XX@p procedure print_font(@!f:integer); {|f| is an internal font number}
  80. XXvar k:0..name_size; {index into |names|}
  81. XXbegin if f=nf then print('UNDEFINED!')
  82. XX@.UNDEFINED@>
  83. XXelse  begin for k:=font_name[f] to font_name[f+1]-1 do
  84. XX    print(xchr[names[k]]);
  85. XX  end;
  86. XXend;
  87. XX  
  88. XX@ The global variabls |pxl_check_sum|,
  89. XX|pxl_design_size| are set from the \.{PXL} file.
  90. XX  
  91. XX@<Glob...@>=
  92. XX@!pxl_check_sum:integer; {check sum found in |pxl_file|}
  93. XX@!pxl_dptr:array [0..max_fonts] of integer; {directory pointers}
  94. XX@!pxl_design_size:integer;
  95. XX 
  96. XX@ Here is a procedure that absorbs the necessary information from a
  97. XX\.{PXL} file, assuming that the file has just been successfully opened.
  98. XX(A complete description of
  99. XX\.{PXL} file format appears elsewhere and will
  100. XXnot be repeated here.) The procedure does not check the \.{PXL} file
  101. XXfor validity, nor does it give explicit information about what is
  102. XXwrong with a \.{PXL} file that proves to be invalid; \.{DVI}-reading
  103. XXprograms need not do this, since \.{PXL} files are almost always valid.
  104. XXThe procedure simply returns |false| if it
  105. XXdetects anything amiss in the \.{PXL} data.
  106. XX  
  107. XXThere is a parameter, |z|, which represents the scaling factor being
  108. XXused to compute the font dimensions; it must be in the range $0<z<2^{27}$.
  109. XX  
  110. XX@d read_pxl(#)==begin #:=pxl_file[nf]^.i; get(pxl_file[nf]); end
  111. XX  
  112. XX@p procedure in_PXL(@!z:integer); {input \.{PXL} data}
  113. XXvar i,j,k,n:short; {indices etc.}
  114. XX@!wp:0..max_widths; {new value of |width_ptr| after successful input}
  115. XX@!raster_address:integer;
  116. XX@!alpha,@!beta:integer; {quantities used in the scaling computation}
  117. XXbegin
  118. XX  if width_ptr+128>max_widths then begin
  119. XX    print_nl;
  120. XX    abort('Need larger width table');
  121. XX  end;
  122. XX  width_base[nf]:=width_ptr;
  123. XX  wp:=width_ptr;
  124. XX  @<Check the header ID@>;
  125. XX  @<Read the trailer@>;
  126. XX  @<Read the font directory@>;
  127. XX  width_ptr:=wp;
  128. XXend;
  129. XX  
  130. XX@ @<Check the header ID@>=
  131. XXbegin
  132. XX  seek_pxl(nf)(0);
  133. XX  get(pxl_file[nf]);
  134. XX  if pxl_file[nf]^.i <> pxl_id then
  135. XX    bad_pxl('bad header id');
  136. XXend
  137. XX  
  138. XX@ @<Read the trailer@>=
  139. XXbegin
  140. XX  seek(pxl_file[nf],s_pxl_file+1);
  141. XX  get(pxl_file[nf]);
  142. XX  if pxl_file[nf]^.i <> pxl_id then
  143. XX    bad_pxl('bad trailer id');
  144. XX  seek(pxl_file[nf],s_pxl_file-3);
  145. XX  get(pxl_file[nf]);
  146. XX  read_pxl(pxl_check_sum);
  147. XX  read_pxl(font_mag[nf]);
  148. XX  read_pxl(pxl_design_size);
  149. XX  read_pxl(pxl_dptr[nf]);
  150. XXend;
  151. XX  
  152. XX@ One important part of |in_PXL| is the width computation, which
  153. XXinvolves multiplying the relative widths in the \.{PXL} file by the
  154. XXscaling factor in the \.{DVI} file. This fixed-point multiplication
  155. XXmust be done with precisely the same accuracy by all \.{DVI}-reading programs,
  156. XXin order to validate the assumptions made by \.{DVI}-writing programs
  157. XXlike \TeX82.
  158. XX  
  159. XXLet us therefore summarize what needs to be done. Each width in a \.{PXL}
  160. XXfile appears as a four-byte quantity called a |fix_word|.  A |fix_word|
  161. XXwhose respective bytes are $(a,b,c,d)$ represents the number
  162. XX$$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr
  163. XXb\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr
  164. XX-16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$
  165. XX(No other choices of $a$ are allowed, since the magnitude of a \.{TFM}
  166. XXdimension must be less than 16.)  We want to multiply this quantity by the
  167. XXinteger~|z|, which is known to be less than $2^{27}$. Let $\alpha=16z$.
  168. XXIf $|z|<2^{23}$, the individual multiplications $b\cdot z$, $c\cdot z$,
  169. XX$d\cdot z$ cannot overflow; otherwise we will divide |z| by 2, 4, 8, or
  170. XX16, to obtain a multiplier less than $2^{23}$, and we can compensate for
  171. XXthis later. If |z| has thereby been replaced by $|z|^\prime=|z|/2^e$, let
  172. XX$\beta=2^{4-e}$; we shall compute
  173. XX$$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$ if $a=0$,
  174. XXor the same quantity minus $\alpha$ if $a=255$.  This calculation must be
  175. XXdone exactly, for the reasons stated above; the following program does the
  176. XXjob in a system-independent way, assuming that arithmetic is exact on
  177. XXnumbers less than $2^{31}$ in magnitude.
  178. XX  
  179. XXThe following code computes pixel widths by simply rounding the \.{PXL}
  180. XXwidths to the nearest integer number of pixels, based on the conversion factor
  181. XX|conv| that converts \.{DVI} units to pixels. However, such a simple
  182. XXformula will not be valid for all fonts, and it will often give results that
  183. XXare off by $\pm1$ when a low-resolution font has been carefully
  184. XXhand-fitted. For example, a font designer often wants to make the letter `m'
  185. XXa pixel wider or narrower in order to make the font appear more consistent.
  186. XX\.{DVI}-to-printer programs should therefore input the correct pixel width
  187. XXinformation from font files whenever there is a chance that it may differ.
  188. XXA warning message may also be desirable in the case that at least one character
  189. XXis found whose pixel width differs from |conv*width| by more than a full pixel.
  190. XX  
  191. XXThose characters that are too large to be downloadable, are marked as such,
  192. XXand will be transferred using raster graphics. We must be especially careful
  193. XXin the y dimension, as the character must fit into the 255*255 box when
  194. XXthe reference point is placed on the baseline. The baseline was set to
  195. XX$255-$|baseline| pixel rows down from the top.
  196. XX@^system dependencies@>
  197. XX  
  198. XX@d pixel_round(#)==round(conv*(#))
  199. XX  
  200. XX@<Read the font dir...@>=
  201. XX@<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>;
  202. XXfor k:=0 to 127 do begin
  203. XX  seek(pxl_file[nf],pxl_dptr[nf]+k*4+2);
  204. XX  get(pxl_file[nf]);
  205. XX  {is the charater too large ?}
  206. XX  if (pxl_file[nf]^.i0 >= 128) or (pxl_file[nf]^.i1 >= 128) then
  207. XX    status[wp]:=too_large
  208. XX  else
  209. XX    status[wp]:=not_loaded;
  210. XX  get(pxl_file[nf]);
  211. XX  get(pxl_file[nf]);
  212. XX  if pxl_file[nf]^.i=0 then begin
  213. XX    width[wp]:=invalid_width;
  214. XX    pixel_width[wp]:=0  end
  215. XX  else begin
  216. XX    get(pxl_file[nf]);
  217. XX    read_pxl_word(nf);
  218. XX    width[wp]:=(((((b3*z)div@'400)+(b2*z))div@'400)+(b1*z))div beta;
  219. XX    if b0>0 then if b0<255 then bad_pxl('strange width for char ', k:1)
  220. XX      else width[wp]:=width[wp]-alpha;
  221. XX    pixel_width[wp]:=pixel_round(width[wp]);
  222. XX  end;
  223. XX  incr(wp);
  224. XXend
  225. XX  
  226. XX@ @<Replace |z|...@>=
  227. XXbegin alpha:=16*z; beta:=16;
  228. XXwhile z>=@'40000000 do
  229. XX  begin z:=z div 2; beta:=beta div 2;
  230. XX  end;
  231. XXend
  232. XX 
  233. XX@* Downloading information to the printer.
  234. XXThe procedure |update_pos| is used to update the printer cursor position.
  235. XXThis is the only place where the cursor is explicitely positioned.
  236. XX  
  237. XX@p procedure update_pos;
  238. XXlabel done;
  239. XXbegin if (lj_h<>hh)or(lj_v<>vv) then begin
  240. XX  write_lj(@=#27'*p'@>);
  241. XX  if (lj_h<>hh) then begin
  242. XX    if abs(lj_h-hh) > hh div 10 then
  243. XX      write_lj_f(hh:1)
  244. XX    else if (lj_h<hh) then
  245. XX      write_lj_f('+', hh-lj_h:1)
  246. XX    else
  247. XX      write_lj_f('-', lj_h-hh:1);
  248. XX    if (lj_v<>vv) then
  249. XX      write_lj_f('x')
  250. XX    else begin
  251. XX      write_lj_f('X');
  252. XX      goto done;
  253. XX    end
  254. XX  end;
  255. XX  if abs(lj_v-vv) > vv div 10 then
  256. XX    write_lj_f(vv:1)
  257. XX  else if (lj_v<vv) then
  258. XX    write_lj_f('+', vv-lj_v:1)
  259. XX  else
  260. XX    write_lj_f('-', lj_v-vv:1);
  261. XX  write_lj_f('Y');
  262. XXend;
  263. XXdone:
  264. XXlj_h:=hh; lj_v:=vv;
  265. XXend;
  266. XX 
  267. XX@ This procedure downloads a single character from a \.{PXL} file.
  268. XX@^system dependencies@>
  269. XX  
  270. XX@p procedure download_char(p:integer);
  271. XXvar i,j:short;
  272. XX@!pixel_wd,@!pixel_ht:integer;
  273. XX@!offsets,char_wd,char_ht,delta_x:i2c;
  274. XX@!raster_address:integer;
  275. XX  
  276. XXbegin
  277. XX  seek(pxl_file[cur_font],pxl_dptr[cur_font]+p*4+2);
  278. XX  get(pxl_file[cur_font]);
  279. XX  pixel_wd:=pxl_file[cur_font]^.i0;
  280. XX  pixel_ht:=pxl_file[cur_font]^.i1;
  281. XX  get(pxl_file[cur_font]);
  282. XX  offsets:=pxl_file[cur_font]^;
  283. XX  get(pxl_file[cur_font]);
  284. XX  raster_address:=pxl_file[cur_font]^.i;
  285. XX  @<Download character header@>;
  286. XX  seek(pxl_file[cur_font],raster_address+2);
  287. XX  for j:=1 to pixel_ht do begin
  288. XX    for i:=1 to (pixel_wd-1) div 8 + 1 do begin
  289. XX      if (i-1) mod 4 = 0 then
  290. XX        get(pxl_file[cur_font]);
  291. XX      write_lj(pxl_file[cur_font]^.c[(i-1) mod 4]);
  292. XX    end;
  293. XX  end
  294. XXend;
  295. XX  
  296. XX@ Download a character header.
  297. XX  
  298. XX@d data_bytes==(pixel_ht*(((pixel_wd-1) div 8)+1))
  299. XX  
  300. XX@<Download character header@>=
  301. XXbegin
  302. XX  if pixel_ht - offsets.i1 > baseline then begin
  303. XX    char_status(cur_font)(p):=pixel_ht-offsets.i1;
  304. XX    offsets.i1:=pixel_ht;  end
  305. XX  else
  306. XX    char_status(cur_font)(p):=loaded_ok;
  307. XX  offsets.i0:=-offsets.i0;
  308. XX  char_wd.i0:=pixel_wd;
  309. XX  char_ht.i0:=pixel_ht;
  310. XX  delta_x.i0:=char_pixel_width(cur_font)(p)*4;
  311. XX  write_lj(@=#27'*c'@>,font_num[cur_font]:1,'d',
  312. XX    ord(vis_chr(p)):1,@='E'#27'(s'@>,
  313. XX    data_bytes+16:1,'W'+
  314. XX    @=#4#0#14#1#0#0@>,
  315. XX    offsets.c[0], offsets.c[1],
  316. XX    offsets.c[2], offsets.c[3],
  317. XX    char_wd.c[0], char_wd.c[1],
  318. XX    char_ht.c[0], char_ht.c[1],
  319. XX    delta_x.c[0], delta_x.c[1]);
  320. XXend
  321. XX  
  322. XX@ This procedure transfers a character in raster form.
  323. XXThis is used for characters which are too large to be stored in
  324. XXthe font memory of the printer.
  325. XX@^system dependencies@>
  326. XX  
  327. XX@p procedure raster_char(p:integer);
  328. XXvar
  329. XXi,j,n:short;
  330. XX@!pixel_ht,@!pixel_wd,@!x_offset,@!y_offset:short;
  331. XX@!raster_address:integer;
  332. XX  
  333. XXbegin
  334. XX  seek(pxl_file[cur_font],pxl_dptr[cur_font]+p*4+2);
  335. XX  get(pxl_file[cur_font]);
  336. XX  pixel_wd:=pxl_file[cur_font]^.i0;
  337. XX  pixel_ht:=pxl_file[cur_font]^.i1;
  338. XX  get(pxl_file[cur_font]);
  339. XX  x_offset:=pxl_file[cur_font]^.i0;
  340. XX  y_offset:=pxl_file[cur_font]^.i1;
  341. XX  get(pxl_file[cur_font]);
  342. XX  raster_address:=pxl_file[cur_font]^.i;
  343. XX  hh:=hh-x_offset; vv:=vv-y_offset;
  344. XX  update_pos;
  345. XX  write_lj(@=#27'*r1A'@>);
  346. XX  seek(pxl_file[cur_font],raster_address+2);
  347. XX  for j:=1 to pixel_ht do begin
  348. XX    write_lj(#27'*b',(pixel_wd-1) div 8 + 1:1, 'W');
  349. XX    for i:=1 to (pixel_wd-1) div 8 + 1 do begin
  350. XX      if (i-1) mod 4 = 0 then
  351. XX        get(pxl_file[cur_font]);
  352. XX      write_lj(pxl_file[cur_font]^.c[(i-1) mod 4]);
  353. XX    end;
  354. XX  end;
  355. XX  lj_v:=lj_v+pixel_ht;
  356. XX  hh:=hh+char_pixel_width(cur_font)(p); vv:=vv+y_offset;
  357. XX  write_lj(@=#27'*rB'@>);
  358. XXend;
  359. XX  
  360. XX@* Optional modes of output.
  361. XXThe starting page is specified by giving a sequence of 1 to 10 numbers or
  362. XXasterisks separated by dots. For example, the specification `\.{1.*.-5}'
  363. XXcan be used to refer to a page output by \TeX\ when $\.{\\count0}=1$
  364. XXand $\.{\\count2}=-5$. (Recall that |bop| commands in a \.{DVI} file
  365. XXare followed by ten `count' values.) An asterisk matches any number,
  366. XXso the `\.*' in `\.{1.*.-5}' means that \.{\\count1} is ignored when
  367. XXspecifying the first page. If several pages match the given specification,
  368. XX\.{DVIplus} will begin with the earliest such page in the file. The
  369. XXdefault specification `\.*' (which matches all pages) therefore denotes
  370. XXthe page at the beginning of the file.
  371. XX  
  372. XXAnother option is the page offset. That is the point on the physical
  373. XXprinter page where the point (0,0) in the DVI file is mapped.
  374. XX  
  375. XXNormally \.{DVIplus} uses default values for the options.
  376. XXIt can be started in such a way that it engages
  377. XXthe user in a brief dialog so that the
  378. XXoptions will be specified.
  379. XX@^system dependencies@>
  380. XX  
  381. XX@<Glob...@>=
  382. XX@!max_pages:integer; {at most this many |bop..eop| pages will be printed}
  383. XX@!resolution:real; {pixels per inch}
  384. XX@!new_mag:integer; {if positive, overrides the postamble's magnification}
  385. XX@!copies:integer;
  386. XX@!h_offset,@!v_offset:integer; {offset where to put (0,0) on physical page}
  387. XX  
  388. XX@ The starting page specification is recorded in two global arrays called
  389. XX|start_count| and |start_there|. For example, `\.{1.*.-5}' is represented
  390. XXby |start_there[0]=true|, |start_count[0]=1|, |start_there[1]=false|,
  391. XX|start_there[2]=true|, |start_count[2]=-5|.
  392. XXWe also set |start_vals=2|, to indicate that count 2 was the last one
  393. XXmentioned. The other values of |start_count| and |start_there| are not
  394. XXimportant, in this example.
  395. XX  
  396. XX@<Glob...@>=
  397. XX@!start_count:array[0..9] of integer; {count values to select starting page}
  398. XX@!start_there:array[0..9] of boolean; {is the |start_count| value relevant?}
  399. XX@!start_vals:0..9; {the last count considered significant}
  400. XX@!count:array[0..9] of integer; {the count values on the current page}
  401. XX  
  402. XX@ @<Set init...@>=
  403. XXmax_pages:=100; start_vals:=0; start_there[0]:=false; copies:=1;
  404. XXresolution:=300.0; new_mag:=0;
  405. XXh_offset:=210; v_offset:=100;
  406. XX  
  407. XX@ Here is a simple subroutine that tests if the current page might be the
  408. XXstarting page.
  409. XX 
  410. XX@p function start_match:boolean; {does |count| match the starting spec?}
  411. XXvar k:0..9;  {loop index}
  412. XX@!match:boolean; {does everything match so far?}
  413. XXbegin match:=true;
  414. XXfor k:=0 to start_vals do
  415. XX  if start_there[k]and(start_count[k]<>count[k]) then match:=false;
  416. XXstart_match:=match;
  417. XXend;
  418. XX  
  419. XX@ The |input_ln| routine waits for the user to type a line at his or her
  420. XXterminal; then it puts ASCII-code equivalents for the characters on that line
  421. XXinto the |buffer| array. The |term_in| file is used for terminal input,
  422. XXand |term_out| for terminal output.
  423. XX@^system dependencies@>
  424. XX  
  425. XX@<Glob...@>=
  426. XX@!buffer:array[0..terminal_line_length] of ASCII_code;
  427. XX@!term_in:text_file; {the terminal, considered as an input file}
  428. XX@!term_out:text_file; {the terminal, considered as an output file}
  429. XX@!arg_index:short; {which command line argument is being processed}
  430. XX@!interactive:boolean;
  431. XX  
  432. XX@ Since the terminal is being used for both input and output, some systems
  433. XXneed a special routine to make sure that the user can see a prompt message
  434. XXbefore waiting for input based on that message. (Otherwise the message
  435. XXmay just be sitting in a hidden buffer somewhere, and the user will have
  436. XXno idea what the program is waiting for.) We shall call a system-dependent
  437. XXsubroutine |update_terminal| in order to avoid this problem.
  438. XX@^system dependencies@>
  439. XX  
  440. XX@d update_terminal == prompt(term_out) {empty the terminal output buffer}
  441. XX  
  442. XX@ During the dialog, \.{DVIplus} will treat the first blank space in a
  443. XXline as the end of that line. Therefore |input_ln| makes sure that there
  444. XXis always at least one blank space in |buffer|.
  445. XX@^system dependencies@>
  446. XX  
  447. XX@p procedure input_ln; {inputs a line from the terminal}
  448. XXvar k:0..terminal_line_length;
  449. XXbegin update_terminal;
  450. XXk:=0;
  451. XXif eoln(term_in) then read_ln(term_in)
  452. XXelse begin while (k<terminal_line_length)and not eoln(term_in) do
  453. XX  begin buffer[k]:=xord[term_in^]; incr(k); get(term_in);
  454. XX  end;
  455. XX  read_ln(term_in);
  456. XXend;
  457. XXbuffer[k]:=" ";
  458. XXend;
  459. XX  
  460. XX@ The global variable |buf_ptr| is used while scanning each line of input;
  461. XXit points to the first unread character in |buffer|.
  462. XX  
  463. XX@<Glob...@>=
  464. XX@!buf_ptr:0..terminal_line_length; {the number of characters read}
  465. XX  
  466. XX@ Here is a routine that scans a (possibly signed) integer and computes
  467. XXthe decimal value. If no decimal integer starts at |buf_ptr|, the
  468. XXvalue 0 is returned. The integer should be less than $2^{31}$ in
  469. XXabsolute value.
  470.  
  471. XX@p function get_integer:integer;
  472. XXvar x:integer; {accumulates the value}
  473. XX@!negative:boolean; {should the value be negated?}
  474. XXbegin if buffer[buf_ptr]="-" then
  475. XX  begin negative:=true; incr(buf_ptr);
  476. XX  end
  477. XXelse negative:=false;
  478. XXx:=0;
  479. XXwhile (buffer[buf_ptr]>="0")and(buffer[buf_ptr]<="9") do
  480. XX  begin x:=10*x+buffer[buf_ptr]-"0"; incr(buf_ptr);
  481. XX  end;
  482. XXif negative then get_integer:=-x @+ else get_integer:=x;
  483. XXend;
  484. XX  
  485. XX@ The selected options are put into global variables by the |dialog|
  486. XXprocedure, which is called just as \.{DVIplus} begins.
  487. XX@^system dependencies@>
  488. XX  
  489. XX@p procedure dialog;
  490. XXlabel 2,3,6,7,8,9,99;
  491. XXvar i,j,k:short;
  492. XXbegin rewrite(term_out, '1', 'NOCCTL'); {prepare the terminal for output}
  493. XXreset(term_in, '1'); {and for input}
  494. XXprint_ln(banner);
  495. XX@<Get flags, check if interactive@>;
  496. XX@<Determine the desired |start_count| values@>;
  497. XX@<Determine the desired |max_pages|@>;
  498. XX@<Determine the number of copies@>;
  499. XX@<Determine the page offset@>;
  500. XX@<Print all the selected options@>;
  501. XXend;
  502. XX 
  503. XX@ @<Get flags, check if interactive@>=
  504. XXarg_index:=1; interactive:=false;
  505. XXrepeat
  506. XX  i:=parameters(arg_index,cur_name,name_length);
  507. XX  if cur_name[1]='-' then begin
  508. XX    incr(arg_index);
  509. XX    if i=1 then
  510. XX      interactive:=true
  511. XX    else case cur_name[2] of
  512. XX      'i','I':interactive:=true;
  513. XX    othercases begin end;
  514. XX    endcases;
  515. XX  end;
  516. XXuntil cur_name[1]<>'-';
  517. XXif not interactive then goto 99;
  518. XX  
  519. XX@ @<Determine the desired |start...@>=
  520. XX2: print('Starting page (default=*): ');
  521. XXinput_ln; buf_ptr:=0; k:=0;
  522. XXif buffer[0]<>" " then
  523. XX  repeat if buffer[buf_ptr]="*" then
  524. XX    begin start_there[k]:=false; incr(buf_ptr);
  525. XX    end
  526. XX  else  begin start_there[k]:=true; start_count[k]:=get_integer;
  527. XX    end;
  528. XX  if (k<9)and(buffer[buf_ptr]=".") then
  529. XX    begin incr(k); incr(buf_ptr);
  530. XX    end
  531. XX  else if buffer[buf_ptr]=" " then start_vals:=k
  532. XX  else  begin print('Type, e.g., 1.*.-5 to specify the ');
  533. XX    print_ln('first page with \count0=1, \count2=-5.');
  534. XX    goto 2;
  535. XX    end;
  536. XX  until start_vals=k
  537. XX  
  538. XX@ @<Determine the desired |max_pages|@>=
  539. XX3: print('Maximum number of pages (default=100): ');
  540. XXinput_ln; buf_ptr:=0;
  541. XXif buffer[0]<>" " then
  542. XX  begin max_pages:=get_integer;
  543. XX  if max_pages<=0 then
  544. XX    begin print_ln('Please type a positive number.');
  545. XX    goto 3;
  546. XX    end;
  547. XX  end
  548. XX  
  549. XX@ @<Determine the number of copies@>=
  550. XX6: print('Number of copies (default=1): ');
  551. XXinput_ln; buf_ptr:=0;
  552. XXif buffer[0]<>" " then
  553. XX  if (buffer[0]>="0")and(buffer[0]<="9") then copies:=get_integer
  554. XX  else  begin print('Type a positive integer to specify ');
  555. XX    print_ln('the number of copies.');
  556. XX    goto 6;
  557. XX    end
  558. XX 
  559. XX@ @<Determine the page offset@>=
  560. XX7: print('Page offset in dots (default=210,100): ');
  561. XXinput_ln; buf_ptr:=0;
  562. XXif buffer[0]=" " then goto 9;
  563. XXif ((buffer[0]>="0")and(buffer[0]<="9")) or (buffer[0]="-") then
  564. XX h_offset:=get_integer
  565. XXelse goto 8;
  566. XXif (buffer[buf_ptr]=",") then incr(buf_ptr);
  567. XXif (buffer[buf_ptr]=" ") then incr(buf_ptr);
  568. XXif ((buffer[buf_ptr]>="0")and(buffer[buf_ptr]<="9")) or
  569. XX   (buffer[buf_ptr]="-") then begin
  570. XX  v_offset:=get_integer;
  571. XX  goto 9; end
  572. XXelse goto 8;
  573. XX8:print('Specify a dot coordinate pair where the (0,0) ');
  574. XX  print_ln('point will be placed.');
  575. XX  goto 7;
  576. XX9:
  577. XX  
  578. XX@ After the dialog is over, we print the options so that the user
  579. XXcan see what \.{DVIplus} thought was specified.
  580. XX  
  581. XX@<Print all the selected options@>=
  582. XX99:print_ln('Options selected:');
  583. XX@.Options selected@>
  584. XXprint('  Starting page = ');
  585. XXfor k:=0 to start_vals do
  586. XX  begin if start_there[k] then print(start_count[k]:1)
  587. XX  else print('*');
  588. XX  if k<start_vals then print('.')
  589. XX  else print_nl;
  590. XX  end;
  591. XXprint_ln('  Maximum number of pages = ',max_pages:1);
  592. XXprint_ln('  Page offset = (', h_offset:1, ',', v_offset:1, ')');
  593. XX  
  594. XX@* Defining fonts.
  595. XX\.{DVIplus} reads the postamble first and loads
  596. XXall of the fonts defined there; then it processes the pages.
  597. XX  
  598. XX@ Approximate the desired magnification to an available one.
  599. XXThe ``magig numbers'' that the desired magnification
  600. XXis compared to are calculated as
  601. XX$1500*1.2^m$, where $m = 1/4,3/4,1.5,2.5,3.5,4.5$
  602. XX  
  603. XX@p function approx_mag(f:integer;d_mag:integer):integer;
  604. XX  
  605. XXbegin
  606. XX  if d_mag < 1569 then
  607. XX    approx_mag := 1500
  608. XX  else if d_mag < 1720 then
  609. XX    approx_mag := 1643
  610. XX  else if d_mag < 1971 then
  611. XX    approx_mag := 1800
  612. XX  else if d_mag < 2366 then
  613. XX    approx_mag := 2160
  614. XX  else if d_mag < 2839 then
  615. XX    approx_mag := 2592
  616. XX  else if d_mag < 3407 then
  617. XX    approx_mag := 3110
  618. XX  else if d_mag < 4089 then
  619. XX    approx_mag := 3732
  620. XX  else
  621. XX    approx_mag:= 4479;
  622. XXend;
  623. XX  
  624. XX@ The following subroutine does the necessary things when a \\{fnt\_def}
  625. XXcommand is being processed.
  626. XX  
  627. XX@p procedure define_font(@!e:integer); {|e| is an external font number}
  628. XXvar f:0..max_fonts;
  629. XX@!p:integer; {length of the area/directory spec}
  630. XX@!n:integer; {length of the font name proper}
  631. XX@!c,@!q,@!d:integer; {check sum, scaled size, and design size}
  632. XX@!m:integer; {|mag| corrected for 300 pixels/inch}
  633. XX@!r:0..name_length; {index into |cur_name|}
  634. XX@!j,@!k:0..name_size; {indices into |names|}
  635. XX@!mismatch:boolean; {do names disagree?}
  636. XXbegin if nf=max_fonts then abort('DVIplus capacity exceeded (max fonts=',
  637. XX    max_fonts:1,')!');
  638. XX@.DVIplus capacity exceeded...@>
  639. XXfont_num[nf]:=e; f:=0;
  640. XXwhile font_num[f]<>e do incr(f);
  641. XX@<Read the font parameters into position for font |nf|, and
  642. XX  print the font name@>;
  643. XX  if f<nf then print_ln('---this font was already defined!');
  644. XX@.this font was already defined@>
  645. XX  @<Load the new font, unless there are problems@>
  646. XXend;
  647. XX  
  648. XX@ @<Read the font parameters into position for font |nf|...@>=
  649. XXc:=signed_quad; font_check_sum[nf]:=c;@/
  650. XXq:=signed_quad; font_scaled_size[nf]:=q;@/
  651. XXd:=signed_quad; font_design_size[nf]:=d;@/
  652. XXp:=get_byte; n:=get_byte;
  653. XXif font_name[nf]+n+p>name_size then
  654. XX  abort('DVIplus capacity exceeded (name size=',name_size:1,')');
  655. XX@.DVIplus capacity exceeded...@>
  656. XXfont_name[nf+1]:=font_name[nf]+n+p;
  657. XXif n+p=0 then abort('Null font name')
  658. XX@.Null font name@>
  659. XXelse for k:=font_name[nf] to font_name[nf+1]-1 do names[k]:=get_byte;
  660. XXfont_used_on[nf+1]:=0;
  661. XXincr(nf);
  662. XXif f=nf-1 then begin
  663. XX  print('Font ', e:1, ': '); print_font(nf-1);
  664. XX  update_terminal;
  665. XXend;
  666. XXdecr(nf)
  667. XX 
  668. XX@ @<Load the new font, unless there are problems@>=
  669. XXbegin
  670. XX@<Compute |desired_mag|@>;
  671. XX@<Move font name into the |cur_name| string@>;
  672. XXif not open_pxl_file(nf) then begin
  673. XX  print_nl;
  674. XX  abort('Cannot open PXL file ', cur_name); end
  675. XX@.Cannot open PXL file@>
  676. XXelse  begin if (q<=0)or(q>=@'1000000000) then begin
  677. XX    print_nl;
  678. XX    abort('PXL file not loaded, bad scale (',q:1,')!'); end
  679. XX@.bad scale@>
  680. XX  else if (d<=0)or(d>=@'1000000000) then begin
  681. XX    print_nl;
  682. XX    abort('PXL file not loaded, bad design size (',d:1,')!'); end
  683. XX@.bad design size@>
  684. XX  else begin
  685. XX    in_PXL(q);
  686. XX    @<Finish loading the new font info@>;
  687. XX  end
  688. XXend
  689. XXend
  690. XX  
  691. XX@ @<Compute |desired_mag|@>=
  692. XXdesired_mag:=round((mag * q * (300.0/200.0))/d+0.5);
  693. XX  
  694. XX@ @<Finish loading...@>=
  695. XXbegin font_space[nf]:=q div 6; {this is a 3-unit ``thin space''}
  696. XXif (c<>0)and(pxl_check_sum<>0)and(c<>pxl_check_sum) then
  697. XX  begin print(' ---beware: check sums do not agree!');
  698. XX@.beware: check sums do not agree@>
  699. XX@.check sums do not agree@>
  700. XX  print(' (',c:1,' vs. ',pxl_check_sum:1,')');
  701. XX  end;
  702. XXd:=round((100.0*conv*q)/(true_conv*d));
  703. XXif d<>100 then
  704. XX  print(' (magnified ',d:1,'%)');
  705. XX@.this font is magnified@>
  706. XXincr(nf); {now the new font is officially present}
  707. XXfont_space[nf]:=0; {for |out_space| and |out_vmove|}
  708. XXend
  709. XX  
  710. XX@ If |p=0|, i.e., if no font directory has been specified, \.{DVIplus}
  711. XXuses the default font directory, which is a
  712. XXsystem-dependent place where the standard fonts are kept.
  713. XX  
  714. XXIn RTE--A, the \.{PXL} files are kept in directories called
  715. XX\.{/TeX/Fonts/MagXXXX}, where \.{XXXX} is the magnification.
  716. XXThe string variable |default_prefix| contains the prefix of these names.
  717. XX@^system dependencies@>
  718. XX  
  719. XX@d default_prefix_name=='/TeX/Fonts/Mag'
  720. XX@d default_prefix_length=14 {change this to the correct length}
  721. XX  
  722. XX@<Glob...@>=
  723. XX@!default_prefix:packed array[1..default_prefix_length] of char;
  724. XX  
  725. XX@ @<Set init...@>=
  726. XXdefault_prefix:=default_prefix_name;
  727. XX  
  728. XX@ The string |cur_name| is set to the external name of the
  729. XX\.{PXL} file for the current font and magnification.
  730. XX@^system dependencies@>
  731. XX  
  732. XX@<Move font name into the |cur_name| string@>=
  733. XXfor k:=1 to name_length do cur_name[k]:=' ';
  734. XXif p=0 then
  735. XX  begin for k:=1 to default_prefix_length do
  736. XX    cur_name[k]:=default_prefix[k];
  737. XX  r:=default_prefix_length;
  738. XX  incr(r);
  739. XX  best_mag:=approx_mag(font_name[nf],desired_mag);
  740. XX  m:=best_mag;
  741. XX  cur_name[r]:=xchr[ m div 1000 + xord['0']];
  742. XX  incr(r);
  743. XX  cur_name[r]:=xchr[ (m div 100) mod 10 + xord['0']];
  744. XX  incr(r);
  745. XX  cur_name[r]:=xchr[ (m div 10) mod 10 + xord['0']];
  746. XX  incr(r);
  747. XX  cur_name[r]:=xchr[ m mod 10 + xord['0']];
  748. XX  incr(r);
  749. XX  cur_name[r]:='/'; end
  750. XXelse
  751. XX  r:=0;
  752. XX  
  753. XXfor k:=font_name[nf] to font_name[nf+1]-1 do
  754. XX  begin incr(r);
  755. XX  if r+4>name_length then
  756. XX    abort('DVIplus capacity exceeded (max font name length=',
  757. XX      name_length:1,')!');
  758. XX@.DVIplus capacity exceeded...@>
  759. XX  cur_name[r]:=xchr[names[k]];
  760. XX  end;
  761. XXcur_name[r+1]:='.'; cur_name[r+2]:='P'; cur_name[r+3]:='X'; cur_name[r+4]:='L'
  762. XX 
  763. @//E*O*F LJ.2.3//
  764. chmod u=rw,g=rw,o=rw LJ.2.3
  765.  
  766. exit 0
  767.