📄 rt2ps.c
字号:
/* * $Id: rt2ps.c,v 1.1.1.1 2000/04/25 13:49:02 fnevgeny Exp $ * * Copyright (c) 1994 HAL Computer Systems International, Ltd. * * HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. * 1315 Dell Avenue * Campbell, CA 95008 * * Author: Greg Hilton * Contributors: Tom Lang, Frank Bieser, and others * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * http://www.gnu.org/copyleft/gpl.html * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* * Name: rt2ps * * Function: convert MIME Rich Text to PostScript * * Author: Tom Lang * * Date: 11/4/93 version 1 * 02/1/94 version 2 - major rewrite, moving much function to the * generated PostScript code. * * Data Format: 7-bit ASCII character strings formatted in accordance * with RFC 1341. */#include <errno.h>#include <ctype.h>#include <stdio.h>#include <sys/types.h>#include <time.h>#include "prolog.h"/* number of keywords */#define MAXKEY 19/* length of longest keyword (RFC says allow 40 chars plus <,/, and > ) */#define MAXKEYLEN 43/* * this array represents all keywords recognized by this program, * but not necessarily all legal keywords. * * the array is sorted by my perception of frequency of usage, in * an attempt to reduce search time. */#define K_NL 0#define K_LT 1#define K_BOLD 2#define K_ITALIC 3#define K_FIXED 4#define K_UNDERLINE 5#define K_CENTER 6#define K_SUPER 7#define K_SUB 8#define K_FL 9#define K_FR 10#define K_INDENT 11#define K_INDENTR 12#define K_OUTDENT 13#define K_OUTDENTR 14#define K_COMMENT 15#define K_NP 16#define K_BIGGER 17#define K_SMALLER 18static char *keys[MAXKEY] = { "nl>", /* 0 */ "lt>", /* 1 */ "bold>", /* 2 */ "italic>", /* 3 */ "fixed>", /* 4 */ "underline>", /* 5 */ "center>", /* 6 */ "superscript>", /* 7 */ "subscript>", /* 8 */ "flushleft>", /* 9 */ "flushright>", /* 10 */ "indent>", /* 11 */ "indentright>", /* 12 */ "outdent>", /* 13 */ "outdentright>", /* 14 */ "comment>", /* 15 */ "np>", /* 16 */ "bigger>", /* 17 */ "smaller>" /* 18 */};/* * tokens are built up in "buff" * PostScript code and macros are built in code */static char buff[1024];static char code[1024];/* * place to save directory name from which program is launched */static char dir[255];/* * font attribute masks, designed so that they can OR together. * note that font change from default (Helvetica) to fixed (Courier) is * handled as an attribute change rather than a font change. this limits * us to two fonts, but that's all that's required by MIME. */#define BOLD 1#define ITALIC 2#define FIXED 4/* * table of font names, indexed by attribute mask, which is * an OR of bold, italic, and fixed font. * * when the prolog code is written to standard output, macros defining * short-hand names for the fonts are defined. */static char *font[8] = { "f1", "f1b", "f1i", "f1bi", "f2", "f2b", "f2i", "f2bi" };/* * justifcation flags are used as bit flags, to allow nesting and also * allow more tolerance of syntax errors like unbalanced token pairs. * * left justifcation implies no special processing of the output. centering * and right justification require extra work. * * if both left and right justification are turned on, the output is fully * justified. note that this is more than what is requried in the RFC - may * be a problem, maybe a feature, maybe nobody cares... * * centering takes precedence over other values. * * if justification is turned on or off in the middle of * a line, the action applies to the whole line. the RFC is fuzzy on this, * but seems to imply this is how it should work. */#define L_JUST 1#define R_JUST 2#define CENTER 4/* * this table converts the justification bit flags to values for the * PostScript JU macro. JU 0 = left, JU 1 = center, JU 2 = right, JU 3 = full */static int jtab[8] = { 0, /* no flags, default to left justify */ 0, /* L_JUST */ 2, /* R_JUST */ 3, /* L_JUST & R_JUST */ 1, /* CENTER */ 1, /* CENTER & anything else = CENTER */ 1, 1};/* * PostScript page coordinates * measured in "points," where 72 points = 1 inch * lower left page corner = 0,0 * 8.5" x 11" paper, portrait orientation assumed * indentation unit is .5 inch, i.e. 36 points */#define Y_TOP 720#define Y_BOT 72#define X_LEFT 72#define X_RIGHT 540#define NORMAL_FONT_SIZE 10#define SMALL_FONT_SIZE 6#define LINE_HEIGHT 12#define INDENT 36/* * global static variables */struct { char *n; /* pointer to program name */ char *d; /* pointer to program directory name */ int keyword; /* flag: keyword just processed */ int c; /* index into the token buffer */ int space; /* flag: collecting white space. this is done to optimize the PostScript code - doing one command for multiple spaces rather than one each space */ int super; /* flag: superscript */ int sub; /* flag: subscript */ int scaled; /* flag: font scaled for sub/super script */ int altFont; /* flag: use alternate font, e.g. Times vs. Helvetica*/ int justify; /* mask: justification attributes */ int justifyOff; /* mask: justif. attrs to reset at <nl> */ int nl; /* flag: <nl> processed for this line */ int fs; /* current font size */ int pfs; /* previous font size */ int ffs; /* full font size */ int atMargin; /* flag: at left margin now */ int prolog; /* flag: pre-pend PostScript prolog to output */ int suppress; /* flag: output suppressed (within a comment) */ int underline; /* flag: underline attribute turned on/off */ int mask; /* font mask: used to select from font array */ int pm; /* previous font mask */ int box; /* flag: draw box around each page */ int showTags; /* flag: show unrecognized MIME tags */ int hdr; /* flag: print running headers */ int pg; /* running header page number */} g = { NULL, /* n */ &dir[0], /* d */ 0, /* keyword */ 0, /* c */ 0, /* space */ 0, /* superscript */ 0, /* subscript */ 0, /* scaled */ 0, /* altFont */ 0, /* justify */ 0, /* justifyOff */ 0, /* nl */ NORMAL_FONT_SIZE, /* fs */ 0, /* pfs */ NORMAL_FONT_SIZE, /* ffs */ 1, /* atMargin */ 1, /* prolog */ 0, /* suppress */ 0, /* underline */ 0, /* mask */ -1, /* pm */ 0, /* box */ 0, /* showTags */ 0, /* hdr */ 1 /* pg */};/* * function prototypes */void prolog();void epilog();void tokenOutput( char * );void tab();int keywordMatch( char * );void controlOutput( int );void foldLow( char * );int getArgs( int, char ** );char *baseName( char *, char * );char *dirName( char *, char * );void showHelp();main(int argc, char **argv){ int c; /* input stream character */ int key; /* keyword index */ /* * process command line arguments, bail out if there's a problem */ if (getArgs( argc, argv ) != 0) exit(1); /* * output PostScript prolog code */ prolog(); /* * read data stream from standard input and filter to stdout */ while((c = getchar()) != EOF) { switch ((char) c) { /* * "newline" in the input stream is treated as white * space, or ignored if it immediately follows a keyword. */ case '\n' : if(g.atMargin == 0) { if(g.space == 0) { tokenOutput(buff); g.space = 1; } buff[g.c++] = ' '; tokenOutput(buff); } break; /* * tab character */ case '\t' : tokenOutput(buff); tab(); break; /* * carriage returns are ignored */ case '\r' : break; /* * space character */ case ' ' : if(g.space == 0) { tokenOutput(buff); g.space = 1; } buff[g.c++] = (char) c; break; case '<' : tokenOutput(buff); buff[g.c++] = (char) c; g.keyword = 1; break; case '>': if(g.space) tokenOutput(buff); buff[g.c++] = (char) c; if(g.keyword) { key = keywordMatch(buff); if(key == 0) { if(g.showTags) tokenOutput(buff); else { g.c = 0; g.space = 0; g.keyword = 0; g.atMargin = 0; } } else controlOutput(key); } break; /* * characters which are special to the PostScript interpreter */ case '\\' : case '(' : case ')' : if(g.space) tokenOutput(buff); buff[g.c++] = '\\'; buff[g.c++] = (char) c; if(g.keyword == 0) g.atMargin = 0; break; default: /* * guard against extraneous stuff in the input */#if 0 if ( iscntrl( (char) c) ) { c = (int) '.'; }#endif /* * copy character to the buffer */ if(g.space) tokenOutput(buff); buff[g.c++] = (char) c; if(g.keyword == 0) g.atMargin = 0; } } /* * wrap up the PostScript output */ epilog(); exit (0);}/* * output a 4-tuple token of the form: * [ (string) size font action ] C * * where: * (string) is a character string to be output * size is the font's point size, or 0 for no change * font is the name of the font, or "x" for no change * action is the action code for this token: * 0 = show character string * 1 = show underlined character string * 2 = show space(s) * 3 = show underlined space(s) * 4 = tab * 5 = underlined tab * 6 = show subscript * 7 = show underlined subscript * 8 = show superscript * 9 = show underlined superscript * the trailing "C" is a macro which causes the token to be processed. * * There are shortcut macros for spaces and tabs: * S = single space character * US = single underlined space * T = tab character * UT = underlined tab character */voidtokenOutput( char *b ){ int action; int fontSize; if(g.c == 0) return; if(g.suppress == 0) { if((g.space) && (g.c == 1)) { if(g.underline) printf("US\n"); else printf("S\n"); } else { buff[g.c] = (char)NULL; /* * determine the "action code" for the "C" macro */ action = (g.super*8)+(g.sub*6)+(g.space*2)+g.underline; /* * there's no checking for too many nested <smaller> * keywords, resulting in a 0 or negative font size. * we'll leave the global variable alone so that * corectly nested </smaller> keywords will eventually * restore it. however, a font size smaller than 6 * will not be sent to the "C" macro. */ fontSize = (g.fs < 6) ? 6 : g.fs;#ifdef DONTCARE if((g.fs == g.pfs) && (g.mask == g.pm)) printf("[(%s) 0 x %i] C\n", buff, action); else#endif printf("[(%s) %i %s %i] C\n", buff, fontSize, font[g.mask], action); g.pfs = g.fs; g.pm = g.mask; } } g.c = 0; g.space = 0; g.keyword = 0; g.atMargin = 0;}/* * output a tab */voidtab(){ if(!g.suppress) { if(g.underline) printf("UT "); else printf("T "); }}/* * a character string delimited by < > has been found. see if it matches a * known keyword. this is a case-insensitive compare. zero is returned if * no match. a positive integer is returned if a match is found, equal to * the keyword code + 1. if the keyword is an "off" keyword, e.g. </bold>, * the return code is negated. * * for example, the keyword code for <bold> is 2. this routine will return * 3 if the keyword is <bold> or -3 if the keyword is </bold>. */intkeywordMatch( char *buff ){ int i; int off = 0; int rc = 0; buff[g.c] = (char)NULL; foldLow(buff); if(*++buff == '/') { buff++; off = 1; } for( i=0; i<MAXKEY; i++ ) { if (strcmp(buff, keys[i]) == 0) { rc = (off) ? -(i+1) : (i+1); break; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -