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