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