summaryrefslogtreecommitdiffstats
path: root/usr.bin/sgmls/sgmls/md1.c
blob: 9a294e3237bc6c1a8f6d1e8dba18a52127eef290 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
#include "sgmlincl.h"         /* #INCLUDE statements for SGML parser. */
/* MDADL: Process ATTLIST declaration.
*/
VOID mdadl(tbuf)
UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
{
     int i;                   /* Loop counter; temporary variable. */
     int adlim;               /* Number of unused ad slots in al. */
     struct ad *alperm = 0;   /* Attribute definition list. */
     int stored = 0;

     mdname = key[KATTLIST];  /* Identify declaration for messages. */
     subdcl = 0;              /* No subject as yet. */
     parmno = 0;              /* No parameters as yet. */
     mdessv = es;             /* Save es level for entity nesting check. */
     reqadn = noteadn = 0;    /* No required attributes yet. */
     idadn = conradn = 0;     /* No special atts yet.*/
     AN(al) = 0;	      /* Number of attributes defined. */
     ADN(al) = 0;             /* Number of ad's in al (atts + name vals).*/
     /* PARAMETER 1: Element name or a group of them.
     */
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("1: element name or group");
     switch (pcbmd.action) {
     case NAS:
          nmgrp[0] = etddef(tbuf);
          nmgrp[1] = 0;
          break;
     case GRPS:
          parsegrp(nmgrp, &pcbgrnm, tbuf);
          break;
     case RNS:           /* Reserved name started. */
          if (ustrcmp(tbuf+1, key[KNOTATION])) {
               mderr(118, tbuf+1, key[KNOTATION]);
               return;
          }
          mdnadl(tbuf);
          return;
     default:
          mderr(121, (UNCH *)0, (UNCH *)0);
          return;
     }
     /* Save first GI for error msgs. */
     if (nmgrp[0])
	  subdcl = nmgrp[0]->etdgi+1;
     /* PARAMETER 2: Attribute definition list.
     */
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("2: attribute list");
     if (pcbmd.action!=NAS) {
          mderr(120, (UNCH *)0, (UNCH *)0);
          return;
     }
     while (pcbmd.action==NAS) {
	  al[ADN(al)+1].adname = savenm(tbuf);
          if ((adlim = ATTCNT-((int)++ADN(al)))<0) {
	       mderr(111, (UNCH *)0, (UNCH *)0);
	       adlfree(al, 1);
	       return;
	  }
          ++AN(al);
          if (mdattdef(adlim, 0)) {
	       adlfree(al, 1);
	       return;
	  }
          parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     }
     if (AN(al)>0) {   /*  Save list only if 1 or more good atts. */
          if (reqadn)  SET(ADLF(al), ADLREQ);    /* Element must have start-tag. */
          if (noteadn) SET(ADLF(al), ADLNOTE);   /* Element cannot be EMPTY. */
          if (conradn) SET(ADLF(al), ADLCONR);   /* Element cannot be EMPTY. */
          alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
          memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
          ds.attcnt += AN(al);         /* Number of attributes defined. */
          ds.attgcnt += ADN(al) - AN(al);  /* Number of att grp members. */
          TRACEADL(alperm);
     }
     /* Clear attribute list for next declaration. */
     MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);

     /* PARAMETER 3: End of declaration.
     */
     /* Next pcb.action was set during attribute definition loop. */
     TRACEMD(emd);
     if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
     if (es!=mdessv) synerr(37, &pcbmd);

     /* EXECUTE: Store the definition for each element name specified.
     */
     TRACEGRP(nmgrp);
     for (i = 0; nmgrp[i]; i++) {
          if (nmgrp[i]->adl) {     /* Error if an ADL exists. */
               mderr(112, (UNCH *)0, (UNCH *)0);
               continue;
          }
          nmgrp[i]->adl = alperm;  /* If virgin, store the adl ptr. */
	  stored = 1;
          if (alperm && nmgrp[i]->etdmod)
	       etdadl(nmgrp[i]); /* Check for conflicts with ETD. */
     }
     if (!stored && alperm) {
	  adlfree(alperm, 1);
	  frem((UNIV)alperm);
     }
}
/* ETDADL: Check compatibility between ETD and ADL.
*/
VOID etdadl(p)
struct etd *p;                /* Pointer to element type definition. */
{
     parmno = 0;
     /* Minimizable element cannot have required attribute. */
     if (GET(p->etdmin, SMO) && GET(p->adl[0].adflags, ADLREQ)) {
          mderr(40, (UNCH *)0, (UNCH *)0);
          RESET(p->etdmin, SMO);
     }
     /* Empty element cannot have NOTATION attribute.
        Attribute is not removed (too much trouble), but we trap
        attempts to specify it on the start-tag in adlval().
     */
     if (GET(p->etdmod->ttype, MNONE)) {
          if (GET(p->adl[0].adflags, ADLNOTE))
               mderr(83, (UNCH *)0, (UNCH *)0);

          /* Empty element cannot have CONREF attribute.
             Attribute is not removed because it just acts
             like IMPLIED anyway.
          */
          if (GET(p->adl[0].adflags, ADLCONR))
               mderr(85, (UNCH *)0, (UNCH *)0);
     }
     /* "-" should not be specified for the end-tag minimization if
	the element has a content reference attribute. */
     if (GET(p->adl[0].adflags, ADLCONR) && BITON(p->etdmin, EMM))
	  mderr(153, (UNCH *)0, (UNCH *)0);
}
/* MDNADL: Process ATTLIST declaration for notation.
           TO DO: Pass deftab and dvtab as parameters so
           that prohibited types can be handled by leaving
           them out of the tables.
*/
VOID mdnadl(tbuf)
UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
{
     int i;                   /* Loop counter; temporary variable. */
     int adlim;               /* Number of unused ad slots in al. */
     struct ad *alperm = 0;   /* Attribute definition list. */
     int stored = 0;

     /* PARAMETER 1: Notation name or a group of them.
     */
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("1: notation name or group");
     switch (pcbmd.action) {
     case NAS:
          nnmgrp[0] = dcndef(tbuf);
          nnmgrp[1] = 0;
          break;
     case GRPS:
          parsngrp(nnmgrp, &pcbgrnm, tbuf);
          break;
     default:
          mderr(121, (UNCH *)0, (UNCH *)0);
          return;
     }
     subdcl = nnmgrp[0]->ename+1;        /* Save first name for error msgs. */
     /* PARAMETER 2: Attribute definition list.
     */
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("2: attribute list");
     if (pcbmd.action!=NAS) {
          mderr(120, (UNCH *)0, (UNCH *)0);
          return;
     }
     while (pcbmd.action==NAS) {
	  al[ADN(al)+1].adname = savenm(tbuf);
          if ((adlim = ATTCNT-((int)ADN(al)++))<0) {
	       mderr(111, (UNCH *)0, (UNCH *)0);
	       adlfree(al, 1);
	       return;
	  }
          ++AN(al);
          if (mdattdef(adlim, 1)) {
	       adlfree(al, 1);
	       return;
	  }
          parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     }
     if (AN(al)>0) {   /*  Save list only if 1 or more good atts. */
          alperm = (struct ad *)rmalloc((1+ADN(al))*ADSZ);
          memcpy((UNIV)alperm, (UNIV)al, (1+ADN(al))*ADSZ );
          ds.attcnt += AN(al);         /* Number of attributes defined. */
          ds.attgcnt += ADN(al) - AN(al);  /* Number of att grp members. */
          TRACEADL(alperm);
     }
     /* Clear attribute list for next declaration. */
     MEMZERO((UNIV)al, (1+ADN(al))*ADSZ);

     /* PARAMETER 3: End of declaration.
     */
     /* Next pcb.action was set during attribute definition loop. */
     TRACEMD(emd);
     if (pcbmd.action!=EMD) {mderr(126, (UNCH *)0, (UNCH *)0); return;}
     if (es!=mdessv) synerr(37, &pcbmd);

     /* EXECUTE: Store the definition for each notation name specified.
     */
     TRACENGR(nnmgrp);
     for (i = 0; nnmgrp[i]; i++) {
          if (nnmgrp[i]->adl) {     /* Error if an ADL exists. */
               mderr(112, (UNCH *)0, (UNCH *)0);
               continue;
          }
          nnmgrp[i]->adl = alperm;  /* If virgin, store the adl ptr. */
	  if (nnmgrp[i]->entsw)
	       fixdatt(nnmgrp[i]);
	  stored = 1;
          TRACEDCN(nnmgrp[i]);
     }
     if (!stored && alperm) {
	  adlfree(alperm, 1);
	  frem((UNIV)alperm);
     }
}

/* Data attributes have been specified for notation p, but entities
have already been declared with notation p.  Fix up the definitions of
all entities with notation p.  Generate an error for any data
attribute that was required. */

VOID fixdatt(p)
struct dcncb *p;
{
     int i;
     for (i = 0; i < ENTHASH; i++) {
	  struct entity *ep;
	  for (ep = etab[i]; ep; ep = ep->enext)
	       if (ep->estore == ESN && ep->etx.n && ep->etx.n->nedcn == p) {
		    int adn;
		    initatt(p->adl);
		    /* Don't use adlval because if there were required
		       attributes the error message wouldn't say what
		       entity was involved. */
		    for (adn = 1; adn <= ADN(al); adn++) {
			 if (GET(ADFLAGS(al,adn), AREQ)) {
			      sgmlerr(218, &pcbstag, ADNAME(al,adn),
				      ep->ename + 1);
			      SET(ADFLAGS(al,adn), AINVALID);
			 }
			 if (BITON(ADFLAGS(al, adn), AGROUP))
			      adn += ADNUM(al, adn);
		    }
		    storedatt(ep->etx.n);
	       }
     }
}

/* MDATTDEF: Process an individual attribute definition.
             The attribute name is parsed by the caller.
             Duplicate attributes are parsed, but removed from list.
             Returns 0 if successful, otherwise returns 1.
*/
int mdattdef(adlim, datt)
int adlim;                    /* Remaining capacity of al (in tokens).*/
int datt;		      /* Non-zero if a data attribute. */
{
     int deftype;             /* Default value type: 0=not keyword. */
     int errsw = 0;           /* 1=semantic error; ignore att. */
     int novalsw = 0;         /* 1=semantic error; treat as IMPLIED. */
     int attadn = (int)ADN(al);   /* Save ad number of this attribute. */
     struct parse *grppcb = NULL; /* PCB for name/token grp parse. */
     int errcode;             /* Error type returned by PARSEVAL, ANMTGRP. */
     UNCH *advalsv;           /* Save area for permanent value ptr. */

     /* PARAMETER 1: Attribute name (parsed by caller).
     */
     TRACEMD("1: attribute name");
     if (anmget((int)ADN(al)-1, al[attadn].adname)) {
          errsw = 1;
          mderr(99, ADNAME(al,attadn), (UNCH *)0);
     }
     ADNUM(al,attadn) = ADFLAGS(al,attadn) = ADLEN(al,attadn) = 0;
     ADVAL(al,attadn) = 0; ADDATA(al,attadn).x = 0; ADTYPE(al,attadn) = ANMTGRP;
     /* PARAMETER 2: Declared value.
     */
     parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("2: declared value");
     switch (pcbmd.action) {
     case NAS:                /* Keyword for value type. */
          switch (ADTYPE(al,attadn) = (UNCH)mapsrch(dvtab, lbuf+1)) {
          case 0:
               mderr(100, ADNAME(al,attadn), lbuf+1);
               return 1;
          case ANOTEGRP:
	       if (datt) {
		    errsw = 1;
		    mderr(156, (UNCH *)0, (UNCH *)0);
	       }
               else if (!noteadn) noteadn = ADN(al);
               else {
                    errsw = 1;
                    mderr(101, ADNAME(al,attadn), (UNCH *)0);
               }
               grppcb = &pcbgrnm;         /* NOTATION requires name grp. */
               parsemd(lbuf, NAMECASE, &pcblitp, NAMELEN);/* Get GRPO*/
               break;
          case AID:
	       if (datt) {
		    errsw = 1;
		    mderr(144, (UNCH *)0, (UNCH *)0);
	       }
               else if (!idadn)
		    idadn = attadn;
               else {
                    errsw = 1;
                    mderr(102, ADNAME(al,attadn), (UNCH *)0);
               }
               break;
	  case AIDREF:
	  case AIDREFS:
	       if (datt) {
		    errsw = 1;
		    mderr(155, (UNCH *)0, (UNCH *)0);
	       }
	       break;
	  case AENTITY:
	  case AENTITYS:
	       if (datt) {
		    errsw = 1;
		    mderr(154, (UNCH *)0, (UNCH *)0);
	       }
	       break;
          }
          break;
     case GRPS:
          grppcb = &pcbgrnt;           /* Normal grp is name token grp. */
          break;
     case EMD:
          mderr(103, ADNAME(al,attadn), (UNCH *)0);
          return 1;
     default:
          mderr(104, ADNAME(al,attadn), (UNCH *)0);
          return 1;
     }
     /* PARAMETER 2A: Name token group.
     */
     if (grppcb != NULL) {
	  TRACEMD("2A: name group");
          switch (pcbmd.action) {
          case GRPS:               /* Name token list. */
               SET(ADFLAGS(al,attadn), AGROUP);
               /* Call routine to parse group, create ad entries in adl. */
               errcode = anmtgrp(grppcb, al+attadn,
				 (GRPCNT<adlim ? GRPCNT+1 : adlim+1),
				 &al[attadn].adnum, ADN(al));
               if (errcode<=0) {
		    if (adlim < GRPCNT)
			 mderr(111, (UNCH *)0, (UNCH *)0);
		    else
			 mderr(105, ADNAME(al,attadn), (UNCH *)0);
                    return 1;
               }
               ADN(al) += ADNUM(al,attadn);    /* Add grp size to total ad cnt.*/
               break;
          default:
               mderr(106, ADNAME(al,attadn), (UNCH *)0);
               return 1;
          }
     }
     /* PARAMETER 3: Default value keyword.
     */
     parsemd(lbuf, AVALCASE,
	     (ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt, LITLEN);
     TRACEMD("3: default keyword");
     switch (pcbmd.action) {
     case RNS:                /* Keyword. */
          deftype = mapsrch(deftab, lbuf+1);
          switch (deftype) {
          case DFIXED:        /* FIXED */
               SET(ADFLAGS(al,attadn), AFIXED);
               parsemd(lbuf, AVALCASE,
		       (ADTYPE(al,attadn)==ACHARS) ? &pcblitr : &pcblitt,
		       LITLEN);  /* Real default. */
               goto parm3x;   /* Go process specified value. */
          case DCURR:         /* CURRENT: If ID, treat as IMPLIED. */
               if (ADTYPE(al,attadn)==AID) {
                    mderr(80, ADNAME(al,attadn), (UNCH *)0);
                    break;
               }
	       if (datt) {
		    mderr(157, (UNCH *)0, (UNCH *)0);
		    break;
	       }
               SET(ADFLAGS(al,attadn), ACURRENT);
               break;
          case DREQ:          /* REQUIRED */
               SET(ADFLAGS(al,attadn), AREQ); ++reqadn;
               break;
          case DCONR:         /* CONREF */
               if (ADTYPE(al,attadn)==AID) {
                    mderr(107, ADNAME(al,attadn), (UNCH *)0);
                    break;
               }
	       if (datt) {
		    mderr(158, (UNCH *)0, (UNCH *)0);
		    break;
	       }
               SET(ADFLAGS(al,attadn), ACONREF); conradn = 1;
          case DNULL:         /* IMPLIED */
               break;
          default:            /* Unknown keyword is an error. */
               mderr(108, ADNAME(al,attadn), lbuf+1);
               errsw = 1;
          }
          if (errsw) {
	       /* Ignore erroneous att. */
	       adlfree(al, attadn);
	       --AN(al);
	       ADN(al) = (UNCH)attadn-1;
	  }
          return(0);
     default:
          break;
     }
     /* PARAMETER 3x: Default value (non-keyword).
     */
     parm3x:
     TRACEMD("3x: default (non-keyword)");
     if (ADTYPE(al,attadn)==AID) { /* If ID, treat as IMPLIED. */
          mderr(81, ADNAME(al,attadn), (UNCH *)0);
          novalsw = 1;	      /* Keep parsing to keep things straight. */
     }
     switch (pcbmd.action) {
     case LIT:                /* Literal. */
     case LITE:               /* Literal. */
          /* Null string (except CDATA) is error: msg and treat as IMPLIED. */
          if (*lbuf == '\0' && ADTYPE(al,attadn)!=ACHARS) {
               mderr(82, ADNAME(al,attadn), (UNCH *)0);
               novalsw = 1;
          }
	  break;
     case NAS:                /* Name character string. */
     case NMT:                /* Name character string. */
     case NUM:                /* Number or number token string. */
	  /* The name won't have a length byte because AVALCASE was specified. */
          break;
     case CDR:
	  parsetkn(lbuf, NMC, LITLEN);
	  break;
     case EMD:
          mderr(109, ADNAME(al,attadn), (UNCH *)0);
          return 1;
     default:
          mderr(110, ADNAME(al,attadn), (UNCH *)0);
          return 1;
     }
     if (errsw) {
	  /* Ignore erroneous att. */
	  adlfree(al, attadn);
	  --AN(al);
	  ADN(al) = (UNCH)attadn-1;
	  return(0);
     }
     if (novalsw) return(0);

     /* PARAMETER 3y: Validate and store default value.
     */
     if (ADTYPE(al,attadn)==ACHARS) {
	  UNS len = vallen(ACHARS, 0, lbuf);
	  if (len > LITLEN) {
	       /* Treat as implied. */
	       sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
	       return 0;
	  }
          /* No more checking for CDATA value. */
          ADNUM(al,attadn) = 0;             /* CDATA is 0 tokens. */
          ADVAL(al,attadn) = savestr(lbuf);/* Store default; save ptr. */
          ADLEN(al,attadn) = len;
          ds.attdef += len;
          return 0;
     }
     /* Parse value and save token count (GROUP implies 1 token). */
     advalsv = (UNCH *)rmalloc(ustrlen(lbuf)+2); /* Storage for tokenized value. */
     errcode = parseval(lbuf, (UNS)ADTYPE(al,attadn), advalsv);
     if (BITOFF(ADFLAGS(al,attadn), AGROUP)) ADNUM(al,attadn) = (UNCH)tokencnt;

     /* If value was invalid, or was a group member that was not in the group,
        issue an appropriate message and set the error switch. */
     if (errcode)
          {sgmlerr((UNS)errcode, &pcbmd, ADNAME(al,attadn), lbuf); errsw = 1;}
     else if ( BITON(ADFLAGS(al,attadn), AGROUP)
          && !amemget(&al[attadn], (int)ADNUM(al,attadn), advalsv) ) {
               sgmlerr(79, &pcbmd, ADNAME(al,attadn), advalsv+1);
               errsw = 1;
     }
     ADLEN(al,attadn) = vallen(ADTYPE(al,attadn), ADNUM(al,attadn), advalsv);
     if (ADLEN(al,attadn) > LITLEN) {
	  sgmlerr(224, &pcbmd, ADNAME(al,attadn), (UNCH *)0);
	  ADLEN(al,attadn) = 0;
	  errsw = 1;
     }
     /* For valid tokenized value, save it and update statistics. */
     if (!errsw) {
	  ADVAL(al,attadn) = advalsv;
          ds.attdef += ADLEN(al,attadn);
          return 0;
     }
     /* If value was bad, free the value's storage and treat as
        IMPLIED or REQUIRED. */
     frem((UNIV)advalsv);          /* Release storage for value. */
     ADVAL(al,attadn) = NULL;         /* And make value NULL. */
     return 0;
}
/* ANMTGRP: Parse a name or name token group, create attribute descriptors
            for its members, and add them to the attribute descriptor list.
            The parse either terminates or returns a good token, so no
            switch is needed.
*/
int anmtgrp(pcb, nt, grplim, adn, adsz)
struct parse *pcb;            /* PCB for name or name token grp. */
struct ad nt[];               /* Buffer for creating name token list. */
int grplim;                   /* Maximum size of list (plus 1). */
UNS *adn;		      /* Ptr to number of names or tokens in grp. */
int adsz;                     /* Size of att def list. */
{
     UNCH adtype = (UNCH)(pcb==&pcbgrnt ? ANMTGRP:ANOTEGRP);/*Attribute type.*/
     int essv = es;           /* Entity stack level when grp started. */

     *adn = 0;                /* Group is empty to start. */
     while (parse(pcb)!=GRPE && *adn<grplim) {
          switch (pcb->action) {
          case NAS_:          /* Name or name token (depending on pcb). */
          case NMT_:
               parsenm(lbuf, NAMECASE);
	       nt[*adn+1].adname = savenm(lbuf);
               if (antvget((int)(adsz+*adn), nt[*adn+1].adname, (UNCH **)0))
                    mderr(98, ntoa((int)*adn+1), nt[*adn+1].adname+1);
               nt[++*adn].adtype = adtype;
               nt[*adn].addef    = NULL;
               continue;

          case EE_:           /* Entity ended (correctly or incorrectly). */
               if (es<essv) {synerr(37, pcb); essv = es;}
               continue;

          case PIE_:          /* PI entity reference (invalid). */
               entpisw = 0;   /* Reset PI entity indicator. */
               synerr(59, pcb);
               continue;

          default:
               break;
          }
          break;
     }
     if (es!=essv) synerr(37, pcb);
     if (*adn==grplim) return -1;
     else return *adn;        /* Return number of tokens. */
}
/* MDDTDS: Process start of DOCTYPE declaration (through MSO).
*/
VOID mddtds(tbuf)
UNCH *tbuf;                   /* Work area for tokenization[LITLEN+2]. */
{
     struct fpi fpicb;        /* Formal public identifier structure. */
     union etext etx;         /* Ptr to entity text. */
     UNCH estore = ESD;       /* Entity storage class. */
     int emdsw = 0;           /* 1=end of declaration found; 0=not yet. */

     mdname = key[KDOCTYPE];  /* Identify declaration for messages. */
     subdcl = NULL;           /* No subject as yet. */
     parmno = 0;              /* No parameters as yet. */
     mdessv = es;             /* Save es for checking entity nesting. */
     dtdrefsw = 0;            /* No external DTD entity as yet. */
     /* PARAMETER 1: Document type name.
     */
     pcbmd.newstate = 0;
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("1: doc type name");
     if (pcbmd.action!=NAS) {mderr(120, (UNCH *)0, (UNCH *)0); return;}
     dtype = savenm(tbuf);
     subdcl = dtype+1;        /* Subject of declaration for error msgs. */

     /* PARAMETER 2: External identifier keyword or MDS.
     */
     pcbmd.newstate = 0;
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("2: extid or MDS");
     switch (pcbmd.action) {
     case NAS:
          if (mdextid(tbuf, &fpicb, dtype+1, &estore, (PNE)0)==0) return;
          if ((etx.x = entgen(&fpicb))==0)
	       mderr(146, dtype+1, (UNCH *)0);
	  else
	       dtdrefsw = 1;  /* Signal external DTD entity. */
          break;
     case MDS:
          goto execute;
     default:
          mderr(128, (UNCH *)0, (UNCH *)0);
          return;
     }
     /* PARAMETER 3: MDS or end of declaration.
     */
     TRACEMD("3: MDS or EMD");
     switch (pcbmd.action) {
     default:                      /* Treat as end of declaration. */
          mderr(126, (UNCH *)0, (UNCH *)0);
     case EMD:
          emdsw = 1;
     case MDS:
          break;
     }
     /* EXECUTE: Store entity definition if an external ID was specified.
     */
     execute:
     if (es!=mdessv) synerr(37, &pcbmd);
     propcb = &pcbmds;        /* Prepare to parse doc type definition (MDS). */
     if (dtdrefsw) {
	  /* TO DO: If concurrent DTD's supported, free existing
	     etext for all but first DTD (or reuse it). */
	  entdef(indtdent, estore, &etx);
	  ++ds.ecbcnt; ds.ecbtext += entlen;
          if (emdsw) {
               REPEATCC;                /* Push back the MDC. */
               *FPOS = lex.d.msc;       /* Simulate end of DTD subset. */
               REPEATCC;                /* Back up to read MSC next. */
               delmscsw = 1;            /* Insert MSC after referenced DTD. */
          }
     }
     indtdsw = 1;                       /* Allow "DTD only" parameters. */
     return;
}
/* MDDTDE: Process DOCTYPE declaration end.
*/
VOID mddtde(tbuf)
UNCH *tbuf;                   /* Work area for tokenization. */
{
     mdessv = es;             /* Save es for checking entity nesting. */
     propcb = &pcbpro;        /* Restore normal prolog parse. */
     indtdsw = 0;             /* Prohibit "DTD only" parameters. */

     mdname = key[KDOCTYPE];  /* Identify declaration for messages. */
     subdcl = dtype+1;        /* Subject of declaration for error msgs. */
     parmno = 0;              /* No parameters as yet. */
     /* PARAMETER 4: End of declaration.
     */
     pcbmd.newstate = 0;
     parsemd(tbuf, NAMECASE, &pcblitp, LITLEN);
     TRACEMD(emd);
     if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
     if (es!=mdessv) synerr(37, &pcbmd);
}
/* MDELEM: Process ELEMENT declaration.
*/
VOID mdelem(tbuf)
UNCH *tbuf;                   /* Work area for tokenization (tbuf). */
{
     UNCH *ranksuff = lbuf;   /* Rank suffix. */
     UNS dctype = 0;          /* Declared content type (from dctab). */
     UNCH fmin = 0;           /* Minimization bit flags. */
     int i;                   /* Loop counter. */
     UNS u;                   /* Temporary variable. */
     struct etd **mexgrp, **pexgrp; /* Ptr to model exceptions array. */
     struct thdr *cmod, *cmodsv;    /* Ptr to content model. */
     UNCH *etdgi;             /* GI of current etd (when going through group).*/
     int minomitted = 0;      /*  Tag minimization parameters omitted. */

     mdname = key[KELEMENT];  /* Identify declaration for messages. */
     subdcl = NULL;           /* No subject as yet. */
     parmno = 0;              /* No parameters as yet. */
     mdessv = es;             /* Save es level for entity nesting check. */
     ranksuff[0] = 0;
     mexgrp = pexgrp = 0;

     /* PARAMETER 1: Element name or a group of them.
     */
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("1: element name or grp");
     switch (pcbmd.action) {
     case NAS:
          nmgrp[0] = etddef(tbuf);
          nmgrp[1] = 0;
          break;
     case GRPS:
          parsegrp(nmgrp, &pcbgrnm, tbuf);
          break;
     default:
          mderr(121, (UNCH *)0, (UNCH *)0);
          return;
     }
     /* Save first GI for trace and error messages. */
     if (nmgrp[0])
	  subdcl = nmgrp[0]->etdgi+1;

     /* PARAMETER 1A: Rank suffix (optional).
     */
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     TRACEMD("1A: rank suffix");
     switch (pcbmd.action) {
     case NUM:
          ustrcpy(ranksuff, tbuf);
          parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     default:
          break;
     }
     /* PARAMETER 2A: Start-tag minimization.
     */
     TRACEMD("2A: start min");
     switch (pcbmd.action) {
     case CDR:
          break;
     case NAS:
	  if (!ustrcmp(tbuf+1, key[KO])) {
	       if (OMITTAG==YES) SET(fmin, SMO);
	       break;
	  }
	  /* fall through */
     default:
	  if (OMITTAG==NO) {minomitted=1; break;}
          mderr(129, tbuf+1, (UNCH *)0);
          return;
     }
     /* Must omit omitted end-tag minimization, if omitted
	start-tag minimization was omitted (because OMITTAG == NO). */
     if (!minomitted) {
	  /* PARAMETER 2B: End-tag minimization.
	   */
	  parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
	  TRACEMD("2B: end min");
	  switch (pcbmd.action) {
	  case NAS:
	       if (ustrcmp(tbuf+1, key[KO])) {mderr(129, tbuf+1, (UNCH *)0); return;}
	       if (OMITTAG==YES) SET(fmin, EMO);
	       break;
	  case CDR:
	       SET(fmin, EMM);
	       break;
	  default:
	       mderr(129, tbuf+1, (UNCH *)0);
	       return;
	  }
	  /* PARAMETER 3: Declared content.
	   */
	  parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     }
     TRACEMD("3: declared content");
     switch (pcbmd.action) {
     case NAS:
          dctype = mapsrch(dctab, tbuf+1);
          if (!dctype) {mderr(24, tbuf+1, (UNCH *)0); return;}
          /* Eliminate incompatibilities among parameters. */
          if (GET(fmin, SMO) && GET(dctype, MNONE+MCDATA+MRCDATA)) {
               mderr(58, (UNCH *)0, (UNCH *)0);
               RESET(fmin, SMO);
          }
          if (GET(dctype, MNONE) && BITON(fmin, EMM)) {
	       mderr(87, (UNCH *)0, (UNCH *)0);
               SET(fmin, EMO);
          }
          /* If valid, process like a content model. */
     case GRPS:
          cmodsv = parsemod((int)(pcbmd.action==GRPS ? 0 : dctype));
          if (cmodsv==0) return;
	  u = (dctype ? 1 : cmodsv->tu.tnum+2) * THSZ;
          cmod = (struct thdr *)rmalloc(u);
          memcpy((UNIV)cmod  , (UNIV)cmodsv, u );
	  ds.modcnt += cmod->tu.tnum;
          TRACEMOD(cmod);
          break;
     default:
          mderr(130, (UNCH *)0, (UNCH *)0);
          return;
     }
     /* PARAMETERS 3A, 3B: Exceptions or end.
     */
     parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
     if (BITOFF(cmod->ttype, MCDATA+MRCDATA+MNONE)) {
          /* PARAMETER 3A: Minus exceptions.
          */
          TRACEMD("3A: -grp");
          switch (pcbmd.action) {
          case MGRP:
	       /* We cheat and use nnmgrp for this. */
               mexgrp = copygrp((PETD *)nnmgrp,
				u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
               ++ds.pmexgcnt; ds.pmexcnt += u-1;
               TRACEGRP(mexgrp);
               parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
          default:
               break;
          }
          /* PARAMETER 3B: Plus exceptions.
          */
          TRACEMD("3B: +grp");
          switch (pcbmd.action) {
          case PGRP:
               pexgrp = copygrp((PETD *)nnmgrp,
				u = parsegrp((PETD *)nnmgrp, &pcbgrnm, tbuf));
               ++ds.pmexgcnt; ds.pmexcnt += u-1;
               TRACEGRP(pexgrp);
               parsemd(tbuf, NAMECASE, &pcblitp, NAMELEN);
          default:
               break;
          }
     }
     /* PARAMETER 4: End of declaration.
     */
     TRACEMD(emd);
     if (pcbmd.action!=EMD) mderr(126, (UNCH *)0, (UNCH *)0);
     if (es!=mdessv) synerr(37, &pcbmd);

     /* EXECUTE: Store the definition for each element name specified.
     */
     TRACEGRP(nmgrp);
     for (i = -1; nmgrp[++i];) {
          etdgi = nmgrp[i]->etdgi;
          if (*ranksuff) {
               if ((tbuf[0] = *etdgi + ustrlen(ranksuff)) - 2 > NAMELEN) {
                    mderr(131, etdgi+1, ranksuff);
                    continue;
               }
               memcpy(tbuf+1, etdgi+1, *etdgi-1);
               ustrcpy(tbuf+*etdgi-1, ranksuff);
               etdcan(etdgi);
               nmgrp[i] = etddef(tbuf);
          }
          if (nmgrp[i]->etdmod) {mderr(56, etdgi+1, (UNCH *)0); continue;}
          etdset(nmgrp[i], fmin+ETDDCL, cmod, mexgrp, pexgrp, nmgrp[i]->etdsrm);
          ++ds.etdcnt;
          if (nmgrp[i]->adl) etdadl(nmgrp[i]); /* Check ETD conflicts. */
          TRACEETD(nmgrp[i]);
     }
}

VOID adlfree(al, aln)
struct ad *al;
int aln;
{
     for (; aln <= ADN(al); aln++) {
	  frem((UNIV)al[aln].adname);
	  if (ADVAL(al, aln))
	       frem((UNIV)ADVAL(al, aln));
	  if (BITON(ADFLAGS(al, aln), AGROUP)) {
	       int i;
	       for (i = 0; i < ADNUM(al, aln); i++)
		    frem((UNIV)al[aln + i + 1].adname);
	       aln += ADNUM(al, aln);
	  }
     }
}

/*
Local Variables:
c-indent-level: 5
c-continued-statement-offset: 5
c-brace-offset: -5
c-argdecl-indent: 0
c-label-offset: -5
comment-column: 30
End:
*/
OpenPOWER on IntegriCloud