📄 et2ps.c
字号:
/* * $Id: et2ps.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: et2ps * * Function: convert MIME Enriched Text to PostScript * * Author: Tom Lang * * Date: 07/05/94 * * Data Format: 7-bit ASCII character strings formatted in accordance * with RFC 1563. */#include <errno.h>#include <ctype.h>#include <stdio.h>#include <sys/types.h>#include <time.h>#include "prolog.h"/* number of keywords */#define MAXKEY 15/* length of longest keyword (RFC says allow 60 chars plus <,/, and > ) */#define MAXKEYLEN 63/* * 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_BOLD 0#define K_ITALIC 1#define K_CENTER 2#define K_FIXED 3#define K_UNDERLINE 4#define K_INDENT 5#define K_INDENTR 6#define K_BIGGER 7#define K_SMALLER 8#define K_FL 9#define K_FR 10#define K_FB 11#define K_NOFILL 12#define K_PARAM 13#define K_EXCERPT 14/* * the "newline" keyword is not a <> delimited token */#define K_NL 15static char *keys[MAXKEY] = { "bold>", /* 0 */ "italic>", /* 1 */ "center>", /* 2 */ "fixed>", /* 3 */ "underline>", /* 4 */ "indent>", /* 5 */ "indentright>", /* 6 */ "bigger>", /* 7 */ "smaller>", /* 8 */ "flushleft>", /* 9 */ "flushright>", /* 10 */ "flushboth>", /* 11 */ "nofill>", /* 12 */ "param>", /* 13 */ "excerpt>" /* 14 */};/* * 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. * * left justifcation implies no special processing of the output. centering, * full justification, and right justification require extra work. * * the most recent (innermost) command takes precedence. * * if justification is turned on or off in the middle of * a line, a line break is assumed before and after the formatting change. * these values correspond to the parameters for the * PostScript JU macro. JU 0 = left, JU 1 = center, JU 2 = right, JU 3 = full */#define L_JUST 0#define CENTER 1#define R_JUST 2#define F_JUST 3/* *//* * 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 altFont; /* flag: use alternate font, e.g. Times vs. Helvetica*/ int justify; /* mask: justification attributes */ int jstack; /* justification stack index */ 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 param) */ 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, /* altFont */ 0, /* justify */ 0, /* jstack */ 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 */};/* * justification attribute stack */#define MAXJSTACK 16static int jstack[MAXJSTACK];/* * function prototypes */void prolog();void epilog();void tokenOutput( char * );void tab();int keywordMatch( char * );void controlOutput( int );void newline();void pushJustify( int );void popJustify( int );void toggleFont( 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. * An isolated newline is treated as a space. * N consecutive newlines are treated as N-1 line breaks. */ case '\n' : /* * if at the left margin, we're in a newline * sequence. */ if(g.atMargin) { controlOutput(K_NL+1); } else { c = getchar(); if ((char) c == '\n') { tokenOutput(buff); controlOutput(K_NL+1); } else { ungetc(c, stdin); if(g.space == 0) { tokenOutput(buff); g.space = 1; } buff[g.c++] = ' '; } } 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; /* * two consecutive <'s are interpreted as a single, * literal '<'. else, this is the beginning of a keyword. */ case '<' : if(g.space) tokenOutput(buff); c = getchar(); if ((char) c == '<') { buff[g.c++] = '<'; } else { ungetc(c, stdin); 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 (unused, from RFC 1341) * 7 = show underlined subscript (unused, from RFC 1341) * 8 = show superscript (unused, from RFC 1341) * 9 = show underlined superscript (unused, from RFC 1341) * 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.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, g.fs, 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 + -