2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: scan.c /main/3 1995/11/08 10:24:54 rswiston $ */
25 Copyright 1986 Tandem Computers Incorporated.
26 This product and information is proprietary of Tandem Computers Incorporated.
27 Copyright 1986, 1987, 1988, 1989 Hewlett-Packard Co.
30 /* Scan.c is the scanner for program PARSER */
50 /* Actually read a character from an input stream */
55 c = m_getc(m_sysent[m_sysecnt]) ;
56 m_saveline[m_svlncnt[m_sysecnt]][m_sysecnt] = c ;
57 if (++m_svlncnt[m_sysecnt] >= M_LINELENGTH) {
58 m_svlncnt[m_sysecnt] = 0 ;
59 m_svlnwrap[m_sysecnt] = TRUE ;
64 /* Expand an entity reference */
65 void m_entexpand(M_ENTITY *openent)
72 m_ungetachar(M_NULLVAL, M_EE, FALSE) ;
74 m_opene[m_eopencnt - 1] = openent ;
76 if (m_stacktop->element &&
77 m_element[m_stacktop->element - 1].content == M_RCDATA)
79 if (m_curcon == LITCON || m_curcon == LITACON)
81 if (! openent->wheredef) {
83 m_err1("%s: System error -- no definition for predeclared entity",
88 if (m_curcon == ENTINLIT)
89 if (openent->type != M_GENERAL) {
91 m_err1("%s: Typed entity not allowed in parameter value",
96 if (m_eopencnt > M_ENTLVL) {
98 m_err1("%s: Too many nested entities", openent->name) ;
102 for (i = 0 ; i < m_eopencnt - 1; i++)
103 if (m_opene[i] == openent) {
105 m_err1("Recursive call to entity %s ignored", openent->name) ;
110 /* If SDATA or PI entity (regular or CODE) at beginning of document
111 instance, call m_startdoc and reset m_curcon past preamble */
112 if (m_curcon == PREAMBLE &&
113 (openent->type == M_SDATA ||
114 openent->type == M_CODESDATA ||
115 openent->type == M_PI ||
116 openent->type == M_CODEPI)) {
123 if (openent->type == M_SDATA || openent->type == M_CODESDATA) {
124 if (! m_stacktop->intext) {
125 if (! m_strtproc(M_NULLVAL)) {
126 if (m_stacktop->oldtop)
127 m_err1("SDATA entity not allowed at this point in %s",
128 m_nameofelt(m_stacktop->element)) ;
130 m_error("Document may not start with SDATA entity") ;
133 m_stacktop->firstre = TRUE ;
134 m_stacktop->intext = TRUE ;
135 if (m_curcon == ELCON || m_curcon == DATACON)
136 m_curcon = POUNDCDATA ;
137 else if (m_curcon == NETELCON || m_curcon == NETDATACON)
138 m_curcon = NETCDATA ;
140 m_stacktop->linestat = M_DCORCET ;
145 if (openent->type == M_CODEPI || openent->type == M_CODESDATA) {
146 if (openent->type == M_CODEPI)
147 m_stacktop->linestat = M_SOMETHING ;
148 m_codeent(openent->codeindex) ;
152 /* PI or SDATA, but not CODE entity */
153 if (openent->type == M_PI || openent->type == M_SDATA) {
154 m_piaction(openent->content, openent->name, openent->type) ;
158 /* Subordinate data file */
159 if (openent->type == M_SYSTEM) {
160 m_sysent[m_sysecnt + 1] = m_openent(openent->content) ;
161 if (m_sysent[m_sysecnt + 1]) {
163 m_line[m_sysecnt] = 1 ;
164 m_svlncnt[m_sysecnt] = 0 ;
165 m_svlnwrap[m_sysecnt] = FALSE ;
167 m_trace("Opening `") ;
168 m_wctrace(openent->content) ;
170 sprintf(buffer, "%d", m_sysecnt) ;
177 m_err1("Unable to open file %s", openent->content) ;
182 /* An entity reference has been encountered. Put the content of the
183 entity, including any leading or trailing delimiters into the input
184 stream in reverse order */
185 /* Closing delimiter */
186 switch (openent->type) {
189 m_undodelim(m_dlmptr[M_TAGC - 1], FALSE) ;
193 m_undodelim(m_dlmptr[M_MDC - 1], FALSE) ;
199 /* Content of entity -- scan for end to reverse string */
200 if (openent->type == M_CDATAENT) dchar = M_CDCHAR ;
201 else dchar = M_ENTNORMAL ;
202 if (p = openent->content)
204 if (p != openent->content) {
207 m_ungetachar((int) *p, dchar, FALSE) ;
208 if (p == openent->content) break ;
212 /* Opening delimiter */
213 switch (openent->type) {
215 m_undodelim(m_dlmptr[M_STAGO - 1], FALSE) ;
219 m_undodelim(m_dlmptr[M_ETAGO - 1], FALSE) ;
223 m_undodelim(m_dlmptr[M_MDO - 1], FALSE) ;
229 } /* End m_entexpand */
231 /* An srlen-character long short-reference delimiter has been found. Verify
232 that it is not the prefix of a general delimiter recognized in context*/
233 LOGICAL m_gendelim(int srlen, int context)
235 int ghold[MAXD + 1] ;
238 int i, n = 0, current, delim[MAXD + 1], oldchars = 0 ;
239 int newcharstart = 0 ;
240 M_HOLDTYPE dhold[MAXD + 1], dchar ;
244 if (! (current = m_contree[context - 1])) return(FALSE) ;
246 for (i = 0 ; i <= srlen ; i++)
247 if (m_srefchartype[i] != M_RSCHAR && m_srefchartype[i] != M_WSCHAR) {
251 if (linestart) return(FALSE) ;
256 while (oldchars <= srlen &&
257 (m_srefchartype[oldchars] == M_RSCHAR ||
258 m_srefchartype[oldchars] == M_WSCHAR))
260 if (oldchars <= srlen)
261 ucase = m_hold[oldchars++] ;
263 if (! newcharstart) newcharstart = n ;
264 ghold[n] = m_getachar(&dhold[n]) ;
265 ucase = m_ctupper(ghold[n]) ;
266 if (dhold[n] != M_NORMAL && dhold[n] != M_ENTNORMAL) break ;
269 (int) m_delimtrie[i].symbol < ucase && m_delimtrie[i].more ;
271 if ((int) m_delimtrie[i].symbol == ucase) {
272 current = m_delimtrie[i].index ;
273 if (! m_delimtrie[current].symbol)
274 delim[n] = m_delimtrie[current].index ;
280 if (! newcharstart) return(FALSE) ;
281 while (n >= newcharstart - 1) {
284 /* Found a delimiter. If it ends with a letter, verify
285 that the following character is not a letter, in order
286 to issue error messages in cases such as <!ENTITYrunon ... */
287 if (m_cttype(ghold[n]) != M_NMSTART) found = TRUE ;
289 next = m_getachar(&dchar) ;
290 m_ungetachar(next, dchar, TRUE) ;
291 if (next == EOF || m_cttype(next) != M_NMSTART)
296 if (delim[n] == M_ERO || delim[n] == M_STAGO ||
297 delim[n] == M_ETAGO) {
298 next = m_getachar(&dchar) ;
299 m_ungetachar(next, dchar, TRUE) ;
300 if (! (m_cttype(next) == M_NMSTART &&
301 (dchar == M_NORMAL || dchar == M_ENTNORMAL))) {
306 while (n >= newcharstart) {
307 m_ungetachar(ghold[n], dhold[n], TRUE) ;
311 } /* End if delim[n] */
312 if (n >= newcharstart) m_ungetachar(ghold[n], dhold[n], TRUE) ;
319 /* Reads next input character from the current source file or from an
321 int m_getachar(M_HOLDTYPE *dchar)
327 M_WCHAR wc_ee, wc_re;
332 mbtowc(&wc_ee, &mb_ee, 1);
333 mbtowc(&wc_re, &mb_re, 1);
334 if (m_toundo && m_sysecnt <= m_sourcefile[m_toundo - 1]) {
335 c = m_savechar[--m_toundo] ;
336 *dchar = m_savedchar[m_toundo] ;
337 if (*dchar == wc_ee) m_atrs = (M_WCHAR) c;
342 if (m_whitespace((M_WCHAR) c) && c != wc_re) {
343 /* White space, but not RE, i.e., space or tab */
344 for (m_wscount = 0 ; m_wscount < M_WSPACELEN ; m_wscount++) {
345 m_wspace[m_wscount] = m_actgetc() ;
346 if (! m_whitespace((M_WCHAR) m_wspace[m_wscount]) ||
347 m_wspace[m_wscount] == wc_re)
350 if (m_whitespace((M_WCHAR) m_wspace[m_wscount]) &&
351 m_wspace[m_wscount] != wc_re) {
352 m_error("Ignoring blank or tab") ;
353 while (m_whitespace((M_WCHAR) m_wspace[m_wscount]) &&
354 m_wspace[m_wscount] != wc_re)
355 m_wspace[m_wscount] = m_actgetc() ;
357 if (m_wscount > m_maxws) m_maxws = m_wscount ;
358 if (m_wspace[m_wscount] == wc_re) c = wc_re ;
360 for (i = 0 ; i <= m_wscount ; i++)
361 m_ungetachar(m_wspace[m_wscount - i], M_NORMAL, FALSE) ;
363 } /* End just read a blank or tab, is it line-trailing? */
364 } /* End read a character from file */
366 m_oldlsindex = (m_oldlsindex + 1) % M_SAVECHAR ;
367 m_oldlinestat[m_oldlsindex] = m_stacktop->linestat ;
368 m_oldatrs[m_oldlsindex] = m_atrs ;
369 if (c == wc_re && *dchar) {
370 if (*dchar == M_NORMAL) m_line[m_sysecnt]++ ;
371 m_stacktop->linestat = M_NOTHING ;
374 else if (*dchar) m_atrs = FALSE ;
378 length = wctomb(buffer, c);
382 sprintf(buffer, "%d", c) ;
385 sprintf(buffer, "%d", *dchar) ;
389 else m_trace("get(EE)\n") ;
394 /* Reads a name token */
395 void m_getname(M_WCHAR first)
401 *(p = m_name) = first ;
403 c = m_getachar(&dchar) ;
404 if (c == EOF) break ;
405 if (dchar != M_NORMAL && dchar != M_ENTNORMAL) break ;
406 if (m_cttype(c) == M_NONNAME) break ;
408 if (p >= m_name + M_NAMELEN) {
410 m_error("Name too long") ;
411 while ((dchar == M_NORMAL || dchar == M_ENTNORMAL) &&
413 m_cttype(c) != M_NONNAME)
414 c = m_getachar(&dchar) ;
418 m_ungetachar(c, dchar, TRUE) ;
422 /* Reads the next token */
423 int m_gettoken(int *c, M_HOLDTYPE *dchar, int context)
425 int hold[MAXD + 1], next ;
427 int i, n = 0, current, delim[MAXD + 1], nexttoken ;
428 M_HOLDTYPE dhold[MAXD + 1] ;
438 if (m_stacktop->oldtop) m_shortref(context) ;
443 if (! (current = m_contree[context - 1])) {
444 *c = m_getachar(dchar) ;
449 hold[n] = m_getachar(&dhold[n]) ;
450 ucase = m_ctupper(hold[n]) ;
452 if (dhold[n] != M_NORMAL && dhold[n] != M_ENTNORMAL) break ;
454 (int) m_delimtrie[i].symbol < ucase && m_delimtrie[i].more ;
456 if ((int) m_delimtrie[i].symbol == ucase) {
457 current = m_delimtrie[i].index ;
458 if (! m_delimtrie[current].symbol)
459 delim[n] = m_delimtrie[current].index ;
468 /* Found a delimiter. If it ends with a letter, verify
469 that the following character is not a letter, in order
470 to issue error messages in cases such as <!ENTITYrunon ... */
471 if (m_cttype(hold[n]) != M_NMSTART) found = TRUE ;
473 *c = m_getachar(dchar) ;
474 m_ungetachar(*c, *dchar, TRUE) ;
475 if (*c == EOF || m_cttype(*c) != M_NMSTART) found = TRUE ;
479 if (delim[n] == M_CRO) {
480 next = m_getachar(dchar) ;
481 if ((*dchar != M_NORMAL && *dchar != M_ENTNORMAL) ||
482 (m_cttype(next) != M_DIGIT))
483 m_ungetachar(next, *dchar, TRUE) ;
485 m_scanval = next - '0' ;
487 next = m_getachar(dchar) ;
488 if ((*dchar != M_NORMAL && *dchar != M_ENTNORMAL) ||
489 (m_cttype(next) != M_DIGIT)) {
490 m_ungetachar(next, *dchar, TRUE) ;
491 if (! m_gettoken(&next, dchar, ENTREF))
492 m_ungetachar(next, *dchar, TRUE) ;
493 if (context == ELCON || context == NETELCON)
494 return(M_BLACKSPACE) ;
495 else return(M_TEXT) ;
497 m_scanval = 10 * m_scanval + next - '0' ;
498 if (m_scanval >= M_CHARSETLEN) {
499 m_error("Invalid character code") ;
500 m_scanval = (m_scanval - next + '0') / 10 ;
501 m_ungetachar(next, *dchar, TRUE) ;
502 if (context == ELCON || context == NETELCON)
503 return(M_BLACKSPACE) ;
504 else return(M_TEXT) ;
506 } /* End loop reading digits after M_CRO */
507 } /* End M_CRO followed by digit */
508 } /* End delim[n] == M_CRO */
509 else if (delim[n] == M_ERO)
511 return(m_gettoken(c, dchar,
512 (m_curcon == RCNEWENT || m_curcon == ENTINLIT) ?
513 m_curcon : context)) ;
514 /* Can be an M_ERO or M_CRO here only if not in context and hence
515 should not be treated as a delimiter */
516 if (delim[n] != M_STAGO && delim[n] != M_ETAGO &&
517 delim[n] != M_ERO && delim[n] != M_CRO)
519 /* M_STAGO and M_ETAGO recognized only if immediately followed by
520 a M_NMSTART character or by an appropriate closing delimiter
521 (latter is a short tag) */
522 if (delim[n] == M_STAGO || delim[n] == M_ETAGO) {
523 next = m_getachar(dchar) ;
524 m_ungetachar(next, *dchar, TRUE) ;
525 if (m_cttype(next) == M_NMSTART &&
526 (*dchar == M_NORMAL || *dchar == M_ENTNORMAL))
528 nexttoken = m_gettoken(&next, dchar,
529 delim[n] == M_STAGO ? SELEMENT : EELEMENT) ;
531 m_undodelim(m_dlmptr[nexttoken - 1], TRUE) ;
534 else m_ungetachar(next, *dchar, TRUE) ;
535 } /* End delim[n] is M_STAGO or M_ETAGO */
536 } /* End if (delim[n]) */
537 if (n) m_ungetachar(hold[n], dhold[n], TRUE) ;
546 /* Reads a literal */
547 void m_litproc(int delim)
551 int savecon = m_curcon ;
555 char mb_re, mb_tab, mb_space, mb_null, mb_ee;
556 M_WCHAR wc_re, wc_tab, wc_space, wc_null, wc_ee;
563 mbtowc(&wc_re, &mb_re, 1);
564 mbtowc(&wc_tab, &mb_tab, 1);
565 mbtowc(&wc_space, &mb_space, 1);
566 mbtowc(&wc_null, &mb_null, 1);
567 mbtowc(&wc_ee, &mb_ee, 1);
569 m_curcon = delim == M_LIT ? LITCON : LITACON ;
570 atentlev = m_eopencnt ;
571 atdelimcon = m_curcon ;
572 for (i = 0 ; i < M_LITLEN + 1 ; i++) {
573 n = m_gettoken(&c, &dchar, m_curcon) ;
576 m_ungetachar(c, dchar, TRUE) ;
577 m_literal[i] = wc_null ;
581 m_literal[i] = (M_WCHAR) m_scanval ;
585 m_literal[i] = wc_null ;
593 m_literal[i] = wc_re ;
597 m_literal[i] = wc_space ;
601 m_literal[i] = wc_tab ;
604 m_literal[i] = (M_WCHAR) c ;
605 if (dchar == wc_ee) {
606 if (m_curcon == ENTINLIT) {
609 if (m_eopencnt == atentlev) {
610 m_curcon = atdelimcon ;
615 m_literal[i] = wc_null ;
617 m_ungetachar(wc_null, wc_ee, FALSE) ;
623 m_error("Internal error processing literal") ;
627 m_error("Literal too long") ;
628 m_literal[i] = wc_null ;
632 /* Called when a missing tagc delimiter is detected */
633 void m_missingtagc(int c, M_HOLDTYPE dchar, LOGICAL start)
636 if (start) m_mberr1("Invalid parameter or missing %s", m_tagc);
637 else m_mberr1("Missing %s in end-tag", m_tagc) ;
639 m_ungetachar(c, dchar, TRUE) ;
644 /* Have found one character in a possible short reference delimiter.
645 Prepare to look for the next one */
646 void m_nextdelimchar(int *n, int i, LOGICAL *linestart, LOGICAL newlinestart,
647 LOGICAL skipblank, unsigned char type)
650 char mb_re,mb_seqchar, mb_rschar;
651 M_WCHAR wc_re,wc_seqchar, wc_rschar;
654 mbtowc(&wc_re, &mb_re, 1);
655 mb_seqchar = M_SEQCHAR;
656 mbtowc(&wc_seqchar, &mb_seqchar, 1);
657 mb_rschar = M_RSCHAR;
658 mbtowc(&wc_rschar, &mb_rschar, 1);
659 m_current[*n + 1] = m_sreftree[i].index ;
660 if (! m_sreftree[m_current[*n + 1]].symbol)
661 m_delim[*n] = m_sreftree[m_current[*n + 1]].index ;
662 *linestart = newlinestart ;
663 m_srefchartype[*n] = type ;
665 for (k = 0 ; k < M_BSEQLEN ; k++) {
666 m_hold[*n + 1 + k] = m_getachar(&m_dhold[*n + 1 + k]) ;
667 if (m_hold[*n + 1 + k] != ' ' && m_hold[*n + 1 + k] != '\t') {
668 m_ungetachar(m_hold[*n + 1 + k], m_dhold[*n + 1 + k], TRUE) ;
671 m_current[*n + 1 + k + 1] = m_current[*n + 1] ;
672 m_delim[*n + 1 + k] = m_delim[*n] ;
673 m_srefchartype[*n + 1 + k] = wc_seqchar ;
678 m_srefchartype[*n] = wc_rschar ;
681 /* Scans past a comment within a markup declaration */
682 void m_readcomments(void)
687 while (! m_gettoken(&c, &dchar, COMCON))
689 m_error("Document ended within a comment") ;
701 char mb_ee, mb_re, mb_space, mb_tab;
702 M_WCHAR wc_ee, wc_re, wc_space, wc_tab;
705 mbtowc(&wc_ee, &mb_ee, 1);
707 mbtowc(&wc_re, &mb_re, 1);
709 mbtowc(&wc_space, &mb_space, 1);
711 mbtowc(&wc_tab, &mb_tab, 1);
713 n = m_gettoken(&c, &dchar, m_curcon) ;
715 if (n != M_ENTITYEND && m_stacktop->linestat == M_NOTHING)
716 m_stacktop->linestat = M_SOMETHING ;
724 m_ungetachar(wc_re, M_ENTNORMAL, FALSE) ;
728 m_ungetachar(wc_space, M_ENTNORMAL, FALSE) ;
732 m_ungetachar(wc_tab, M_ENTNORMAL, FALSE) ;
742 /* Check for Entity End */
743 if (dchar == wc_ee) {
745 if (m_stacktop->element &&
746 m_element[m_stacktop->element - 1].content == M_RCDATA) {
747 if (m_eopencnt == m_stacktop->thisent) {
748 if (m_netlevel) m_curcon = NETRCDATA ;
749 else m_curcon = RCDATAEL ;}
750 else if (m_eopencnt < m_stacktop->thisent)
751 m_stacktop->thisent = m_eopencnt ;
753 if (m_newcon(m_curcon - 1, M_ENTITYEND - 1)) return(M_ENTITYEND) ;
756 /* Whitespace character--check if could be data. If so,
757 if it's a RE, check if its significant */
758 if (m_whitespace((M_WCHAR) c)) {
759 if (! m_newcon(m_curcon - 1, M_TEXT - 1)) continue ;
760 if (c != wc_re || m_curcon == PROCINT || m_curcon == LITCON ||
761 m_curcon == LITENT || m_curcon == LITAENT) {
770 m_closent(m_sysent[m_sysecnt--]) ;
772 m_trace("Closing to level ") ;
773 sprintf(buffer, "%d", m_sysecnt) ;
782 ((m_curcon == SELEMENT ||
783 m_curcon == EELEMENT ||
784 m_curcon == ENTNAME ||
785 m_curcon == MAPNAME ||
786 m_curcon == AMAPNAME)
787 && m_cttype(c) == M_NMSTART) ||
788 ((m_curcon == ATTNAME || m_curcon == ATTVAL ||
789 m_curcon == NEEDVI) &&
790 m_cttype(c) != M_NONNAME)
792 m_getname((M_WCHAR) c) ;
797 m_err1("Expecting value for %s",
798 &m_pname[m_parameter[m_ppsave - 1].paramname]) ;
800 m_missingtagc(c, dchar, TRUE) ;
804 m_missingtagc(c, dchar, TRUE) ;
807 m_attvonly(m_saveatt) ;
809 m_missingtagc(c, dchar, TRUE) ;
812 if (! m_stacktop->oldtop)
813 m_scanel = m_arc[m_state[0].first - 1].label ;
814 else m_scanel = m_stacktop->element ;
815 m_stacktop->holdre = FALSE ;
817 m_missingtagc(c, dchar, FALSE) ;
823 if (! m_newcon(m_curcon - 1, M_TEXT - 1)) return(M_BLACKSPACE) ;
829 /* Process explicit or implied USEMAP or ADDMAP */
830 void m_setmap(int map, LOGICAL useoradd)
835 if (! m_stacktop->oldtop) {
836 m_error("Program error: attempt to set map for empty stack") ;
842 if (m_stacktop->map && m_stacktop->oldtop->map != m_stacktop->map)
843 m_free(m_stacktop->map, "short reference map") ;
844 /* Done, if USEMAP */
846 m_stacktop->map = NULL ;
849 /* <!ADDMAP #EMPTY> restores map from beginning of element */
850 m_stacktop->map = m_stacktop->oldtop->map ;
851 if (m_element[m_stacktop->element - 1].srefptr)
852 m_setmap(m_element[m_stacktop->element - 1].srefptr,
853 (LOGICAL) m_element[m_stacktop->element - 1].useoradd) ;
857 /* Allocate and initialize a new map if needed */
858 if (! m_stacktop->map || m_stacktop->map == m_stacktop->oldtop->map) {
860 (int *) m_malloc(sizeof(int) * M_SREFCNT, "short reference map") ;
861 for (i = 0 ; i < M_SREFCNT ; i++)
862 if (! useoradd && m_stacktop->oldtop->map)
863 m_stacktop->map[i] = m_stacktop->oldtop->map[i] ;
864 else m_stacktop->map[i] = M_NULLVAL ;
866 /* Clear an old map if replacing it */
869 for (i = 0 ; i < M_SREFCNT ; i++)
870 m_stacktop->map[i] = M_NULLVAL ;
872 /* Offset into m_map is 2, 1 for 0-based indexing, 1 for #EMPTY code */
873 for (sref = m_map[map - 2] ; sref ; sref = m_sref[sref - 1].next)
874 m_stacktop->map[m_sref[sref - 1].sref - 1] = m_sref[sref - 1].entity ;
877 /* Check for short reference delimiters */
878 void m_shortref(int context)
883 LOGICAL linestart = m_atrs ;
888 mbtowc(&wc_ee, &mb_ee, 1);
890 /* If no short references defined, don't try to match one */
891 if (sizeof(m_sreftree)/sizeof(M_PTRIE) == 1) return ;
893 /* Can return if using MARKUP extensions and no map is active */
894 if (! m_conform && ! m_stacktop->map) return ;
897 m_srefchartype[0] = M_RSCHAR ;
900 /* Search through short reference delimiter tree */
906 if (linestart && m_srefchartype[n] >= M_RSCHAR)
908 for (i = m_current[n] ;
909 m_sreftree[i].more && m_sreftree[i].symbol < RS ;
911 if (m_sreftree[i].symbol == RS)
913 m_nextdelimchar(&n, i, &linestart, FALSE, FALSE, M_RSCHAR) ;
918 /* Look for white space sequence */
919 if (m_srefchartype[n] >= M_WSCHAR)
921 for (i = m_current[n] ;
922 m_sreftree[i].more && m_sreftree[i].symbol < WSSEQ ;
924 if (m_sreftree[i].symbol == WSSEQ)
926 m_nextdelimchar(&n, i, &linestart, FALSE, TRUE, M_WSCHAR) ;
931 /* Look at next character from input stream */
932 m_hold[n] = m_getachar(&m_dhold[n]) ;
933 if (m_dhold[n] == wc_ee ||
934 (m_dhold[n] != M_NORMAL && m_dhold[n] != M_ENTNORMAL))
936 m_srefchartype[n] = M_REGCHAR ;
940 /* Look for blank sequence */
941 if (m_srefchartype[n] >= M_BSCHAR &&
942 (m_hold[n] == ' ' || m_hold[n] == '\t'))
944 for (i = m_current[n] ;
945 m_sreftree[i].more && m_sreftree[i].symbol < BLANKSEQ ;
947 if (m_sreftree[i].symbol == BLANKSEQ &&
948 (m_hold[n] == ' ' || m_hold[n] == '\t'))
950 m_nextdelimchar(&n, i, &linestart, FALSE, TRUE, M_BSCHAR) ;
955 /* Look for regular character */
956 c = m_ctupper(m_hold[n]) ;
957 if (m_cttype(c) != M_NMSTART)
959 for (i = m_current[n] ;
960 m_sreftree[i].more && (int) m_sreftree[i].symbol < c ;
962 if ((int) m_sreftree[i].symbol == c)
964 m_nextdelimchar(&n, i, &linestart, m_atrs, FALSE, M_REGCHAR) ;
969 m_srefchartype[n] = M_REGCHAR ;
971 } /* End search through sref delimiter tree */
977 /* Found a delimiter. If letters were allowed in short references
978 would check here for runon situations such as <!ENTITYrunon ... */
979 if (m_gendelim(n, context))
981 for (i = n ; i >= 0 ; i--)
982 if (m_srefchartype[i] < M_WSCHAR)
983 m_ungetachar(m_hold[i], m_dhold[i], TRUE) ;
987 for (i = n ; i >= 0 ; i--)
988 if (m_srefchartype[i] < M_WSCHAR)
993 if (linestart) m_atrs = FALSE ;
994 if (m_stacktop->map && m_stacktop->map[m_delim[n] - 1])
997 &m_entities[m_stacktop->map[m_delim[n] - 1] - 1]) ;
1002 for (i = n ; i >= 0 ; i--)
1003 if (m_srefchartype[i] < M_WSCHAR)
1004 m_ungetachar(m_hold[i], M_CDCHAR, TRUE) ;
1008 if (m_srefchartype[n] < M_WSCHAR)
1009 m_ungetachar(m_hold[n], m_dhold[n], TRUE) ;
1010 if (m_srefchartype[n] > M_REGCHAR)
1012 m_srefchartype[n]-- ;
1021 /* Test for significant record ends. Ignore RE (\n) if
1022 1) It is the first RE in the content and no data character
1023 or contextual end tag has occurred
1024 2) Something has occurred on the line but not a data character
1025 or contextual end tag [linestat == M_SOMETHING]
1026 3) If a record end might be the last one in an element, save it
1030 /* Check for first RE in content and no preceding content */
1032 (! m_stacktop->firstre && m_oldlinestat[m_oldlsindex] != M_DCORCET)) {
1033 m_stacktop->firstre = TRUE ;
1036 /* Check for line containing other than data characters or contextual
1038 if (m_start && m_oldlinestat[m_oldlsindex] == M_SOMETHING) return ;
1039 /* Save the RE to see what follows */
1041 m_stacktop->holdre = TRUE ;
1043 } /* End white space */
1045 /* Returns a context-dependent delimiter string to input stream so
1046 characters can be reread one at a time in another context */
1047 void m_undodelim(M_WCHAR *delim, LOGICAL flag)
1051 for (p = delim ; *p ; p++) ;
1055 m_ungetachar((int) *p, M_NORMAL, flag) ;
1056 if (p == delim) return ;
1061 /* Place a character on the current input stream. The character may have
1062 been scanned and determined not to be part of the current token or it
1063 may be in the expansion of an entity*/
1064 void m_ungetachar(int c, M_HOLDTYPE dchar, LOGICAL preread)
1072 mbtowc(&wc_ee, &mb_ee, 1);
1076 length = wctomb(buffer, c);
1080 sprintf(buffer, "%d", c) ;
1083 sprintf(buffer, "%d", dchar) ;
1087 else m_trace("unget(EE)\n") ;
1089 m_inctest(&m_toundo, M_SAVECHAR, "M_SAVECHAR") ;
1090 m_sourcefile[m_toundo - 1] = m_sysecnt ;
1091 m_savedchar[m_toundo - 1] = dchar ;
1092 m_savechar[m_toundo - 1] = dchar == wc_ee ? (int) m_atrs : c ;
1094 m_stacktop->linestat = m_oldlinestat[m_oldlsindex] ;
1095 m_atrs = m_oldatrs[m_oldlsindex] ;
1096 m_oldlsindex = (m_oldlsindex - 1 + M_SAVECHAR) % M_SAVECHAR ;
1098 if (m_toundo > m_maxundo) m_maxundo = m_toundo ;
1100 if (dchar == M_NORMAL) m_line[m_sysecnt]-- ;
1103 /* Have encountered an M_ERO. If the entity reference is valid, process it*/
1104 LOGICAL m_vldentref(void)
1113 mbtowc(&wc_ee, &mb_ee, 1);
1114 next = m_getachar(&dchar) ;
1115 if (next != EOF && m_cttype(next) == M_NMSTART && dchar != wc_ee) {
1116 m_getname((M_WCHAR) next) ;
1117 if (! m_gettoken(&next, &dchar, ENTREF))
1118 if (next != M_RE) m_ungetachar(next, dchar, TRUE) ;
1119 if (openent = (M_ENTITY *) m_lookfortrie(m_name, m_enttrie))
1120 m_entexpand(openent) ;
1121 else m_err1("Reference to undefined entity '%s'", m_name) ;
1124 m_ungetachar(next, dchar, TRUE) ;