Opostdaisy.c 28 KB

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