/* Copyright (c) Xerox Corporation 1993. All rights reserved. */ /* tioga.c -- Read a tioga file. David Nichols December, 1990 */ #include #include #include #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); }