home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 5 Edit
/
05-Edit.zip
/
txict100.zip
/
texicvt1.00
/
source
/
utilrtf.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1997-03-31
|
21KB
|
814 lines
/*
================================================================================
Texinfo converting Tools
Release 1.00 28.03.97
(c) 1996 by Andreas Kaiser
(c) 1997 by Karl Heinz Marbaise
================================================================================
Discription:
Utils for the converter Texinfo to RTF
Authors:
Andreas Kaiser
Karl Heinz Marbaise
e-mail:
Internet: KHMarbaise@p69.ks.fido.de
Fido-net: 2:2452/117.69
Bugs, question:
to above e-mail adress.
Register:
Please send a e-mail to above adress to register.
(include the release you want to register)
This registration should be done to let me
know how many people using these tools and
if it is worth to invest more time in continuing
development these tools or let the first release
of them be the last.
That is the only reason to make a registration.
I think a e-mail is not to much, isn't it?
License:
The "Texinfo converting tools" are 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, or (at your option)
any later version.
The "Texinfo converting tools" are distributed in the hope that
they 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.
You should have received a copy of the GNU General Public License
along with the "Texinfo converting tools" ; see the file COPYING.
If not, write to the:
Free Software Foundation,
59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
See \texicvt1.00\COPYING for details.
================================================================================
*/
/*
------------------------------------------------------------------------------
(R)evision (C)ontrol (S)ystem
------------------------------------------------------------------------------
*/
#ifdef __RCS__
static const char *utilhtml_cc = "$Id: UTILRTF.CC 1.3 1997/03/22 17:36:44 KHM Exp $";
#endif
#include "info.h"
#include <ctype.h>
#include <alloca.h>
#include <limits.h>
#include <minmax.h>
static char * old_font = "default";
static int preface = 1;
////////////////////////////////////////////////////////////////////////
static const char *fstack[10] = {"default"};
static int fstackx = 0;
void
font(const char *name, const char *size)
{
if (!name)
name = fstack[fstackx];
if (strcmp(name, "default") == 0) {
PUTA(":font facename=default size=0x0.");
} else
PUTA(":font facename=" << name << " size=" << size << '.');
}
void
beg_example(const char *fontname)
{
newpara = 0;
++nofill;
PUTL ();
PUT ("\\par {\\f11 ");
/*margin(+10);*/
fstack[++fstackx] = fontname;
/*font(0);*/
PUTL();
newpara = 0;
}
void
end_example()
{
newpara = 0;
--nofill;
--fstackx;
/*font(0);*/
/*margin(-10);*/
PUT ("\\par }"); PUTL ();
/**out << "</PRE>" << endl;*/
/*PUTL();*/
newpara = 0;
}
////////////////////////////////////////////////////////////////////////
void
words(String& line)
{
int i = 0;
String tmp;
int pos;
for (const char *p1 = line.chars(), *end = p1 + line.length();;) {
while (p1 < end && isspace(*p1))
++p1;
if (p1 == end)
break;
const char *p2 = p1;
while (p2 < end && *p2 != ',')
++p2;
if (i < MaxW)
{
tmp = String (p1, p2 - p1);
if (tmp.length ())
{
pos = tmp.length ()-1;
while (tmp.length () && (isspace(tmp[pos]) || tmp[pos] == '\t'))
tmp.del (pos--,1);
}
w[i++] = tmp;
}
if (p2 == end)
break;
p1 = p2 + 1;
}
while (i < MaxW)
w[i++] = null;
}
void
spaced(String& line)
{
int i = 0;
for (const char *p1 = line.chars(), *end = p1 + line.length();;) {
while (p1 < end && isspace(*p1))
++p1;
if (p1 == end)
break;
const char *p2 = p1;
while (p2 < end && !isspace(*p2))
++p2;
if (i < MaxW)
w[i++] = String(p1, p2 - p1);
if (p2 == end)
break;
p1 = p2 + 1;
}
while (i < MaxW)
w[i++] = null;
}
////////////////////////////////////////////////////////////////////////
static int hstack[6];
static int hlevel = 0;
void
heading(int level, const char *s)
{
if (istackp != istack)
return;
if (f_node) {
if (preface)
PUT(":h2." << s << endl << ":lm margin=1.");
}
/*else { */
if (debug)
cerr << "Heading, logical level=" << level
<< " stack level=" << hlevel
<< " stacked=" << hstack[hlevel];
if (level > hstack[hlevel])
hstack[++hlevel] = level;
else while (level < hstack[hlevel])
--hlevel;
if (debug)
cerr << " panel level=" << hlevel << endl;
if (node_id) {
panel_id = node_id;
node_id = 0;
} else
panel_id = ++hdid;
panel_name = s;
/* *out << "\\page {\\cs16\\super" << endl; */
*out << "{\\cs16\\super" << endl;
*out << "${\\footnote \\pard\\plain \\s15 \\f4\\fs20\\lang1031 {\\cs16\\super $}" << s << "}" << endl;
*out << "}" << endl;
*out << "\\pard \\qc\\brdrb\\brdrs\\brdrw15\\brsp20 {\\b\\fs28 " << s << endl;
*out << "\\par }" << endl;
*out << "\\pard \\par " << endl;
/*PUT("<H" << hlevel << ">" << s << "</H" << hlevel << ">" << endl);*/
/*PUT(":h" << hlevel << " id=hd" << panel_id << '.' << s
<< endl << ":lm margin=1.");*/
/* } */
}
void
Menu::flush()
{
int x1;
int x2;
String name;
String Node;
String Filename;
String Text;
if (!line.length())
return;
x1 = line.index(":");
if (debug)
cerr << "Menu::flush ()" << endl
<< " line=\"" << line << "\"" << endl;
if (x1>=0)
{
x2 = line.index (":", x1+1);
/* Is this a menu entry like:
* Node:: discription
*/
if (x2 > 0)
{
/* Yes it is. */
if ((x2-x1) == 1)
name = line.before (x1);
else
cerr << "Menu::flush ()" << endl
<< " the second colon is not positioned after the first!" << endl;
if (!table.contains(name))
table[name] = Name(++hdid);
for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
;
Node = line.before (x1);
Text = line.from (x2);
if (!Text.length ())
Text = Node;
*out << "\\par {\\strike " << Text << "}" <<
"{\\v " << Node << "}" << endl;
}
else
{
/* If we came here it might be an
* entry like this:
* Entry: node-name. Discription
*/
/* search the positition of the dot */
x2 = line.index (".", x1+1);
for (x1 += 1; x1 < line.length() && isspace(line[x1]); ++x1)
;
name = line.at (x1, x2-x1);
for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
;
/* check if a file name is part of the node */
if (name.index("(", 1) == 1)
{
/* extract the file name */
Filename = name.at (name.index("(",1), name.index (")", 2));
while (name[0]!=')' && name.length ())
name.del(0,1);
}
else
Filename = "";
if (Filename.length())
{
/* Node out of another file */
cerr << "Menu::line ()" << endl
<< " actualy we don't support this" << endl;
}
else
{
}
Text = line.from (x2);
if (!Text.length ())
Text = name;
if (!table.contains(name))
table[name] = Name(++hdid);
*out << "\\par {\\strike " << Text << "}" <<
"{\\v " << name << "}" << endl;
if (debug)
cerr << "*** Node=\"" << name << "\"" << endl
<< " Text=\"" << Text << "\"" << endl
<< " File=\"" << Filename << "\"" << endl;
}
} /* if (x1>=0)... */
/****************************
if (debug)
cerr << "Menu::flush (): line=\"" << line << "\"" << endl;
if (line.length() == 0)
return;
int x1 = line.index(":");
if (x1 >= 0) {
int x2 = line.index(":", x1+1);
if (x2 >= 0) {
String name = line.at(x1+1, x2-x1-1);
if (name.length() == 0)
name = line.before(x1);
if (!table.contains(name))
table[name] = Name(++hdid);
for (x2 += 1; x2 < line.length() && isspace(line[x2]); ++x2)
;
*out << "\\par {\\strike " << line.from(x2) << "}" <<
"{\\v " << line.before(x1) << "}" << endl;
}
}
******************************/
line = "";
}
void
node(String name, String next, String prev, String up)
{
int NodeId;
char Buffer[20];
if (table.contains(up)) {
if (f_node)
hlevel = table[up].level + 1;
} else if (name == "Top" || up.length() == 0) {
if (f_node)
hlevel = 0;
} else {
cerr << "<up> node undefined in '" << name << "', '" << next
<< "', '" << prev << "', '" << up << '\'' << endl;
cerr.flush();
#if 0
exit(1);
#endif
}
if (debug)
cerr << "Define name='" << name << "' next='" << next
<< "' prev='" << prev << "' up='" << up << "'";
Name& entry = table[name];
if (entry.id) {
if (entry.defined) {
cerr << "Node '" << name << "' redefined " << endl;
cerr.flush();
#if 0
exit(1);
#endif
}
entry.defined = 1;
if (debug)
cerr << ", known id=" << entry.id << endl;
} else {
table[name] = Name(++hdid, 1, hlevel);
if (debug)
cerr << ", new id=" << hdid << endl;
}
if (f_node && hlevel >= 1 && hlevel <= 6 && istackp == istack)
{
preface = 0;
*out << "\\page {\\cs16\\super" << endl;
*out << "#{\\footnote \\pard\\plain \\s15 \\f4\\fs20\\lang1031 {\\cs16\\super #}" << name << "}" << endl;
/* create only if the next node exists */
if (next.length ())
{
NodeId = entry.id;
sprintf (Buffer, "%04d", NodeId);
*out << "+{\\footnote \\pard\\plain \\s15 \\f4\\fs20\\lang1031 {\\cs16\\super +}" << Buffer << "}" << endl;
}
/* *out << "${\\footnote \\pard\\plain \\s15 \\f4\\fs20\\lang1031 {\\cs16\\super $}" << name << "}" << endl; */
*out << "}" << endl;
/* #{\footnote \pard\plain \s15 \f4\fs20\lang1031 {\cs16\super #}ThirdThema}
K{\footnote \pard\plain \s15 \f4\fs20\lang1031 {\cs16\super K}entfernen;loeschen;usw}
+{\footnote \pard\plain \s15 \f4\fs20\lang1031 {\cs16\super +}Contents}}
\par Hier wird Loeschen Text definiert.
*/
/*PUT("<A NAME=\"" << name << "\">" << endl);*/
/* PUT(":h" << hlevel << " id=hd" << entry.id << '.' << name
<< endl << ":lm margin=1."); */
}
node_name = name;
node_id = entry.id;
}
void
xref(char *see, String name, String entry, String topic, String file, String manual)
{
if (debug)
cerr << "Refer to name='" << name << "' entry='" << entry
<< "' topic='" << topic << "' file='" << file
<< "' manual='" << manual << "'";
if (see)
PUTS(see);
if (file.empty()) {
if (!table.contains(name)) {
table[name] = Name(++hdid);
if (debug)
cerr << " new id=" << hdid << endl;
} else
if (debug)
cerr << " known id=" << table[name].id << endl;
*out << "{\\strike " << name << "}"
<< "{\\v ";
/* *out << "<A HREF=\"#" << name << "\">";*/
/*PUTS(":link reftype=hd refid=hd" << table[name].id << '.');*/
if (topic.length()) {
/*PUT(topic);*/ *out << topic;
} else
/*PUT(name);*/ *out << name;
if (entry.length())
*out << "<H1>" << entry << "</H1>";
/*PUT(": " << entry);*/
*out << name << "}";
} else
*out << "Section " << topic << " of <H1>" << manual << "</H1>";
/*PUTS("Section " << topic << " of :hp1." << manual << ":ehp1.");*/
}
////////////////////////////////////////////////////////////////////////
static int current_margin = 0;
static void
set_margin(int indent)
{
current_margin = indent;
/*PUTA(":lm margin=" << (1 + current_margin) << '.');*/
}
// > 0: indent
// < 0: extend
// = 0: reset
int
margin(int delta)
{
int old = current_margin;
if (delta) {
current_margin += delta;
if (current_margin < 0)
current_margin = 0;
} else
current_margin = 0;
/*PUTA(":lm margin=" << (1 + current_margin) << '.');*/
return old;
}
void
item_begin(const char *text, int it, char *ic)
{
if (istackp == istack) {
istackp->indent = current_margin;
istackp->nested = 1;
}
++istackp;
istackp->type = it;
istackp->cat = ic;
istackp->beg = Item();
istackp->end = Item();
istackp->indent = current_margin;
switch (it) {
case 'o':
istackp->indent += 3;
break;
case 'u':
istackp->indent += 5;
break;
case 'p':
istackp->indent += 12;
break;
}
istackp->nested = 0;
istackp->count = 0;
for (ItemType *p = istack; p < istackp; ++p)
if (p->type == 'p')
++istackp->nested;
/*PUTL();*/
if (!istackp->nested)
PUT(text);
newpara = 0;
}
void
ItemType::item(const char *text)
{
newpara = 0;
if (debug)
cerr << "ItemType::item (): \"" << text << "\"" << endl;
if (nested) {
set_margin((istackp-1)->indent);
*out << ":p.";
switch (type) {
case 'o':
margin(+1);
*out << ".&larrow.";
margin(+2);
break;
case 'u':
margin(+2);
*out << ++count << '.';
margin(+3);
break;
}
} else if (type == 'p')
*out << ":pt.";
else
*out << "\\par ";
if (text && *text) {
if (beg.fontname)
*out << ":font facename=" << beg.fontname
<< " size=" FontSize ".";
if (beg.hpnumber == 100)
*out << "&sqbul.";
else if (beg.hpnumber)
*out << ":hp" << beg.hpnumber << '.';
if (beg.delimiter)
*out << beg.delimiter;
*out << text << " ";
if (end.delimiter)
*out << end.delimiter;
if (end.hpnumber)
*out << ":ehp" << end.hpnumber << '.';
if (end.fontname)
*out << ":font facename=" << end.fontname
<< " size=" FontSize ".";
}
if (type == 'p') {
if (nested)
margin(+12);
else
*out << ":pd.";
}
}
void
item_end(const char *text)
{
PUTL();
if (istackp->nested)
newpara = 1;
else {
PUT(text);
newpara = 0;
}
--istackp;
set_margin(istackp->indent);
}
////////////////////////////////////////////////////////////////////////
static void
xentry(String& xk, XEntry& xe)
{
PUT(":pt." << xk << endl << ":pd.");
int ne = 0;
for (Pix item = xe.first(); item; xe.next(item)) {
if (ne++)
PUT(".br" << endl);
XItem& xi = xe(item);
PUT(":link reftype=hd refid=hd" << xi.id << '.'
<< xi.title << ":elink." << endl);
}
}
void
indexref(const char *classname, const String& text)
{
indexes[classname].entries[text].add(XItem(panel_name, panel_id));
if (f_index) {
static int id = 0;
PUT(":i1 id=i" << ++id << '.' << text);
PUTL();
}
}
void
printindex(String& classname)
{
XClassT& xc = indexes[classname].entries;
int ckeys[UCHAR_MAX+1], digit = 0, other = 0;
enum { Small, CType, Medium, Huge } mode;
const Limit = 1000;
if (xc.length() >= Limit) {
memset(ckeys, 0, sizeof ckeys);
for (Pix entry = xc.first(); entry; xc.next(entry)) {
unsigned char c = xc.key(entry)[0];
if (isalpha(c))
++ckeys[toupper(c)];
else
++ckeys[c];
}
mode = Medium;
for (int i = 0; i <= UCHAR_MAX; ++i) {
if (ckeys[i] >= Limit) {
mode = Huge;
break;
}
if (isdigit(i))
digit += ckeys[i];
else if (!isalpha(i))
other += ckeys[i];
}
if (mode == Medium && digit < Limit && other < Limit)
mode = CType;
} else
mode = Small;
switch (mode) {
case Huge: {
int count = xc.length();
int chunk = count / 50;
int i = 0;
String *keys = new String [count];
Pix entry;
for (entry = xc.first(); entry; xc.next(entry))
keys[i++] = xc.key(entry).before(' ');
i = 0;
for (entry = xc.first(); entry; xc.next(entry)) {
if (i % chunk == 0) {
if (i)
PUT(":eparml." << endl)
PUT(":h" << hlevel+1 << '.'
<< keys[i]
<< " &dot.&dot.&dot. "
<< keys[min(i+chunk-1, count-1)]
<< endl);
PUT(":parml tsize=50 break=none compact." << endl);
}
xentry(xc.key(entry), xc.contents(entry));
++i;
}
delete [] keys;
}
break;
case Medium: {
unsigned char c0 = 0;
for (Pix entry = xc.first(); entry; xc.next(entry)) {
unsigned char c = toupper(xc.key(entry)[0]);
if (c != c0) {
if (c0)
PUT(":eparml.");
c0 = c;
PUT(":h" << hlevel+1 << '.' << c << endl);
PUT(":parml tsize=50 break=none compact." << endl);
}
xentry(xc.key(entry), xc.contents(entry));
}
}
break;
case CType: {
unsigned char c1, c2 = 0;
for (Pix entry = xc.first(); entry; xc.next(entry)) {
unsigned char c = toupper(xc.key(entry)[0]);
if (!isalpha(c))
continue;
if (c > c2) {
if (c2)
PUT(":eparml." << endl);
c1 = c;
int n = ckeys[c1];
for (c2 = c1; isalpha(c2+1); ++c2) {
n += ckeys[c2+1];
if (n > 100)
break;
}
PUT(":h" << hlevel+1 << '.');
if (c1 != c2)
PUT(c1 << "&dot.&dot.&dot." << c2)
else
PUT(c1);
PUT(endl);
PUT(":parml tsize=50 break=none compact." << endl);
}
xentry(xc.key(entry), xc.contents(entry));
}
if (digit) {
PUT(":eparml." << endl);
PUT(":h" << hlevel+1 << ".0&dot.&dot.&dot.9" << endl);
PUT(":parml tsize=50 break=none compact." << endl);
for (Pix entry = xc.first(); entry; xc.next(entry)) {
unsigned char c = toupper(xc.key(entry)[0]);
if (isdigit(c))
xentry(xc.key(entry), xc.contents(entry));
}
}
if (other) {
PUT(":eparml." << endl);
PUT(":h" << hlevel+1 << ".&dot.&dot.&dot." << endl);
PUT(":parml tsize=50 break=none compact." << endl);
for (Pix entry = xc.first(); entry; xc.next(entry)) {
unsigned char c = toupper(xc.key(entry)[0]);
if (!isalpha(c) && !isdigit(c))
xentry(xc.key(entry), xc.contents(entry));
}
}
}
break;
case Small:
PUT(":parml tsize=50 break=none compact." << endl);
for (Pix entry = xc.first(); entry; xc.next(entry))
xentry(xc.key(entry), xc.contents(entry));
}
PUT(":eparml.");
PUTL();
}
////////////////////////////////////////////////////////////////////////
void
single_word(const char *text)
{
int ipf = 0;
while (*text) {
char c = *text++;
switch (c) {
case ' ':
if (ipf)
break;
PUTS("&rbl.");
continue;
case ':':
case '&':
ipf = 1;
break;
}
PUTS(c);
}
}
////////////////////////////////////////////////////////////////////////
void
para()
{
if (!plevel) {
PUT ("\\par \\par "); /* *out << "<P>"; */
newpara = 0;
}
}
////////////////////////////////////////////////////////////////////////
void
setflag(String& line)
{
/*cerr << "setflag: " << line << endl;*/
int x = line.index(' ');
/*cerr << "setflag: " << x << endl;*/
if (x < 0)
{
x = line.index('=');
}
if (x >= 0)
{
flags[line.before(x)] = line.after(x);
/* cerr << "setflag: before=" << line.before(x) << " after=" << line.after(x) << endl;*/
}
else
flags[line] = "";
}