📄 htstring.c
字号:
/* Case-independent string comparison HTString.c**** Original version came with listserv implementation.** Version TBL Oct 91 replaces one which modified the strings.** 02-Dec-91 (JFG) Added stralloccopy and stralloccat** 23 Jan 92 (TBL) Changed strallocc* to 8 char HTSAC* for VM and suchlike** 6 Oct 92 (TBL) Moved WWW_TraceFlag in here to be in library** 15 Nov 98 (TD) Added HTSprintf.*/#include <HTUtils.h>#include <LYLeaks.h>#include <LYStrings.h>#ifndef NO_LYNX_TRACEPUBLIC BOOLEAN WWW_TraceFlag = 0; /* Global trace flag for ALL W3 code */PUBLIC int WWW_TraceMask = 0; /* Global trace flag for ALL W3 code */#endif#ifndef VC#define VC "unknown"#endif /* !VC */#ifdef _WINDOWSCONST char * HTLibraryVersion = "2.14FM"; /* String for help screen etc */#elsePUBLIC CONST char * HTLibraryVersion = VC; /* String for help screen etc */#endif/*** strcasecomp8 is a variant of strcasecomp (below)** ------------ -----------** but uses 8bit upper/lower case information** from the current display charset.** It returns 0 if exact match.*/PUBLIC int strcasecomp8 ARGS2( CONST char*, a, CONST char *, b){ CONST char *p = a; CONST char *q = b; for ( ; *p && *q; p++, q++) { int diff = UPPER8(*p, *q); if (diff) return diff; } if (*p) return 1; /* p was longer than q */ if (*q) return -1; /* p was shorter than q */ return 0; /* Exact match */}/*** strncasecomp8 is a variant of strncasecomp (below)** ------------- ------------** but uses 8bit upper/lower case information** from the current display charset.** It returns 0 if exact match.*/PUBLIC int strncasecomp8 ARGS3( CONST char*, a, CONST char *, b, int, n){ CONST char *p = a; CONST char *q = b; for ( ; ; p++, q++) { int diff; if (p == (a+n)) return 0; /* Match up to n characters */ if (!(*p && *q)) return (*p - *q); diff = UPPER8(*p, *q); if (diff) return diff; } /*NOTREACHED*/}#ifndef VM /* VM has these already it seems */#ifdef SH_EX /* 1997/12/23 (Tue) 16:40:31 *//* * This array is designed for mapping upper and lower case letter * together for a case independent comparison. The mappings are * based upon ascii character sequences. */static unsigned char charmap[] = { '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',};PUBLIC int strcasecomp ARGS2( CONST char*, s1, CONST char*, s2){ register unsigned char *cm = charmap; register unsigned char *us1 = (unsigned char *)s1; register unsigned char *us2 = (unsigned char *)s2; while (cm[*us1] == cm[*us2++]) if (*us1++ == '\0') return(0); return (cm[*us1] - cm[*--us2]);}PUBLIC int strncasecomp ARGS3( CONST char*, a, CONST char*, b, int, n){ register unsigned char *cm = charmap; register unsigned char *us1 = (unsigned char *)a; register unsigned char *us2 = (unsigned char *)b; while ((long)(--n) >= 0 && cm[*us1] == cm[*us2++]) if (*us1++ == '\0') return(0); return ((long)n < 0 ? 0 : cm[*us1] - cm[*--us2]);}#else /* SH_EX *//* Strings of any length** ---------------------*/PUBLIC int strcasecomp ARGS2( CONST char*, a, CONST char *, b){ CONST char *p = a; CONST char *q = b; for ( ; *p && *q; p++, q++) { int diff = TOLOWER(*p) - TOLOWER(*q); if (diff) return diff; } if (*p) return 1; /* p was longer than q */ if (*q) return -1; /* p was shorter than q */ return 0; /* Exact match */}/* With count limit** ----------------*/PUBLIC int strncasecomp ARGS3( CONST char*, a, CONST char *, b, int, n){ CONST char *p = a; CONST char *q = b; for ( ; ; p++, q++) { int diff; if (p == (a+n)) return 0; /* Match up to n characters */ if (!(*p && *q)) return (*p - *q); diff = TOLOWER(*p) - TOLOWER(*q); if (diff) return diff; } /*NOTREACHED*/}#endif /* SH_EX */#endif /* VM */#ifdef NOT_ASCII/* Case-insensitive with ASCII collating sequence** ----------------*/PUBLIC int AS_casecomp ARGS2( CONST char*, p, CONST char*, q){ int diff; for ( ; ; p++, q++) { if (!(*p && *q)) return (UCH(*p) - UCH(*q)); diff = TOASCII(TOLOWER(*p)) - TOASCII(TOLOWER(*q)); if (diff) return diff; } /*NOTREACHED*/}/* With count limit and ASCII collating sequence** ----------------** AS_cmp uses n == -1 to compare indefinite length.*/PUBLIC int AS_ncmp ARGS3( CONST char *, p, CONST char *, q, unsigned int, n){ CONST char *a = p; int diff; for ( ; (p-a) < n; p++, q++) { if (!(*p && *q)) return (UCH(*p) - UCH(*q)); diff = TOASCII(*p) - TOASCII(*q); if (diff) return diff; } return 0; /* Match up to n characters */}/* With ASCII collating sequence** ----------------*/PUBLIC int AS_cmp ARGS2( CONST char *, p, CONST char *, q){ return( AS_ncmp( p, q, -1 ) );}#endif /* NOT_ASCII *//* Allocate a new copy of a string, and returns it*/PUBLIC char * HTSACopy ARGS2( char **, dest, CONST char *, src){ if (src != 0) { if (src != *dest) { FREE(*dest); *dest = (char *) malloc (strlen(src) + 1); if (*dest == NULL) outofmem(__FILE__, "HTSACopy"); strcpy (*dest, src); } } else { FREE(*dest); } return *dest;}/* String Allocate and Concatenate*/PUBLIC char * HTSACat ARGS2( char **, dest, CONST char *, src){ if (src && *src && (src != *dest)) { if (*dest) { int length = strlen(*dest); *dest = (char *)realloc(*dest, length + strlen(src) + 1); if (*dest == NULL) outofmem(__FILE__, "HTSACat"); strcpy (*dest + length, src); } else { *dest = (char *)malloc(strlen(src) + 1); if (*dest == NULL) outofmem(__FILE__, "HTSACat"); strcpy (*dest, src); } } return *dest;}/* Find next Field** ---------------**** On entry,** *pstr points to a string containig white space separated** field, optionlly quoted.**** On exit,** *pstr has been moved to the first delimiter past the** field** THE STRING HAS BEEN MUTILATED by a 0 terminator**** returns a pointer to the first field*/PUBLIC char * HTNextField ARGS1( char **, pstr){ char * p = *pstr; char * start; /* start of field */ while (*p && WHITE(*p)) p++; /* Strip white space */ if (!*p) { *pstr = p; return NULL; /* No first field */ } if (*p == '"') { /* quoted field */ p++; start = p; for (; *p && *p!='"'; p++) { if (*p == '\\' && p[1]) p++; /* Skip escaped chars */ } } else { start = p; while (*p && !WHITE(*p)) p++; /* Skip first field */ } if (*p) *p++ = '\0'; *pstr = p; return start;}/* Find next Token** ---------------** Finds the next token in a string** On entry,** *pstr points to a string to be parsed.** delims lists characters to be recognized as delimiters.** If NULL, default is white space "," ";" or "=".** The word can optionally be quoted or enclosed with** chars from bracks.** Comments surrrounded by '(' ')' are filtered out** unless they are specifically reqested by including** ' ' or '(' in delims or bracks.** bracks lists bracketing chars. Some are recognized as** special, for those give the opening char.** If NULL, defaults to <"> and "<" ">".** found points to location to fill with the ending delimiter** found, or is NULL.**** On exit,** *pstr has been moved to the first delimiter past the** field** THE STRING HAS BEEN MUTILATED by a 0 terminator** found points to the delimiter found unless it was NULL.** Returns a pointer to the first word or NULL on error*/PUBLIC char * HTNextTok ARGS4( char **, pstr, CONST char *, delims, CONST char *, bracks, char *, found){ char * p = *pstr; char * start = NULL; BOOL get_blanks, skip_comments; BOOL get_comments; BOOL get_closing_char_too = FALSE; char closer; if (!pstr || !*pstr) return NULL; if (!delims) delims = " ;,=" ; if (!bracks) bracks = "<\"" ; get_blanks = (BOOL) (!strchr(delims,' ') && !strchr(bracks,' ')); get_comments = (BOOL) (strchr(bracks,'(') != NULL); skip_comments = (BOOL) (!get_comments && !strchr(delims,'(') && !get_blanks);#define skipWHITE(c) (!get_blanks && WHITE(c)) while (*p && skipWHITE(*p)) p++; /* Strip white space */ if (!*p) { *pstr = p; if (found) *found = '\0'; return NULL; /* No first field */ } while (1) { /* Strip white space and other delimiters */ while (*p && (skipWHITE(*p) || strchr(delims,*p))) p++; if (!*p) { *pstr = p; if (found) *found = *(p-1); return NULL; /* No field */ } if (*p == '(' && (skip_comments || get_comments)) { /* Comment */ int comment_level = 0; if (get_comments && !start) start = p+1; for(;*p && (*p!=')' || --comment_level>0); p++) { if (*p == '(') comment_level++; else if (*p == '"') { /* quoted field within Comment */ for(p++; *p && *p!='"'; p++) if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */ if (!*p) break; /* (invalid) end of string found, leave */ } if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */ } if (get_comments) break; if (*p) p++; if (get_closing_char_too) { if (!*p || (!strchr(bracks,*p) && strchr(delims,*p))) { break; } else get_closing_char_too = (BOOL) (strchr(bracks,*p) != NULL); } } else if (strchr(bracks,*p)) { /* quoted or bracketed field */ switch (*p) { case '<': closer = '>'; break; case '[': closer = ']'; break; case '{': closer = '}'; break; case ':': closer = ';'; break; default: closer = *p; } if (!start) start = ++p; for(;*p && *p!=closer; p++) if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */ if (get_closing_char_too) { p++; if (!*p || (!strchr(bracks,*p) && strchr(delims,*p))) { break; } else get_closing_char_too = (BOOL) (strchr(bracks,*p) != NULL); } else break; /* kr95-10-9: needs to stop here */ } else { /* Spool field */ if (!start) start = p; while(*p && !skipWHITE(*p) && !strchr(bracks,*p) && !strchr(delims,*p)) p++; if (*p && strchr(bracks,*p)) { get_closing_char_too = TRUE; } else { if (*p=='(' && skip_comments) { *pstr = p; HTNextTok(pstr, NULL, "(", found); /* Advance pstr */ *p = '\0'; if (*pstr && **pstr) (*pstr)++; return start; } break; /* Got it */ } } } if (found) *found = *p; if (*p) *p++ = '\0'; *pstr = p; return start;}PRIVATE char *HTAlloc ARGS2(char *, ptr, size_t, length){ if (ptr != 0) ptr = (char *)realloc(ptr, length); else ptr = (char *)malloc(length); if (ptr == 0) outofmem(__FILE__, "HTAlloc"); return ptr;}/* * If SAVE_TIME_NOT_SPACE is defined, StrAllocVsprintf will hang on to * its temporary string buffers instead of allocating and freeing them * in each invocation. They only grow and never shrink, and won't be * cleaned up on exit. - kw */#if defined(_REENTRANT) || defined(_THREAD_SAFE) || defined(LY_FIND_LEAKS)#undef SAVE_TIME_NOT_SPACE#endif/* * Replacement for sprintf, allocates buffer on the fly according to what's needed * for its arguments. Unlike sprintf, this always concatenates to the destination * buffer, so we do not have to provide both flavors. */typedef enum { Flags, Width, Prec, Type, Format } PRINTF;#define VA_INTGR(type) ival = va_arg((*ap), type)#define VA_FLOAT(type) fval = va_arg((*ap), type)#define VA_POINT(type) pval = (void *)va_arg((*ap), type)#define NUM_WIDTH 10 /* allow for width substituted for "*" in "%*s" */ /* also number of chars assumed to be needed in addition to a given precision in floating point formats */#define GROW_EXPR(n) (((n) * 3) / 2)#define GROW_SIZE 256PUBLIC_IF_FIND_LEAKS char * StrAllocVsprintf ARGS4( char **, pstr, size_t, dst_len, CONST char *, fmt, va_list *, ap){#ifdef SAVE_TIME_NOT_SPACE static size_t tmp_len = 0; static size_t fmt_len = 0; static char *tmp_ptr = NULL; static char *fmt_ptr = NULL;#else size_t tmp_len = GROW_SIZE; char *tmp_ptr = 0; char *fmt_ptr;#endif /* SAVE_TIME_NOT_SPACE */ size_t have, need; char *dst_ptr = *pstr; CONST char *format = fmt; if (fmt == 0 || *fmt == '\0') return 0;#ifdef USE_VASPRINTF if (pstr && !dst_len) { if (*pstr) FREE(*pstr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -