Annotation of libwww/Library/src/HTString.c, revision 2.25
2.10 frystyk 1: /* HTString.c
2: ** DYNAMIC STRING UTILITIES
3: **
2.21 frystyk 4: ** (c) COPYRIGHT MIT 1995.
2.10 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
1.1 timbl 6: **
7: ** Original version came with listserv implementation.
8: ** Version TBL Oct 91 replaces one which modified the strings.
9: ** 02-Dec-91 (JFG) Added stralloccopy and stralloccat
10: ** 23 Jan 92 (TBL) Changed strallocc* to 8 char HTSAC* for VM and suchlike
11: ** 6 Oct 92 (TBL) Moved WWW_TraceFlag in here to be in library
12: */
2.8 frystyk 13:
2.12 frystyk 14: /* Library include files */
15: #include "tcp.h"
1.1 timbl 16: #include "HTUtils.h"
2.13 frystyk 17: #include "HTTCP.h"
2.8 frystyk 18: #include "HTString.h" /* Implemented here */
1.1 timbl 19:
2.12 frystyk 20: #ifdef NO_STDIO
21: PUBLIC FILE *WWWTrace = NULL;
22: #endif
23:
1.1 timbl 24: PUBLIC int WWW_TraceFlag = 0; /* Global trace flag for ALL W3 code */
25:
26: #ifndef VC
27: #define VC "unknown"
28: #endif
29:
30: PUBLIC CONST char * HTLibraryVersion = VC; /* String for help screen etc */
31:
2.13 frystyk 32: PRIVATE long HTTimeZone = 0L; /* Offset from GMT in seconds */
33:
34: /* ------------------------------------------------------------------------- */
35:
2.12 frystyk 36: #ifndef VM /* VM has these already it seems */
1.1 timbl 37:
38: /* Strings of any length
39: ** ---------------------
40: */
41: PUBLIC int strcasecomp ARGS2 (CONST char*,a, CONST char *,b)
42: {
2.13 frystyk 43: int diff;
44: for( ; *a && *b; a++, b++) {
45: if ((diff = TOLOWER(*a) - TOLOWER(*b)))
46: return diff;
47: }
48: if (*a) return 1; /* a was longer than b */
49: if (*b) return -1; /* a was shorter than b */
50: return 0; /* Exact match */
1.1 timbl 51: }
52:
53:
54: /* With count limit
55: ** ----------------
56: */
57: PUBLIC int strncasecomp ARGS3(CONST char*,a, CONST char *,b, int,n)
58: {
59: CONST char *p =a;
60: CONST char *q =b;
61:
62: for(p=a, q=b;; p++, q++) {
63: int diff;
64: if (p == a+n) return 0; /* Match up to n characters */
65: if (!(*p && *q)) return *p - *q;
66: diff = TOLOWER(*p) - TOLOWER(*q);
67: if (diff) return diff;
68: }
69: /*NOTREACHED*/
70: }
71: #endif
72:
2.7 luotonen 73:
74: /*
75: * strcasestr(s1,s2) -- like strstr(s1,s2) but case-insensitive.
76: */
77: PUBLIC char * strcasestr ARGS2(char *, s1,
78: char *, s2)
79: {
2.9 frystyk 80: char * ptr = s1;
2.7 luotonen 81:
82: if (!s1 || !s2 || !*s2) return s1;
83:
2.9 frystyk 84: while (*ptr) {
85: if (TOUPPER(*ptr) == TOUPPER(*s2)) {
86: char * cur1 = ptr + 1;
2.7 luotonen 87: char * cur2 = s2 + 1;
88: while (*cur1 && *cur2 && TOUPPER(*cur1) == TOUPPER(*cur2)) {
89: cur1++;
90: cur2++;
91: }
92: if (!*cur2) {
2.13 frystyk 93: if (TRACE)
2.12 frystyk 94: fprintf(TDEST, "Debug....... strcasestr(s1 = \"%s\", s2 = \"%s\") => \"%s\"\n",
95: s1,s2,ptr);
2.9 frystyk 96: return ptr;
2.7 luotonen 97: }
98: }
2.9 frystyk 99: ptr++;
2.7 luotonen 100: }
2.12 frystyk 101: if (TRACE)
102: fprintf(TDEST,
103: "Debug....... strcasestr(s1=\"%s\", s2=\"%s\") => No match\n",
104: s1,s2);
2.7 luotonen 105: return NULL;
106: }
107:
108:
109:
1.1 timbl 110: /* Allocate a new copy of a string, and returns it
111: */
112: PUBLIC char * HTSACopy
113: ARGS2 (char **,dest, CONST char *,src)
114: {
115: if (*dest) free(*dest);
116: if (! src)
117: *dest = NULL;
118: else {
119: *dest = (char *) malloc (strlen(src) + 1);
120: if (*dest == NULL) outofmem(__FILE__, "HTSACopy");
121: strcpy (*dest, src);
122: }
123: return *dest;
124: }
125:
2.6 timbl 126: /* String Allocate and Concatenate
127: */
1.1 timbl 128: PUBLIC char * HTSACat
129: ARGS2 (char **,dest, CONST char *,src)
130: {
131: if (src && *src) {
132: if (*dest) {
133: int length = strlen (*dest);
134: *dest = (char *) realloc (*dest, length + strlen(src) + 1);
135: if (*dest == NULL) outofmem(__FILE__, "HTSACat");
136: strcpy (*dest + length, src);
137: } else {
138: *dest = (char *) malloc (strlen(src) + 1);
139: if (*dest == NULL) outofmem(__FILE__, "HTSACat");
140: strcpy (*dest, src);
141: }
142: }
143: return *dest;
2.6 timbl 144: }
145:
146:
147: /* Find next Field
148: ** ---------------
149: **
150: ** On entry,
2.13 frystyk 151: ** *pstr points to a string containing a word separated
2.20 frystyk 152: ** by white white space "," ";" or "=". The word
2.13 frystyk 153: ** can optionally be quoted using <"> or "<" ">"
154: ** Comments surrrounded by '(' ')' are filtered out
2.6 timbl 155: **
156: ** On exit,
157: ** *pstr has been moved to the first delimiter past the
158: ** field
159: ** THE STRING HAS BEEN MUTILATED by a 0 terminator
160: **
2.13 frystyk 161: ** Returns a pointer to the first word or NULL on error
2.6 timbl 162: */
163: PUBLIC char * HTNextField ARGS1(char **, pstr)
164: {
165: char * p = *pstr;
2.13 frystyk 166: char * start;
167:
168: while (1) {
2.20 frystyk 169: /* Strip white space and other delimiters */
170: while (*p && (WHITE(*p) || *p==',' || *p==';' || *p=='=')) p++;
2.13 frystyk 171: if (!*p) {
172: *pstr = p;
173: return NULL; /* No field */
174: }
2.20 frystyk 175:
2.13 frystyk 176: if (*p == '"') { /* quoted field */
177: start = ++p;
178: for(;*p && *p!='"'; p++)
179: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
180: } else if (*p == '<') { /* quoted field */
181: for(;*p && *p!='>'; p++)
182: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
183: } else if (*p == '(') { /* Comment */
184: for(;*p && *p!=')'; p++)
185: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
186: p++;
2.20 frystyk 187: } else { /* Spool field */
2.13 frystyk 188: start = p;
2.20 frystyk 189: while(*p && !WHITE(*p) && *p!=',' && *p!=';' && *p!='=')
2.13 frystyk 190: p++;
191: break; /* Got it */
2.6 timbl 192: }
193: }
2.13 frystyk 194: if (*p) *p++ = '\0';
2.6 timbl 195: *pstr = p;
196: return start;
2.13 frystyk 197: }
198:
199:
200: /*
201: ** Returns a string pointer to a static area of the current calendar
202: ** time in RFC 1123 format, for example
203: **
204: ** Sun, 06 Nov 1994 08:49:37 GMT
205: **
206: ** The result can be given in both local and GMT dependent on the flag
207: */
208: PUBLIC CONST char *HTDateTimeStr ARGS2(time_t *, calendar, BOOL, local)
209: {
210: static char buf[40];
211:
212: #ifndef NO_STRFTIME
213: if (local) {
2.24 frystyk 214: /*
215: ** Solaris 2.3 has a bug so we _must_ use reentrant version
216: ** Thomas Maslen <tmaslen@verity.com>
217: */
218: #if defined(HT_REENTRANT) || defined(SOLARIS)
2.17 frystyk 219: struct tm loctime;
220: localtime_r(calendar, &loctime);
221: strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", &loctime);
222: #else
2.13 frystyk 223: struct tm *loctime = localtime(calendar);
224: strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", loctime);
2.24 frystyk 225: #endif /* SOLARIS || HT_REENTRANT */
2.13 frystyk 226: } else {
2.24 frystyk 227: #if defined(HT_REENTRANT) || defined(SOLARIS)
2.17 frystyk 228: struct tm gmt;
229: gmtime_r(calendar, &gmt);
230: strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", &gmt);
231: #else
2.13 frystyk 232: struct tm *gmt = gmtime(calendar);
233: strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", gmt);
2.24 frystyk 234: #endif /* SOLARIS || HT_REENTRANT */
2.13 frystyk 235: }
236: #else
237: if (local) {
2.24 frystyk 238: #if defined(HT_REENTRANT)
239: struct tm loctime;
240: localtime_r(calendar, &loctime);
241: #else
2.13 frystyk 242: struct tm *loctime = localtime(calendar);
2.24 frystyk 243: #endif /* HT_REENTRANT */
2.13 frystyk 244: sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d",
245: wkday[gmt->tm_wday],
246: gmt->tm_mday,
247: month[gmt->tm_mon],
248: gmt->tm_year % 100,
249: gmt->tm_hour,
250: gmt->tm_min,
251: gmt->tm_sec);
252: } else {
2.24 frystyk 253: #if defined(HT_REENTRANT) || defined(SOLARIS)
254: struct tm gmt;
255: gmtime_r(calendar, &gmt);
256: #else
2.13 frystyk 257: struct tm *gmt = gmtime(calendar);
2.24 frystyk 258: #endif
2.13 frystyk 259: sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d GMT",
260: wkday[gmt->tm_wday],
261: gmt->tm_mday,
262: month[gmt->tm_mon],
263: gmt->tm_year % 100,
264: gmt->tm_hour,
265: gmt->tm_min,
266: gmt->tm_sec);
267: }
268: #endif
269: return buf;
270: }
271:
272:
273: /*
274: ** Returns a Message-ID string including the open '<' and the closing '>'.
275: ** The format of the string is:
276: **
277: ** "<" time-in-sec "Z" process-id "@" FQDN ">"
278: **
279: ** or on systems that doesn't have process-id:
280: **
281: ** "<" time-in-sec "Z" user "@" FQDN ">"
282: **
283: ** Returns a pointer to the MessageID
284: */
285: PUBLIC CONST char *HTMessageIdStr NOARGS
286: {
287: static char buf[80];
288: time_t sectime = time(NULL);
289: #ifndef NO_GETPID
290: CONST char *address = HTGetDomainName();
291: #else
292: CONST char *address = HTGetMailAddress();
293: #endif /* NO_GETPID */
294: if (!address) address = tmpnam(NULL);
295: if ((!address || !*address) && sectime < 0) {
296: if (TRACE)
297: fprintf(TDEST, "MessageID... Can't make a unique MessageID\n");
298: return "";
299: }
300: #ifndef NO_GETPID
301: sprintf(buf, "<%ldZ%d@%s>", sectime, getpid(), address ? address : "@@@");
302: #else
303: sprintf(buf, "<%ldZ%s>", sectime, address ? address : "@@@");
304: #endif /* NO_GETPID */
305:
306: *(buf+79) = '\0';
307: return buf;
308: }
309:
310:
311: /* Date and Time Parser
312: ** --------------------
313: ** These functions are taken from the server written by Ari Luotonen
314: */
315:
316: PRIVATE char * month_names[12] =
317: {
318: "Jan", "Feb", "Mar", "Apr", "May", "Jun",
319: "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
320: };
321:
322: PRIVATE int make_num ARGS1(CONST char *, s)
323: {
324: if (*s >= '0' && *s <= '9')
325: return 10 * (*s - '0') + *(s+1) - '0';
326: else
327: return *(s+1) - '0';
328: }
329:
330: PRIVATE int make_month ARGS1(CONST char *, s)
331: {
332: int i;
333: for (i=0; i<12; i++)
334: if (!strncasecomp(month_names[i], s, 3))
335: return i;
336: return 0;
337: }
338:
339: /* Timezone Offset
340: ** ---------------
341: ** Calculates the offset from GMT in seconds
342: */
343: PUBLIC long HTGetTimeZoneOffset NOARGS
344: {
345: #ifndef NO_TIMEZONE
346: {
347: time_t cur_t = time(NULL);
2.24 frystyk 348: #ifdef HT_REENTRANT
349: struct tm loctime;
350: struct tm *local = (struct tm *) localtime_r(&cur_t, &loctime);
351: #else
352: struct tm *local = localtime(&cur_t);
353: #endif /* HT_REENTRANT */
2.22 frystyk 354: if (daylight && local->tm_isdst>0) { /* daylight time? */
355: #ifndef NO_ALTZONE
356: HTTimeZone = altzone;
357: #else
358: /* Assumes a fixed DST offset of 1 hour, which is probably wrong */
359: HTTimeZone = timezone - 3600;
360: #endif
361: } else { /* no */
362: HTTimeZone = timezone;
363: }
2.13 frystyk 364: HTTimeZone = -HTTimeZone;
365: if (TRACE)
2.14 frystyk 366: fprintf(TDEST,"TimeZone.... GMT + (%02d) hours (including DST)\n",
2.13 frystyk 367: (int) HTTimeZone/3600);
368: }
2.14 frystyk 369: #else
370: #ifndef NO_GMTOFF
371: {
372: time_t cur_t = time(NULL);
2.24 frystyk 373: #ifdef HT_REENTRANT
374: struct tm loctime;
375: localtime_r(&cur_t, &loctime);
376: #else
2.14 frystyk 377: struct tm * local = localtime(&cur_t);
2.24 frystyk 378: #endif /* HT_REENTRANT */
2.14 frystyk 379: HTTimeZone = local->tm_gmtoff;
2.22 frystyk 380: if (TRACE)
381: fprintf(TDEST,"TimeZone.... GMT + (%02d) hours (including DST)\n",
382: (int)local->tm_gmtoff / 3600);
2.14 frystyk 383: }
384: #else
385: if (TRACE) fprintf(TDEST,"TimeZone.... Not defined\n");
2.13 frystyk 386: #endif /* !NO_TIMEZONE */
387: #endif /* !NO_GMTOFF */
388: return HTTimeZone;
389: }
390:
391: /*
392: ** Parse a str in GMT format to a local time time_t representation
2.19 frystyk 393: ** Four formats are accepted:
394: **
395: ** Wkd, 00 Mon 0000 00:00:00 GMT (rfc1123)
396: ** Weekday, 00-Mon-00 00:00:00 GMT (rfc850)
397: ** Wkd Mon 00 00:00:00 0000 GMT (ctime)
398: ** 1*DIGIT (delta-seconds)
2.13 frystyk 399: */
400: PUBLIC time_t HTParseTime ARGS1(CONST char *, str)
401: {
402: CONST char * s;
403: struct tm tm;
404: time_t t;
405:
406: if (!str) return 0;
407:
2.19 frystyk 408: if ((s = strchr(str, ','))) { /* Thursday, 10-Jun-93 01:29:59 GMT */
2.13 frystyk 409: s++; /* or: Thu, 10 Jan 1993 01:29:59 GMT */
410: while (*s && *s==' ') s++;
2.19 frystyk 411: if (strchr(s,'-')) { /* First format */
2.13 frystyk 412: if (TRACE)
413: fprintf(TDEST, "Format...... Weekday, 00-Mon-00 00:00:00 GMT\n");
414: if ((int)strlen(s) < 18) {
415: if (TRACE)
416: fprintf(TDEST,
417: "ERROR....... Not a valid time format \"%s\"\n",s);
418: return 0;
419: }
420: tm.tm_mday = make_num(s);
421: tm.tm_mon = make_month(s+3);
422: tm.tm_year = make_num(s+7);
423: tm.tm_hour = make_num(s+10);
424: tm.tm_min = make_num(s+13);
425: tm.tm_sec = make_num(s+16);
2.19 frystyk 426: } else { /* Second format */
2.13 frystyk 427: if (TRACE)
428: fprintf(TDEST, "Format...... Wkd, 00 Mon 0000 00:00:00 GMT\n");
429: if ((int)strlen(s) < 20) {
430: if (TRACE)
431: fprintf(TDEST,
432: "ERROR....... Not a valid time format \"%s\"\n",s);
433: return 0;
434: }
435: tm.tm_mday = make_num(s);
436: tm.tm_mon = make_month(s+3);
437: tm.tm_year = (100*make_num(s+7) - 1900) + make_num(s+9);
438: tm.tm_hour = make_num(s+12);
439: tm.tm_min = make_num(s+15);
440: tm.tm_sec = make_num(s+18);
441:
442: }
2.19 frystyk 443: } else if (isdigit(*str)) { /* delta seconds */
444: t = time(NULL) + atol(str); /* Current local calendar time */
2.24 frystyk 445: if (TRACE) {
446: #ifdef HT_REENTRANT
447: char buffer[CTIME_MAX];
448: fprintf(TDEST, "Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, (char *) ctime_r(&t, buffer, CTIME_MAX));
449: #else
2.19 frystyk 450: fprintf(TDEST, "Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, ctime(&t));
2.24 frystyk 451: #endif
452: }
2.19 frystyk 453: return t;
454:
455: } else { /* Try the other format: Wed Jun 9 01:29:59 1993 GMT */
2.13 frystyk 456: if (TRACE)
457: fprintf(TDEST, "Format...... Wkd Mon 00 00:00:00 0000 GMT\n");
458: s = str;
459: while (*s && *s==' ') s++;
460: if (TRACE)
461: fprintf(TDEST, "Trying...... The Wrong time format: %s\n", s);
462: if ((int)strlen(s) < 24) {
463: if (TRACE)
464: fprintf(TDEST, "ERROR....... Not a valid time format \"%s\"\n",s);
465: return 0;
466: }
467: tm.tm_mday = make_num(s+8);
468: tm.tm_mon = make_month(s+4);
469: tm.tm_year = make_num(s+22);
470: tm.tm_hour = make_num(s+11);
471: tm.tm_min = make_num(s+14);
472: tm.tm_sec = make_num(s+17);
473: }
474: if (tm.tm_sec < 0 || tm.tm_sec > 59 ||
475: tm.tm_min < 0 || tm.tm_min > 59 ||
476: tm.tm_hour < 0 || tm.tm_hour > 23 ||
477: tm.tm_mday < 1 || tm.tm_mday > 31 ||
478: tm.tm_mon < 0 || tm.tm_mon > 11 ||
479: tm.tm_year <70 || tm.tm_year >120) {
480: if (TRACE) fprintf(TDEST,
481: "ERROR....... Parsed illegal time: %02d.%02d.%02d %02d:%02d:%02d\n",
482: tm.tm_mday, tm.tm_mon+1, tm.tm_year,
483: tm.tm_hour, tm.tm_min, tm.tm_sec);
484: return 0;
485: }
486:
2.16 frystyk 487: #if !defined(NO_TIMEZONE) && !defined(NO_ALTZONE)
2.14 frystyk 488: tm.tm_isdst = daylight; /* Already taken into account */
489: #else
490: tm.tm_isdst = -1;
491: #endif
492:
2.13 frystyk 493: #ifndef NO_MKTIME
494: t = mktime(&tm);
2.18 frystyk 495: t += (HTTimeZone);
2.13 frystyk 496: #else
497: #ifndef NO_TIMEGM
498: t = timegm(&tm);
499: #else
2.18 frystyk 500: if (TRACE) fprintf(TDEST,"Time String. Can not be parsed\n");
2.13 frystyk 501: #endif /* !NO_TIMEGM */
502: #endif /* !NO_MKTIME */
503:
504: if (TRACE)
505: fprintf(TDEST,
506: "Time string. %s parsed to %ld seconds, or in local time: %s",
507: str, (long) t, ctime(&t));
508: return t;
1.1 timbl 509: }
2.23 frystyk 510:
511:
512: /* Strip white space off a string
513: ** ------------------------------
514: **
515: ** On exit,
516: ** Return value points to first non-white character, or to 0 if none.
517: ** All trailing white space is OVERWRITTEN with zero.
518: */
519:
520: PUBLIC char * HTStrip ARGS1(char *, s)
521: {
522: #define SPACE(c) ((c==' ')||(c=='\t')||(c=='\n'))
523: char * p=s;
524: if (!s) return NULL; /* Doesn't dump core if NULL */
525: for(p=s;*p;p++); /* Find end of string */
526: for(p--;p>=s;p--) {
527: if(SPACE(*p)) *p=0; /* Zap trailing blanks */
528: else break;
529: }
530: while(SPACE(*s))s++; /* Strip leading blanks */
531: return s;
532: }
2.25 ! frystyk 533:
! 534:
! 535: /* HTNumToStr
! 536: ** Converts a long (byte count) to a string
! 537: ** ----------------------------------------
! 538: ** This function was a PAIN! In computer-world 1K is 1024 bytes
! 539: ** and 1M is 1024K -- however, sprintf() still formats in base-10.
! 540: ** Therefore I output only until 999, and then start using the
! 541: ** next unit. This doesn't work wrong, it's just a feature.
! 542: ** The "str" must be large enough to contain the result.
! 543: */
! 544: PUBLIC void HTNumToStr ARGS2(unsigned long, n, char *, str)
! 545: {
! 546: double size = n/1024.0;
! 547: if (n < 1000)
! 548: sprintf(str, "%dK", n>0 ? 1 : 0);
! 549: else if (size + 0.999 < 1000)
! 550: sprintf(str, "%dK", (int)(size + 0.5));
! 551: else if ((size /= 1024) < 9.9)
! 552: sprintf(str, "%.1fM", (size + 0.05));
! 553: else if (size < 1000)
! 554: sprintf(str, "%dM", (int)(size + 0.5));
! 555: else if ((size /= 1024) < 9.9)
! 556: sprintf(str, "%.1fG", (size + 0.05));
! 557: else
! 558: sprintf(str, "%dG", (int)(size + 0.5));
! 559: }
! 560:
Webmaster