This is fixrtf3.1.c in view mode; [Download] [Up]
/***************************************************************************
* *
* fixrtf (version 3.1) *
* *
****************************************************************************
* *
* Usage: fixrtf [-blr] filter file(s)_to_convert *
* *
* Currently supported options: *
* *
* -b Back up contents of file and save as filename with '~' on end *
* (default is to overwrite). *
* -l Use filter in your home directory ~/Library/rtf_filters *
* -r Translate backwards (ie mac-next filter does next to mac) *
* *
****************************************************************************
* *
* This source code is free. You may do whatever you wish with it, as long *
* as you leave the credits below and document any changes/enhancements you *
* may make. *
* *
* I have tested this program on my own files, and it works well, with no *
* disastrous bugs so far. I provide it, however, on an 'as is' basis, and *
* I make no claims that it is perfect and will do exactly what you want. *
* MAKE BACKUP COPIES BEFORE YOU USE IT! *
* *
****************************************************************************
* *
* This program corrects certain anomalies in RTF formats for non-ascii *
* characters. There are, as far as I know, 5 RTF formats: mac, pc, ansi, *
* next, and something else for pc's that I no longer have information on. *
* Basically, each platform has its own encoding of characters outside of *
* the standard 7-bit ascii system. NeXT for example largely uses the *
* PostScript ISOLatin I encoding vector (in release 2.0). This is very *
* much different from the Macintosh encoding--left double quotes from a *
* Mac RTF file appear in WriteNow on the NeXT as the onequarter fraction *
* symbol. *
* *
* These 'extended ascii' characters are normally encoded in RTF as an *
* escape sequence: \'xx where xx are two hex digits. This number is the *
* ascii encoding for the particular platform. fixrtf basically translates *
* these into the appropriate escapes for the platform you want, based on a *
* translation table you supply as the first argument. *
* *
* That's the easy part. Now, there are (at least) two problems I am aware *
* of currently. WriteNow is downright *defective* as an RTF reader/writer: *
* it writes some non-ascii characters *literally* into the RTF file, and *
* does not recognize and automatically translate the extended sequences of *
* other platforms (but then that's the whole purpose of this program). *
* Also, on the NeXT, some font-switching is going on behind you back with *
* certain characters. For example, the partialdiff symbol, available from *
* the keyboard whatever font you're using, is actually from the Symbol *
* font. fixrtf does its best to find sequences of the form (switch to *
* Symbol, one character, switch to another font), but this method is prone *
* to severe errors--the font switched 'back' to may not be the one from *
* before the Symbol character, and if there are more than one Symbol *
* characters in a row.... *
* *
* The translation table: *
* *
* fixrtf uses a translation table or filter, which may reside in either *
* the /LocalLibrary/rtf_filters, or in your home directory's library as *
* ~/Library/rtf_filters. Filters may be bidirectional, but since there may *
* be multiple escapes leading to the same final character (prime example: *
* WriteNow writing a uacute instead of \'f3 in the RTF file), you may want *
* to make dedicated one-way filters, and note that on the name (with a -1w *
* on the end or something). fixrtf v3 currently 'ships' with two filters, *
* mac-next and mac-next-wn, the latter more suited for conversions *from* *
* WriteNow on the NeXT (I was too lazy to switch the columns). And now for *
* the format.... *
* *
* Each line of the filter is of the form *
* *
* digit sequence digit sequence comments *
* *
* for example, *
* *
* 0 \'8b 0 \'d8 atilde *
* *
* The zeros mean that the character is *not* in the Symbol font; 1 says *
* they are. The backslash quote things are the RTF encodings for the *
* Postscript character atilde (see the Ref manual) on the two platforms. *
* The convention is that sequences on the left, when found in the file *
* being translated, are replaced by sequences on the right, unless the -r *
* option is used, in which case translation quite naturally occurs in the *
* opposite direction. *
* *
* Please note that column one of each line *MUST* contain a digit for the *
* entry to be properly read. Any other type of character in column one is *
* taken to indicate the whole line as a comment. *
* *
* An added feature: if the sequence entry for the 'from' column happens *
* not to begin with \' the sequence is treated as literal; in other words *
* fixrtf could be used as a global batch search-and-replace mechanism. It *
* makes use of the \' for speedy access to an array indexed by ascii value *
* and does a sequential search of a smaller array for other sequences. For *
* more details, read the code. *
* *
****************************************************************************
* *
* BUGS: *
* *
* As previously stated, fixrtf will not properly translate groups of NeXT *
* Symbol font characters to their destination equivalents. There is of *
* course always the question of RTF control words getting munged in the *
* translation process: that, in my opinion, would require writing a full- *
* blown RTF reader/writer, a task I am not currently up to. This program *
* intended as a low-end fix to what can be a very obnoxious problem. *
* *
* And last, but not least, DO NOT USE THIS on files that contain large *
* passages of text in the Symbol font! I have not had the opportunity to *
* see what the encoding for this font is, but I am sure it differs both *
* across and within platforms (in the sense that symbols don't correspond *
* to 'standard' keyboard layout. *
* *
****************************************************************************
* *
* written by: Nik A Gervae *
* 832 Packard St., #2 *
* Ann Arbor, MI 48104 *
* *
* Nik_Gervae@ub.cc.umich.edu 313-994-4123 *
* *
****************************************************************************
* *
* last modified 1991 04 05 fr *
* *
* Version history: *
* *
* 1991 02 11 mo Version 1.0--a quick fix, with poor error checking and *
* support of only one infile, one outfile. *
* *
* 1991 02 13 we Version 2.0--added multiple file support--infiles only *
* are specified, and are now overwritten, unless the -b *
* option is given; then the original is saved with a *
* tilde appended to the name. *
* Added 5 new character conversions. *
* Much better error checking added. Still doesn't check *
* whether the file is indeed a Mac RTF file or not! *
* *
* 1991 04 04 fr Version 3.0--added external filter files for customiz- *
* ability, and to handle slightly exceptional cases. *
* Filters can be bidirectional. New options specify *
* use of user's personal filters & reverse translation. *
* At this time no support for Symbol font. Minimal RTF *
* format checking (ie opening left brace)--still no *
* platform check (but you know what you're doing right?) *
* *
* 1991 04 16 tu Version 3.1--a minor bug fix. *
* *
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h> /** for getuid() */
#include <pwd.h> /** for getpwuid(..) */
#define BUFSIZE 2048
#define NUMSYM 30 /** size of symbol filter array */
#define NUMASCII 256 /** size of extended ascii filter array */
#define NUMOTHER 30 /** size of other character filer array */
#define MAXLEN 80 /** max length of filter input line */
#define PATHLEN 200 /** max length of full pathname */
#define BKNAMELEN 100 /** maximum length of backup file name */
#define BKMARK "~" /** this is appended to indicate backup */
#define WINDLEN 20 /** scanning window size */
#define EXCHLEN 6 /** max length of strings exchanged in tx */
#define FONTDEFLEN 10 /** length of string defining Symbol font */
#define ASCII_ESC_LEN 4 /** FULL length of escape--not just prefix */
#define LIBDIR "/Library/rtf_filters/"
#define GLOBFILTERDIR "/LocalLibrary/rtf_filters/"
#define FONTTABLE "{\\fonttbl"
#define SYMBOL "Symbol"
#define SYMBOLFONTDEF "\\ftech Symbol"
#define BACKSLASH '\\'
#define QUOTE '\''
#define LBRACE '{'
#define RBRACE '}'
#define SCOLON ';'
#define SPACE ' '
#define ENDCHAR '\0'
#define NOSTRING -1
#define UNKNOWN "????" /** undefined string */
#define ASCII_ESC "\\\'" /** RTF prefix for non-ascii characters */
/************************/
/*** GLOBAL VARIABLES ***/
/************************/
typedef struct any_ar { /** free-form array for various characters */
char fromStr[EXCHLEN];
char toStr[EXCHLEN];
int symCode;
} AnyCell;
typedef struct asc_ar { /** ascii-code indexed array for ascii chars */
char toStr[EXCHLEN];
int symCode;
} AsciiCell;
AnyCell symbolSet[NUMSYM]; /** characters to translate *from* Symbol */
AsciiCell asciiSet[NUMASCII]; /** 'extended' ascii to translate *from* */
AnyCell otherSet[NUMOTHER]; /** grab bag of other chars */
char symbolFont[FONTDEFLEN]; /** the RTF string defining the Symbol font */
int backup; /* option flags */
int library;
int reverse;
/*******************************************/
/*** FUNCTION DECLARATIONS AND HIERARCHY ***/
/*******************************************/
void usage(char **argv);
void readFilter(char *thefilter);
int getline(FILE *theFile, char line[], int len);
int asciiesc(char thestr[]);
int convert(char *filename, FILE *infile, FILE *outfile);
int advance(char window[], FILE *infile, FILE *outfile);
int translateAsciiEsc(char window[], FILE *outfile);
int translateSymEsc(char window[], FILE *outfile);
int isSymEsc(char window[], char theSym[]);
int findFont(char window[]);
int translateAny(char window[], AnyCell theSet[], int setSize,
FILE *outfile);
char *findFontTable(char buffer[], char *filename,
FILE *infile, FILE *outfile);
int strpos(char *string, char *substring);
char *findSymbolFont(char *filename, FILE *infile, FILE *outfile);
/***************************************************************************
* *
* Parse the command arguments, open the files, set up the tables, and go! *
* *
***************************************************************************/
main(int argc, char *argv[])
{
FILE *infile; /** file to translate */
FILE *outfile; /** file to output; makes sense, no? */
char tempname[L_tmpnam]; /** temporary name of output file */
char bkname[BKNAMELEN]; /** for backup file */
int i, j; /** loop counters */
int err; /** file error flag */
if (argc < 3) /* Check the usage. */
usage(argv);
backup = 0; /* Assume we'll be overwriting. */
library = 0; /* ...and using a filter in /LocalLibrary/rtf_filters. */
reverse = 0; /* ...and translating in column order. */
/*** Check for options */
for (i = 1; argv[i][0] == '-' && i < argc; ++i) {
for (j = 1; argv[i][j] != '\0'; ++j)
switch (argv[i][j]) {
case 'b' : backup = 1; /* Do back up. */
break;
case 'l' : library = 1; /* Use ~/Library/rtf_filters. */
break;
case 'r' : reverse = 1; /* Go from right to left column. */
break;
default : usage(argv);
break;
} /*switch*/
} /*for i*/
readFilter(argv[i]); /* Now load the translation tables. */
++i; /* And advance to first file to translate. */
/*** Begin the main loop. */
for ( ; i < argc; ++i) {
err = 0;
/*** Open the input file. */
if ((infile = fopen(argv[i], "r")) == NULL) {
perror(argv[i]);
err = 1;
fclose(infile);
} /*if infile*/
/*** Open or create the output file. */
tmpnam(tempname);
if ((outfile = fopen(tempname, "w")) == NULL) {
perror(argv[0]);
err = 1;
fclose(outfile);
} /*if outfile*/
/*** If nothing's gone wrong, convert the file. */
if (!err) {
if (convert(argv[i], infile, outfile) == 0) {
if (backup) {
strncpy(bkname, argv[i], BKNAMELEN + 1 - strlen(BKMARK));
strcat(bkname, BKMARK);
if (rename(argv[i], bkname) != 0)
perror(argv[i]);
else if (rename(tempname, argv[i]) != 0)
perror("rename temprary file: ");
} /*if backup*/
else {
if (remove(argv[i]) != 0 )
perror(argv[i]);
else if (rename(tempname, argv[i]) != 0)
perror("rename temprary file: ");
} /*else*/
} /*if convert*/
else {
fclose(infile);
fclose(outfile);
if (remove(tempname) != 0 )
perror("remove temporary file: ");
} /*else*/
} /*if!err*/
} /*for*/
} /*main*/
/***************************************************************************
* *
* usage() *
* *
* Somebody doesn't know how to use this; tell them. *
* *
***************************************************************************/
void usage(char **args)
{
fprintf(stderr, "usage: %s [-lbr] file(s)_to_convert\n", args[0]);
exit(1);
} /*usage*/
/***************************************************************************
* *
* readFilter() *
* *
* Read in the filter file specified by the first argument, and fill up the *
* translation tables. *
* *
***************************************************************************/
void readFilter(char *thefilter)
{
FILE *infilter; /** filter file pointer */
char filtername[PATHLEN]; /** full pathname of filter file */
int filterlen; /** length of current pathname */
uid_t the_uid; /** user id of person using program */
struct passwd *upw; /** struct containing user info for person using */
/* program (person logged in) */
char theline[MAXLEN];
int i, sym, oth; /** array indices for tranlation tables */
int tosym, frsym; /** character supposed to be in Symbol font? */
char tostr[EXCHLEN],frstr[EXCHLEN]; /** the character definitions */
/*** Open the filter file. */
filtername[0] = '\0';
if (library) { /*** In the user's home directory. */
the_uid = getuid();
upw = getpwuid(the_uid);
strncpy(filtername, upw->pw_dir, PATHLEN);
filterlen = strlen(filtername);
strncat(filtername, LIBDIR, PATHLEN - filterlen);
filterlen = strlen(filtername);
strncat(filtername, thefilter, PATHLEN - filterlen);
} /*if library*/
else { /*** In the global filter library. */
if (thefilter[0] != '/')
strncpy(filtername, GLOBFILTERDIR, PATHLEN);
filterlen = strlen(filtername);
strncat(filtername, thefilter, PATHLEN - filterlen);
} /*else*/
if ((infilter = fopen(filtername, "r")) == NULL) {
perror(filtername);
exit(-1);
} /*if infilter*/
/*** Initialize the arrays. */
for (i = 0; i < NUMSYM; ++i) {
symbolSet[i].fromStr[0] = NOSTRING;
symbolSet[i].toStr[0] = NOSTRING;
symbolSet[i].symCode = 0;
} /*for i*/
for (i = 0; i < NUMASCII; ++i) {
asciiSet[i].toStr[0] = NOSTRING;
asciiSet[i].symCode = 0;
} /*for i*/
for (i = 0; i < NUMOTHER; ++i) {
otherSet[i].fromStr[0] = NOSTRING;
otherSet[i].toStr[0] = NOSTRING;
otherSet[i].symCode = 0;
} /*for i*/
sym = oth = 0;
/*** And fill 'er up. */
while (getline(infilter, theline, MAXLEN) != EOF) {
if (!isdigit(theline[0])) continue;
if (reverse)
sscanf(theline, "%i %s %i %s", &tosym, &tostr, &frsym, &frstr);
else sscanf(theline, "%i %s %i %s", &frsym, &frstr, &tosym, &tostr);
if (frsym) {
strncpy(symbolSet[sym].fromStr, frstr, EXCHLEN);
strncpy(symbolSet[sym].toStr, tostr, EXCHLEN);
symbolSet[sym].symCode = tosym;
++sym;
} /*if frsym*/
else if ((i = asciiesc(frstr)) >= 0) {
strncpy(asciiSet[i].toStr, tostr, EXCHLEN);
asciiSet[i].symCode = tosym;
} /*else if i*/
else if (!strcmp(frstr, UNKNOWN)) continue;
else {
strncpy(otherSet[oth].toStr, tostr, EXCHLEN);
strncpy(otherSet[oth].fromStr, frstr, EXCHLEN);
otherSet[oth].symCode = tosym;
++oth;
} /*else*/
} /*while*/
} /*readFilter*/
/***************************************************************************
* *
* getline() *
* *
* getline reads up to (len - 1) characters from theFile, and advances to *
* the beginning of the next line (ie past the newline). A terminating *
* newline occuring before (len - 1) characters will be added to the *
* string; this way the user may check if truncation occured. *
* *
***************************************************************************/
int getline(FILE *theFile, char line[], int len)
{
int c, i;
i = 0;
while (--len > 0 && (c = getc(theFile)) != EOF && c != '\n')
line[i++] = c;
if (c == '\n')
line[i++] = c;
else while ((c = getc(theFile)) != '\n' && c != EOF)
;
line[i] = '\0';
if (c == EOF && i == 0) return EOF;
else return i;
} /*getline*/
/***************************************************************************
* *
* asciiesc() *
* *
* Return the ascii value of the excape sequence, or 0 if it isn't one. *
* *
***************************************************************************/
int asciiesc(char thestr[])
{
int i;
if (thestr[0] == BACKSLASH && thestr[1] == QUOTE &&
(isdigit(thestr[2]) || (thestr[2] >= 'a' && thestr[2] <= 'f')) &&
(isdigit(thestr[3]) || (thestr[3] >= 'a' && thestr[3] <= 'f')) ) {
sscanf(&thestr[2], "%2x", &i);
return i;
} /*if thestr*/
return -1;
} /*asciiesc*/
/***************************************************************************
* *
* convert() *
* *
* Go through file, trying to translate the current first few characters *
* into whatever is appropriate. *
* *
***************************************************************************/
int convert(char *filename, FILE *infile, FILE *outfile)
{
char *symFontPtr;
char window[WINDLEN + 1]; /** scan window */
int i; /** loop counter */
int slide; /** # characters translated */
fprintf(stderr, "Converting %s...\n", filename);
/*** Initialize the window. */
for (i = 0; i < WINDLEN + 1; ++i)
window[i] = ENDCHAR;
/*** Find out how the Symbol font is defined in this file. */
/*** If it isn't define it. */
symFontPtr = findSymbolFont(filename, infile, outfile);
if (symFontPtr == NULL) {
fprintf(stderr, "Error finding file %s\'s font table.\n", filename);
return -1;
} /*if*/
else {
strncpy(symbolFont, symFontPtr, sizeof(symbolFont));
} /*else*/
/*** Now just chug through and translate whatever you can. */
while (advance(window, infile, outfile) != EOF) {
if (slide = translateSymEsc(window, outfile))
;
else if (slide = translateAsciiEsc(window, outfile))
;
else if (slide = translateAny(window, otherSet, NUMOTHER, outfile))
;
/*** Get rid of whatever is being replaced. */
for (i = 0; i < slide; ++i) {
window[i] = ENDCHAR;
} /*for i*/
} /*while*/
fclose(infile);
fflush(outfile);
fclose(outfile);
} /*convert*/
/***************************************************************************
* *
* advance() *
* *
* Output the first character of the present window, shuffle the others *
* forward by one, and fill in the remainder of the array. This array is *
* used as a scan 'window' (hence the name), in that the first part is *
* checked by various transate...() routines and replaced in the outfile. *
* *
***************************************************************************/
int advance(char window[], FILE *infile, FILE *outfile)
{
int i, j; /* loop counter */
/*** Output the first character if it hasn't been touched. */
if (window[0] != ENDCHAR) {
putc(window[0], outfile);
window[0] = ENDCHAR;
} /*if window[0]*/
/*** Advance the array to fill emptied cells. */
for (j = 0; window[j] == ENDCHAR && j < WINDLEN; ++j)
;
for (i = 0; j < WINDLEN; ++i, ++j) {
window[i] = window[j];
} /*for i*/
/*** Now fill in the emptied spots. */
for ( ; i < WINDLEN; ++i) /* Get characters for those slots. */
window[i] = getc(infile);
return window[0];
} /*advance*/
/***************************************************************************
* *
* translateAsciiEsc() *
* *
* Use asciiesc() to find out if we're at an RTF ascii escape, and if so *
* use the value returned as an index into the ascii escape table to find *
* out what to replace it with. If that character should be rendered in the *
* Symbol font, add the appropriate control structures. *
* *
***************************************************************************/
int translateAsciiEsc(char window[], FILE *outfile)
{
int theEsc, i;
if ((theEsc = asciiesc(window)) > -1) {
if (asciiSet[theEsc].toStr[0] > NOSTRING) {
if (asciiSet[theEsc].symCode) fprintf(outfile, "%c%s ",
LBRACE, symbolFont);
fprintf(outfile, "%s", asciiSet[theEsc].toStr);
if (asciiSet[theEsc].symCode) fprintf(outfile, "%c", RBRACE);
} /*if asciiSet*/
else {
for (i = 0; i < ASCII_ESC_LEN; ++i) {
putc(window[i], outfile);
} /*for i*/
} /*else*/
return ASCII_ESC_LEN; /* whether or not it was translated */
} /*if theEsc*/
return 0;
} /*translateAsciiEsc*/
/***************************************************************************
* *
* translateSymEsc() *
* *
* If we're at a single character in the Symbol font, see if it can be *
* translated. The actual change is made by translateAny() (below). *
* *
***************************************************************************/
int translateSymEsc(char window[], FILE *outfile)
{
char theSym[EXCHLEN];
int slen, i;
if ((slen = isSymEsc(window, theSym)) > 0) {
if (translateAny(theSym, symbolSet, NUMSYM, outfile))
;
else {
for (i = 0; i < slen; ++i) {
putc(window[i], outfile);
} /*for i*/
} /*else*/
return slen;
} /*if slen*/
else return 0;
} /*translateSymEsc*/
/***************************************************************************
* *
* isSymEsc() *
* *
* Just go along until you hit something that obviously can't be a Symbol *
* sequence for one character. Legal sequences are: *
* *
* \f23 C\f22 or {\f23 C} *
* *
* where \f23 is the defintion of the Symbol font (symbolFont below), \f22 *
* is some other font, and C is an arbitrary character (or ascii escape!). *
* *
***************************************************************************/
int isSymEsc(char window[], char theSym[])
{
int sflen;
int braced;
int i, j;
i = 0;
sflen = strlen(symbolFont);
if (braced = (window[i] == LBRACE)) ++i;
if (!strncmp(&window[i], symbolFont, sflen)) i += sflen;
else return 0;
if (isspace(window[i])) ++i;
if (window[i+1] == LBRACE || window[i+1] == RBRACE ||
window[i+1] == BACKSLASH) {
theSym[0] = window[i++];
} /*if window[i+1]*/
else if (asciiesc(&window[i])) {
strncpy(theSym, &window[i], ASCII_ESC_LEN);
i += ASCII_ESC_LEN;
} /*else if asciiesc*/
else return 0;
if (braced) {
if (window[i] == RBRACE) return (i + 1);
else return 0;
} /*if braced*/
else if (j = findFont(&window[i])) return (i + j);
else return 0;
} /*isSymEsc*/
/***************************************************************************
* *
* findFont() *
* *
* Find a sequence of the form '\fd...d ' where d...d is a string of *
* consecutive decimal digits, and the space at the end is any nondigit *
* character. A single whitespace character is considered part of the font *
* change. *
* *
***************************************************************************/
int findFont(char window[])
{
int i;
if (window[0] == BACKSLASH && window[1] == 'f' && isdigit(window[2])) {
i = 3;
while (isdigit(window[i])) ++i;
if (isspace(window[i])) ++i;
return i;
} /*if window*/
else return 0;
} /*findFont*/
/***************************************************************************
* *
* translateAny() *
* *
* Go through the whole array of sequences to translate, trying to match to *
* the current window. If there's a match, write out the substiture, adding *
* Symbol font changers if necessary. *
* *
***************************************************************************/
int translateAny(char window[], AnyCell theSet[], int setSize, FILE *outfile)
{
int i, llen;
for (i = 0; i < setSize; ++i) {
llen = strlen(theSet[i].fromStr);
if (!strncmp(window, theSet[i].fromStr, llen)) {
if (theSet[i].symCode) fprintf(outfile, "%c%s",
LBRACE, symbolFont);
fprintf(outfile, "%s", theSet[i].toStr);
if (theSet[i].symCode) fprintf(outfile, "%c", RBRACE);
return llen;
} /*if !strncmp*/
} /*for*/
return 0;
} /*translateAny*/
/***************************************************************************
* *
* findSymbolFont() *
* *
* Get the character string defining the Symbol font in the document, or *
* append one to the end of the font table if there is no definition. This *
* is a messy piece of code. I tried. *
* *
***************************************************************************/
char *findSymbolFont(char *filename, FILE *infile, FILE *outfile)
{
char buffer[BUFSIZE]; /** what we're looking at */
char symFontEntry[35]; /** what we're looking for */
char symFont[FONTDEFLEN]; /** what we're really looking for */
int c, i, j; /** loop etc variables */
int go; /** search flag */
/*** Assume we haven't found anything yet. */
symFontEntry[0] = ENDCHAR;
/*** Make sure there's a font table. */
if (findFontTable(buffer, filename, infile, outfile) == NULL) {
fprintf(stderr, "%s: font table not found.\n", filename);
return NULL;
} /*if findFontTable*/
else {
/*** Good! We found one. On to work....find that \f definition. */
if ((i = strpos(buffer, SYMBOL)) > 0) {
for ( ; buffer[i] != BACKSLASH && i > 0; --i)
;
for ( --i; buffer[i] != BACKSLASH && i > 0; --i)
;
for (j = 0; j < 10; ) {
symFont[j++] = buffer[i++];
if (buffer[i] == BACKSLASH) break;
} /*for j*/
symFont[j] = '\0';
} /*if i*/
else {
/*** No such luck. Have to make up a \f definition. */
/*** So find the highest one, and use one higher than that. */
int fnum, newf; /** definition we're looking at */
fnum = newf = 0;
go = 1;
i = 0;
while (go) {
for ( ; !isdigit(buffer[i]) && buffer[i] != ENDCHAR; ++i)
;
if (buffer[i] == ENDCHAR) break;
sscanf(&buffer[i], "%d", &newf);
if (newf > fnum)
fnum = newf;
for ( ; isdigit(buffer[i]) && buffer[i] != ENDCHAR; ++i)
;
if (buffer[i] == '\0') break;
} /*while go*/
fnum++;
sprintf(symFont, "\\f%d", fnum);
sprintf(symFontEntry, "{%s%s;}", SYMBOLFONTDEF, symFont);
} /*else*/
/*** Write out the table with the new entry. */
for (i = 0; buffer[i] != ENDCHAR && i < sizeof(buffer); ++i)
;
if (buffer[i] == ENDCHAR) {
buffer[--i] = ENDCHAR; /*** Strip the last '}'. */
} /*if buffer[i]*/
else return NULL; /*** Fatal error. */
strcat(buffer, symFontEntry);
strcat(buffer, "}");
fprintf(outfile, "%s", buffer);
return symFont;
} /*else -- symbol table was found*/
/*** I warned you. A messy piece of code. */
} /*findSymbolFont*/
/***************************************************************************
* *
* findFontTable() *
* *
* Look for the sequence {\fonttbl in the document following the first *
* brace. *
* *
***************************************************************************/
char *findFontTable(char buffer[], char *filename, FILE *infile, FILE *outfile)
{
int c, i; /** loop counters etc */
int braceLevel; /** should be obvious */
/*** Read up to the first RTF group; dump characters to output file. */
if ((c = getc(infile)) != '{') {
fprintf(stderr, "%s is obviously not an RTF file.\n", filename);
return NULL;
} /*if c*/
else putc(c, outfile);
/*** Go up to the first '{' past the beginning of the file. */
while ((c = getc(infile)) != '{' && c != EOF) {
if (c == '}') {
fprintf(stderr, "%s: bad RTF format; ", filename);
fprintf(stderr, "brace in wrong place.\n");
return NULL;
} /*if c*/
else putc(c, outfile);
} /*while c*/
if (c == EOF) {
fprintf(stderr, "%s: RTF format may be wrong.\n", filename);
return NULL;
} /*if c*/
/*** Otherwise c is a '{'. */
/*** Now find the font table. */
braceLevel = 1; /*** We've found one so far. */
i = 0;
buffer[i++] = c;
while ((c = getc(infile)) != EOF && braceLevel > 0 && i < BUFSIZE - 1) {
/*to me: Implement \n conversions here; replace buffer[i++] = c;.*/
buffer[i++] = c;
if (c == '{') ++braceLevel;
else if (c == '}') --braceLevel;
} /*while c*/
ungetc(c, infile);
buffer[i++] = '\0';
if (i == BUFSIZE) {
fprintf(stderr, "Buffer overflow.\n");
return NULL;
} /*if i*/
if (braceLevel > 0 || c == EOF) {
fprintf(stderr, "Can't understand RTF format; braces may be wrong.\n");
return NULL;
}
return strstr(buffer, "\\fonttbl");
} /*findFontTable*/
/***************************************************************************
* *
* strpos() *
* *
* Get the pointer to the substring and subtract the original string's *
* pointer to get its ordinal position. *
* *
***************************************************************************/
int strpos(char *string, char *substring)
{
char *res; /** result of strstr() */
if ((res = strstr(string, substring)) == NULL)
return -1;
else return (res - string);
} /*strpos*/ These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.