📄 doc2rtf.c
字号:
/*
* doc2rtf.c -- program to convert Gnuplot .DOC format to MS windows
* help (.rtf) format.
*
* This involves stripping all lines with a leading digit or
* a leading @, #, or %.
* Modified by Maurice Castro from doc2gih.c by Thomas Williams
* Further modified for PM GSview by Russell Lang 1996-10-15
* Write Win4 contents file. Not working yet because Win4
* considers a book to end when another book starts.
* It does not support the hierarchical structure of
* the GSview help file where topics may occur at the
* same level as a book and after the book.
* First line of file is Window Title.
* Changed to ANSI C. rjl 1998-01-10
* Removed isspace() which doesn't work for Greek characters.
*
* usage: doc2rtf file.doc file.rtf [file.cnt] [-d]
*
*/
/* note that tables must begin in at least the second column to */
/* be formatted correctly and tabs are forbidden */
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE_LEN 1024
#define TRUE 1
#define FALSE 0
char *hex = "0123456789ABCDEF";
struct LIST
{
int level;
int line;
char *string;
struct LIST *next;
};
struct LIST *list = NULL;
struct LIST *head = NULL;
struct LIST *keylist = NULL;
struct LIST *keyhead = NULL;
int debug = FALSE;
void parse(FILE *a, FILE *b);
int lookup(char *s);
void putquoted(char *s, FILE *f);
void footnote(char c, char *s, FILE *b);
void refs(int l, FILE *f);
void convert(FILE *a, FILE *b);
void process_line(char *line, FILE *b);
int
main(int argc,char *argv[])
{
FILE * infile;
FILE * outfile;
FILE * cntfile = NULL;
if (argc>1 && argv[argc-1][0]=='-' && argv[argc-1][1]=='d') {
debug = TRUE;
argc--;
}
if ( (argc > 4) || (argc < 3) ) {
fprintf(stderr,"Usage: %s infile outfile\n", argv[0]);
return(1);
}
if ( (infile = fopen(argv[1],"r")) == (FILE *)NULL) {
fprintf(stderr,"%s: Can't open %s for reading\n",
argv[0], argv[1]);
return(1);
}
if ( (outfile = fopen(argv[2],"w")) == (FILE *)NULL) {
fprintf(stderr,"%s: Can't open %s for writing\n",
argv[0], argv[2]);
}
if (argc==4) {
if ( (cntfile = fopen(argv[3],"w")) == (FILE *)NULL) {
fprintf(stderr,"%s: Can't open %s for writing\n",
argv[0], argv[3]);
}
}
if (cntfile) {
char basename[256];
strcpy(basename, argv[2]);
strtok(basename, ".");
strcat(basename, ".hlp");
fprintf(cntfile, ":Base %s\n", basename);
}
parse(infile, cntfile);
convert(infile,outfile);
return(0);
}
/* scan the file and build a list of line numbers where particular levels are */
void parse(FILE *a, FILE *b)
{
static char line[MAX_LINE_LEN];
char *c;
int lineno=0;
int lastline=0;
struct LIST *lasttopic=NULL;
if (fgets(line, MAX_LINE_LEN, a)) {
if (b)
fprintf(b, ":Title %s", line+1);
}
while (fgets(line,MAX_LINE_LEN,a))
{
lineno++;
if (isdigit(line[0]))
{
if (list == NULL)
head = (list = (struct LIST *) malloc(sizeof(struct LIST)));
else
list = (list->next = (struct LIST *) malloc(sizeof(struct LIST)));
list->line = lastline = lineno;
list->level = line[0] - '0';
list->string = (char *) malloc (strlen(line)+1);
c = strtok(&(line[1]),"\n");
strcpy(list->string, c);
list->next = NULL;
if (b) {
if (lasttopic) {
/* Doesn't work, so just dump all at the top level
if (list->level > lasttopic->level) {
fprintf(b, "%d %s\n", lasttopic->level, lasttopic->string);
fprintf(b, "%d %s=loc%d\n", lasttopic->level+1, lasttopic->string, lasttopic->line);
}
else
*/
fprintf(b, "%d %s=loc%d\n", lasttopic->level, lasttopic->string, lasttopic->line);
}
lasttopic = list;
}
}
if (line[0]=='?')
{
if (keylist == NULL)
keyhead = (keylist = (struct LIST *) malloc(sizeof(struct LIST)));
else
keylist = (keylist->next = (struct LIST *) malloc(sizeof(struct LIST)));
keylist->line = lastline;
keylist->level = line[0] - '0';
keylist->string = (char *) malloc (strlen(line)+1);
c = strtok(&(line[1]),"\n");
strcpy(keylist->string, c);
keylist->next = NULL;
}
}
if (b)
fprintf(b, "%d %s=loc%d\n", lasttopic->level, lasttopic->string, lasttopic->line);
rewind(a);
}
/* look up an in text reference */
int
lookup(char *s)
{
char *c;
char tokstr[MAX_LINE_LEN];
char *match;
int l;
strcpy(tokstr, s);
/* first try the ? keyword entries */
keylist = keyhead;
while (keylist != NULL)
{
c = keylist->string;
while (*c == ' ') c++;
if (!strcmp(s, c)) return(keylist->line);
keylist = keylist->next;
}
/* then try titles */
#ifdef GNUPLOT
match = strtok(tokstr, " \n\t");
l = 0; /* level */
list = head;
while (list != NULL)
{
c = list->string;
while (*c == ' ') c++;
if (!strcmp(match, c))
{
l = list->level;
match = strtok(NULL, "\n\t ");
if (match == NULL)
{
return(list->line);
}
}
if (l > list->level)
break;
list = list->next;
}
#else
/* we list keys explicitly, rather than building them from multiple levels */
list = head;
while (list != NULL)
{
c = list->string;
while (*c == ' ') c++;
if (!strcmp(s, c)) return(list->line);
list = list->next;
}
#endif
return(-1);
}
void putquoted(char *s, FILE *f)
{
for (; *s; s++) {
if (*s & 0x80) {
fputc((char)0x5c, f);
fputc((char)0x27, f);
fputc(hex[(*s&0xf0)>>4], f);
fputc(hex[(*s)&0x0f], f);
}
else
fputc(*s, f);
}
}
/* search through the list to find any references */
void refs(int l, FILE *f)
{
int curlevel;
char str[MAX_LINE_LEN];
char *c;
/* find current line */
list = head;
while (list->line != l)
list = list->next;
curlevel = list->level;
list = list->next; /* look at next element before going on */
if (list != NULL)
fprintf(f,"\\par");
while (list != NULL)
{
/* we are onto the next topic so stop */
if (list->level == curlevel)
break;
/* these are the next topics down the list */
if (list->level == curlevel+1)
{
c = list->string;
while (*c == ' ') c++;
fprintf(f,"\\par{\\uldb ");
putquoted(c, f);
fprintf(f,"}");
fprintf(f,"{\\v loc%d}\n",list->line);
}
list = list->next;
}
}
/* generate an RTF footnote with reference char c and text s */
void footnote(char c, char *s, FILE *b)
{
/* This is the new format, but it doesn't work for HC31
fprintf(b,"%c{\\footnote ", c);
*/
fprintf(b,"%c{\\footnote %c ", c, c);
putquoted(s, b);
fprintf(b,"}\n",s);
}
void convert(FILE *a, FILE *b)
{
static char line[MAX_LINE_LEN];
/* generate rtf header */
fprintf(b,"{\\rtf1\\ansi "); /* vers 1 rtf, ansi char set */
fprintf(b,"\\deff0"); /* default font font 0 */
/* font table: font 0 proportional, font 1 fixed */
fprintf(b,"{\\fonttbl{\\f0\\fswiss Arial;}{\\f1\\fmodern Courier New;}}\n");
/* skip title line */
fgets(line, MAX_LINE_LEN, a);
/* process each line of the file */
while (fgets(line,MAX_LINE_LEN,a)) {
process_line(line, b);
}
/* close final page and generate trailer */
fprintf(b,"}{\\plain \\page}\n");
fprintf(b,"}\n");
}
void process_line(char *line, FILE *b)
{
static int line_count = 0;
static char line2[MAX_LINE_LEN];
static int last_line;
int i;
int j;
static int startpage = 1;
char str[MAX_LINE_LEN];
char topic[MAX_LINE_LEN];
int k, l;
static int tabl=0;
static int para=0;
static int llpara=0;
static int inquote = FALSE;
static int inref = FALSE;
line_count++;
i = 0;
j = 0;
while (line[i] != '\0')
{
switch(line[i])
{
case '\\':
case '{':
case '}':
line2[j] = '\\';
j++;
line2[j] = line[i];
break;
case '\r':
case '\n':
break;
case '`': /* backquotes mean boldface or link */
if (line[1]==' ') /* tabular line */
line2[j] = line[i];
else if ((!inref) && (!inquote))
{
k=i+1; /* index into current string */
l=0; /* index into topic string */
while ((line[k] != '`') && (line[k] != '\0'))
{
topic[l] = line[k];
k++;
l++;
}
topic[l] = '\0';
k = lookup(topic);
if ((k > 0) && (k != last_line))
{
line2[j++] = '{';
line2[j++] = '\\';
line2[j++] = 'u';
line2[j++] = 'l';
line2[j++] = 'd';
line2[j++] = 'b';
line2[j] = ' ';
inref = k;
}
else
{
if (debug)
fprintf(stderr,"Can't make link for \042%s\042 on line %d\n",topic,line_count);
line2[j++] = '{';
line2[j++] = '\\';
line2[j++] = 'b';
line2[j] = ' ';
inquote = TRUE;
}
}
else
{
if (inquote && inref)
fprintf(stderr, "Warning: Reference Quote conflict line %d\n", line_count);
if (inquote)
{
line2[j] = '}';
inquote = FALSE;
}
if (inref)
{
/* must be inref */
sprintf(topic,"%d",inref);
line2[j++] = '}';
line2[j++] = '{';
line2[j++] = '\\';
line2[j++] = 'v';
line2[j++] = ' ';
line2[j++] = 'l';
line2[j++] = 'o';
line2[j++] = 'c';
k = 0;
while (topic[k] != '\0')
{
line2[j++] = topic[k];
k++;
}
line2[j] = '}';
inref = 0;
}
}
break;
default:
if (line[i] & 0x80) {
/* extended characters so use hexadecimal */
line2[j++] = (char)0x5c; /* \ */
line2[j++] = (char)0x27; /* ' */
line2[j++] = hex[(line[i]&0xf0)>>4];
line2[j] = hex[(line[i]&0x0f)];
}
else
line2[j] = line[i];
}
i++;
j++;
line2[j] = '\0';
}
i = 1;
switch(line[0]) { /* control character */
case '?': { /* interactive help entry */
if ((line2[1] != '\0') && (line2[1] != ' '))
footnote('K',&(line2[1]),b);
break;
}
case '@': { /* start/end table */
break; /* ignore */
}
case '#': { /* latex table entry */
break; /* ignore */
}
case '%': { /* troff table entry */
break; /* ignore */
}
case '\n': /* empty text line */
fprintf(b,"\\par\n");
llpara = para;
para = 0;
tabl = 0;
break;
case ' ': { /* normal text line */
if ((line2[1] == '\0') || (line2[1] == '\n'))
{
fprintf(b,"\\par\n");
llpara = para;
para = 0;
tabl = 0;
}
if (line2[1] == ' ')
{
if (!tabl)
{
fprintf(b,"\\par\n");
}
fprintf(b,"{\\pard \\plain \\f1\\fs20 ");
fprintf(b,"%s",&line2[1]);
fprintf(b,"}\\par\n");
llpara = 0;
para = 0;
tabl = 1;
}
else
{
if (!para)
{
if (llpara)
fprintf(b,"\\par\n"); /* blank line between paragraphs */
llpara = 0;
para = 1; /* not in para so start one */
tabl = 0;
fprintf(b,"\\pard \\plain \\qj \\fs20 \\f0 ");
}
fprintf(b,"%s \n",&line2[1]);
}
break;
}
default: {
if (isdigit(line[0])) { /* start of section */
if (!startpage)
{
refs(last_line,b);
fprintf(b,"}{\\plain \\page}\n");
}
para = 0; /* not in a paragraph */
tabl = 0;
last_line = line_count;
startpage = 0;
fprintf(b,"{\n");
sprintf(str,"browse:%05d", line_count);
footnote('+',str,b);
footnote('$',&(line2[1]),b); /* title */
fprintf(b,"{\\b \\fs24 %s}\\plain\\par\\par\n",&(line2[1]));
/* output unique ID */
sprintf(str,"loc%d", line_count);
footnote('#',str,b);
} else
fprintf(stderr, "unknown control code '%c' in column 1, line %d\n",
line[0], line_count);
break;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -