/* lineout.c - Implements line-oriented output format. Written by James Clark (jjc@jclark.com). */ #include "config.h" #include "std.h" #include "entity.h" /* Templates for entity control blocks. */ #include "adl.h" /* Definitions for attribute list processing. */ #include "sgmlmain.h" /* Main interface to SGML services. */ #include "lineout.h" #include "appl.h" static VOID flush_data P((void)); static VOID define_external_entity P((PNE)); static VOID define_entity P((UNCH *)); static VOID handle_attributes P((UNCH *, struct ad *)); static VOID handle_token_list P((UNCH *, struct ad *, int)); static VOID handle_single_token P((UNCH *, struct ad *, int)); static VOID output_notation P((UNCH *, UNCH *, UNCH *)); static VOID output_internal_entity P((UNCH *, int, UNCH *)); static VOID output_external_entity P((UNCH *, int, UNIV, UNCH *, UNCH *, UNCH *)); static VOID output_subdoc P((UNCH *, UNIV, UNCH *, UNCH *)); #ifdef SUPPORT_SUBDOC static VOID process_subdoc P((UNCH *, UNIV)); #endif /* SUPPORT_SUBDOC */ static VOID output_record_end P((void)); static VOID output_pcdata P((UNS, UNCH *)); static VOID output_cdata P((UNS, UNCH *)); static VOID output_sdata P((UNS, UNCH *)); static VOID output_entity_reference P((UNCH *)); static VOID output_start_tag P((UNCH *)); static VOID output_end_tag P((UNCH *)); static VOID output_processing_instruction P((UNS, UNCH *)); static VOID output_implied_attribute P((UNCH *, UNCH *)); static char *attribute_type_string P((int)); static VOID output_begin_attribute P((UNCH *, UNCH *, int)); static VOID output_attribute_token P((UNS, UNCH *)); static VOID output_end_attribute P((void)); static VOID print_data P((UNS, UNCH *, int)); static VOID print_string P((UNS, UNCH *, int)); static VOID print_id P((UNIV, UNCH *, UNCH *)); static VOID print_filename P((char *)); static VOID output_location P((void)); static VOID output_appinfo P((UNS, UNCH *)); static int have_data = 0; static char *current_filename = 0; static unsigned long current_lineno = 0; VOID process_document(subdocsw) int subdocsw; { enum sgmlevent rc; struct rcbtag rcbtag; struct rcbdata rcbdaf; while ((rc = sgmlnext(&rcbdaf, &rcbtag)) != SGMLEOD) { #ifdef SUPPORT_SUBDOC if (rc == SGMLDAF && !CONTERSW(rcbdaf) && NDESW(rcbdaf) && NEXTYPE(NEPTR(rcbdaf)) == ESNSUB) { if (!suppsw && !sgmlment(NEENAME(NEPTR(rcbdaf)))) define_external_entity(NEPTR(rcbdaf)); process_subdoc(NEENAME(NEPTR(rcbdaf)) + 1, NEID(NEPTR(rcbdaf))); continue; } #endif /* SUPPORT_SUBDOC */ if (!suppsw) switch (rc) { case SGMLDAF: if (CONTERSW(rcbdaf)) break; if (CDESW(rcbdaf)) output_cdata(CDATALEN(rcbdaf), CDATA(rcbdaf)); else if (SDESW(rcbdaf)) output_sdata(CDATALEN(rcbdaf), CDATA(rcbdaf)); else if (NDESW(rcbdaf)) { assert(NEXTYPE(NEPTR(rcbdaf)) != ESNSUB); if (!sgmlment(NEENAME(NEPTR(rcbdaf)))) define_external_entity(NEPTR(rcbdaf)); output_entity_reference(NEENAME(NEPTR(rcbdaf)) + 1); } else output_pcdata(CDATALEN(rcbdaf), CDATA(rcbdaf)); break; case SGMLSTG: if (CONTERSW(rcbtag)) break; if (ALPTR(rcbtag)) handle_attributes((UNCH *)NULL, ALPTR(rcbtag)); output_start_tag(CURGI(rcbtag)); break; case SGMLETG: if (CONTERSW(rcbtag)) break; output_end_tag(CURGI(rcbtag)); break; case SGMLPIS: if (CONTERSW(rcbdaf)) break; output_processing_instruction(PDATALEN(rcbdaf), PDATA(rcbdaf)); break; case SGMLREF: if (CONTERSW(rcbdaf)) break; output_record_end(); break; case SGMLAPP: if (CONTERSW(rcbdaf)) break; if (!subdocsw) output_appinfo(ADATALEN(rcbdaf), ADATA(rcbdaf)); break; default: abort(); } } } /* Output an indication that the document was conforming. */ VOID output_conforming() { if (!suppsw) printf("%c\n", CONFORMING_CODE); } static VOID define_external_entity(p) PNE p; { if (NEXTYPE(p) == ESNSUB) output_subdoc(NEENAME(p) + 1, NEID(p), NEPUBID(p), NESYSID(p)); else { if (!NEDCNMARK(p)) output_notation(NEDCN(p) + 1, NEDCNPUBID(p), NEDCNSYSID(p)); output_external_entity(NEENAME(p) + 1, NEXTYPE(p), NEID(p), NEPUBID(p), NESYSID(p), NEDCN(p) + 1); if (NEAL(p)) handle_attributes(NEENAME(p) + 1, NEAL(p)); } } static VOID define_entity(ename) UNCH *ename; { int rc; PNE np; UNCH *tp; if (sgmlment(ename)) /* already defined it */ return; rc = sgmlgent(ename, &np, &tp); switch (rc) { case 1: define_external_entity(np); break; case 2: case 3: output_internal_entity(ename + 1, rc == 3, tp); break; } } /* ENT is the name of the entity with which these attributes are associated; if it's NULL, they're associated with the next start tag. */ static VOID handle_attributes(ent, al) UNCH *ent; struct ad *al; { int aln; for (aln = 1; aln <= ADN(al); aln++) { if (GET(ADFLAGS(al, aln), AERROR)) ; else if (GET(ADFLAGS(al, aln), AINVALID)) ; else if (ADVAL(al, aln) == NULL) output_implied_attribute(ent, ADNAME(al, aln)); else if (ADTYPE(al, aln) >= ATKNLIST) handle_token_list(ent, al, aln); else handle_single_token(ent, al, aln); if (BITON(ADFLAGS(al, aln), AGROUP)) aln += ADNUM(al, aln); } } static VOID handle_token_list(ent, al, aln) UNCH *ent; struct ad *al; int aln; { UNCH *ptr; int i; if (ADTYPE(al, aln) == AENTITYS) { ptr = ADVAL(al, aln); for (i = 0; i < ADNUM(al, aln); i++) { /* Temporarily make token look like normal name with length and EOS. */ UNCH c = ptr[*ptr + 1]; ptr[*ptr + 1] = '\0'; *ptr += 2; define_entity(ptr); *ptr -= 2; ptr += *ptr + 1; *ptr = c; } } output_begin_attribute(ent, ADNAME(al, aln), ADTYPE(al, aln)); ptr = ADVAL(al, aln); for (i = 0; i < ADNUM(al, aln); i++) { /* The first byte is a length NOT including the length byte; the tokens are not EOS terminated. */ output_attribute_token(*ptr, ptr + 1); ptr += *ptr + 1; } output_end_attribute(); } static VOID handle_single_token(ent, al, aln) UNCH *ent; struct ad *al; int aln; { if (ADTYPE(al, aln) == ANOTEGRP && !DCNMARK(ADDATA(al, aln).x)) output_notation(ADVAL(al, aln) + 1, ADDATA(al, aln).x->pubid, ADDATA(al, aln).x->sysid); else if (ADTYPE(al, aln) == AENTITY) define_entity(ADVAL(al, aln)); output_begin_attribute(ent, ADNAME(al, aln), ADTYPE(al, aln)); if (ADTYPE(al, aln) == ACHARS) output_attribute_token(ustrlen(ADVAL(al, aln)), ADVAL(al, aln)); else output_attribute_token(*ADVAL(al, aln) - 2, ADVAL(al, aln) + 1); output_end_attribute(); } static VOID output_notation(name, pubid, sysid) UNCH *name; UNCH *pubid, *sysid; { flush_data(); print_id((UNIV)0, pubid, sysid); printf("%c%s\n", DEFINE_NOTATION_CODE, name); } static VOID output_internal_entity(ename, is_sdata, text) UNCH *ename; int is_sdata; UNCH *text; { flush_data(); printf("%c%s %s ", DEFINE_INTERNAL_ENTITY_CODE, ename, is_sdata ? "SDATA" : "CDATA"); print_string(text ? ustrlen(text) : 0, text, 0); putchar('\n'); } static VOID output_subdoc(nm, id, pubid, sysid) UNCH *nm; UNIV id; UNCH *pubid, *sysid; { flush_data(); print_id(id, pubid, sysid); printf("%c%s\n", DEFINE_SUBDOC_ENTITY_CODE, nm); } #ifdef SUPPORT_SUBDOC static VOID process_subdoc(nm, id) UNCH *nm; UNIV id; { if (!suppsw) { flush_data(); output_location(); printf("%c%s\n", START_SUBDOC_CODE, nm); fflush(stdout); } fflush(stderr); if (id) { char **argv; int ret; argv = make_argv(id); ret = run_process(argv); if (ret != 0) suberr++; current_filename = 0; free(argv); if (ret == 0) get_subcaps(); } else { suberr++; appl_error(E_SUBDOC, nm); } if (!suppsw) printf("%c%s\n", END_SUBDOC_CODE, nm); } #endif /* SUPPORT_SUBDOC */ static VOID output_external_entity(nm, xtype, id, pubid, sysid, dcn) UNCH *nm, *dcn; UNIV id; UNCH *pubid, *sysid; int xtype; { char *type; flush_data(); print_id(id, pubid, sysid); switch (xtype) { case ESNCDATA: type = "CDATA"; break; case ESNNDATA: type = "NDATA"; break; case ESNSDATA: type = "SDATA"; break; default: return; } printf("%c%s %s %s\n", DEFINE_EXTERNAL_ENTITY_CODE, nm, type, dcn); } static VOID output_record_end() { static UNCH re = RECHAR; print_data(1, &re, 0); } static VOID output_pcdata(n, s) UNS n; UNCH *s; { print_data(n, s, 0); } static VOID output_cdata(n, s) UNS n; UNCH *s; { print_data(n, s, 0); } static VOID output_sdata(n, s) UNS n; UNCH *s; { print_data(n, s, 1); } static VOID output_entity_reference(s) UNCH *s; { flush_data(); output_location(); printf("%c%s\n", REFERENCE_ENTITY_CODE, s); } static VOID output_start_tag(s) UNCH *s; { flush_data(); output_location(); printf("%c%s\n", START_CODE, s); } static VOID output_end_tag(s) UNCH *s; { flush_data(); printf("%c%s\n", END_CODE, s); } static VOID output_processing_instruction(n, s) UNS n; UNCH *s; { flush_data(); output_location(); putchar(PI_CODE); print_string(n, s, 0); putchar('\n'); } static VOID output_appinfo(n, s) UNS n; UNCH *s; { flush_data(); output_location(); putchar(APPINFO_CODE); print_string(n, s, 0); putchar('\n'); } static VOID output_implied_attribute(ent, aname) UNCH *ent, *aname; { flush_data(); if (ent) printf("%c%s %s IMPLIED\n", DATA_ATTRIBUTE_CODE, ent, aname); else printf("%c%s IMPLIED\n", ATTRIBUTE_CODE, aname); } static char *attribute_type_string(type) int type; { switch (type) { case ANMTGRP: case ANAME: case ANMTOKE: case ANUTOKE: case ANUMBER: case ANAMES: case ANMTOKES: case ANUTOKES: case ANUMBERS: case AID: case AIDREF: case AIDREFS: return "TOKEN"; case ANOTEGRP: return "NOTATION"; case ACHARS: return "CDATA"; case AENTITY: case AENTITYS: return "ENTITY"; } #if 0 fatal("invalid attribute type %d", type); #endif return "INVALID"; } static VOID output_begin_attribute(ent, aname, type) UNCH *ent, *aname; int type; { flush_data(); if (ent) printf("%c%s %s %s", DATA_ATTRIBUTE_CODE, ent, aname, attribute_type_string(type)); else printf("%c%s %s", ATTRIBUTE_CODE, aname, attribute_type_string(type)); } static VOID output_attribute_token(vallen, val) UNS vallen; UNCH *val; { putchar(' '); print_string(vallen, val, 0); } static VOID output_end_attribute() { putchar('\n'); } static VOID print_data(n, s, is_sdata) UNS n; UNCH *s; int is_sdata; { if (n > 0 || is_sdata) { if (n == 1 && *s == RECHAR) current_lineno++; else output_location(); if (!have_data) putchar(DATA_CODE); print_string(n, s, is_sdata); have_data = 1; } } static VOID flush_data() { if (have_data) { putchar('\n'); have_data = 0; } } static VOID output_location() { char *filename; unsigned long lineno; int filename_changed = 0; if (!locsw) return; if (!sgmlloc(&lineno, &filename)) return; if (!current_filename || strcmp(filename, current_filename) != 0) filename_changed = 1; else if (lineno == current_lineno) return; flush_data(); printf("%c%lu", LOCATION_CODE, lineno); current_lineno = lineno; if (filename_changed) { putchar(' '); print_filename(filename); current_filename = filename; } putchar('\n'); } static VOID print_string(slen, s, is_sdata) UNS slen; UNCH *s; int is_sdata; { if (is_sdata) fputs("\\|", stdout); while (slen > 0) { UNCH ch = *s++; slen--; if (ch == DELSDATA) { if (is_sdata) ; /* I don't think this should happen */ else fputs("\\|", stdout); ; } else if (ch == DELCDATA) ; else { if (ch == DELNONCH) { if (!slen) break; ch = UNSHIFTNON(*s); s++; slen--; } switch (ch) { case RECHAR: fputs("\\n", stdout); break; case '\\': fputs("\\\\", stdout); break; default: if (ISASCII(ch) && isprint(ch)) putchar(ch); else printf("\\%03o", ch); break; } } } if (is_sdata) fputs("\\|", stdout); } static VOID print_id(id, pubid, sysid) UNIV id; UNCH *pubid; UNCH *sysid; { if (pubid) { putchar(PUBID_CODE); print_string(ustrlen(pubid), pubid, 0); putchar('\n'); } if (sysid) { putchar(SYSID_CODE); print_string(ustrlen(sysid), sysid, 0); putchar('\n'); } if (id) { char *p; for (p = id; *p != '\0'; p++) { putchar(FILE_CODE); do { switch (*p) { case '\\': fputs("\\\\", stdout); break; case '\n': fputs("\\n", stdout); break; default: if (ISASCII(*p) && isprint((UNCH)*p)) putchar(*p); else printf("\\%03o", (UNCH)*p); break; } } while (*++p); putchar('\n'); } } } static VOID print_filename(s) char *s; { for (; *s; s++) switch (*s) { case '\\': fputs("\\\\", stdout); break; case '\n': fputs("\\n", stdout); break; default: if (ISASCII(*s) && isprint((UNCH)*s)) putchar(*s); else printf("\\%03o", (UNCH)*s); break; } } /* Local Variables: c-indent-level: 5 c-continued-statement-offset: 5 c-brace-offset: -5 c-argdecl-indent: 0 c-label-offset: -5 End: */