677 lines
15 KiB
C
677 lines
15 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs 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 Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $XConsortium: lineout.c /main/3 1996/06/19 17:15:55 drk $ */
|
|
/* 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:
|
|
*/
|