Annotation of libwww/Library/src/HTWWWStr.c, revision 2.30
2.1 frystyk 1: /* HTWWWStr.c
2: ** WWW RELATED STRING UTILITIES
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.30 ! frystyk 6: ** @(#) $Id: HTWWWStr.c,v 2.29 1998/12/15 02:54:42 frystyk Exp $
2.1 frystyk 7: **
8: ** Now 13 95 Spwaned from HTString.c
9: */
10:
11: /* Library include files */
2.24 frystyk 12: #include "wwwsys.h"
2.10 frystyk 13: #include "WWWUtil.h"
2.1 frystyk 14: #include "HTParse.h"
2.17 frystyk 15: #include "HTInet.h"
2.11 frystyk 16: #include "HTUser.h"
2.1 frystyk 17: #include "HTWWWStr.h" /* Implemented here */
18:
19: PRIVATE char * months[12] = {
20: "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
21: };
22:
2.8 frystyk 23: #ifndef HAVE_STRFTIME
2.1 frystyk 24: PRIVATE char * wkdays[7] = {
2.28 frystyk 25: "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
2.1 frystyk 26: };
27: #endif
28:
29: /* ------------------------------------------------------------------------- */
30:
31: /* Find next Field
32: ** ---------------
33: ** Finds the next RFC822 token in a string
34: ** On entry,
35: ** *pstr points to a string containing a word separated
36: ** by white white space "," ";" or "=". The word
37: ** can optionally be quoted using <"> or "<" ">"
38: ** Comments surrrounded by '(' ')' are filtered out
39: **
40: ** On exit,
41: ** *pstr has been moved to the first delimiter past the
42: ** field
43: ** THE STRING HAS BEEN MUTILATED by a 0 terminator
44: **
45: ** Returns a pointer to the first word or NULL on error
46: */
47: PUBLIC char * HTNextField (char ** pstr)
48: {
49: char * p = *pstr;
50: char * start = NULL;
2.14 frystyk 51: if (!pstr || !*pstr) return NULL;
2.1 frystyk 52: while (1) {
53: /* Strip white space and other delimiters */
2.21 frystyk 54: while (*p && (isspace((int) *p) || *p==',' || *p==';' || *p=='=')) p++;
2.1 frystyk 55: if (!*p) {
56: *pstr = p;
57: return NULL; /* No field */
58: }
59:
60: if (*p == '"') { /* quoted field */
61: start = ++p;
62: for(;*p && *p!='"'; p++)
63: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
64: break; /* kr95-10-9: needs to stop here */
65: } else if (*p == '<') { /* quoted field */
66: start = ++p;
67: for(;*p && *p!='>'; p++)
68: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
69: break; /* kr95-10-9: needs to stop here */
70: } else if (*p == '(') { /* Comment */
71: for(;*p && *p!=')'; p++)
72: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
73: p++;
74: } else { /* Spool field */
75: start = p;
2.21 frystyk 76: while(*p && !isspace((int) *p) && *p!=',' && *p!=';' && *p!='=')
2.1 frystyk 77: p++;
78: break; /* Got it */
79: }
80: }
2.22 frystyk 81: if (*p) *p++ = '\0';
82: *pstr = p;
83: return start;
84: }
85:
86: /* Find next LWS delimited token
87: ** -----------------------------
88: ** On entry,
89: ** *pstr points to a string containing a word separated
90: ** by white white space "," ";" or "=". The word
91: ** can optionally be quoted using <"> or "<" ">"
92: ** Comments surrrounded by '(' ')' are filtered out
93: **
94: ** On exit,
95: ** *pstr has been moved to the first delimiter past the
96: ** field
97: ** THE STRING HAS BEEN MUTILATED by a 0 terminator
98: **
99: ** Returns a pointer to the first word or NULL on error
100: */
101: PUBLIC char * HTNextLWSToken (char ** pstr)
102: {
103: char * p = *pstr;
104: char * start = NULL;
105: if (!pstr || !*pstr) return NULL;
106:
107: /* Strip initial white space */
108: while (*p && (isspace((int) *p))) p++;
109: if (!*p) {
110: *pstr = p;
111: return NULL; /* No field */
112: }
113:
114: /* Now search for the next white space */
115: start = p;
116: while(*p && !isspace((int) *p)) p++;
117:
2.1 frystyk 118: if (*p) *p++ = '\0';
119: *pstr = p;
120: return start;
121: }
122:
2.16 frystyk 123: /* Find next Name-value pair
124: ** -------------------------
125: ** This is the same as HTNextField but it does not look for '=' as a
126: ** separator so if there is a name-value pair then both parts are
127: ** returned.
128: ** Returns a pointer to the first word or NULL on error
129: */
130: PUBLIC char * HTNextPair (char ** pstr)
131: {
132: char * p = *pstr;
133: char * start = NULL;
134: if (!pstr || !*pstr) return NULL;
135: while (1) {
136: /* Strip white space and other delimiters */
137: while (*p && (*p==',' || *p==';')) p++;
138: if (!*p) {
139: *pstr = p;
140: return NULL; /* No field */
141: }
142:
143: if (*p == '"') { /* quoted field */
144: start = ++p;
145: for(;*p && *p!='"'; p++)
146: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
147: break; /* kr95-10-9: needs to stop here */
148: } else if (*p == '<') { /* quoted field */
149: start = ++p;
150: for(;*p && *p!='>'; p++)
151: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
152: break; /* kr95-10-9: needs to stop here */
153: } else if (*p == '(') { /* Comment */
154: for(;*p && *p!=')'; p++)
155: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
156: p++;
157: } else { /* Spool field */
158: start = p;
159: while(*p && *p!=',' && *p!=';')
2.20 frystyk 160: p++;
161: break; /* Got it */
162: }
163: }
164: if (*p) *p++ = '\0';
165: *pstr = p;
166: return start;
167: }
168:
169: /* Find next "/" delimied segment
170: ** ------------------------------
171: ** This is the same as HTNextField but it includes "/" as a delimiter.
172: ** Returns a pointer to the first segment or NULL on error
173: */
174: PUBLIC char * HTNextSegment (char ** pstr)
175: {
176: char * p = *pstr;
177: char * start = NULL;
178: if (!pstr || !*pstr) return NULL;
179: while (1) {
180: /* Strip white space and other delimiters */
2.21 frystyk 181: while (*p && (isspace((int) *p) || *p==',' || *p==';' || *p=='=' || *p=='/')) p++;
2.20 frystyk 182: if (!*p) {
183: *pstr = p;
184: return NULL; /* No field */
185: }
186:
187: if (*p == '"') { /* quoted field */
188: start = ++p;
189: for(;*p && *p!='"'; p++)
190: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
191: break; /* kr95-10-9: needs to stop here */
192: } else if (*p == '<') { /* quoted field */
193: start = ++p;
194: for(;*p && *p!='>'; p++)
195: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
196: break; /* kr95-10-9: needs to stop here */
197: } else if (*p == '(') { /* Comment */
198: for(;*p && *p!=')'; p++)
199: if (*p == '\\' && *(p+1)) p++; /* Skip escaped chars */
200: p++;
201: } else { /* Spool field */
202: start = p;
2.21 frystyk 203: while(*p && !isspace((int) *p) && *p!=',' && *p!=';' && *p!='=' && *p!='/')
2.16 frystyk 204: p++;
205: break; /* Got it */
206: }
207: }
208: if (*p) *p++ = '\0';
209: *pstr = p;
210: return start;
211: }
212:
2.1 frystyk 213: /*
2.14 frystyk 214: ** Find the next s-expression token from a string of characters.
215: ** We return the name of this expression and the param points to the
216: ** parameters.
217: **
218: ** NOTE: The string has been mutilated by '/0's
219: */
220: PUBLIC char * HTNextSExp (char ** exp, char ** param)
221: {
222: char * p = *exp;
223: char * name = NULL;
224: if (!exp || !*exp) return NULL;
2.21 frystyk 225: while (*p && isspace((int) *p)) p++; /* Strip leading white space */
2.14 frystyk 226: if (!*p) {
227: *exp = p;
228: return NULL; /* No field */
229: }
230: if (*p == '{') { /* Open bracket */
231: int cnt = 1;
232: /*
233: ** Look for name of this expression. If we find a token then search
234: ** for the rest of the expression and remove the end '}'
235: */
236: p++;
237: if ((name = HTNextField(&p)) == NULL) return NULL;
2.21 frystyk 238: while (*p && isspace((int) *p)) p++;
2.14 frystyk 239: *param = p;
240: while (*p) {
241: if (*p == '{') cnt++;
242: if (*p == '}') cnt--;
243: if (!cnt) {
244: *p = '\0';
245: break;
246: }
247: p++;
248: }
249: }
250: return name;
251: }
252:
253: /*
2.1 frystyk 254: ** Returns a Message-ID string including the open '<' and the closing '>'.
255: ** The format of the string is:
256: **
257: ** "<" time-in-sec "Z" process-id "@" FQDN ">"
258: **
259: ** or on systems that doesn't have process-id:
260: **
261: ** "<" time-in-sec "Z" user "@" FQDN ">"
262: **
263: ** Returns a pointer to the MessageID
264: */
2.11 frystyk 265: PUBLIC const char * HTMessageIdStr (HTUserProfile * up)
2.1 frystyk 266: {
267: static char buf[80];
268: time_t sectime = time(NULL);
2.8 frystyk 269: #ifdef HAVE_GETPID
2.11 frystyk 270: const char * address = HTUserProfile_fqdn(up);
2.1 frystyk 271: #else
2.11 frystyk 272: const char * address = HTUserProfile_email(up);
2.8 frystyk 273: #endif /* HAVE_GETPID */
2.1 frystyk 274: if (!address) address = tmpnam(NULL);
275: if ((!address || !*address) && sectime < 0) {
2.9 hallam 276: if (CORE_TRACE)
2.6 eric 277: HTTrace("MessageID... Can't make a unique MessageID\n");
2.1 frystyk 278: return "";
279: }
2.8 frystyk 280: #ifdef HAVE_GETPID
2.23 frystyk 281: sprintf(buf, "<%ldZ%ld@%s>", (long)sectime, (long)getpid(), address ? address : "@@@");
2.1 frystyk 282: #else
283: sprintf(buf, "<%ldZ%s>", sectime, address ? address : "@@@");
2.8 frystyk 284: #endif /* HAVE_GETPID */
2.1 frystyk 285:
286: *(buf+79) = '\0';
287: return buf;
288: }
289:
290: /* Date and Time Parser
291: ** --------------------
292: ** These functions are taken from the server written by Ari Luotonen
293: */
2.14 frystyk 294: #if 0
2.8 frystyk 295: PRIVATE int make_num (const char * s)
2.1 frystyk 296: {
297: if (*s >= '0' && *s <= '9')
298: return 10 * (*s - '0') + *(s+1) - '0';
299: else
300: return *(s+1) - '0';
301: }
2.14 frystyk 302: #endif
303: PRIVATE int make_month (char * s, char ** ends)
2.1 frystyk 304: {
2.14 frystyk 305: char * ptr = s;
2.21 frystyk 306: while (!isalpha((int) *ptr)) ptr++;
2.14 frystyk 307: if (*ptr) {
308: int i;
309: *ends = ptr+3;
310: for (i=0; i<12; i++)
311: if (!strncasecomp(months[i], ptr, 3)) return i;
312: }
2.1 frystyk 313: return 0;
314: }
315:
316: /*
317: ** Parse a str in GMT format to a local time time_t representation
318: ** Four formats are accepted:
319: **
320: ** Wkd, 00 Mon 0000 00:00:00 GMT (rfc1123)
321: ** Weekday, 00-Mon-00 00:00:00 GMT (rfc850)
322: ** Wkd Mon 00 00:00:00 0000 GMT (ctime)
323: ** 1*DIGIT (delta-seconds)
324: */
2.16 frystyk 325: PUBLIC time_t HTParseTime (const char * str, HTUserProfile * up, BOOL expand)
2.1 frystyk 326: {
2.14 frystyk 327: char * s;
2.1 frystyk 328: struct tm tm;
329: time_t t;
330:
331: if (!str) return 0;
332:
333: if ((s = strchr(str, ','))) { /* Thursday, 10-Jun-93 01:29:59 GMT */
334: s++; /* or: Thu, 10 Jan 1993 01:29:59 GMT */
335: while (*s && *s==' ') s++;
336: if (strchr(s,'-')) { /* First format */
2.9 hallam 337: if (CORE_TRACE)
2.6 eric 338: HTTrace("Format...... Weekday, 00-Mon-00 00:00:00 GMT\n");
2.1 frystyk 339: if ((int)strlen(s) < 18) {
2.9 hallam 340: if (CORE_TRACE)
2.6 eric 341: HTTrace(
2.1 frystyk 342: "ERROR....... Not a valid time format \"%s\"\n",s);
343: return 0;
344: }
2.14 frystyk 345: tm.tm_mday = strtol(s, &s, 10);
346: tm.tm_mon = make_month(s, &s);
2.16 frystyk 347: tm.tm_year = strtol(++s, &s, 10);
2.14 frystyk 348: tm.tm_hour = strtol(s, &s, 10);
349: tm.tm_min = strtol(++s, &s, 10);
350: tm.tm_sec = strtol(++s, &s, 10);
351:
2.1 frystyk 352: } else { /* Second format */
2.9 hallam 353: if (CORE_TRACE)
2.6 eric 354: HTTrace("Format...... Wkd, 00 Mon 0000 00:00:00 GMT\n");
2.1 frystyk 355: if ((int)strlen(s) < 20) {
2.9 hallam 356: if (CORE_TRACE)
2.19 frystyk 357: HTTrace("ERROR....... Not a valid time format \"%s\"\n",s);
2.1 frystyk 358: return 0;
359: }
2.14 frystyk 360: tm.tm_mday = strtol(s, &s, 10);
361: tm.tm_mon = make_month(s, &s);
362: tm.tm_year = strtol(s, &s, 10) - 1900;
363: tm.tm_hour = strtol(s, &s, 10);
364: tm.tm_min = strtol(++s, &s, 10);
365: tm.tm_sec = strtol(++s, &s, 10);
2.1 frystyk 366: }
2.21 frystyk 367: } else if (isdigit((int) *str)) {
2.19 frystyk 368:
369: if (strchr(str, 'T')) { /* ISO (limited format) date string */
370: if (CORE_TRACE) HTTrace("Format...... YYYY.MM.DDThh:mmStzWkd\n");
371: s = (char *) str;
372: while (*s && *s==' ') s++;
373: if ((int)strlen(s) < 21) {
374: if (CORE_TRACE)
375: HTTrace("ERROR....... Not a valid time format `%s\'\n", s);
376: return 0;
377: }
378: tm.tm_year = strtol(s, &s, 10) - 1900;
379: tm.tm_mon = strtol(++s, &s, 10);
380: tm.tm_mday = strtol(++s, &s, 10);
381: tm.tm_hour = strtol(++s, &s, 10);
382: tm.tm_min = strtol(++s, &s, 10);
383: tm.tm_sec = strtol(++s, &s, 10);
384:
385: } else { /* delta seconds */
386: t = expand ? time(NULL) + atol(str) : atol(str);
387: if (CORE_TRACE) {
388: if (expand) {
2.1 frystyk 389: #ifdef HT_REENTRANT
2.19 frystyk 390: char buffer[CTIME_MAX];
391: HTTrace("Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, (char *) ctime_r(&t, buffer, CTIME_MAX));
2.1 frystyk 392: #else
2.19 frystyk 393: HTTrace("Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, ctime(&t));
2.1 frystyk 394: #endif
2.19 frystyk 395: } else {
396: HTTrace("Time string. Delta-time %s parsed to %ld seconds\n", str, (long) t);
397: }
2.16 frystyk 398: }
2.19 frystyk 399: return t;
2.1 frystyk 400: }
401:
402: } else { /* Try the other format: Wed Jun 9 01:29:59 1993 GMT */
2.19 frystyk 403: if (CORE_TRACE) HTTrace("Format...... Wkd Mon 00 00:00:00 0000 GMT\n");
2.14 frystyk 404: s = (char *) str;
2.1 frystyk 405: while (*s && *s==' ') s++;
2.19 frystyk 406: if (CORE_TRACE) HTTrace("Trying...... The Wrong time format: %s\n", s);
2.1 frystyk 407: if ((int)strlen(s) < 24) {
2.9 hallam 408: if (CORE_TRACE)
2.6 eric 409: HTTrace("ERROR....... Not a valid time format \"%s\"\n",s);
2.1 frystyk 410: return 0;
411: }
2.14 frystyk 412: tm.tm_mon = make_month(s, &s);
413: tm.tm_mday = strtol(s, &s, 10);
414: tm.tm_hour = strtol(s, &s, 10);
415: tm.tm_min = strtol(++s, &s, 10);
416: tm.tm_sec = strtol(++s, &s, 10);
417: tm.tm_year = strtol(s, &s, 10) - 1900;
2.1 frystyk 418: }
419: if (tm.tm_sec < 0 || tm.tm_sec > 59 ||
420: tm.tm_min < 0 || tm.tm_min > 59 ||
421: tm.tm_hour < 0 || tm.tm_hour > 23 ||
422: tm.tm_mday < 1 || tm.tm_mday > 31 ||
423: tm.tm_mon < 0 || tm.tm_mon > 11 ||
424: tm.tm_year <70 || tm.tm_year >120) {
2.9 hallam 425: if (CORE_TRACE) HTTrace(
2.1 frystyk 426: "ERROR....... Parsed illegal time: %02d.%02d.%02d %02d:%02d:%02d\n",
427: tm.tm_mday, tm.tm_mon+1, tm.tm_year,
428: tm.tm_hour, tm.tm_min, tm.tm_sec);
429: return 0;
430: }
431:
2.30 ! frystyk 432: #if 0
2.8 frystyk 433: #if defined(HAVE_TIMEZONE) && defined(HAVE_ALTZONE)
2.1 frystyk 434: tm.tm_isdst = daylight; /* Already taken into account */
2.30 ! frystyk 435: HTTrace("Time string. Daylight is %s\n",
! 436: daylight>0 ? "on" : daylight==0 ? "off" : "unknown");
! 437: #endif
2.1 frystyk 438: #else
2.30 ! frystyk 439: /* Let mktime decide whether we have DST or not */
2.1 frystyk 440: tm.tm_isdst = -1;
441: #endif
442:
2.8 frystyk 443: #ifdef HAVE_MKTIME
2.1 frystyk 444: t = mktime(&tm);
2.17 frystyk 445: t += (up ? HTUserProfile_timezone(up) : HTGetTimeZoneOffset());
2.1 frystyk 446: #else
2.8 frystyk 447: #ifdef HAVE_TIMEGM
2.1 frystyk 448: t = timegm(&tm);
449: #else
2.8 frystyk 450: #error "Neither mktime nor timegm defined"
451: #endif /* HAVE_TIMEGM */
452: #endif /* HAVE_MKTIME */
2.1 frystyk 453:
2.30 ! frystyk 454: if (CORE_TRACE) {
! 455: char buf[30];
! 456: *buf='\0';
! 457: HTDateDirStr(&t, buf, 30);
! 458: HTTrace("Time string. %s parsed to %ld seconds in local time (%s)\n",
! 459: str, (long) t, buf);
! 460: }
2.1 frystyk 461: return t;
462: }
463:
464: /*
465: ** Returns a string pointer to a static area of the current calendar
466: ** time in RFC 1123 format, for example
467: **
468: ** Sun, 06 Nov 1994 08:49:37 GMT
469: **
470: ** The result can be given in both local and GMT dependent on the flag
471: */
2.8 frystyk 472: PUBLIC const char *HTDateTimeStr (time_t * calendar, BOOL local)
2.1 frystyk 473: {
474: static char buf[40];
475:
2.8 frystyk 476: #ifdef HAVE_STRFTIME
2.1 frystyk 477: if (local) {
478: /*
479: ** Solaris 2.3 has a bug so we _must_ use reentrant version
480: ** Thomas Maslen <tmaslen@verity.com>
481: */
482: #if defined(HT_REENTRANT) || defined(SOLARIS)
483: struct tm loctime;
484: localtime_r(calendar, &loctime);
485: strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", &loctime);
486: #else
487: struct tm *loctime = localtime(calendar);
488: strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", loctime);
489: #endif /* SOLARIS || HT_REENTRANT */
490: } else {
491: #if defined(HT_REENTRANT) || defined(SOLARIS)
492: struct tm gmt;
493: gmtime_r(calendar, &gmt);
494: strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", &gmt);
495: #else
496: struct tm *gmt = gmtime(calendar);
497: strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", gmt);
498: #endif /* SOLARIS || HT_REENTRANT */
499: }
500: #else
501: if (local) {
502: #if defined(HT_REENTRANT)
503: struct tm loctime;
504: localtime_r(calendar, &loctime);
505: #else
506: struct tm *loctime = localtime(calendar);
507: #endif /* HT_REENTRANT */
2.24 frystyk 508: sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d",
2.12 frystyk 509: wkdays[loctime->tm_wday],
510: loctime->tm_mday,
511: months[loctime->tm_mon],
2.24 frystyk 512: loctime->tm_year + 1900,
2.12 frystyk 513: loctime->tm_hour,
514: loctime->tm_min,
515: loctime->tm_sec);
2.1 frystyk 516: } else {
517: #if defined(HT_REENTRANT) || defined(SOLARIS)
518: struct tm gmt;
519: gmtime_r(calendar, &gmt);
520: #else
521: struct tm *gmt = gmtime(calendar);
522: #endif
2.24 frystyk 523: sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d GMT",
2.1 frystyk 524: wkdays[gmt->tm_wday],
525: gmt->tm_mday,
526: months[gmt->tm_mon],
2.24 frystyk 527: gmt->tm_year + 1900,
2.1 frystyk 528: gmt->tm_hour,
529: gmt->tm_min,
530: gmt->tm_sec);
531: }
532: #endif
533: return buf;
534: }
535:
536: /* HTDateDirStr
537: ** ------------
538: ** Generates a date string used in directory listings
539: */
540: PUBLIC BOOL HTDateDirStr (time_t * time, char * str, int len)
541: {
2.8 frystyk 542: #ifdef HAVE_STRFTIME
2.1 frystyk 543: #if defined(HT_REENTRANT) || defined(SOLARIS)
544: struct tm loctime;
545: localtime_r(time, &loctime);
2.29 frystyk 546: strftime(str, len, "%d-%b-%Y %H:%M", &loctime);
2.1 frystyk 547: return YES;
548: #else
2.29 frystyk 549: strftime(str, len, "%d-%b-%Y %H:%M", localtime(time));
2.1 frystyk 550: return YES;
551: #endif /* HT_REENTRANT || SOLARIS */
552: #else
553: if (len >= 16) {
554: struct tm *loctime = localtime(time);
2.12 frystyk 555: sprintf(str,"%02d-%s-%02d %02d:%02d",
2.1 frystyk 556: loctime->tm_mday,
557: months[loctime->tm_mon],
558: loctime->tm_year % 100,
559: loctime->tm_hour,
560: loctime->tm_min);
561: return YES;
562: }
563: return NO;
2.8 frystyk 564: #endif /* HAVE_STRFTIME */
2.1 frystyk 565: }
566:
567: /* HTNumToStr
568: ** Converts a long (byte count) to a string
569: ** ----------------------------------------
570: ** This function was a PAIN! In computer-world 1K is 1024 bytes
571: ** and 1M is 1024K -- however, sprintf() still formats in base-10.
572: ** Therefore I output only until 999, and then start using the
573: ** next unit. This doesn't work wrong, it's just a feature.
574: ** The "str" must be large enough to contain the result.
575: */
576: PUBLIC void HTNumToStr (unsigned long n, char * str, int len)
577: {
578: double size = n/1024.0;
579: if (len < 6) {
580: *str = '\0';
581: return;
582: }
583: if (n < 1000)
584: sprintf(str, "%dK", n>0 ? 1 : 0);
585: else if (size + 0.999 < 1000)
586: sprintf(str, "%dK", (int)(size + 0.5));
587: else if ((size /= 1024) < 9.9)
588: sprintf(str, "%.1fM", (size + 0.05));
589: else if (size < 1000)
590: sprintf(str, "%dM", (int)(size + 0.5));
591: else if ((size /= 1024) < 9.9)
592: sprintf(str, "%.1fG", (size + 0.05));
593: else
594: sprintf(str, "%dG", (int)(size + 0.5));
2.12 frystyk 595: }
596:
597: /*
598: ** Matches MIME constructions for content-types and others like
599: ** them, for example "text/html", "text/plain". It can also match
600: ** wild cards like "text/<star>" and "<star>/<star>. We use <star>
601: ** instead of * in order note to make C like comments :-)
602: */
603: PUBLIC BOOL HTMIMEMatch (HTAtom * tmplate, HTAtom * actual)
604: {
605: const char *t, *a;
606: char *st, *sa;
607: BOOL match = NO;
608:
609: if (tmplate && actual && (t = HTAtom_name(tmplate))) {
610: if (!strcmp(t, "*"))
611: return YES;
612:
613: if (strchr(t, '*') &&
614: (a = HTAtom_name(actual)) &&
615: (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
616:
617: *sa = 0;
618: *st = 0;
619:
620: if ((*(st-1)=='*' &&
621: (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
622: (*(st+1)=='*' && !strcasecomp(t,a)))
623: match = YES;
624:
625: *sa = '/';
626: *st = '/';
627: }
628: }
629: return match;
2.1 frystyk 630: }
631:
632: /* Convert file URLs into a local representation
633: ** ---------------------------------------------
634: ** The URL has already been translated through the rules in get_physical
635: ** in HTAccess.c and all we need to do now is to map the path to a local
636: ** representation, for example if must translate '/' to the ones that
637: ** turn the wrong way ;-)
638: ** Returns:
639: ** OK: local file (that must be freed by caller)
640: ** Error: NULL
641: */
2.11 frystyk 642: PUBLIC char * HTWWWToLocal (const char * url, const char * base,
643: HTUserProfile * up)
2.1 frystyk 644: {
645: if (url) {
646: char * access = HTParse(url, base, PARSE_ACCESS);
647: char * host = HTParse(url, base, PARSE_HOST);
648: char * path = HTParse(url, base, PARSE_PATH+PARSE_PUNCTUATION);
2.11 frystyk 649: const char * myhost = HTUserProfile_fqdn(up);
2.1 frystyk 650:
651: /* Find out if this is a reference to the local file system */
2.16 frystyk 652: if ((*access && strcmp(access, "file") && strcmp(access, "cache")) ||
653: (*host && strcasecomp(host, "localhost") &&
654: myhost && strcmp(host, myhost))) {
2.1 frystyk 655: if (PROT_TRACE)
2.6 eric 656: HTTrace("LocalName... Not on local file system\n");
2.5 frystyk 657: HT_FREE(access);
658: HT_FREE(host);
659: HT_FREE(path);
2.1 frystyk 660: return NULL;
661: } else {
662: char *ptr;
663: if ((ptr = strchr(path, ';')) || (ptr = strchr(path, '?')))
664: *ptr = '\0';
665:
666: /*
667: ** Do whatever translation is required here in order to fit your
668: ** platform _before_ the path is unescaped.
669: */
670: #ifdef VMS
671: HTVMS_checkDecnet(path);
672: #endif
2.3 frystyk 673: #ifdef WWW_MSWINDOWS
2.27 frystyk 674: /* An absolute pathname with logical drive */
2.25 frystyk 675: if (*path == '/' && path[2] == ':') {
2.27 frystyk 676: char *orig=path, *dest=path+1;
2.25 frystyk 677: while((*orig++ = *dest++));
678:
679: /* A network host */
680: } else if (*host && strcasecomp(host, "localhost")) {
681: char * newpath = NULL;
682: StrAllocMCopy(&newpath, "//", host, path, NULL);
683: HT_FREE(path);
684: path = newpath;
2.27 frystyk 685: }
686:
687: /* Convert '/' to '\' */
688: {
689: char *p = path;
690: while (*p) {
691: if (*p=='/') *p='\\';
692: p++;
693: }
2.25 frystyk 694: }
2.1 frystyk 695: #endif
696:
697: HTUnEscape(path); /* Take out the escaped characters */
698: if (PROT_TRACE)
2.6 eric 699: HTTrace("Node........ `%s' means path `%s'\n",url,path);
2.5 frystyk 700: HT_FREE(access);
701: HT_FREE(host);
2.1 frystyk 702: return path;
703: }
704: }
705: return NULL;
706: }
707:
708: /* Convert a local file name into a URL
709: ** ------------------------------------
710: ** Generates a WWW URL name from a local file name or NULL if error.
711: ** Returns:
712: ** OK: local file (that must be freed by caller)
713: ** Error: NULL
714: */
2.8 frystyk 715: PUBLIC char * HTLocalToWWW (const char * local)
2.1 frystyk 716: {
2.25 frystyk 717: char * escaped = NULL;
2.1 frystyk 718: if (local && *local) {
2.26 frystyk 719: #ifdef VMS
2.25 frystyk 720: char * unescaped = NULL;
721: if ((unescaped = (char *) HT_MALLOC(strlen(local) + 10)) == NULL)
722: HT_OUTOFMEM("HTLocalToWWW");
723: strcpy(unescaped, "file:"); /* We get an absolute file name */
2.26 frystyk 724:
2.1 frystyk 725: /* convert directory name to Unix-style syntax */
726: {
727: char * disk = strchr (local, ':');
728: char * dir = strchr (local, '[');
729: if (disk) {
730: *disk = '\0';
2.25 frystyk 731: strcat(unescaped, "/");
732: strcat(unescaped, local);
2.1 frystyk 733: }
734: if (dir) {
735: char *p;
736: *dir = '/'; /* Convert leading '[' */
737: for (p = dir ; *p != ']'; ++p)
738: if (*p == '.') *p = '/';
739: *p = '\0'; /* Cut on final ']' */
2.25 frystyk 740: strcat(unescaped, dir);
2.1 frystyk 741: }
742: }
2.26 frystyk 743: escaped = HTEscape(unescaped, URL_DOSFILE);
2.25 frystyk 744: HT_FREE(unescaped);
745:
2.1 frystyk 746: #else /* not VMS */
747: #ifdef WIN32
2.26 frystyk 748: char * unescaped = NULL;
749: if ((unescaped = (char *) HT_MALLOC(strlen(local) + 10)) == NULL)
750: HT_OUTOFMEM("HTLocalToWWW");
751: strcpy(unescaped, "file:"); /* We get an absolute file name */
2.25 frystyk 752: if (strchr(local, ':')) strcat(unescaped, "/");
753: {
754: const char *p = local;
755: char *q = unescaped+strlen(unescaped);
756: while (*p) {
757: if (*p=='\\') {
758: *q++='/';
759: } else
760: *q++=*p;
761: p++;
762: }
763: *q = '\0';
764: }
765: escaped = HTEscape(unescaped, URL_DOSFILE);
766: HT_FREE(unescaped);
767:
768: #else /* Unix */
2.26 frystyk 769: char * escaped_path = HTEscape(local, URL_PATH);
770: escaped = StrAllocMCopy(&escaped, "file:", escaped_path, NULL);
771: HT_FREE(escaped_path);
2.25 frystyk 772:
2.1 frystyk 773: #endif /* not WIN32 */
774: #endif /* not VMS */
775: }
2.25 frystyk 776: return escaped;
2.1 frystyk 777: }
Webmaster