Opostdaisy.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /*
  10. *
  11. * postdaisy - PostScript translator for Diablo 1640 files.
  12. *
  13. * A program that translates Diablo 1640 files into PostScript. Absolutely nothing
  14. * is guaranteed. Quite a few things haven't been implemented, and what's been
  15. * done isn't well tested. Most of the documentation used to write this program
  16. * was taken from the 'Diablo Emulator' section of a recent Imagen manual.
  17. *
  18. * Some of document comments that are generated may not be right. Most of the test
  19. * files I used produced a trailing blank page. I've put a check in formfeed() that
  20. * won't print the last page if it doesn't contain any text, but PAGES comments may
  21. * not be right. The DOCUMENTFONTS comment will also be wrong if auto underline or
  22. * bold printing have been turned on by escape commands.
  23. *
  24. * The brute force approach used to implement horizontal and vertical tabs leaves
  25. * much to be desired, and may not work for very small initial hmi and vmi values.
  26. * At the very least I should have used malloc() to get space for the two tabstop
  27. * arrays after hmi and vmi are known!
  28. *
  29. * Reverse printing mode hasn't been tested at all, but what's here should be
  30. * close even though it's not efficient.
  31. *
  32. * The PostScript prologue is copied from *prologue before any of the input files
  33. * are translated. The program expects that the following PostScript procedures
  34. * are defined in that file:
  35. *
  36. * setup
  37. *
  38. * mark ... setup -
  39. *
  40. * Handles special initialization stuff that depends on how this program
  41. * was called. Expects to find a mark followed by key/value pairs on the
  42. * stack. The def operator is applied to each pair up to the mark, then
  43. * the default state is set up.
  44. *
  45. * pagesetup
  46. *
  47. * page pagesetup -
  48. *
  49. * Does whatever is needed to set things up for the next page. Expects to
  50. * find the current page number on the stack.
  51. *
  52. * t
  53. *
  54. * mark str1 x1 str2 x2 ... strn xn y hmi t mark
  55. *
  56. * Handles all the text on the stack. Characters in the strings are
  57. * printed using hmi as the character advance, and all strings are at
  58. * vertical position y. Each string is begins at the horizontal position
  59. * that preceeds it.
  60. *
  61. * f
  62. *
  63. * font f -
  64. *
  65. * Use font f, where f is the full PostScript font name. Only used when
  66. * we switch to auto underline (Courier-Italic) or bold (Courier-Bold)
  67. * printing.
  68. *
  69. * done
  70. *
  71. * done
  72. *
  73. * Makes sure the last page is printed. Only needed when we're printing
  74. * more than one page on each sheet of paper.
  75. *
  76. * Many default values, like the magnification and orientation, are defined in
  77. * the prologue, which is where they belong. If they're changed (by options), an
  78. * appropriate definition is made after the prologue is added to the output file.
  79. * The -P option passes arbitrary PostScript through to the output file. Among
  80. * other things it can be used to set (or change) values that can't be accessed by
  81. * other options.
  82. *
  83. */
  84. #include <stdio.h>
  85. #include <signal.h>
  86. #include <ctype.h>
  87. #include <fcntl.h>
  88. #include "comments.h" /* PostScript file structuring comments */
  89. #include "gen.h" /* general purpose definitions */
  90. #include "path.h" /* for the prologue */
  91. #include "ext.h" /* external variable declarations */
  92. #include "postdaisy.h" /* a few special definitions */
  93. char *optnames = "a:c:f:h:l:m:n:o:p:r:s:v:x:y:A:C:E:J:L:P:DI";
  94. char *prologue = POSTDAISY; /* default PostScript prologue */
  95. char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
  96. int formsperpage = 1; /* page images on each piece of paper */
  97. int copies = 1; /* and this many copies of each sheet */
  98. char htabstops[COLUMNS]; /* horizontal */
  99. char vtabstops[ROWS]; /* and vertical tabs */
  100. int res = RES; /* input file resolution - sort of */
  101. int hmi = HMI; /* horizontal motion index - 1/120 inch */
  102. int vmi = VMI; /* vertical motion index - 1/48 inch */
  103. int ohmi = HMI; /* original hmi */
  104. int ovmi = VMI; /* and vmi - for tabs and char size */
  105. int hpos = 0; /* current horizontal */
  106. int vpos = 0; /* and vertical position */
  107. int lastx = -1; /* printer's last horizontal */
  108. int lasty = -1; /* and vertical position */
  109. int lasthmi = -1; /* hmi for current text strings */
  110. int lastc = -1; /* last printed character */
  111. int prevx = -1; /* at this position */
  112. int leftmargin = LEFTMARGIN; /* page margins */
  113. int rightmargin = RIGHTMARGIN;
  114. int topmargin = TOPMARGIN;
  115. int bottommargin = BOTTOMMARGIN;
  116. int stringcount = 0; /* number of strings on the stack */
  117. int stringstart = 1; /* column where current one starts */
  118. int advance = 1; /* -1 if in backward print mode */
  119. int lfiscr = OFF; /* line feed implies carriage return */
  120. int crislf = OFF; /* carriage return implies line feed */
  121. int linespp = 0; /* lines per page if it's positive */
  122. int markedpage = FALSE; /* helps prevent trailing blank page */
  123. int page = 0; /* page we're working on */
  124. int printed = 0; /* printed this many pages */
  125. Fontmap fontmap[] = FONTMAP; /* for translating font names */
  126. char *fontname = "Courier"; /* use this PostScript font */
  127. int shadowprint = OFF; /* automatic bold printing if ON */
  128. FILE *fp_in; /* read from this file */
  129. FILE *fp_out = stdout; /* and write stuff here */
  130. FILE *fp_acct = NULL; /* for accounting data */
  131. /*****************************************************************************/
  132. main(agc, agv)
  133. int agc;
  134. char *agv[];
  135. {
  136. /*
  137. *
  138. * A simple program that translates Diablo 1640 files into PostScript. Nothing
  139. * is guaranteed - the program not well tested and doesn't implement everything.
  140. *
  141. */
  142. argc = agc; /* other routines may want them */
  143. argv = agv;
  144. prog_name = argv[0]; /* really just for error messages */
  145. init_signals(); /* sets up interrupt handling */
  146. header(); /* PostScript header comments */
  147. options(); /* handle the command line options */
  148. setup(); /* for PostScript */
  149. arguments(); /* followed by each input file */
  150. done(); /* print the last page etc. */
  151. account(); /* job accounting data */
  152. exit(x_stat); /* not much could be wrong */
  153. } /* End of main */
  154. /*****************************************************************************/
  155. init_signals()
  156. {
  157. int interrupt(); /* signal handler */
  158. /*
  159. *
  160. * Makes sure we handle interrupts.
  161. *
  162. */
  163. if ( signal(SIGINT, interrupt) == SIG_IGN ) {
  164. signal(SIGINT, SIG_IGN);
  165. signal(SIGQUIT, SIG_IGN);
  166. signal(SIGHUP, SIG_IGN);
  167. } else {
  168. signal(SIGHUP, interrupt);
  169. signal(SIGQUIT, interrupt);
  170. } /* End else */
  171. signal(SIGTERM, interrupt);
  172. } /* End of init_signals */
  173. /*****************************************************************************/
  174. header()
  175. {
  176. int ch; /* return value from getopt() */
  177. int old_optind = optind; /* for restoring optind - should be 1 */
  178. /*
  179. *
  180. * Scans the option list looking for things, like the prologue file, that we need
  181. * right away but could be changed from the default. Doing things this way is an
  182. * attempt to conform to Adobe's latest file structuring conventions. In particular
  183. * they now say there should be nothing executed in the prologue, and they have
  184. * added two new comments that delimit global initialization calls. Once we know
  185. * where things really are we write out the job header, follow it by the prologue,
  186. * and then add the ENDPROLOG and BEGINSETUP comments.
  187. *
  188. */
  189. while ( (ch = getopt(argc, argv, optnames)) != EOF )
  190. if ( ch == 'L' )
  191. prologue = optarg;
  192. else if ( ch == '?' )
  193. error(FATAL, "");
  194. optind = old_optind; /* get ready for option scanning */
  195. fprintf(stdout, "%s", CONFORMING);
  196. fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
  197. fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
  198. fprintf(stdout, "%s %s\n", PAGES, ATEND);
  199. fprintf(stdout, "%s", ENDCOMMENTS);
  200. if ( cat(prologue) == FALSE )
  201. error(FATAL, "can't read %s", prologue);
  202. if ( DOROUND )
  203. cat(ROUNDPAGE);
  204. fprintf(stdout, "%s", ENDPROLOG);
  205. fprintf(stdout, "%s", BEGINSETUP);
  206. fprintf(stdout, "mark\n");
  207. } /* End of header */
  208. /*****************************************************************************/
  209. options()
  210. {
  211. int ch; /* return value from getopt() */
  212. int n; /* for CR and LF modes */
  213. /*
  214. *
  215. * Reads and processes the command line options. Added the -P option so arbitrary
  216. * PostScript code can be passed through. Expect it could be useful for changing
  217. * definitions in the prologue for which options have not been defined.
  218. *
  219. * Although any PostScript font can be used, things will only work for constant
  220. * width fonts.
  221. *
  222. */
  223. while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
  224. switch ( ch ) {
  225. case 'a': /* aspect ratio */
  226. fprintf(stdout, "/aspectratio %s def\n", optarg);
  227. break;
  228. case 'c': /* copies */
  229. copies = atoi(optarg);
  230. fprintf(stdout, "/#copies %s store\n", optarg);
  231. break;
  232. case 'f': /* use this PostScript font */
  233. fontname = get_font(optarg);
  234. fprintf(stdout, "/font /%s def\n", fontname);
  235. break;
  236. case 'h': /* default character spacing */
  237. ohmi = hmi = atoi(optarg) * HSCALE;
  238. fprintf(stdout, "/hmi %s def\n", optarg);
  239. break;
  240. case 'l': /* lines per page */
  241. linespp = atoi(optarg);
  242. break;
  243. case 'm': /* magnification */
  244. fprintf(stdout, "/magnification %s def\n", optarg);
  245. break;
  246. case 'n': /* forms per page */
  247. formsperpage = atoi(optarg);
  248. fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
  249. fprintf(stdout, "/formsperpage %s def\n", optarg);
  250. break;
  251. case 'o': /* output page list */
  252. out_list(optarg);
  253. break;
  254. case 'p': /* landscape or portrait mode */
  255. if ( *optarg == 'l' )
  256. fprintf(stdout, "/landscape true def\n");
  257. else fprintf(stdout, "/landscape false def\n");
  258. break;
  259. case 'r': /* set CR and LF modes */
  260. n = atoi(optarg);
  261. if ( n & 01 )
  262. lfiscr = ON;
  263. else lfiscr = OFF;
  264. if ( n & 02 )
  265. crislf = ON;
  266. else crislf = OFF;
  267. break;
  268. case 's': /* point size */
  269. fprintf(stdout, "/pointsize %s def\n", optarg);
  270. break;
  271. case 'v': /* default line spacing */
  272. ovmi = vmi = atoi(optarg) * VSCALE;
  273. break;
  274. case 'x': /* shift things horizontally */
  275. fprintf(stdout, "/xoffset %s def\n", optarg);
  276. break;
  277. case 'y': /* and vertically on the page */
  278. fprintf(stdout, "/yoffset %s def\n", optarg);
  279. break;
  280. case 'A': /* force job accounting */
  281. case 'J':
  282. if ( (fp_acct = fopen(optarg, "a")) == NULL )
  283. error(FATAL, "can't open accounting file %s", optarg);
  284. break;
  285. case 'C': /* copy file straight to output */
  286. if ( cat(optarg) == FALSE )
  287. error(FATAL, "can't read %s", optarg);
  288. break;
  289. case 'E': /* text font encoding */
  290. fontencoding = optarg;
  291. break;
  292. case 'L': /* PostScript prologue file */
  293. prologue = optarg;
  294. break;
  295. case 'P': /* PostScript pass through */
  296. fprintf(stdout, "%s\n", optarg);
  297. break;
  298. case 'R': /* special global or page level request */
  299. saverequest(optarg);
  300. break;
  301. case 'D': /* debug flag */
  302. debug = ON;
  303. break;
  304. case 'I': /* ignore FATAL errors */
  305. ignore = ON;
  306. break;
  307. case '?': /* don't understand the option */
  308. error(FATAL, "");
  309. break;
  310. default: /* don't know what to do for ch */
  311. error(FATAL, "missing case for option %c\n", ch);
  312. break;
  313. } /* End switch */
  314. } /* End while */
  315. argc -= optind; /* get ready for non-option args */
  316. argv += optind;
  317. } /* End of options */
  318. /*****************************************************************************/
  319. char *get_font(name)
  320. char *name; /* name the user asked for */
  321. {
  322. int i; /* for looking through fontmap[] */
  323. /*
  324. *
  325. * Called from options() to map a user's font name into a legal PostScript name.
  326. * If the lookup fails *name is returned to the caller. That should let you choose
  327. * any PostScript font, although things will only work well for constant width
  328. * fonts.
  329. *
  330. */
  331. for ( i = 0; fontmap[i].name != NULL; i++ )
  332. if ( strcmp(name, fontmap[i].name) == 0 )
  333. return(fontmap[i].val);
  334. return(name);
  335. } /* End of get_font */
  336. /*****************************************************************************/
  337. setup()
  338. {
  339. /*
  340. *
  341. * Handles things that must be done after the options are read but before the
  342. * input files are processed.
  343. *
  344. */
  345. writerequest(0, stdout); /* global requests eg. manual feed */
  346. setencoding(fontencoding);
  347. fprintf(stdout, "setup\n");
  348. if ( formsperpage > 1 ) {
  349. if ( cat(formfile) == FALSE )
  350. error(FATAL, "can't read %s", formfile);
  351. fprintf(stdout, "%d setupforms\n", formsperpage);
  352. } /* End if */
  353. fprintf(stdout, "%s", ENDSETUP);
  354. } /* End of setup */
  355. /*****************************************************************************/
  356. arguments()
  357. {
  358. /*
  359. *
  360. * Makes sure all the non-option command line arguments are processed. If we get
  361. * here and there aren't any arguments left, or if '-' is one of the input files
  362. * we'll process stdin.
  363. *
  364. */
  365. fp_in = stdin;
  366. if ( argc < 1 )
  367. text();
  368. else { /* at least one argument is left */
  369. while ( argc > 0 ) {
  370. if ( strcmp(*argv, "-") == 0 )
  371. fp_in = stdin;
  372. else if ( (fp_in = fopen(*argv, "r")) == NULL )
  373. error(FATAL, "can't open %s", *argv);
  374. text();
  375. if ( fp_in != stdin )
  376. fclose(fp_in);
  377. argc--;
  378. argv++;
  379. } /* End while */
  380. } /* End else */
  381. } /* End of arguments */
  382. /*****************************************************************************/
  383. done()
  384. {
  385. /*
  386. *
  387. * Finished with all the input files, so mark the end of the pages, make sure the
  388. * last page is printed, and restore the initial environment.
  389. *
  390. */
  391. fprintf(stdout, "%s", TRAILER);
  392. fprintf(stdout, "done\n");
  393. fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
  394. fprintf(stdout, "%s %d\n", PAGES, printed);
  395. } /* End of done */
  396. /*****************************************************************************/
  397. account()
  398. {
  399. /*
  400. *
  401. * Writes an accounting record to *fp_acct provided it's not NULL. Accounting
  402. * is requested using the -A or -J options.
  403. *
  404. */
  405. if ( fp_acct != NULL )
  406. fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
  407. } /* End of account */
  408. /*****************************************************************************/
  409. text()
  410. {
  411. int ch; /* next input character */
  412. /*
  413. *
  414. * Translates the next input file into PostScript. The redirect(-1) call forces
  415. * the initial output to go to /dev/null - so the stuff formfeed() does at the
  416. * end of each page doesn't go to stdout.
  417. *
  418. */
  419. redirect(-1); /* get ready for the first page */
  420. formfeed(); /* force PAGE comment etc. */
  421. inittabs();
  422. while ( (ch = getc(fp_in)) != EOF )
  423. switch ( ch ) {
  424. case '\010': /* backspace */
  425. backspace();
  426. break;
  427. case '\011': /* horizontal tab */
  428. htab();
  429. break;
  430. case '\012': /* new line */
  431. linefeed();
  432. break;
  433. case '\013': /* vertical tab */
  434. vtab();
  435. break;
  436. case '\014': /* form feed */
  437. formfeed();
  438. break;
  439. case '\015': /* carriage return */
  440. carriage();
  441. break;
  442. case '\016': /* extended character set - SO */
  443. break;
  444. case '\017': /* extended character set - SI */
  445. break;
  446. case '\031': /* next char from supplementary set */
  447. break;
  448. case '\033': /* 2 or 3 byte escape sequence */
  449. escape();
  450. break;
  451. default:
  452. if ( isascii(ch) && isprint(ch) )
  453. oput(ch);
  454. break;
  455. } /* End switch */
  456. formfeed(); /* next file starts on a new page? */
  457. } /* End of text */
  458. /*****************************************************************************/
  459. inittabs()
  460. {
  461. int i; /* loop index */
  462. /*
  463. *
  464. * Initializes the horizontal and vertical tab arrays. The way tabs are handled is
  465. * quite inefficient and may not work for all initial hmi or vmi values.
  466. *
  467. */
  468. for ( i = 0; i < COLUMNS; i++ )
  469. htabstops[i] = ((i % 8) == 0) ? ON : OFF;
  470. for ( i = 0; i < ROWS; i++ )
  471. vtabstops[i] = ((i * ovmi) > BOTTOMMARGIN) ? ON : OFF;
  472. } /* End of inittabs */
  473. /*****************************************************************************/
  474. cleartabs()
  475. {
  476. int i; /* loop index */
  477. /*
  478. *
  479. * Clears all horizontal and vertical tab stops.
  480. *
  481. */
  482. for ( i = 0; i < ROWS; i++ )
  483. htabstops[i] = OFF;
  484. for ( i = 0; i < COLUMNS; i++ )
  485. vtabstops[i] = OFF;
  486. } /* End of cleartabs */
  487. /*****************************************************************************/
  488. formfeed()
  489. {
  490. /*
  491. *
  492. * Called whenever we've finished with the last page and want to get ready for the
  493. * next one. Also used at the beginning and end of each input file, so we have to
  494. * be careful about what's done. I've added a simple test before the showpage that
  495. * should eliminate the extra blank page that was put out at the end of many jobs,
  496. * but the PAGES comments may be wrong.
  497. *
  498. */
  499. if ( fp_out == stdout ) /* count the last page */
  500. printed++;
  501. endline(); /* print the last line */
  502. fprintf(fp_out, "cleartomark\n");
  503. if ( feof(fp_in) == 0 || markedpage == TRUE )
  504. fprintf(fp_out, "showpage\n");
  505. fprintf(fp_out, "saveobj restore\n");
  506. fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
  507. if ( ungetc(getc(fp_in), fp_in) == EOF )
  508. redirect(-1);
  509. else redirect(++page);
  510. fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
  511. fprintf(fp_out, "/saveobj save def\n");
  512. fprintf(fp_out, "mark\n");
  513. writerequest(printed+1, fp_out);
  514. fprintf(fp_out, "%d pagesetup\n", printed+1);
  515. vgoto(topmargin);
  516. hgoto(leftmargin);
  517. markedpage = FALSE;
  518. } /* End of formfeed */
  519. /*****************************************************************************/
  520. linefeed()
  521. {
  522. int line = 0; /* current line - based on ovmi */
  523. /*
  524. *
  525. * Adjust our current vertical position. If we've passed the bottom of the page
  526. * or exceeded the number of lines per page, print it and go to the upper left
  527. * corner of the next page. This routine is also called from carriage() if crislf
  528. * is ON.
  529. *
  530. */
  531. vmot(vmi);
  532. if ( lfiscr == ON )
  533. hgoto(leftmargin);
  534. if ( linespp > 0 ) /* means something so see where we are */
  535. line = vpos / ovmi + 1;
  536. if ( vpos > bottommargin || line > linespp )
  537. formfeed();
  538. } /* End of linefeed */
  539. /*****************************************************************************/
  540. carriage()
  541. {
  542. /*
  543. *
  544. * Handles carriage return character. If crislf is ON we'll generate a line feed
  545. * every time we get a carriage return character.
  546. *
  547. */
  548. if ( shadowprint == ON ) /* back to normal mode */
  549. changefont(fontname);
  550. advance = 1;
  551. shadowprint = OFF;
  552. hgoto(leftmargin);
  553. if ( crislf == ON )
  554. linefeed();
  555. } /* End of carriage */
  556. /*****************************************************************************/
  557. htab()
  558. {
  559. int col; /* 'column' we'll be at next */
  560. int i; /* loop index */
  561. /*
  562. *
  563. * Tries to figure out where the next tab stop is. Wasn't positive about this
  564. * one, since hmi can change. I'll assume columns are determined by the original
  565. * value of hmi. That fixes them on the page, which seems to make more sense than
  566. * letting them float all over the place.
  567. *
  568. */
  569. endline();
  570. col = hpos/ohmi + 1;
  571. for ( i = col; i < ROWS; i++ )
  572. if ( htabstops[i] == ON ) {
  573. col = i;
  574. break;
  575. } /* End if */
  576. hgoto(col * ohmi);
  577. lastx = hpos;
  578. } /* End of htab */
  579. /*****************************************************************************/
  580. vtab()
  581. {
  582. int line; /* line we'll be at next */
  583. int i; /* loop index */
  584. /*
  585. *
  586. * Looks for the next vertical tab stop in the vtabstops[] array and moves to that
  587. * line. If we don't find a tab we'll just move down one line - shouldn't happen.
  588. *
  589. */
  590. endline();
  591. line = vpos/ovmi + 1;
  592. for ( i = line; i < COLUMNS; i++ )
  593. if ( vtabstops[i] == ON ) {
  594. line = i;
  595. break;
  596. } /* End if */
  597. vgoto(line * ovmi);
  598. } /* End of vtab */
  599. /*****************************************************************************/
  600. backspace()
  601. {
  602. /*
  603. *
  604. * Moves backwards a distance equal to the current value of hmi, but don't go
  605. * past the left margin.
  606. *
  607. */
  608. endline();
  609. if ( hpos - leftmargin >= hmi )
  610. hmot(-hmi);
  611. else hgoto(leftmargin); /* maybe just ignore the backspace?? */
  612. lastx = hpos;
  613. } /* End of backspace */
  614. /*****************************************************************************/
  615. escape()
  616. {
  617. int ch; /* control character */
  618. /*
  619. *
  620. * Handles special codes that are expected to follow an escape character. The
  621. * initial escape character is followed by one or two bytes.
  622. *
  623. */
  624. switch ( ch = getc(fp_in) ) {
  625. case 'T': /* top margin */
  626. topmargin = vpos;
  627. break;
  628. case 'L': /* bottom margin */
  629. bottommargin = vpos;
  630. break;
  631. case 'C': /* clear top and bottom margins */
  632. bottommargin = BOTTOMMARGIN;
  633. topmargin = TOPMARGIN;
  634. break;
  635. case '9': /* left margin */
  636. leftmargin = hpos;
  637. break;
  638. case '0': /* right margin */
  639. rightmargin = hpos;
  640. break;
  641. case '1': /* set horizontal tab */
  642. htabstops[hpos/ohmi] = ON;
  643. break;
  644. case '8': /* clear horizontal tab at hpos */
  645. htabstops[hpos/ohmi] = OFF;
  646. break;
  647. case '-': /* set vertical tab */
  648. vtabstops[vpos/ovmi] = ON;
  649. break;
  650. case '2': /* clear all tabs */
  651. cleartabs();
  652. break;
  653. case '\014': /* set lines per page */
  654. linespp = getc(fp_in);
  655. break;
  656. case '\037': /* set hmi to next byte minus 1 */
  657. hmi = HSCALE * (getc(fp_in) - 1);
  658. break;
  659. case 'S': /* reset hmi to default */
  660. hmi = ohmi;
  661. break;
  662. case '\011': /* move to column given by next byte */
  663. hgoto((getc(fp_in)-1) * ohmi);
  664. break;
  665. case '?': /* do carriage return after line feed */
  666. lfiscr = ON;
  667. break;
  668. case '!': /* don't generate carriage return */
  669. lfiscr = OFF;
  670. break;
  671. case '5': /* forward print mode */
  672. advance = 1;
  673. break;
  674. case '6': /* backward print mode */
  675. advance = -1;
  676. break;
  677. case '\036': /* set vmi to next byte minus 1 */
  678. vmi = VSCALE * (getc(fp_in) - 1);
  679. break;
  680. case '\013': /* move to line given by next byte */
  681. vgoto((getc(fp_in)-1) * ovmi);
  682. break;
  683. case 'U': /* positive half line feed */
  684. vmot(vmi/2);
  685. break;
  686. case 'D': /* negative half line feed */
  687. vmot(-vmi/2);
  688. break;
  689. case '\012': /* negative line feed */
  690. vmot(-vmi);
  691. break;
  692. case '\015': /* clear all margins */
  693. bottommargin = BOTTOMMARGIN;
  694. topmargin = TOPMARGIN;
  695. leftmargin = BOTTOMMARGIN;
  696. rightmargin = RIGHTMARGIN;
  697. break;
  698. case 'E': /* auto underscore - use italic font */
  699. changefont("/Courier-Oblique");
  700. break;
  701. case 'R': /* disable auto underscore */
  702. changefont(fontname);
  703. break;
  704. case 'O': /* bold/shadow printing */
  705. case 'W':
  706. changefont("/Courier-Bold");
  707. shadowprint = ON;
  708. break;
  709. case '&': /* disable bold printing */
  710. changefont(fontname);
  711. shadowprint = OFF;
  712. break;
  713. case '/': /* ignored 2 byte escapes */
  714. case '\\':
  715. case '<':
  716. case '>':
  717. case '%':
  718. case '=':
  719. case '.':
  720. case '4':
  721. case 'A':
  722. case 'B':
  723. case 'M':
  724. case 'N':
  725. case 'P':
  726. case 'Q':
  727. case 'X':
  728. case '\010':
  729. break;
  730. case ',': /* ignored 3 byte escapes */
  731. case '\016':
  732. case '\021':
  733. getc(fp_in);
  734. break;
  735. case '3': /* graphics mode - should quit! */
  736. case '7':
  737. case 'G':
  738. case 'V':
  739. case 'Y':
  740. case 'Z':
  741. error(FATAL, "graphics mode is not implemented");
  742. break;
  743. default:
  744. error(FATAL, "missing case for escape o%o\n", ch);
  745. break;
  746. } /* End switch */
  747. } /* End of escape */
  748. /*****************************************************************************/
  749. vmot(n)
  750. int n; /* move this far vertically */
  751. {
  752. /*
  753. *
  754. * Move vertically n units from where we are.
  755. *
  756. */
  757. vpos += n;
  758. } /* End of vmot */
  759. /*****************************************************************************/
  760. vgoto(n)
  761. int n; /* new vertical position */
  762. {
  763. /*
  764. *
  765. * Moves to absolute vertical position n.
  766. *
  767. */
  768. vpos = n;
  769. } /* End of vgoto */
  770. /*****************************************************************************/
  771. hmot(n)
  772. int n; /* move this horizontally */
  773. {
  774. /*
  775. *
  776. * Moves horizontally n units from our current position.
  777. *
  778. */
  779. hpos += n * advance;
  780. if ( hpos < leftmargin )
  781. hpos = leftmargin;
  782. } /* End of hmot */
  783. /*****************************************************************************/
  784. hgoto(n)
  785. int n; /* go to this horizontal position */
  786. {
  787. /*
  788. *
  789. * Moves to absolute horizontal position n.
  790. *
  791. */
  792. hpos = n;
  793. } /* End of hgoto */
  794. /*****************************************************************************/
  795. changefont(name)
  796. char *name;
  797. {
  798. /*
  799. *
  800. * Changes the current font. Used to get in and out of auto underscore and bold
  801. * printing.
  802. *
  803. */
  804. endline();
  805. fprintf(fp_out, "%s f\n", name);
  806. } /* End of changefont */
  807. /*****************************************************************************/
  808. startline()
  809. {
  810. /*
  811. *
  812. * Called whenever we want to be certain we're ready to start pushing characters
  813. * into an open string on the stack. If stringcount is positive we've already
  814. * started, so there's nothing to do. The first string starts in column 1.
  815. *
  816. */
  817. if ( stringcount < 1 ) {
  818. putc('(', fp_out);
  819. stringstart = lastx = hpos;
  820. lasty = vpos;
  821. lasthmi = hmi;
  822. lastc = -1;
  823. prevx = -1;
  824. stringcount = 1;
  825. } /* End if */
  826. } /* End of startline */
  827. /*****************************************************************************/
  828. endline()
  829. {
  830. /*
  831. *
  832. * Generates a call to the PostScript procedure that processes the text on the
  833. * the stack - provided stringcount is positive.
  834. *
  835. */
  836. if ( stringcount > 0 )
  837. fprintf(fp_out, ")%d %d %d t\n", stringstart, lasty, lasthmi);
  838. stringcount = 0;
  839. } /* End of endline */
  840. /*****************************************************************************/
  841. endstring()
  842. {
  843. /*
  844. *
  845. * Takes the string we've been working on and adds it to the output file. Called
  846. * when we need to adjust our horizontal position before starting a new string.
  847. * Also called from endline() when we're done with the current line.
  848. *
  849. */
  850. if ( stringcount > 0 ) {
  851. fprintf(fp_out, ")%d(", stringstart);
  852. lastx = stringstart = hpos;
  853. stringcount++;
  854. } /* End if */
  855. } /* End of endstring */
  856. /*****************************************************************************/
  857. oput(ch)
  858. int ch; /* next output character */
  859. {
  860. /*
  861. *
  862. * Responsible for adding all printing characters from the input file to the
  863. * open string on top of the stack. The only other characters that end up in
  864. * that string are the quotes required for special characters. Reverse printing
  865. * mode hasn't been tested but it should be close. hpos and lastx should disagree
  866. * each time (except after startline() does something), and that should force a
  867. * call to endstring() for every character.
  868. *
  869. */
  870. if ( stringcount > 100 ) /* don't put too much on the stack */
  871. endline();
  872. if ( vpos != lasty )
  873. endline();
  874. if ( advance == -1 ) /* for reverse printing - move first */
  875. hmot(hmi);
  876. startline();
  877. if ( lastc != ch || hpos != prevx ) {
  878. if ( lastx != hpos )
  879. endstring();
  880. if ( ch == '\\' || ch == '(' || ch == ')' )
  881. putc('\\', fp_out);
  882. putc(ch, fp_out);
  883. lastc = ch;
  884. prevx = hpos;
  885. lastx += lasthmi;
  886. } /* End if */
  887. if ( advance != -1 )
  888. hmot(hmi);
  889. markedpage = TRUE;
  890. } /* End of oput */
  891. /*****************************************************************************/
  892. redirect(pg)
  893. int pg; /* next page we're printing */
  894. {
  895. static FILE *fp_null = NULL; /* if output is turned off */
  896. /*
  897. *
  898. * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
  899. * otherwise output goes to stdout.
  900. *
  901. */
  902. if ( pg >= 0 && in_olist(pg) == ON )
  903. fp_out = stdout;
  904. else if ( (fp_out = fp_null) == NULL )
  905. fp_out = fp_null = fopen("/dev/null", "w");
  906. } /* End of redirect */
  907. /*****************************************************************************/