/* Copyright (c) Xerox Corporation 1993. All rights reserved. */
/* tioga.c -- Read a tioga file.
David Nichols
December, 1990 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "tioga.h"
#include "tread.h"
extern char *malloc();
#define TRUE 1
#define FALSE 0
#define MAXLEVELS 50 /* max nesting levels */
tioga←FromFile(r, f, procs, data)
struct tread←Reader *r;
FILE *f;
struct tread←Procs *procs;
char *data;
{
struct stat s;
unsigned char *p;
int result;
if (fstat(fileno(f), &s) < 0)
return -1;
p = (unsigned char *) malloc(s.st←size);
if (p == NULL)
return -1;
if (fread(p, 1, s.st←size, f) != s.st←size) {
free(p);
return -1;
}
result = tioga←FromBuffer(r, p, s.st←size, procs, data);
if (r == NULL)
free(p);
return result;
}
tioga←FromBuffer(r, buf, len, procs, data)
struct tread←Reader *r;
unsigned char *buf;
long len;
struct tread←Procs *procs;
char *data;
{
struct tread←Reader myR;
if (r == NULL)
r = &myR;
if (tread←Init(r, buf, len, procs, data) < 0)
return -1;
/* Ok, we're ready to go. */
return DoWork(buf, r);
}
/* Actually do the work. For now, we'll just print out what we see. */
static int DoWork(buf, r)
unsigned char *buf;
struct tread←Reader *r;
{
enum tioga←ControlOp op;
int iFormat, iProp;
int terminalNode = FALSE;
int lastWasTerminal = FALSE;
int level = 0;
int i;
int nRuns;
long length;
long runLen = 0;
long len;
/* main loop */
op = tread←GetOp(r);
for (;;) {
if (terminalTextNodeFirst <= op && op <= terminalTextNodeLast) {
/* Get the format name, then drop down */
iFormat = (int) op - (int) terminalTextNodeFirst;
if (iFormat >= r->nFormats) {
tioga←Error("Illegal format index %d\n", iFormat);
iFormat = 0;
}
terminalNode = TRUE;
}
else if (startNodeFirst <= op && op <= startNodeLast) {
/* Get the format name, then drop down */
iFormat = (int) op - (int) startNodeFirst;
if (iFormat >= r->nFormats) {
tioga←Error("Illegal format index %d\n", iFormat);
iFormat = 0;
}
terminalNode = FALSE;
}
else {
switch (op) {
case endNode:
/* todo */
if (level >= 0)
--level;
else
tioga←Error("Too many endNodes.\n");
(*r->procs->endNode)(r);
op = tread←GetOp(r);
continue;
case startNode:
tread←GetStr(r);
iFormat = tread←AddFormat(r, r->str);
terminalNode = FALSE;
break;
case terminalTextNode:
tread←GetStr(r);
iFormat = tread←AddFormat(r, r->str);
terminalNode = TRUE;
break;
case rope:
case comment:
length = tread←GetInt(r);
/* Get newline, just don't pass it to client. */
tread←SGetRope(r, op == rope ? &r->text : &r->com,
length + 1);
/* convert newlines if should */
FixNewlines(r->str, length + 1);
(*r->procs->insertText)(r, r->str, length, op == comment);
if (runLen != 0 && runLen != length)
tioga←Error("Rope length(%d) doesn't match run length(%d)\n",
length, runLen);
runLen = 0;
/* bump by one */
op = tread←GetOp(r);
continue;
case runs:
nRuns = tread←GetInt(r);
runLen = 0;
for (i = 0; i < nRuns; ++i) {
int rl;
int iLook;
op = tread←GetOp(r);
if (looksFirst <= op && op <= looksLast)
/* Look it up. */
iLook = (int) op - (int) looksFirst;
else if (look1 <= op && op <= look3)
iLook = GetLookChars(r,
(int) op - (int) look1 + 1);
else if (op == looks) {
/* 4 bytes of bit vector */
long l = tread←GetByte(r);
l = (l << 8) | tread←GetByte(r);
l = (l << 8) | tread←GetByte(r);
l = (l << 8) | tread←GetByte(r);
iLook = tread←AddLooks(r, l);
}
if (iLook >= r->nLooks) {
tioga←Error("Look index(%d) too large.\n",
iLook);
iLook = 0;
}
rl = tread←GetInt(r);
(*r->procs->addLooks)(r, r->looks[iLook], runLen, rl);
runLen += rl;
}
op = tread←GetOp(r);
continue;
case prop:
tread←GetStr(r);
iProp = tread←AddProp(r, r->str);
len = tread←GetInt(r);
tread←SGetRope(r, &r->control, len);
(*r->procs->handleProp)(r, r->props[iProp], r->str, len);
op = tread←GetOp(r);
continue;
case propShort:
iProp = tread←GetByte(r);
if (iProp >= r->nProps) {
tioga←Error("Property index(%d) out of range.\n",
iProp);
iProp = 0;
}
len = tread←GetInt(r);
tread←SGetRope(r, &r->control, len);
(*r->procs->handleProp)(r, r->props[iProp], r->str, len);
op = tread←GetOp(r);
continue;
case endOfFile:
if (level == 0)
break; /* top level */
/* Supply missing endNode ops. */
op = endNode;
continue;
case otherNode:
case otherNodeShort:
case otherNodeSpecs:
case otherNodeSpecsShort:
default:
tioga←Error("Illegal op code: %d\n", (int) op);
op = tread←GetOp(r);
continue;
}
}
if (level == 0 && op == endOfFile)
break;
/* If we make it here, then we want to start a new text node. */
if (lastWasTerminal)
(*r->procs->endNode)(r);
lastWasTerminal = terminalNode;
(*r->procs->startNode)(r, r->formats[iFormat]);
if (!terminalNode)
++level;
/* else stayed at same level */
op = tread←GetOp(r);
}
return 0;
}
/* Print, converting newlines. */
static FixNewlines(s, len)
register char *s;
register long len;
{
while (len > 0) {
if (*s == '\r')
*s = '\n';
++s;
--len;
}
}
static long GetLookChars(r, n)
struct tread←Reader *r;
int n;
{
long l = 0;
int c;
/* todo: find out about bit ordering in Mesa */
while (n > 0) {
c = tread←GetByte(r);
if ('a' <= c && c <= 'a' + 31)
l |= 1 << (31 - (c - 'a'));
else
tioga←Error("Illegal look char: %d\n", c);
--n;
}
return tread←AddLooks(r, l);
}
tioga←Error(msg, a1, a2, a3)
char *msg;
{
fprintf(stderr, "Error: ");
fprintf(stderr, msg, a1, a2, a3);
}