static i4 ad0_cqmatch( ADULcstate *pat, /* the string holding the pattern matching char */ u_char *endpat, /* pointer to end of char string */ ADULcstate *str, /* the other string */ u_char *endstr, /* pointer to the end */ bool bignore) /* If TRUE, ignored blanks and null chars */ { adulnext(pat); /* find a non-blank, non-null char in str, if ignoring these */ if (bignore) { while (adulptr(str) < endstr) { if ((!adulspace(str) && adultrans(str) != 0)) break; adulnext(str); } } if (adulptr(str) < endstr) { _VOID_ adultrans(str); adulnext(str); return (ad0_3clexc_pm(pat, endpat, str, endstr, FALSE, bignore)); } else { return (1); } }
static bool ad0_cpmchk( ADULcstate *str, /* string to look for PM chars in */ u_char *endstr) /* end of str */ { ADULcstate st; STRUCT_ASSIGN_MACRO(*str, st); while (adulptr(&st) < endstr) { switch (adultrans(&st)/COL_MULTI) { case DB_PAT_ONE: case DB_PAT_ANY: case DB_PAT_LBRAC: /* Don't want to look for RBRAC */ return (TRUE); default: adulnext(&st); break; } } return (FALSE); }
static DB_STATUS ad0_llkqmatch( ADF_CB *adf_scb, register ADULcstate *sst, u_char *ends, register ADULcstate *pst, u_char *endp, ADULcstate *est, bool bignore, i4 n, i4 *rcmp) { adulnext(sst); while (adulptr(sst) < ends) { if (bignore && (adulspace(sst) || adulisnull(sst))) { _VOID_ adultrans(sst); adulnext(sst); } else { _VOID_ adultrans(sst); adulnext(sst); if (!--n) return (ad0_llike(adf_scb, sst, ends, pst, endp, est, bignore, rcmp)); } } *rcmp = -1; /* string is shorter than pattern */ return (E_DB_OK); }
DB_STATUS ad0_llike( ADF_CB *adf_scb, register ADULcstate *sst, u_char *ends, register ADULcstate *pst, u_char *endp, ADULcstate *est, bool bignore, i4 *rcmp) { i4 cc; /* the `character class' for pch */ i4 stat; u_char match; /* the untranslated character */ for (;;) /* loop through pattern string */ { int count = 0; DB_STATUS (*llkmatch)(ADF_CB *,ADULcstate *,u_char*,ADULcstate*,u_char*, ADULcstate*,bool,i4,i4*) = ad0_llkpmatch; /* ** Get the next character from the pattern string, ** handling escape sequences, and ignoring blanks if required. ** ----------------------------------------------------------- */ if (adulptr(pst) >= endp) { /* end of pattern string */ cc = AD_CC6_EOS; } else { if (est != NULL && !adulcmp(pst, est)) { adulnext(pst); /* we have an escape sequence */ if (adulptr(pst) >= endp) { /* ERROR: escape at end of pattern string not allowed */ return (adu_error(adf_scb, E_AD1017_ESC_AT_ENDSTR, 0)); } match = *(pst->lstr); _VOID_ adultrans(pst); /* increment pointer, ignore return */ switch (match) /* the RAW character value */ { case AD_1LIKE_ONE: case AD_2LIKE_ANY: case '-': cc = AD_CC0_NORMAL; break; case AD_3LIKE_LBRAC: cc = AD_CC4_LBRAC; break; case AD_4LIKE_RBRAC: cc = AD_CC5_RBRAC; break; default: if (!adulcmp(pst, est)) cc = AD_CC0_NORMAL; else /* ERROR: illegal escape sequence */ return (adu_error(adf_scb, E_AD1018_BAD_ESC_SEQ, 0)); break; } } else { /* not an escape character */ match = *(pst->lstr); _VOID_ adultrans(pst); /* increment pointer, ignore return */ switch (match) /* the RAW character value */ { case AD_1LIKE_ONE: cc = AD_CC2_ONE; break; case AD_2LIKE_ANY: cc = AD_CC3_ANY; break; case '-': cc = AD_CC1_DASH; break; case AD_3LIKE_LBRAC: case AD_4LIKE_RBRAC: default: cc = AD_CC0_NORMAL; break; } } } if ( bignore && cc == AD_CC0_NORMAL && (adulspace(pst) || adulisnull(pst)) ) { adulnext(pst); continue; /* ignore blanks and null chars for the C datatype */ } /* Now we have the next pattern string character and its class */ /* ----------------------------------------------------------- */ switch (cc) { case AD_CC0_NORMAL: case AD_CC1_DASH: for (;;) { if (adulptr(sst) >= ends) { *rcmp = -1; /* string is shorter than pattern */ return (E_DB_OK); } if (!bignore || (!adulspace(sst) && !adulisnull(sst))) break; adulnext(sst); } if ((stat = adulcmp(sst, pst)) != 0) { *rcmp = stat; return (E_DB_OK); } break; case AD_CC2_ONE: count = 1; adulnext(pst); llkmatch = ad0_llkqmatch; /*FALLTHROUGH*/ case AD_CC3_ANY: while (adulptr(pst) < endp) { match = *(pst->lstr); if (match == AD_1LIKE_ONE) { _VOID_ adultrans(pst); /* increment pointer, ignore return */ count++; } else if (match == AD_2LIKE_ANY) { _VOID_ adultrans(pst); /* increment pointer, ignore return */ llkmatch = ad0_llkpmatch; } else if (!bignore || !adulspace(pst) && !adulisnull(pst)) break; adulnext(pst); } return llkmatch(adf_scb, sst, ends, pst, endp, est, bignore, count, rcmp); case AD_CC4_LBRAC: return (ad0_llklmatch(adf_scb, sst, ends, pst, endp, est, bignore, rcmp)); case AD_CC5_RBRAC: /* ** ERROR: bad range specification. */ return (adu_error(adf_scb, E_AD1015_BAD_RANGE, 0)); case AD_CC6_EOS: /* ** End of pattern string. Check for rest of other string. */ while (adulptr(sst) < ends) { if (!bignore || (!adulspace(sst) && !adulisnull(sst))) { *rcmp = 1; /* string is longer than pattern */ return (E_DB_OK); } adulnext(sst); } *rcmp = 0; return (E_DB_OK); default: /* ** ERROR: should *NEVER* get here. */ return (adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0)); } adulnext(pst); adulnext(sst); } }
static i4 ad0_clmatch( ADULcstate *pat, /* the string holding the pattern matching char */ u_char *endpat, /* end of the pattern string */ ADULcstate *str, /* the other string */ u_char *endstr, /* end of the string */ bool bignore) /* If TRUE, ignore blanks and null chars */ { i4 oldc; i4 found; i4 bfound; i4 ret_val = -1; auto ADULcstate sst, pst; oldc = 0; adulnext(pat); /* Look for an empty range, if found, just ignore it */ while (adulptr(pat) < endpat) { if (adultrans(pat)/COL_MULTI == DB_PAT_RBRAC) { /* empty range, ignore it */ adulnext(pat); return (ad0_3clexc_pm(pat, endpat, str, endstr, FALSE, bignore)); } else { if (bignore && (adulspace(pat) || adultrans(pat) == 0)) adulnext(pat); else break; } } /* find a non-blank, non-null char in s, if ignoring these */ while (adulptr(str) < endstr) { if (bignore && (adulspace(str) || adultrans(str) == 0)) { adulnext(str); continue; } /* search for a match on 'c' */ found = 0; /* assume failure */ bfound = 0; /* assume failure */ while (adulptr(pat) < endpat) { switch(adultrans(pat)/COL_MULTI) { case DB_PAT_RBRAC: { adulnext(pat); if (bfound) { /* ** Since we found a blank or null char in the pattern ** range, and blanks and null chars are being ignored, ** try this first to see if the two are equal by ** ignoring the range altogether. */ STRUCT_ASSIGN_MACRO(*pat, pst); STRUCT_ASSIGN_MACRO(*str, sst); ret_val = ad0_3clexc_pm(&pst, endpat, &sst, endstr, FALSE, bignore); } if (ret_val != 0 && found) { adulnext(str); ret_val = ad0_3clexc_pm(pat, endpat, str, endstr, FALSE, bignore); } return (ret_val); } case AD_DASH_CHAR: if (oldc == 0 || (adulnext(pat), adulptr(pat) >= endpat)) return (-1); /* not found ... really an error */ if (oldc - adultrans(str) <= 0 && adulcmp(pat, str) >= 0) found++; break; default: oldc = adultrans(pat); if (bignore && (adulspace(pat) || oldc == 0)) bfound++; if (adultrans(str) == oldc) found++; } adulnext(pat); } return (-1); /* no match ... this should actually be an error, ** because if we reach here, we would have an LBRAC ** without an associated RBRAC. */ } return (1); }
static i4 ad0_cpmatch( ADULcstate *pat, /* the string holding the pattern matching char */ u_char *endpat, /* pointer to end of pattern char string */ ADULcstate *str, /* the string to be checked */ u_char *endstr, /* pointer to end of string */ bool bignore) /* if TRUE, we ignore blanks and null chars */ { ADULcstate psave; ADULcstate ssave; u_i4 c; u_i4 d; adulnext(pat); /* ** Skip over blanks and null chars if requested -- This fixes a ** bug where "a* " would not match "aaa". The extra space after ** the '*' is often put in by EQUEL programs. */ while ( adulptr(pat) < endpat && bignore && (adulspace(pat) || (c = adultrans(pat)) == 0) ) { adulnext(pat); } if (adulptr(pat) >= endpat) return (0); /* a match if no more chars in p */ /* ** If the next character in "pat" is not another ** pattern matching character, then scan until ** first matching char and continue comparison. */ c = adultrans(pat)/COL_MULTI; if (c != DB_PAT_ANY && c != DB_PAT_LBRAC && c != DB_PAT_ONE) { while (adulptr(str) < endstr) { d = adultrans(str)/COL_MULTI; if ( adulcmp(pat, str) == 0 || d == DB_PAT_ANY || d == DB_PAT_LBRAC || d == DB_PAT_ONE ) { STRUCT_ASSIGN_MACRO(*pat, psave); STRUCT_ASSIGN_MACRO(*str, ssave); if (ad0_3clexc_pm(&psave, endpat, &ssave, endstr, FALSE, bignore) == 0) return (0); } adulnext(str); } } else { while (adulptr(str) < endstr) { STRUCT_ASSIGN_MACRO(*pat, psave); STRUCT_ASSIGN_MACRO(*str, ssave); if (ad0_3clexc_pm(&psave, endpat, &ssave, endstr, FALSE, bignore) == 0) return (0); /* match */ _VOID_ adultrans(str); adulnext(str); } } return (-1); /* no match */ }
i4 ad0_3clexc_pm( register ADULcstate *str1, u_char *endstr1, register ADULcstate *str2, u_char *endstr2, bool bpad, bool bignore) { u_i4 ch1; u_i4 ch2; i4 stat; bool have_bpadded = FALSE; u_char blank = AD_BLANK_CHAR; loop: while (adulptr(str1) < endstr1) { ch1 = adultrans(str1); switch (ch1/COL_MULTI) { case DB_PAT_ONE: if (have_bpadded) return (1); /* must have bpadded str2 */ else return (ad0_cqmatch(str1, endstr1, str2, endstr2, bignore)); case DB_PAT_ANY: if (have_bpadded) return (1); /* must have bpadded str2 */ else return (ad0_cpmatch(str1, endstr1, str2, endstr2, bignore)); case DB_PAT_LBRAC: if (have_bpadded) return (1); /* must have bpadded str2 */ else return (ad0_clmatch(str1, endstr1, str2, endstr2, bignore)); case NULLCHAR: if (bignore) break; /* else, fall thru to `default:' */ default: if (bignore && adulspace(str1)) break; while (adulptr(str2) < endstr2) { ch2 = adultrans(str2); switch (ch2/COL_MULTI) { case DB_PAT_ONE: if (have_bpadded) return (-1); /* must have bpadded str1 */ else return (-ad0_cqmatch(str2, endstr2, str1, endstr1, bignore)); case DB_PAT_ANY: if (have_bpadded) return (-1); /* must have bpadded str1 */ else return (-ad0_cpmatch(str2, endstr2, str1, endstr1, bignore)); case DB_PAT_LBRAC: if (have_bpadded) return (-1); /* must have bpadded str1 */ else return (-ad0_clmatch(str2, endstr2, str1, endstr1, bignore)); case NULLCHAR: if (bignore) { adulnext(str2); continue; } /* else, fall thru to `default:' */ default: if (bignore && adulspace(str2)) { adulnext(str2); continue; } if ((stat = ch1 - ch2) == 0) { adulnext(str1); adulnext(str2); goto loop; } else { return (stat); } } } /* string 2 is out of characters, string 1 still has some */ /* examine remainder of string 1 for any characters */ while (adulptr(str1) < endstr1) { ch1 = adultrans(str1); switch (ch1/COL_MULTI) { case DB_PAT_ONE: return (1); /* must have bpadded str2 */ case DB_PAT_ANY: if (have_bpadded) return (1); /* must have bpadded str2 */ else bpad = FALSE; continue; case DB_PAT_LBRAC: if (have_bpadded) return (1); /* must have bpadded str2 */ else return (ad0_clmatch(str1, endstr1, str2, endstr2, bignore)); case NULLCHAR: adulnext(str1); if (bignore) continue; if (bpad && !ad0_cpmchk(str1, endstr1)) return (-1); /* nullchar < padded blank */ else return (1); /* str1 longer than str2 */ default: if (adulspace(str1)) { adulnext(str1); if (bignore) continue; if (bpad) { have_bpadded = TRUE; continue; /* blank = blank */ } else { return (1); /* str1 longer than str2 */ } } else { if ( bpad && adulccmp(str1, (u_char *)" ") < 0 && (adulnext(str1), !ad0_cpmchk(str1, endstr1)) ) return (-1); else return (1); /* str1 longer than str2, or ** ch1 greater than a blank. */ } } } return (0); /* str1 = str2 */ } adulnext(str1); } /* string 1 is out of characters */ /* examine remainder of string 2 for any characters */ while (adulptr(str2) < endstr2) { ch2 = adultrans(str2); switch (ch2/COL_MULTI) { case DB_PAT_ONE: return (-1); /* must have bpadded str1 */ case DB_PAT_ANY: adulnext(str2); if (have_bpadded) return (-1); /* must have bpadded str1 */ else bpad = FALSE; continue; case DB_PAT_LBRAC: if (have_bpadded) return (-1); /* must have bpadded str1 */ else return (-ad0_clmatch(str2, endstr2, str1, endstr1, bignore)); case NULLCHAR: adulnext(str2); if (bignore) continue; if (bpad && !ad0_cpmchk(str2, endstr2)) return (1); /* blank > nullchar */ else return (-1); /* str1 shorter than str2 */ default: if (adulspace(str2)) { adulnext(str2); if (bignore) continue; if (bpad) { have_bpadded = TRUE; continue; /* blank = blank */ } else { return (-1); /* str1 shorter than str2 */ } } else { if ( bpad && adulccmp(str2, (u_char *)" ") < 0 && (adulnext(str2), !ad0_cpmchk(str2, endstr2)) ) return (1); else return (-1); /* str1 shorter than str2, or ** ch2 greater than a blank. */ } } } return (0); /* str1 = str2 */ }
static DB_STATUS ad0_llklmatch( ADF_CB *adf_scb, register ADULcstate *sst, u_char *ends, register ADULcstate *pst, u_char *endp, ADULcstate *est, bool bignore, i4 *rcmp) { ADULcstate savep; i4 cc; i4 cur_state = AD_S1_IN_RANGE_DASH_NORM; bool empty_range = TRUE; bool match_found = FALSE; adulnext(pst); for (;;) { /* ** Get the next character from the pattern string, ** handling escape sequences, and ignoring blanks if required. ** ----------------------------------------------------------- */ if (adulptr(pst) >= endp) { return (adu_error(adf_scb, E_AD1015_BAD_RANGE, 0)); } else { if (est != NULL && !adulcmp(pst, est)) { /* we have an escape sequence */ adulnext(pst); if (adulptr(pst) >= endp) { /* ERROR: escape at end of pattern string not allowed */ return (adu_error(adf_scb, E_AD1017_ESC_AT_ENDSTR, 0)); } switch (adultrans(pst)/COL_MULTI) { case AD_1LIKE_ONE: case AD_2LIKE_ANY: case '-': cc = AD_CC0_NORMAL; break; case AD_3LIKE_LBRAC: cc = AD_CC4_LBRAC; break; case AD_4LIKE_RBRAC: cc = AD_CC5_RBRAC; break; default: if (!adulcmp(pst, est)) cc = AD_CC0_NORMAL; else /* ERROR: illegal escape sequence */ return (adu_error(adf_scb, E_AD1018_BAD_ESC_SEQ, 0)); break; } } else { /* not an escape character */ switch (adultrans(pst)/COL_MULTI) { case AD_1LIKE_ONE: cc = AD_CC2_ONE; break; case AD_2LIKE_ANY: cc = AD_CC3_ANY; break; case '-': cc = AD_CC1_DASH; break; case AD_3LIKE_LBRAC: case AD_4LIKE_RBRAC: default: cc = AD_CC0_NORMAL; break; } } } if (cc == AD_CC6_EOS) return (adu_error(adf_scb, E_AD1015_BAD_RANGE, 0)); if (cc == AD_CC2_ONE || cc == AD_CC3_ANY || cc == AD_CC4_LBRAC) return (adu_error(adf_scb, E_AD1016_PMCHARS_IN_RANGE, 0)); if ( bignore && cc == AD_CC0_NORMAL && (adulspace(pst) || adulisnull(pst)) ) { adulnext(pst); continue; /* ignore blanks and null chars for the C datatype */ } /* ** Now, we have the next pattern character. Switch on the current ** state, then do something depending on what character class ** the next pattern character falls in. Note, that we should be ** guaranteed at this point to have either `NORMAL', `DASH', or `RBRAC'. ** All other cases have been handled above as error conditions. */ switch (cur_state) { case AD_S1_IN_RANGE_DASH_NORM: switch (cc) { case AD_CC0_NORMAL: case AD_CC1_DASH: empty_range = FALSE; STRUCT_ASSIGN_MACRO(*pst, savep); cur_state = AD_S2_IN_RANGE_DASH_IS_OK; break; case AD_CC5_RBRAC: /* end of the range spec, range *MUST* have been empty. */ adulnext(pst); return (ad0_llike(adf_scb, sst, ends, pst, endp, est, bignore, rcmp)); default: /* should *NEVER* get here */ return (adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0)); } break; case AD_S2_IN_RANGE_DASH_IS_OK: switch (cc) { case AD_CC0_NORMAL: if (adulptr(sst) < ends && adulcmp(sst, &savep) == 0) match_found = TRUE; STRUCT_ASSIGN_MACRO(*pst, savep); /* cur_state remains AD_S2_IN_RANGE_DASH_IS_OK */ break; case AD_CC1_DASH: /* do nothing, but change cur_state */ cur_state = AD_S3_IN_RANGE_AFTER_DASH; break; case AD_CC5_RBRAC: /* end of the range spec, and we have a saved char so range */ /* was not empty. */ if (adulptr(sst) < ends && adulcmp(sst, &savep) == 0) match_found = TRUE; if (match_found) { adulnext(sst); adulnext(pst); return (ad0_llike(adf_scb, sst, ends, pst, endp, est, bignore, rcmp)); } *rcmp = -1; /* if string not in range, call it < pat */ return (E_DB_OK); default: /* should *NEVER* get here */ return (adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0)); } break; case AD_S3_IN_RANGE_AFTER_DASH: switch (cc) { case AD_CC0_NORMAL: if (adulcmp(&savep, pst) <= 0) { if ( adulptr(sst) < ends && adulcmp(sst, &savep) >= 0 && adulcmp(sst, pst) <= 0 ) { match_found = TRUE; } cur_state = AD_S4_IN_RANGE_DASH_NOT_OK; break; } /* fall through to BAD-RANGE ... x-y, where x > y */ case AD_CC1_DASH: case AD_CC5_RBRAC: return (adu_error(adf_scb, E_AD1015_BAD_RANGE, 0)); default: /* should *NEVER* get here */ return (adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0)); } break; case AD_S4_IN_RANGE_DASH_NOT_OK: switch (cc) { case AD_CC0_NORMAL: STRUCT_ASSIGN_MACRO(*pst, savep); cur_state = AD_S2_IN_RANGE_DASH_IS_OK; break; case AD_CC1_DASH: return (adu_error(adf_scb, E_AD1015_BAD_RANGE, 0)); case AD_CC5_RBRAC: /* end of the range spec, no saved char, and range was not */ /* empty. */ if (match_found) { adulnext(sst); adulnext(pst); return (ad0_llike(adf_scb, sst, ends, pst, endp, est, bignore, rcmp)); } *rcmp = -1; /* if string not in range, call it < pat */ return (E_DB_OK); default: /* should *NEVER* get here */ return (adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0)); } break; default: /* should *NEVER* get here */ return (adu_error(adf_scb, E_AD9999_INTERNAL_ERROR, 0)); } adulnext(pst); } }
static DB_STATUS ad0_llkpmatch( ADF_CB *adf_scb, register ADULcstate *sst, u_char *ends, register ADULcstate *pst, u_char *endp, ADULcstate *est, bool bignore, i4 n, i4 *rcmp) { DB_STATUS db_stat; ADULcstate nsst, npst; adulnext(sst); while (n && adulptr(sst) < ends) { if (!bignore || !adulspace(sst) && !adulisnull(sst)) n--; _VOID_ adultrans(sst); adulnext(sst); } if (n > 0) { /* String too short for pattern */ *rcmp = -1; return (E_DB_OK); } if (adulptr(pst) >= endp) { /* Last relevant char in pattern was `MATCH-ANY' so we have a match. */ *rcmp = 0; return (E_DB_OK); } while (adulptr(sst) <= ends) /* must be `<=', not just `<' */ { STRUCT_ASSIGN_MACRO(*sst, nsst); STRUCT_ASSIGN_MACRO(*pst, npst); if (db_stat = ad0_llike(adf_scb, &nsst, ends, &npst, endp, est, bignore, rcmp) ) return (db_stat); if (*rcmp == 0) return (E_DB_OK); /* match */ _VOID_ adultrans(sst); adulnext(sst); } /* Finished with string and no match found ... call it `<' by convention. */ *rcmp = -1; return (E_DB_OK); }
/*{ ** Name: maketable - compile a collation description ** ** Description: ** Read a collation description file and create a collation table. ** The table is a modified TRIE structure with a complete map ** at the top level and sparse maps below. ** ** Inputs: ** desfile collation description filename ** ** Outputs: ** none ** ** Returns: ** pointer to collation table on success ** NULL on failure ** ** Exceptions: ** none ** ** Side Effects: ** none ** ** History: ** 03-may-89 (anton) ** Created. ** 17-Jun-89 (anton) ** Moved to ADU from CL ** 17-Jul-89 (anton) ** replace 16 with COL_MULTI and use adulstrinit not aducolinit ** 21-jun-93 (geri) ** Added 2 bugfixes which were in the the 6.4 version: ** 31892: better syntax checking and sane delimiter ** handling; 31993: multiple character pattern match ** rules were not handled correctly. ** 1-oct-04 (toumi01) ** On file-not-found error, make that clear rather than just issuing ** a bogus and misleading syntax error message. ** 1-May-2008 (kibro01) b120307 ** When we find a "+", just check the next character isn't also a "+", ** since it ought to be possible to set the collation relative to "+" ** by having a line "++1:<". */ static ADULTABLE * maketable( char *desfile) { FILE *fp; i4 n; char buf[MAX_LOC]; u_char *s; register i4 lno = 0; register i4 errcnt = 0; i2 *sp, v, t, tt; struct ADUL_tstate *ts; LOCATION loc; ADULcstate cs; STcopy(desfile, buf); LOfroms(FILENAME, buf, &loc); if (SIopen(&loc, "r", &fp) != OK) { SIprintf("aducompile: Unable to open input file \"%s\".\n", loc.string ); return NULL; } w.tab.magic = ADUL_MAGIC; w.tab.nstate = 0; for (n = 0; n < 256; n++) w.tab.firstchar[n] = n * COL_MULTI; while (SIgetrec(buf, sizeof buf, fp) != ENDFILE) { lno++; if (*buf == ':') { /* line is a comment */ continue; } adulstrinit(&w.tab, (u_char*)buf, &cs); v = 0; sp = NULL; while ((t = *(s = adulptr(&cs))) != ':') { /* If this is '+', just confirm that the next character isn't, ** since the construction "++1:<" would be fine, setting < as the ** character 1 place beyond + (kibro01) b120307 */ if (t == '+' && (*(s+1) != '+')) { if (*++s == '*') { v = ADUL_SKVAL; while (*++s != ':' && *s != '\n') continue; if (*s == '\n') { /* syntax error: report line and line number */ SIprintf("Syntax error on line %d: %s", lno, buf); errcnt++; s = NULL; } break; } tt = 0; while ((t = *s - '0') <= 9 && t >= 0) { tt = tt * 10 + t; s++; } adulstrinit(&w.tab, s, &cs); if (sp == NULL) sp = &v; *sp += tt; continue; } if (t == '\n') { /* syntax error - line has no ':' */ SIprintf("Syntax error on line %d: %s", lno, buf); errcnt++; s = NULL; break; } t = adultrans(&cs); adulnext(&cs); if (sp == NULL) { v = t; sp = &v; } else { ts = &w.tab.statetab[w.tab.nstate]; ts->match = *sp; ts->flags = ADUL_LMULT; *sp = w.tab.nstate++ | ADUL_TMULT; ts->nomatch = t; sp = &ts->nomatch; } } if (s == NULL) { /* syntax error occurred */ continue; /* to the next line */ } sp = &w.tab.firstchar[255 & *++s]; ts = NULL; if (*s == '\n') { SIprintf("Syntax error on line %d (no substitution string): %s", lno, buf); continue; } while (*++s != '\n') { while (*sp & ADUL_TMULT) { ts = &w.tab.statetab[*sp & ADUL_TDATA]; if (ts->testchr == *s) { sp = &ts->match; if (*++s == '\n') { goto done; } } else { sp = &ts->nomatch; } } ts = &w.tab.statetab[w.tab.nstate]; ts->match = ts->nomatch = *sp; *sp = ADUL_TMULT | w.tab.nstate++; sp = &ts->match; ts->testchr = *s; ts->flags = ADUL_FINAL; } done: if (ts) ts->flags ^= ADUL_FINAL; *sp = v; } if (errcnt == 0) return &w.tab; return NULL; }