[0001] [0002] [0003] [0004] [0005] [0006] [0007] [0008] [0009] [0010] [0011] [0012] [0013] [0014] [0015] [0016] [0017] [0018] [0019] [0020] [0021] [0022] [0023] [0024] [0025] [0026] [0027] [0028] [0029] [0030] [0031] [0032] [0033] [0034] [0035] [0036] [0037] [0038] [0039] [0040] [0041] [0042] [0043] [0044] [0045] [0046] [0047] [0048] [0049] [0050] [0051] [0052] [0053] [0054] [0055] [0056] [0057] [0058] [0059] [0060] [0061] [0062] [0063] [0064] [0065] [0066] [0067] [0068] [0069] [0070] [0071] [0072] [0073] [0074] [0075] [0076] [0077] [0078] [0079] [0080] [0081] [0082] [0083] [0084] [0085] [0086] [0087] [0088] [0089] [0090] [0091] [0092] [0093] [0094] [0095] [0096] [0097] [0098] [0099] [0100] [0101] [0102] [0103] [0104] [0105] [0106] [0107] [0108] [0109] [0110] [0111] [0112] [0113] [0114] [0115] [0116] [0117] [0118] [0119] [0120] [0121] [0122] [0123] [0124] [0125] [0126] [0127] [0128] [0129] [0130] [0131] [0132] [0133] [0134] [0135] [0136] [0137] [0138] [0139] [0140] [0141] [0142] [0143] [0144] [0145] [0146] [0147] [0148] [0149] [0150] [0151] [0152] [0153] [0154] [0155] [0156] [0157] [0158] [0159] [0160] [0161] [0162] [0163] [0164] [0165] [0166] [0167] [0168] [0169] [0170] [0171] [0172] [0173] [0174] [0175] [0176] [0177] [0178] [0179] [0180] [0181] [0182] [0183] [0184] [0185] [0186] [0187] [0188] [0189] [0190] [0191] [0192] [0193] [0194] [0195] [0196] [0197] [0198] [0199] [0200] [0201] [0202] [0203] [0204] [0205] [0206] [0207] [0208] [0209] [0210] [0211] [0212] [0213] [0214] [0215] [0216] [0217] [0218] [0219] [0220] [0221] [0222] [0223] [0224] [0225] [0226] [0227] [0228] [0229] [0230] [0231] [0232] [0233] [0234] [0235] [0236] [0237] [0238] [0239] [0240] [0241] [0242] [0243] [0244] [0245] [0246] [0247] [0248] [0249] [0250] [0251] [0252] [0253] [0254] [0255] [0256] [0257] [0258] [0259] [0260] [0261] [0262] [0263] [0264] [0265] [0266] [0267] [0268] [0269] [0270] [0271] [0272] [0273] [0274] [0275] [0276] [0277] [0278] [0279] [0280] [0281] [0282] [0283] [0284] [0285] [0286] [0287] [0288] [0289] [0290] [0291] [0292] [0293] [0294] [0295] [0296] [0297] [0298] [0299] [0300] [0301] [0302] [0303] [0304] [0305] [0306] [0307] [0308] [0309] [0310] [0311] [0312] [0313] [0314] [0315] [0316] [0317] [0318] [0319] [0320] [0321] [0322] [0323] [0324] [0325] [0326] [0327] [0328] [0329] [0330] [0331] [0332] [0333] [0334] [0335] [0336] [0337] [0338] [0339] [0340] [0341] [0342] [0343] [0344] [0345] [0346] [0347] [0348] [0349]
/*****************************************************************************/ /* test.c Test a condition returning true or false. REGEX EVALUATION ---------------- Uses the GNU RX1.5 regular expression package. Evaluation is done using case-insensitive, EGREP-compatible matching. A detailed tutorial on regular expression capabilities and usage is well beyond the scope of this document. This summary is only to serve as a quick mnemonic. VWcms regular expressions support the following set of operators. Operator Overview Description Usage ----------- ----- Match-self Operator Ordinary characters Match-any-character Operator . Concatenation Operator Juxtaposition. Repetition Operators * + ? {} Alternation Operator | List Operators [...] [^...] Grouping Operators (...) Back-reference Operator \digit Anchoring Operators ^ $ Backslash Operator Escape meta-character (e.g. \ ^ . $ | [ () The following operators are used to match one, or in conjunction with the repetition operators more, characters of the target string. These single and leading characters are reserved meta-characters and must be escaped using a leading backslash ("\") if required as a literal character in the matching pattern. Matching Operators Expression Purpose ---------- ------- ^ Match the beginning of the line . Match any character $ Match the end of the line | Alternation (or) [abc] Match only a, b or c [^abc] Match anything except a, b and c [a-z0-9] Match any character in the range a to z or 0 to 9 Repetition operators control the extent, or number, of whatever the matching operators match. These are also reserved meta-characters and must be escaped using a leading backslash if required as a literal character. Repetition Operators Expression Function ---------- -------- * Match 0 or more times + Match 1 or more times ? Match 1 or zero times {n} Match exactly n times {n,} Match at least n times {n,m} Match at least n but not more than m times Regular expression equivalents of these common wildcards asterisk ('*') .* question mark ('?') . percentage ('%') . VERSION HISTORY --------------- 04-JUL-2019 MGD initial */ /*****************************************************************************/ #include "wasdoc.h" #include "regex.h" #include <descrip.h> #include <starlet.h> #include <unixlib.h> extern int dbug; /*****************************************************************************/ /* NULL or empty value is false. If test NULL or empty then positive number value is true, zero/negative false, and if empty then the fact the value exists is true (otherwise it would have been false). If test contains a string then test by matching it (keyword or regex) against the value. */ int testCondition ( struct wasdoc_st *docptr, char *value, char *test ) { /* if the value is empty then false */ if (!value || !*value) return (0); /* if no keyword or regex */ if (!test || !*test) { /* if value an integer then negative and zero is false, positive true */ if (isdigit(*value)) return (atoi(value) > 0); /* no keyword/regex then mere existance is considered true */ return (1); } return (testMatch (docptr, value, test) != NULL); } /*****************************************************************************/ /* The time: conditional allows document behaviour to change according to the time of day (or even year), comparing the supplied parameter to the current system time in one of three forms. 1) A twenty-four hour clock range as 'hhmm-hhmm', for example '1200-1759', which should be read as "twelve noon to five fifty-nine PM" (i.e. as a time range in minutes), where the first is the start time and the second the end time of a range. If the current time is within that range (inclusive) the conditional returns true, otherwise false. If the range doesn't look correct false is always returned. 2) A single digit, '1'..'7', representing the day of the week, where 1 is Monday, 2 is Tuesday .. 7 is Sunday. Not exactly the historical way of numbering weekdays (ask any student of Judaism) but it is what lib$day_of_week() returns :^) 3) The final way (if neither of the above) is as a string match with a VMS comparision time (i.e. 'yyyy-mmm-dd hh-mm-ss.hh'). */ int testTime ( struct wasdoc_st *docptr, char *param ) { static char timeString [24]; static $DESCRIPTOR (timeStringDsc, timeString); static $DESCRIPTOR (timeFaoDsc, "!4UL-!2ZL-!2ZL !2ZL:!2ZL:!2ZL.!2ZL\0"); int currentMinute, dayOfWeek, endMinute, result, startMinute, theDay; ulong time64[2]; ushort numTime [7]; char *cptr, *pptr; /*********/ /* begin */ /*********/ sys$gettim (&time64); pptr = param; if (docptr->insight >= 5) wasDocInsight (docptr, "%s", pptr); if (isdigit(pptr[0]) && !isdigit(pptr[1])) { /* day of week, 1 == Monday, 2 == Tuesday .. 7 == Sunday */ lib$day_of_week (&time64, &dayOfWeek); result = 0; for (cptr = pptr; *cptr; cptr++) { if (!isdigit(*cptr)) continue; theDay = *cptr - '0'; if (theDay == dayOfWeek) result = 1; } if (docptr->insight >= 5) wasDocInsight (docptr, "%s%d %s == %u", result ? "✓" : "✗", result, param, dayOfWeek); return (result); } sys$numtim (numTime, time64); if (isdigit(pptr[0]) && isdigit(pptr[1]) && isdigit(pptr[2]) && isdigit(pptr[3]) && pptr[4] == '-' && isdigit(pptr[5]) && isdigit(pptr[6]) && isdigit(pptr[7]) && isdigit(pptr[8])) { /* time range */ result = 1; startMinute = (((pptr[0]-'0')*10) + (pptr[1]-'0')) * 60; if (startMinute > 1380) result = 0; startMinute += ((pptr[2]-'0')*10) + (pptr[3]-'0'); if (startMinute >= 1440) result = 0; endMinute = (((pptr[5]-'0')*10) + (pptr[6]-'0')) * 60; if (endMinute > 1380) result = 0; endMinute += ((pptr[7]-'0')*10) + (pptr[8]-'0'); if (endMinute >= 1440) result = 0; if (result) { currentMinute = numTime[3] * 60 + numTime[4]; if (startMinute <= currentMinute && currentMinute <= endMinute) result = 1; else result = 0; if (docptr->insight >= 5) wasDocInsight (docptr, "%s%d %u <= %u <= %u", result ? "✓" : "✗", result, startMinute, currentMinute, endMinute); return (result); } if (docptr->insight >= 5) wasDocInsight (docptr, "FALSE times?"); return (result); } /* comparison time string */ sys$fao (&timeFaoDsc, NULL, &timeStringDsc, numTime[0], numTime[1], numTime[2], numTime[3], numTime[4], numTime[5], numTime[6]); if (*pptr == '^') result = (testMatch (docptr, timeString, pptr+1) != NULL); else result = decc$match_wild (timeString, pptr); if (docptr->insight >= 5) wasDocInsight (docptr, "%s%d %s \'%s\'", result ? "✓" : "✗", result, timeString, pptr); return (result); } /*****************************************************************************/ /* Look for |this| in |that|. Can be a keyword or a regular expression. Return a pointer to the character immediately following the match, or a NULL. */ char* testMatch ( struct wasdoc_st *docptr, char *that, char *this ) { char *cptr, *sptr; if (dbug>1) fprintf (stdout, "testMatch()\n"); if (docptr->insight >= 5) wasDocInsight (docptr, "%s %s", this, that); if (*this == '^') return (testRegex (docptr, that, this+1)); while (*that) { if (tolower(*that) != tolower(*this)) { that++; continue; } cptr = that; sptr = this; for (;;) { if (!*cptr || !*sptr) break; if (tolower(*cptr) != tolower(*sptr)) break; cptr++; sptr++; } if (!*sptr) return (cptr); that++; } return (NULL); } /*****************************************************************************/ /* Search for the supplied regular expression in the pointed-to text. The search is case-insensitive. If a hit occurs return a pointer to the next character after the hit. If a hit does not occur return a NULL. */ char* testRegex ( struct wasdoc_st *docptr, char *that, char *thisRegEx ) { static int RegexCflags = REG_EXTENDED | REG_ICASE, RegexEflags = 0; static regex_t *rexptr; static regex_t regexp; int retval; char RegExErrMsg [256]; regmatch_t pmatch; /*********/ /* begin */ /*********/ if (dbug>1) fprintf (stdout, "testRegex()\n"); if (!that) { /* initialise */ if (!rexptr) return (NULL); regfree (®exp); rexptr = NULL; return (NULL); } if (!rexptr) { retval = regcomp (®exp, thisRegEx, RegexCflags); if (retval) { regerror (retval, ®exp, RegExErrMsg, sizeof(RegExErrMsg)); if (docptr->insight >= 2) wasDocInsight(docptr, "%s", RegExErrMsg); regfree (®exp); return (NULL); } rexptr = ®exp; } retval = regexec (rexptr, that, 1, &pmatch, RegexEflags); if (retval) { regfree (®exp); rexptr = NULL; return (NULL); } return (that + pmatch.rm_so); } /*****************************************************************************/