1 
2 /* Map in a .ddb file and provide access to the information there */
3 
4 #include <stdio.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <time.h>
8 
9 #include "nsl-defs.h"
10 #include "lt-comment.h"
11 #include "readddb.h"
12 #include "lt-rhash.h"
13 #include "lt-safe.h"
14 #include "string16.h"
15 
16 static boolean ShowElement(RHTEntry*,const Char*,void*);
17 static boolean ShowEntity(RHTEntry*,const Char*,void*);
18 static boolean putqs(const Char*);
19 
20 const char8* ContentType[]={ "mixedGroup", "any", "cdata",
21 			"rcdata", "empty", "elementOnlyGroup" };
22 const char8* DeclaredValue[]={ "cdata", "name", "number", "nmtoken", "nutoken",
23 			"entity", "idref", "names", "numbers", "nmtokens",
24 			"nutokens", "entities", "idrefs", "id", "notation",
25 			"nameTokenGroup" };
26 const char8* DefaultValueType[]={ "required", "current", "implied", "conref",
27 			   "defaulted", "fixed" };
28 const char8* DeclType[]={ "", "% ", "{dkt}", "{lkt}" };
29 const char8* DataType[]={ "sgmlText", "pi", "cdata",
30 			 "sdata", "ndata", "subdoc" };
31 const char8* DefType[]={ "internal", "unresolved system",
32 		  "unresolved public", "resolved" };
33 
34 /* readddb(filename): Read a DDB file and return its contents as a
35    pointer to a DDBHeader */
36 
readddb(const char8 * filename)37 DDBHeader* readddb(const char8* filename) {
38   int length;
39   DDBHeader* ddb;
40   ECNN(ddb=(DDBHeader*)mmapfile(filename,&length));
41   if (ddb->cookie==CookieVal) {
42     return ddb;
43   } else if ((ddb->cookie & 0xffffff00)==(CookieVal & 0xffffff00)) {
44     LT_ERROR1(LEDDB, "%s is an old incompatible .ddb file --\n"
45 		        "remake it (e.g. by deleting and re-running mknsg) "
46 		        "and try again\n",filename);
47     return NULL;
48   } else if ((ddb->cookie & 0xffff0000)==(CookieVal & 0xffff0000)) {
49     LT_ERROR1(LEDDB,"%s is a .ddb file built with the wrong CHAR_SIZE --\n"
50 		       "remake it (e.g. by deleting and re-running mknsg) "
51 		       "and try again\n",filename);
52     return NULL;
53   } else if(((ddb->cookie >> 24) & 0xff) == (CookieVal & 0xff) &&
54 	    ((ddb->cookie >> 16) & 0xff) == ((CookieVal >> 8) & 0xff))
55   {
56     LT_ERROR1(LEDDB,"%s is a ddb file with the wrong byte order --\n"
57 		       "remake it (e.g. by deleting and re-running mknsg) "
58 		       "and try again\n",filename);
59     return NULL;
60   } else {
61     LT_ERROR1(LEDDB,
62 	   "%s is not a .ddb file\n",
63 	   filename);
64     return NULL;
65   }
66 }
67 
68 /* Print a DDBHeader structure to stdout in a human readable format */
69 
showddb(const DDBHeader * ddb)70 boolean showddb(const DDBHeader* ddb) {
71   RHashTableHdr *eltHdr,*entHdr;
72   char *eltBase,*entBase;
73   char *sBase=(char*)ddb;
74   ECEF(sFprintf(Stdout,"DDB file for %s dumped at %s",
75 	       sBase+(ddb->sourceFileNameOffset),
76 	       ctime( &ddb->timestamp)));
77   ECEF(sFprintf(Stdout,"   DTD: %S, based on %s.\n",
78 	       sBase+sizeof(DDBHeader),
79 	       (ddb->dtdFileNameOffset)?sBase+(ddb->dtdFileNameOffset):"<no external dtd file>"));
80   eltHdr=(RHashTableHdr*)(sBase+(ddb->elementTableOffset));
81   eltBase=((char*)eltHdr)+eltHdr->length;
82   ECFF(rmaphash(ShowElement,eltHdr,(void*)eltBase));
83   if (ddb->entityTableOffset) {
84     entHdr=(RHashTableHdr*)(sBase+(ddb->entityTableOffset));
85     entBase=((char*)entHdr)+entHdr->length;
86     ECFF(rmaphash(ShowEntity,entHdr,(void*)entBase));
87   }
88   return TRUE;
89 }
90 
91 /* Internal function (of showddb) to display SGML element definitions */
92 
ShowElement(RHTEntry * entry,const Char * key,void * eltBase)93 boolean ShowElement(RHTEntry* entry,const Char* key,void *eltBase) {
94   int i,nAttr,j,prefix;
95   AttributeSummary* attrBase;
96   Char *lab;
97 
98   NSL_ElementSummary_I* eltSum=(NSL_ElementSummary_I*)(((char*)eltBase)
99 						       +entry->eval);
100 
101   ECEF(sFprintf(Stdout, "<!ELEMENT %S %s %s %s>\n",
102 	       key,
103 	       eltSum->omitStart?"o":"-",
104 	       eltSum->omitEnd?"o":"-",
105 	       ContentType[(int)(eltSum->contentType)]));
106   if ((nAttr=eltSum->numAttr)) {
107     prefix=11+Strlen(key);
108     ECEF(sFprintf(Stdout,"<!ATTLIST %S ",key));
109     attrBase=(AttributeSummary*)(eltSum+1);
110     for (i=0;i<nAttr;i++) {
111       int n, declaredValue = (int)(attrBase[i].declaredValue);
112       Char *avp;
113       ECEF(sFprintf(Stdout, "%S %s",
114 		   (lab=(Char*)&attrBase[i])+attrBase[i].namePtr,
115 		   DeclaredValue[declaredValue]));
116       if( (n=(int)attrBase[i].numAV) ){
117 	/* If this attribute is an enumeration type then */
118 	/* print out the allowed values                  */
119 	avp=lab+attrBase[i].allowedValuesPtr;
120 	ECEF(sFprintf(Stdout,":("));
121 	ECEF(sFprintf(Stdout,"%S",avp));
122 	while( --n > 0 ){
123 	  avp = avp + Strlen(avp) + 1 ;
124 	  ECEF(sFprintf(Stdout,"|%S",avp));
125 	}
126 	ECEF(sFprintf(Stdout,")"));
127       }
128       ECEF(sFprintf(Stdout, " %s",
129 		    DefaultValueType[(int)(attrBase[i].defaultValueType)]));
130       if (attrBase[i].defaultPtr) {
131 	ECEF(sFprintf(Stdout,":%S",
132 		     lab+attrBase[i].defaultPtr));
133       }
134       if ((i+1)<nAttr) {
135 	ECEF(sPutc('\n', Stdout));
136 	for (j=0;j<prefix;j++) {
137 	  ECEF(sPutc(' ', Stdout));
138 	}
139       }
140     }
141     ECEF(sFprintf(Stdout,">\n"));
142   }
143   return TRUE;
144 }
145 
146 /* Internal function (of showddb) to display SGML entity definitions */
147 
ShowEntity(RHTEntry * entry,const Char * key,void * entBase)148 boolean ShowEntity(RHTEntry* entry,const Char* key, void *entBase) {
149 
150   /* note we never see parameter entities, as they're not dumped,
151      because they're not public */
152 
153   EntitySummary* entSum=(EntitySummary*)(((char*)entBase)+entry->eval);
154 
155   ECEF(sFprintf(Stdout,"<!ENTITY %s%S %s:(%s)",
156 	       DeclType[(int)(entSum->declType)],
157 	       (Char*)key,
158 	       DataType[(int)(entSum->dataType)],
159 	       DefType[(int)(entSum->defType)]));
160   ECFF(putqs((Char*)(entSum+1)));
161   ECEF(sFprintf(Stdout,">\n"));
162   return TRUE;
163 }
164 
165 /* Internal function (of ShowEntity) to display SGML element definitions
166    Prints (to stdout) a properly quoted version of the input string */
167 
putqs(const Char * str)168 boolean putqs(const Char* str) {
169   int i,len;
170   if (Strchr(str,'\'')) {
171     if (Strchr(str,'"')) {
172       ECEF(sPutc('\'', Stdout));
173       len=Strlen(str);
174       for (i=0;i<len;i++) {
175 	if (str[i]=='\'') {
176 	  ECEF(sFprintf(Stdout,"&dq;"));
177 	}
178 	else {
179 	  ECEF(sPutc(str[i], Stdout));
180 	}
181       }
182       ECEF(sPutc('\'', Stdout));
183     }
184     else {
185       ECEF(sFprintf(Stdout,"\"%S\"",str));
186     }
187   }
188   else {
189     ECEF(sFprintf(Stdout,"\'%S\'",str));
190   }
191   return TRUE;
192 }
193 
194 /* New function which checks that any external DTD files referred to
195    by DDB file have not been changed later than the DDB file.
196    Returns FALSE if ddbFile is older than its external DTD.
197    Can only be a heuristic check. */
198 
checkddb(const char8 * ddbFile,const DDBHeader * ddb,boolean quiet)199 boolean checkddb(const char8* ddbFile, const DDBHeader* ddb, boolean quiet){
200   struct stat buf;
201   const char * extDtd = (char*)ddb+(ddb->dtdFileNameOffset);
202   char actualextDtdFile[300];
203   size_t len;
204   int NWAPPL = 3+LENERR;
205 
206   if( ddb->dtdFileNameOffset ){
207     if( ( strstr(extDtd,"SYSTEM ") || strstr(extDtd,"system ") ) &&
208 	( strstr(extDtd,"\"")      || strstr(extDtd,"'"))){
209       extDtd += strcspn(extDtd,"\"\'")+1;
210       len = strcspn(extDtd,"\"\'");
211       if( len > 299 ){
212 	if( !quiet ){
213 	  WARN1(NWAPPL,"Warning: external DTD filename too long %s.\n", extDtd);
214 	}
215 	return TRUE;
216       }
217       strncpy(actualextDtdFile,extDtd,len);
218       actualextDtdFile[len] = '\000';
219       if( stat(actualextDtdFile,&buf) == 0 ){
220 	time_t dtdTime = buf.st_mtime;
221 	if( stat(ddbFile,&buf) == 0 ){
222 	  if( dtdTime > buf.st_mtime ){
223 	    /* External DTD file newer than DDB file - DDB file may be
224 	       outofdate */
225 	    if( !quiet ){
226 	      WARN2(NWAPPL,"Warning: external DTD file %s is newer than DDB file %s.\n",
227 		    actualextDtdFile,ddbFile);
228 	    }
229 	    return FALSE;
230 	  }
231 	} else {
232 	  if( !quiet ){
233 	    WARN1(NWAPPL,"Warning: couldn't stat() DDB file %s.\n", ddbFile);
234 	  }
235 	}
236       } else {
237 	/* We couldnt stat() the external DTD file */
238 	if( !quiet ){
239 	  WARN1(NWAPPL,"Warning: stat() couldn't access external DTD file '%s'\n",
240 		actualextDtdFile);
241 	  WARN1(NWAPPL,"referenced from DDB file %s.\n",ddbFile);
242 	}
243       }
244     } else {
245       /* Nothing - we're not going to start resolving PUBLIC identifiers */
246       /* What about URLs ? */
247     }
248   } else {
249     /* No external DTD file specified in DDB - so we need not do any
250        checking */
251   }
252   return TRUE;
253 }
254 
255