521 lines
11 KiB
C
521 lines
11 KiB
C
/* $Id$
|
|
|
|
Part of SWI-Prolog
|
|
|
|
Author: Jan Wielemaker
|
|
E-mail: jan@swi.psy.uva.nl
|
|
WWW: http://www.swi-prolog.org
|
|
Copyright (C): 1985-2002, University of Amsterdam
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it 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 this library; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#define _ISOC99_SOURCE 1 /* fwprintf(), etc prototypes */
|
|
#include <stdio.h>
|
|
#include <wchar.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <wctype.h>
|
|
#include <time.h>
|
|
#include "dtd.h"
|
|
#include "util.h"
|
|
#include "prolog.h"
|
|
|
|
static int errors;
|
|
|
|
/*******************************
|
|
* PROLOG SYNTAX *
|
|
*******************************/
|
|
|
|
typedef enum
|
|
{ AT_LOWER,
|
|
AT_QUOTE,
|
|
AT_FULLSTOP,
|
|
AT_SYMBOL,
|
|
AT_SOLO,
|
|
AT_SPECIAL
|
|
} atomtype;
|
|
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
Contributed by Richard O'Keefe. Thanks!
|
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
static int
|
|
atomType(ichar const *s, int len)
|
|
{ static ichar const symbols[] = L"#$&*+-./:<=>?@\\^`~";
|
|
unsigned char const *u = (unsigned char const *)s;
|
|
|
|
switch (len)
|
|
{ case 0:
|
|
return AT_QUOTE;
|
|
case 1:
|
|
return iswlower(u[0]) ? AT_LOWER
|
|
: u[0] == '.' ? AT_FULLSTOP
|
|
: u[0] == '!' ? AT_SOLO
|
|
: u[0] == ';' ? AT_SOLO
|
|
: u[0] == ',' ? AT_SOLO
|
|
: AT_QUOTE;
|
|
case 2:
|
|
if (u[0] == '[' && u[1] == ']') return AT_SPECIAL;
|
|
if (u[0] == '{' && u[1] == '}') return AT_SPECIAL;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (iswlower(u[0]))
|
|
{ do ++u; while (--len > 0 && (iswalnum(*u) || *u == '_'));
|
|
return len == 0 ? AT_LOWER : AT_QUOTE;
|
|
} else if (wcschr(symbols, *u) != NULL)
|
|
{ do ++u; while (--len > 0 && wcschr(symbols, *u) != 0);
|
|
return len == 0 ? AT_SYMBOL : AT_QUOTE;
|
|
} else
|
|
{ return AT_QUOTE;
|
|
}
|
|
}
|
|
|
|
|
|
static const ichar *
|
|
atom(const ichar *text)
|
|
{ int len = wcslen(text);
|
|
|
|
switch(atomType(text, len))
|
|
{ case AT_QUOTE:
|
|
case AT_FULLSTOP:
|
|
{ ichar *tmp = ringallo((len*2+1)*sizeof(ichar));
|
|
ichar *o = tmp;
|
|
|
|
*o++ = '\'';
|
|
for( ; --len >= 0; text++)
|
|
{ switch( *text )
|
|
{ case '\n':
|
|
*o++ = '\\';
|
|
*o++ = 'n';
|
|
break;
|
|
case '\r':
|
|
*o++ = '\\';
|
|
*o++ = 'r';
|
|
break;
|
|
case '\t':
|
|
*o++ = '\\';
|
|
*o++ = 't';
|
|
break;
|
|
case '\'':
|
|
*o++ = '\\';
|
|
default:
|
|
*o++ = *text;
|
|
}
|
|
}
|
|
*o++ = '\'';
|
|
*o = '\0';
|
|
|
|
return tmp;
|
|
}
|
|
default:
|
|
return text;
|
|
}
|
|
}
|
|
|
|
|
|
static const char *
|
|
bool(int val)
|
|
{ return val ? "true" : "false";
|
|
}
|
|
|
|
|
|
static void
|
|
prolog_print_entity(const char *which, dtd_entity *e)
|
|
{ switch( e->type )
|
|
{ case ET_LITERAL:
|
|
wprintf(L"%s(%ls, %ls).\n",
|
|
which,
|
|
atom(e->name->name),
|
|
atom(e->value));
|
|
break;
|
|
case ET_SYSTEM:
|
|
wprintf(L"%s(%ls, system(%ls)).\n",
|
|
which,
|
|
atom(e->name->name),
|
|
atom(e->exturl));
|
|
break;
|
|
case ET_PUBLIC:
|
|
wprintf(L"%s(%ls, public(%ls, %ls)).\n",
|
|
which,
|
|
atom(e->name->name),
|
|
atom(e->extid),
|
|
atom(e->exturl));
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
prolog_print_model(dtd_model *m)
|
|
{ dtd_model *sub;
|
|
int n = 0;
|
|
const char *sep;
|
|
|
|
switch(m->type)
|
|
{ case MT_PCDATA:
|
|
printf("'#pcdata'");
|
|
goto card;
|
|
case MT_ELEMENT:
|
|
wprintf(L"%ls", atom(m->content.element->name->name));
|
|
goto card;
|
|
case MT_AND:
|
|
sep = " & ";
|
|
break;
|
|
case MT_SEQ:
|
|
sep = ", ";
|
|
break;
|
|
case MT_OR:
|
|
sep = "|";
|
|
break;
|
|
case MT_UNDEF:
|
|
default:
|
|
assert(0);
|
|
sep = NULL; /* should not be used */
|
|
break;
|
|
}
|
|
|
|
printf("(");
|
|
for(sub = m->content.group; sub; sub=sub->next)
|
|
{ if ( n++ > 0 )
|
|
printf("%s", sep);
|
|
prolog_print_model(sub);
|
|
}
|
|
printf(")");
|
|
|
|
card:
|
|
switch(m->cardinality)
|
|
{ case MC_ONE:
|
|
break;
|
|
case MC_OPT:
|
|
printf("?");
|
|
break;
|
|
case MC_REP:
|
|
printf("*");
|
|
break;
|
|
case MC_PLUS:
|
|
printf("+");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
prolog_print_content(dtd_element *e)
|
|
{ dtd_edef *def = e->structure;
|
|
|
|
switch( def->type )
|
|
{ case C_EMPTY:
|
|
printf("empty");
|
|
break;
|
|
case C_CDATA:
|
|
printf("cdata");
|
|
break;
|
|
case C_RCDATA:
|
|
printf("rcdata");
|
|
break;
|
|
case C_ANY:
|
|
printf("any");
|
|
break;
|
|
default:
|
|
if ( def->content )
|
|
{ printf("model(");
|
|
prolog_print_model(def->content);
|
|
printf(")");
|
|
} else
|
|
{ printf("[]");
|
|
fwprintf(stderr,
|
|
L"Warning: element %s has no content model\n",
|
|
e->name->name);
|
|
errors++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static ichar *
|
|
istrblank(const ichar *s)
|
|
{ for( ; *s; s++ )
|
|
{ if ( iswspace(*s) )
|
|
return (ichar *)s;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
print_listval(attrtype type, int len, const ichar *text)
|
|
{ ichar *t = sgml_malloc((len+1)*sizeof(ichar));
|
|
|
|
istrncpy(t, text, len);
|
|
t[len] = '\0';
|
|
|
|
if ( type == AT_NUMBERS )
|
|
wprintf(L"%ls", t);
|
|
else
|
|
wprintf(L"%ls", atom(t));
|
|
|
|
sgml_free(t);
|
|
}
|
|
|
|
|
|
static void
|
|
prolog_print_attribute(dtd_element *e, dtd_attr *at)
|
|
{ wprintf(L" attribute(%ls, %ls, ",
|
|
atom(e->name->name), atom(at->name->name));
|
|
|
|
switch(at->type) /* print type */
|
|
{ case AT_CDATA:
|
|
printf("cdata");
|
|
break;
|
|
case AT_ENTITY:
|
|
printf("entity");
|
|
break;
|
|
case AT_ENTITIES:
|
|
printf("entities");
|
|
break;
|
|
case AT_ID:
|
|
printf("id");
|
|
break;
|
|
case AT_IDREF:
|
|
printf("idref");
|
|
break;
|
|
case AT_IDREFS:
|
|
printf("list(idref)");
|
|
break;
|
|
case AT_NAME:
|
|
printf("name");
|
|
break;
|
|
case AT_NAMES:
|
|
printf("list(name)");
|
|
break;
|
|
case AT_NMTOKEN:
|
|
printf("nmtoken");
|
|
break;
|
|
case AT_NMTOKENS:
|
|
printf("list(nmtoken)");
|
|
break;
|
|
case AT_NOTATION:
|
|
printf("notation");
|
|
break;
|
|
case AT_NUMBER:
|
|
printf("number");
|
|
break;
|
|
case AT_NUMBERS:
|
|
printf("list(number)");
|
|
break;
|
|
case AT_NAMEOF:
|
|
{ dtd_name_list *nl;
|
|
int n = 0;
|
|
|
|
printf("nameof([");
|
|
for(nl = at->typeex.nameof; nl; nl = nl->next)
|
|
{ if ( n++ > 0 )
|
|
printf(", ");
|
|
wprintf(L"%ls", atom(nl->value->name));
|
|
}
|
|
printf("])");
|
|
}
|
|
break;
|
|
case AT_NUTOKEN:
|
|
printf("nutoken");
|
|
break;
|
|
case AT_NUTOKENS:
|
|
printf("list(nutoken)");
|
|
break;
|
|
}
|
|
|
|
printf(", "); /* print default */
|
|
switch(at->def)
|
|
{ case AT_REQUIRED:
|
|
printf("required");
|
|
break;
|
|
case AT_CURRENT:
|
|
printf("current");
|
|
break;
|
|
case AT_CONREF:
|
|
printf("conref");
|
|
break;
|
|
case AT_IMPLIED:
|
|
printf("implied");
|
|
break;
|
|
case AT_DEFAULT:
|
|
case AT_FIXED:
|
|
{ char *f = (at->def == AT_DEFAULT ? "default" : "fixed");
|
|
|
|
printf("%s(", f);
|
|
|
|
switch( at->type )
|
|
{ case AT_CDATA:
|
|
wprintf(L"%ls", atom(at->att_def.cdata));
|
|
break;
|
|
case AT_NUMBER:
|
|
printf("%ld", at->att_def.number);
|
|
break;
|
|
case AT_NAME:
|
|
case AT_NUTOKEN:
|
|
case AT_NMTOKEN:
|
|
wprintf(L"%ls", atom(at->att_def.name->name));
|
|
break;
|
|
default:
|
|
if ( at->islist )
|
|
{ const ichar *val = at->att_def.list;
|
|
const ichar *e;
|
|
int an = 0;
|
|
|
|
printf("[");
|
|
for(e=istrblank(val); e; val = e+1, e=istrblank(val))
|
|
{ if ( e == val )
|
|
continue; /* skip spaces */
|
|
if ( an++ > 0 )
|
|
printf(", ");
|
|
print_listval(at->type, e-val, val);
|
|
}
|
|
if ( an++ > 0 )
|
|
printf(", ");
|
|
print_listval(at->type, istrlen(val), val);
|
|
printf("]");
|
|
break;
|
|
}
|
|
assert(0);
|
|
}
|
|
|
|
printf(")");
|
|
}
|
|
}
|
|
|
|
printf(").\n");
|
|
}
|
|
|
|
|
|
static void
|
|
prolog_print_element(dtd_element *e, unsigned int flags)
|
|
{ ichar nbuf[MAXNMLEN];
|
|
|
|
istrcpy(nbuf, e->name->name);
|
|
istrupper(nbuf);
|
|
|
|
wprintf(L"\n%% Element <%s>\n", nbuf);
|
|
|
|
if ( e->structure )
|
|
{ dtd_edef *def = e->structure;
|
|
|
|
wprintf(L"element(%ls, omit(%s, %s), ",
|
|
atom(e->name->name),
|
|
bool(def->omit_open),
|
|
bool(def->omit_close));
|
|
prolog_print_content(e);
|
|
printf(").\n");
|
|
|
|
if ( def->excluded )
|
|
{ dtd_element_list *el;
|
|
|
|
for(el = def->excluded; el; el=el->next)
|
|
wprintf(L"exclude(%ls, %ls).\n",
|
|
atom(e->name->name),
|
|
atom(el->value->name->name));
|
|
}
|
|
if ( def->included )
|
|
{ dtd_element_list *el;
|
|
|
|
for(el = def->included; el; el=el->next)
|
|
wprintf(L"include(%ls, %ls).\n",
|
|
atom(e->name->name),
|
|
atom(el->value->name->name));
|
|
}
|
|
|
|
if ( flags & PL_PRINT_ATTRIBUTES )
|
|
{ dtd_attr_list *al;
|
|
|
|
for(al=e->attributes; al; al=al->next)
|
|
prolog_print_attribute(e, al->attribute);
|
|
}
|
|
} else
|
|
{ fwprintf(stderr, L"Warning: element %s has no definition\n",
|
|
e->name->name);
|
|
errors++;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
prolog_print_dtd(dtd *dtd, unsigned int flags)
|
|
{ dtd_entity *et;
|
|
dtd_element *e;
|
|
time_t now;
|
|
|
|
if ( !dtd->doctype )
|
|
fprintf(stderr, "DTD has no document type\n");
|
|
|
|
time(&now);
|
|
|
|
if ( !flags )
|
|
flags = PL_PRINT_ALL;
|
|
|
|
errors = 0;
|
|
|
|
wprintf(L"/* This file represents the SGML DOCTYPE \"%s\"\n", dtd->doctype);
|
|
printf(" converted using dtd2pl version %s\n", DTD2PL_VERSION);
|
|
printf(" Conversion date: %s\n\n", ctime(&now));
|
|
printf(" dtd2pl is written by Jan Wielemaker\n");
|
|
printf(" E-mail: jan@swi.psy.uva.nl\n");
|
|
printf("*/\n\n");
|
|
|
|
wprintf(L":- module(%s_dtd, []).\n\n", dtd->doctype);
|
|
printf(":- op(100, xf, ?).\n");
|
|
printf(":- op(100, xf, +).\n");
|
|
printf(":- op(100, xf, *).\n");
|
|
printf(":- op(200, xfy, &).\n");
|
|
|
|
printf("\n");
|
|
printf(":- discontiguous\n");
|
|
printf("\tattribute/4,\n");
|
|
printf("\telement/3,\n");
|
|
printf("\texclude/2,\n");
|
|
printf("\tinclude/2.\n");
|
|
|
|
if ( flags & PL_PRINT_PENTITIES )
|
|
{ printf("\n");
|
|
for( et=dtd->pentities; et; et=et->next )
|
|
prolog_print_entity("parameter_entity", et);
|
|
}
|
|
|
|
if ( flags & PL_PRINT_ENTITIES )
|
|
{ printf("\n");
|
|
for( et=dtd->entities; et; et=et->next )
|
|
prolog_print_entity("entity", et);
|
|
}
|
|
|
|
if ( flags & PL_PRINT_ELEMENTS )
|
|
{ printf("\n");
|
|
for( e=dtd->elements; e; e=e->next )
|
|
prolog_print_element(e, flags);
|
|
}
|
|
|
|
if ( errors )
|
|
{ fprintf(stderr, "Warning: DTD contained %d errors\n", errors);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|