/**************************************************************** * * * Copyright 2001, 2009 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #include "mdef.h" #include "gtm_stdlib.h" #include "gtm_string.h" #include "gtm_ctype.h" #include "zshow.h" #include "patcode.h" #ifdef UNICODE_SUPPORTED #include "gtm_utf8.h" #endif LITREF unsigned char lower_to_upper_table[]; #define FORMAT_PRINTABLE(cp) \ { \ memcpy(&dstptr[des->len], cpstart, (cp) - cpstart); \ des->len += (int)((cp) - cpstart); \ } #define FORMAT_CHAR(c) \ { \ dstptr[des->len] = c; \ ++(des->len); \ } /* Routine that transforms a ZWR subscript to the internal string representation */ boolean_t zwr2format(mstr *src, mstr *des) { unsigned char ch, chtmp, *cp, *cpstart, *end, *dstptr, *strnext; int fastate, num; des->len = 0; if (src->len > 0) { cp = (unsigned char *)src->addr; end = cp + src->len; dstptr = (unsigned char*)des->addr; fastate = 0; for (cpstart = cp; cp < end; ) { switch(fastate) { case 0: /* state that interprets graphic vs. non-graphic */ ch = *cp++; if ('$' == ch) { ch = chtmp = lower_to_upper_table[*cp++]; if (('C' != ch) && (('Z' != ch) || ('C' != (ch = lower_to_upper_table[*cp++])) || ('H' != (ch = lower_to_upper_table[*cp++])))) return FALSE; if ('(' != (ch = *cp++)) return FALSE; fastate = ('C' == chtmp) ? 2 : 3; } else if ('"' == ch) { /* beginning of a quoted string: prepare for the new graphic substring */ fastate = 1; cpstart = cp; } else if ('0' <= ch && ch <= '9') { /* a numeric subscript */ FORMAT_CHAR(ch); fastate = 4; } else if ('.' == ch) { FORMAT_CHAR(ch); fastate = 5; } else return FALSE; break; case 1: /* Continuation of graphic string */ ch = *cp++; if ('"' == ch) { if (cp < end) { switch (*cp) { case '"': /* print the graphic string upto the first quote */ FORMAT_PRINTABLE(cp); cpstart = ++cp; break; case '_': FORMAT_PRINTABLE(cp - 1); fastate = 0; ++cp; break; default: return FALSE; } } else FORMAT_PRINTABLE(cp - 1); } break; case 2: /* parsing the string after $C( */ A2I(cp, end, num); /* NOTE: cp is updated accordingly */ if (num < 0) return FALSE; if (!gtm_utf8_mode) { if (num > 255) return FALSE; FORMAT_CHAR(num); } #ifdef UNICODE_SUPPORTED else { strnext = UTF8_WCTOMB(num, &dstptr[des->len]); if (strnext == &dstptr[des->len]) return FALSE; /* illegal code points in $C() */ des->len += (int)(strnext - &dstptr[des->len]); } #endif switch(ch = *cp++) { case ',': break; case ')': if (cp < end && '_' != *cp++) return FALSE; fastate = 0; break; default: return FALSE; break; } break; case 3: /* parsing the string after $ZCH( */ A2I(cp, end, num); /* NOTE: cp is updated accordingly */ if (num < 0 || num > 255) return FALSE; FORMAT_CHAR(num); switch(ch = *cp++) { case ',': break; case ')': if (cp < end && '_' != *cp++) return FALSE; fastate = 0; break; default: return FALSE; break; } break; case 4: /* a numeric subscript - decimal might still come */ ch = *cp++; if ('0' <= ch && ch <= '9') { FORMAT_CHAR(ch); } else if ('.' == ch) { FORMAT_CHAR(ch); fastate = 5; } else return FALSE; break; case 5: /* a numeric subscript - already seen decimal */ ch = *cp++; if ('0' <= ch && ch <= '9') { FORMAT_CHAR(ch); } else return FALSE; break; default: return FALSE; break; } } } return TRUE; } /* Routine to compute the length of the KEY in ZWR format */ int zwrkeylength(char* ptr, int len) { int keylength, keystate; unsigned ch, chtmp; boolean_t keepgoing; keylength = 0; /* determine length of key */ keystate = 0; keepgoing = TRUE; while ((keylength < len) && keepgoing) /* slightly different here from go_load since we can get kill records too */ { ch = ptr[keylength++]; switch (keystate) { case 0: /* in global name */ if ('=' == ch) /* end of key */ { keylength--; keepgoing = FALSE; } else if ('(' == ch) /* start of subscripts */ keystate = 1; break; case 1: /* in subscripts area, but out of "..." or $C(...) */ switch (ch) { case ')': /* end of subscripts ==> end of key */ keepgoing = FALSE; break; case '"': /* step into "..." */ keystate = 2; break; case '$': /* step into $C(...) */ chtmp = TOUPPER(ptr[keylength]); assert(('C' == chtmp && '(' == ptr[keylength + 1]) || ('Z' == chtmp && 'C' == TOUPPER(ptr[keylength + 1]) && 'H' == TOUPPER(ptr[keylength + 2]) && '(' == ptr[keylength + 3])); keylength += ('C' == chtmp) ? 2 : 4; keystate = 3; break; } break; case 2: /* in "..." */ if ('"' == ch) { switch (ptr[keylength]) { case '"': /* "" */ keylength++; break; case '_': /* _$C(...) or _$ZCH(...) */ assert('$' == ptr[keylength + 1]); chtmp = TOUPPER(ptr[keylength + 2]); assert(('C' == chtmp && '(' == ptr[keylength + 3]) || ('Z' == chtmp && 'C' == TOUPPER(ptr[keylength + 3]) && 'H' == TOUPPER(ptr[keylength + 4]) && '(' == ptr[keylength + 5])); keylength += ('C' == chtmp) ? 4 : 6; keystate = 3; break; default: /* step out of "..." */ keystate = 1; } } break; case 3: /* in $C(...) or $ZCH(...) */ if (')' == ch) { if ('_' == ptr[keylength]) /* step into "..." or $C(...) or $ZCH(...) */ { assert('"' == ptr[keylength + 1] || '$' == ptr[keylength + 1]); if ('"' == ptr[keylength + 1]) { /* step into "..." by advancing over the begin quote */ keylength += 2; keystate = 2; } else { /* step into $C(..) or $ZCH(...) but do not advance over dollar ($) */ keylength += 1; keystate = 1; } break; } else keystate = 1; /* step out of $C(...) */ } break; default: assert(FALSE); break; } } return keylength; }