Annotation of libwww/Library/src/HTString.c, revision 2.30

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
2.28      frystyk    12: **       9 Oct 95 (KR)  fixed problem with double quotes in HTNextField
1.1       timbl      13: */
2.8       frystyk    14: 
2.12      frystyk    15: /* Library include files */
                     16: #include "tcp.h"
1.1       timbl      17: #include "HTUtils.h"
2.13      frystyk    18: #include "HTTCP.h"
2.26      frystyk    19: #include "HTParse.h"
2.8       frystyk    20: #include "HTString.h"                                   /* Implemented here */
1.1       timbl      21: 
2.12      frystyk    22: #ifdef NO_STDIO
                     23: PUBLIC FILE *WWWTrace = NULL;
                     24: #endif
                     25: 
1.1       timbl      26: PUBLIC int WWW_TraceFlag = 0;  /* Global trace flag for ALL W3 code */
                     27: 
                     28: #ifndef VC
                     29: #define VC "unknown"
                     30: #endif
                     31: 
                     32: PUBLIC CONST char * HTLibraryVersion = VC; /* String for help screen etc */
                     33: 
2.13      frystyk    34: PRIVATE long HTTimeZone = 0L;                 /* Offset from GMT in seconds */
2.26      frystyk    35: PRIVATE char * months[12] = {
                     36:     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
                     37: };
                     38: 
                     39: #ifdef NO_STRFTIME
                     40: PRIVATE char * wkdays[7] = {
                     41:     "Mon","Tue","Wed","Thu","Fri","Sat","Sun"
                     42: };
                     43: #endif
2.13      frystyk    44: 
                     45: /* ------------------------------------------------------------------------- */
                     46: 
1.1       timbl      47: /*     Strings of any length
                     48: **     ---------------------
                     49: */
2.29      frystyk    50: PUBLIC int strcasecomp (CONST char * a, CONST char * b)
1.1       timbl      51: {
2.13      frystyk    52:     int diff;
                     53:     for( ; *a && *b; a++, b++) {
                     54:        if ((diff = TOLOWER(*a) - TOLOWER(*b)))
                     55:            return diff;
                     56:     }
                     57:     if (*a) return 1;                  /* a was longer than b */
                     58:     if (*b) return -1;                 /* a was shorter than b */
                     59:     return 0;                          /* Exact match */
1.1       timbl      60: }
                     61: 
                     62: 
                     63: /*     With count limit
                     64: **     ----------------
                     65: */
2.29      frystyk    66: PUBLIC int strncasecomp (CONST char * a, CONST char * b, int n)
1.1       timbl      67: {
                     68:        CONST char *p =a;
                     69:        CONST char *q =b;
                     70:        
                     71:        for(p=a, q=b;; p++, q++) {
                     72:            int diff;
                     73:            if (p == a+n) return 0;     /*   Match up to n characters */
                     74:            if (!(*p && *q)) return *p - *q;
                     75:            diff = TOLOWER(*p) - TOLOWER(*q);
                     76:            if (diff) return diff;
                     77:        }
                     78:        /*NOTREACHED*/
                     79: }
                     80: 
2.7       luotonen   81: 
                     82: /*
2.29      frystyk    83: ** strcasestr(s1,s2) -- like strstr(s1,s2) but case-insensitive.
                     84: */
                     85: PUBLIC char * strcasestr (char * s1, char * s2)
2.7       luotonen   86: {
2.9       frystyk    87:     char * ptr = s1;
2.7       luotonen   88: 
                     89:     if (!s1 || !s2 || !*s2) return s1;
                     90: 
2.9       frystyk    91:     while (*ptr) {
                     92:        if (TOUPPER(*ptr) == TOUPPER(*s2)) {
                     93:            char * cur1 = ptr + 1;
2.7       luotonen   94:            char * cur2 = s2 + 1;
                     95:            while (*cur1 && *cur2 && TOUPPER(*cur1) == TOUPPER(*cur2)) {
                     96:                cur1++;
                     97:                cur2++;
                     98:            }
2.29      frystyk    99:            if (!*cur2) return ptr;
2.7       luotonen  100:        }
2.9       frystyk   101:        ptr++;
2.7       luotonen  102:     }
                    103:     return NULL;
                    104: }
                    105: 
                    106: 
                    107: 
1.1       timbl     108: /*     Allocate a new copy of a string, and returns it
                    109: */
2.29      frystyk   110: PUBLIC char * HTSACopy (char ** dest, CONST char * src)
1.1       timbl     111: {
                    112:   if (*dest) free(*dest);
                    113:   if (! src)
                    114:     *dest = NULL;
                    115:   else {
                    116:     *dest = (char *) malloc (strlen(src) + 1);
                    117:     if (*dest == NULL) outofmem(__FILE__, "HTSACopy");
                    118:     strcpy (*dest, src);
                    119:   }
                    120:   return *dest;
                    121: }
                    122: 
2.6       timbl     123: /*     String Allocate and Concatenate
                    124: */
2.29      frystyk   125: PUBLIC char * HTSACat (char ** dest, CONST char * src)
1.1       timbl     126: {
                    127:   if (src && *src) {
                    128:     if (*dest) {
                    129:       int length = strlen (*dest);
                    130:       *dest = (char *) realloc (*dest, length + strlen(src) + 1);
                    131:       if (*dest == NULL) outofmem(__FILE__, "HTSACat");
                    132:       strcpy (*dest + length, src);
                    133:     } else {
                    134:       *dest = (char *) malloc (strlen(src) + 1);
                    135:       if (*dest == NULL) outofmem(__FILE__, "HTSACat");
                    136:       strcpy (*dest, src);
                    137:     }
                    138:   }
                    139:   return *dest;
2.6       timbl     140: }
                    141: 
                    142: 
                    143: /*     Find next Field
                    144: **     ---------------
                    145: **
                    146: ** On entry,
2.13      frystyk   147: **     *pstr   points to a string containing a word separated
2.20      frystyk   148: **             by white white space "," ";" or "=". The word
2.13      frystyk   149: **             can optionally be quoted using <"> or "<" ">"
                    150: **             Comments surrrounded by '(' ')' are filtered out
2.6       timbl     151: **
                    152: ** On exit,
                    153: **     *pstr   has been moved to the first delimiter past the
                    154: **             field
                    155: **             THE STRING HAS BEEN MUTILATED by a 0 terminator
                    156: **
2.13      frystyk   157: **     Returns a pointer to the first word or NULL on error
2.6       timbl     158: */
2.29      frystyk   159: PUBLIC char * HTNextField (char ** pstr)
2.6       timbl     160: {
                    161:     char * p = *pstr;
2.28      frystyk   162:     char * start = NULL;
2.13      frystyk   163: 
                    164:     while (1) {
2.20      frystyk   165:        /* Strip white space and other delimiters */
                    166:        while (*p && (WHITE(*p) || *p==',' || *p==';' || *p=='=')) p++;
2.13      frystyk   167:        if (!*p) {
                    168:            *pstr = p;
                    169:            return NULL;                                         /* No field */
                    170:        }
2.20      frystyk   171: 
2.13      frystyk   172:        if (*p == '"') {                                     /* quoted field */
                    173:            start = ++p;
                    174:            for(;*p && *p!='"'; p++)
                    175:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
2.28      frystyk   176:            break;                          /* kr95-10-9: needs to stop here */
2.13      frystyk   177:        } else if (*p == '<') {                              /* quoted field */
2.28      frystyk   178:            start = ++p;
2.13      frystyk   179:            for(;*p && *p!='>'; p++)
                    180:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
2.28      frystyk   181:            break;                          /* kr95-10-9: needs to stop here */
2.13      frystyk   182:        } else if (*p == '(') {                                   /* Comment */
                    183:            for(;*p && *p!=')'; p++)
                    184:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    185:            p++;
2.20      frystyk   186:        } else {                                              /* Spool field */
2.13      frystyk   187:            start = p;
2.20      frystyk   188:            while(*p && !WHITE(*p) && *p!=',' && *p!=';' && *p!='=')
2.13      frystyk   189:                p++;
                    190:            break;                                                 /* Got it */
2.6       timbl     191:        }
                    192:     }
2.13      frystyk   193:     if (*p) *p++ = '\0';
2.6       timbl     194:     *pstr = p;
                    195:     return start;
2.13      frystyk   196: }
                    197: 
2.29      frystyk   198: /*     HTStringMatch
                    199: **     -------------
                    200: **     String comparison function for file names with one wildcard * in the
                    201: **     template. Arguments are:
                    202: **
                    203: **     tmpl    is a template string to match the name against.
                    204: **             agaist, may contain a single wildcard character * which
                    205: **             matches zero or more arbitrary characters.
                    206: **     name    is the name to be matched agaist the template.
                    207: **
                    208: **     returns  YES, if filename matches the template, else NO
                    209: */
                    210: PUBLIC BOOL HTStringMatch (CONST char * tmpl, CONST char * name)
                    211: {
                    212:     while (*tmpl && *name && *tmpl==*name) tmpl++, name++;
                    213:     return ((!*tmpl && !*name) || (*tmpl=='*')) ? YES : NO;
                    214: }    
                    215: 
                    216: PUBLIC BOOL HTStringCaseMatch (CONST char * tmpl, CONST char * name)
                    217: {
                    218:     while (*tmpl && *name && TOUPPER(*tmpl)==TOUPPER(*name)) tmpl++, name++;
                    219:     return ((!*tmpl && !*name) || (*tmpl=='*')) ? YES : NO;
                    220: }    
                    221: 
2.13      frystyk   222: /*
                    223: **     Returns a Message-ID string including the open '<' and the closing '>'.
                    224: **     The format of the string is:
                    225: **
                    226: **             "<" time-in-sec "Z" process-id "@" FQDN ">"
                    227: **
                    228: **     or on systems that doesn't have process-id:
                    229: **
                    230: **             "<" time-in-sec "Z" user "@" FQDN ">"
                    231: **
                    232: **     Returns a pointer to the MessageID
                    233: */
2.29      frystyk   234: PUBLIC CONST char *HTMessageIdStr (void)
2.13      frystyk   235: {
                    236:     static char buf[80];
                    237:     time_t sectime = time(NULL);
                    238: #ifndef NO_GETPID
                    239:     CONST char *address = HTGetDomainName();
                    240: #else
                    241:     CONST char *address = HTGetMailAddress();
                    242: #endif /* NO_GETPID */
                    243:     if (!address) address = tmpnam(NULL);
                    244:     if ((!address || !*address) && sectime < 0) {
2.28      frystyk   245:        if (WWWTRACE)
2.30    ! frystyk   246:            TTYPrint(TDEST, "MessageID...  Can't make a unique MessageID\n");
2.13      frystyk   247:        return "";
                    248:     }
                    249: #ifndef NO_GETPID
                    250:     sprintf(buf, "<%ldZ%d@%s>", sectime, getpid(), address ? address : "@@@");
                    251: #else
                    252:     sprintf(buf, "<%ldZ%s>", sectime, address ? address : "@@@");
                    253: #endif /* NO_GETPID */
                    254: 
                    255:     *(buf+79) = '\0';
                    256:     return buf;
                    257: }
                    258: 
                    259: 
                    260: /*     Date and Time Parser
                    261: **     --------------------
                    262: **     These functions are taken from the server written by Ari Luotonen
                    263: */
                    264: 
2.29      frystyk   265: PRIVATE int make_num (CONST char *  s)
2.13      frystyk   266: {
                    267:     if (*s >= '0' && *s <= '9')
                    268:        return 10 * (*s - '0') + *(s+1) - '0';
                    269:     else
                    270:        return *(s+1) - '0';
                    271: }
                    272: 
2.29      frystyk   273: PRIVATE int make_month (CONST char *  s)
2.13      frystyk   274: {
                    275:     int i;
                    276:     for (i=0; i<12; i++)
2.26      frystyk   277:        if (!strncasecomp(months[i], s, 3))
2.13      frystyk   278:            return i;
                    279:     return 0;
                    280: }
                    281: 
                    282: /*     Timezone Offset
                    283: **     ---------------
                    284: **     Calculates the offset from GMT in seconds
                    285: */
2.29      frystyk   286: PUBLIC long HTGetTimeZoneOffset (void)
2.13      frystyk   287: {
                    288: #ifndef NO_TIMEZONE
                    289:     {
                    290:        time_t cur_t = time(NULL);
2.24      frystyk   291: #ifdef HT_REENTRANT
                    292:        struct tm loctime;
                    293:        struct tm *local = (struct tm *) localtime_r(&cur_t, &loctime);
                    294: #else
                    295:        struct tm *local = localtime(&cur_t);
                    296: #endif /* HT_REENTRANT */
2.22      frystyk   297:        if (daylight && local->tm_isdst>0) {               /* daylight time? */
                    298: #ifndef NO_ALTZONE
                    299:            HTTimeZone = altzone;
                    300: #else
                    301:            /* Assumes a fixed DST offset of 1 hour, which is probably wrong */
                    302:            HTTimeZone = timezone - 3600;
                    303: #endif
                    304:        } else {                                                       /* no */
                    305:            HTTimeZone = timezone;
                    306:        }
2.13      frystyk   307:        HTTimeZone = -HTTimeZone;
2.28      frystyk   308:        if (WWWTRACE)
2.30    ! frystyk   309:            TTYPrint(TDEST,"TimeZone.... GMT + (%02d) hours (including DST)\n",
2.13      frystyk   310:                    (int) HTTimeZone/3600);
                    311:     }
2.14      frystyk   312: #else
                    313: #ifndef NO_GMTOFF
                    314:     {
                    315:        time_t cur_t = time(NULL);
2.24      frystyk   316: #ifdef HT_REENTRANT
                    317:        struct tm loctime;
                    318:        localtime_r(&cur_t, &loctime);
                    319: #else
2.14      frystyk   320:        struct tm * local = localtime(&cur_t);
2.24      frystyk   321: #endif /* HT_REENTRANT */
2.14      frystyk   322:        HTTimeZone = local->tm_gmtoff;
2.28      frystyk   323:        if (WWWTRACE)
2.30    ! frystyk   324:            TTYPrint(TDEST,"TimeZone.... GMT + (%02d) hours (including DST)\n",
2.22      frystyk   325:                    (int)local->tm_gmtoff / 3600);
2.14      frystyk   326:     }
                    327: #else
2.30    ! frystyk   328:     if (WWWTRACE) TTYPrint(TDEST,"TimeZone.... Not defined\n");
2.13      frystyk   329: #endif /* !NO_TIMEZONE */
                    330: #endif /* !NO_GMTOFF */
                    331:     return HTTimeZone;
                    332: }
                    333: 
                    334: /*
                    335: **     Parse a str in GMT format to a local time time_t representation
2.19      frystyk   336: **     Four formats are accepted:
                    337: **
                    338: **             Wkd, 00 Mon 0000 00:00:00 GMT           (rfc1123)
                    339: **             Weekday, 00-Mon-00 00:00:00 GMT         (rfc850)
                    340: **             Wkd Mon 00 00:00:00 0000 GMT            (ctime)
                    341: **             1*DIGIT                                 (delta-seconds)
2.13      frystyk   342: */
2.29      frystyk   343: PUBLIC time_t HTParseTime (CONST char *  str)
2.13      frystyk   344: {
                    345:     CONST char * s;
                    346:     struct tm tm;
                    347:     time_t t;
                    348: 
                    349:     if (!str) return 0;
                    350: 
2.19      frystyk   351:     if ((s = strchr(str, ','))) {       /* Thursday, 10-Jun-93 01:29:59 GMT */
2.13      frystyk   352:        s++;                            /* or: Thu, 10 Jan 1993 01:29:59 GMT */
                    353:        while (*s && *s==' ') s++;
2.19      frystyk   354:        if (strchr(s,'-')) {                                 /* First format */
2.28      frystyk   355:            if (WWWTRACE)
2.30    ! frystyk   356:                TTYPrint(TDEST, "Format...... Weekday, 00-Mon-00 00:00:00 GMT\n");
2.13      frystyk   357:            if ((int)strlen(s) < 18) {
2.28      frystyk   358:                if (WWWTRACE)
2.30    ! frystyk   359:                    TTYPrint(TDEST,
2.13      frystyk   360:                            "ERROR....... Not a valid time format \"%s\"\n",s);
                    361:                return 0;
                    362:            }
                    363:            tm.tm_mday = make_num(s);
                    364:            tm.tm_mon = make_month(s+3);
                    365:            tm.tm_year = make_num(s+7);
                    366:            tm.tm_hour = make_num(s+10);
                    367:            tm.tm_min = make_num(s+13);
                    368:            tm.tm_sec = make_num(s+16);
2.19      frystyk   369:        } else {                                            /* Second format */
2.28      frystyk   370:            if (WWWTRACE)
2.30    ! frystyk   371:                TTYPrint(TDEST, "Format...... Wkd, 00 Mon 0000 00:00:00 GMT\n");
2.13      frystyk   372:            if ((int)strlen(s) < 20) {
2.28      frystyk   373:                if (WWWTRACE)
2.30    ! frystyk   374:                    TTYPrint(TDEST,
2.13      frystyk   375:                            "ERROR....... Not a valid time format \"%s\"\n",s);
                    376:                return 0;
                    377:            }
                    378:            tm.tm_mday = make_num(s);
                    379:            tm.tm_mon = make_month(s+3);
                    380:            tm.tm_year = (100*make_num(s+7) - 1900) + make_num(s+9);
                    381:            tm.tm_hour = make_num(s+12);
                    382:            tm.tm_min = make_num(s+15);
                    383:            tm.tm_sec = make_num(s+18);
                    384: 
                    385:        }
2.19      frystyk   386:     } else if (isdigit(*str)) {                                    /* delta seconds */
                    387:        t = time(NULL) + atol(str);           /* Current local calendar time */
2.28      frystyk   388:        if (WWWTRACE) {
2.24      frystyk   389: #ifdef HT_REENTRANT
                    390:            char buffer[CTIME_MAX];
2.30    ! frystyk   391:            TTYPrint(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));
2.24      frystyk   392: #else
2.30    ! frystyk   393:            TTYPrint(TDEST, "Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, ctime(&t));
2.24      frystyk   394: #endif
                    395:        }
2.19      frystyk   396:        return t;
                    397: 
                    398:     } else {         /* Try the other format:  Wed Jun  9 01:29:59 1993 GMT */
2.28      frystyk   399:        if (WWWTRACE)
2.30    ! frystyk   400:            TTYPrint(TDEST, "Format...... Wkd Mon 00 00:00:00 0000 GMT\n");
2.13      frystyk   401:        s = str;
                    402:        while (*s && *s==' ') s++;
2.28      frystyk   403:        if (WWWTRACE)
2.30    ! frystyk   404:            TTYPrint(TDEST, "Trying...... The Wrong time format: %s\n", s);
2.13      frystyk   405:        if ((int)strlen(s) < 24) {
2.28      frystyk   406:            if (WWWTRACE)
2.30    ! frystyk   407:                TTYPrint(TDEST, "ERROR....... Not a valid time format \"%s\"\n",s);
2.13      frystyk   408:            return 0;
                    409:        }
                    410:        tm.tm_mday = make_num(s+8);
                    411:        tm.tm_mon = make_month(s+4);
                    412:        tm.tm_year = make_num(s+22);
                    413:        tm.tm_hour = make_num(s+11);
                    414:        tm.tm_min = make_num(s+14);
                    415:        tm.tm_sec = make_num(s+17);
                    416:     }
                    417:     if (tm.tm_sec  < 0  ||  tm.tm_sec  > 59  ||
                    418:        tm.tm_min  < 0  ||  tm.tm_min  > 59  ||
                    419:        tm.tm_hour < 0  ||  tm.tm_hour > 23  ||
                    420:        tm.tm_mday < 1  ||  tm.tm_mday > 31  ||
                    421:        tm.tm_mon  < 0  ||  tm.tm_mon  > 11  ||
                    422:        tm.tm_year <70  ||  tm.tm_year >120) {
2.30    ! frystyk   423:        if (WWWTRACE) TTYPrint(TDEST,
2.13      frystyk   424:        "ERROR....... Parsed illegal time: %02d.%02d.%02d %02d:%02d:%02d\n",
                    425:               tm.tm_mday, tm.tm_mon+1, tm.tm_year,
                    426:               tm.tm_hour, tm.tm_min, tm.tm_sec);
                    427:        return 0;
                    428:     }
                    429: 
2.16      frystyk   430: #if !defined(NO_TIMEZONE) && !defined(NO_ALTZONE)
2.14      frystyk   431:     tm.tm_isdst = daylight;                   /* Already taken into account */
                    432: #else
                    433:     tm.tm_isdst = -1;
                    434: #endif
                    435: 
2.13      frystyk   436: #ifndef NO_MKTIME
                    437:     t = mktime(&tm);
2.18      frystyk   438:     t += (HTTimeZone);
2.13      frystyk   439: #else
                    440: #ifndef NO_TIMEGM
                    441:     t = timegm(&tm);
                    442: #else
2.30    ! frystyk   443:     if (WWWTRACE) TTYPrint(TDEST,"Time String. Can not be parsed\n");
2.13      frystyk   444: #endif /* !NO_TIMEGM */
                    445: #endif /* !NO_MKTIME */
                    446: 
2.28      frystyk   447:     if (WWWTRACE)
2.30    ! frystyk   448:        TTYPrint(TDEST,
2.13      frystyk   449:                "Time string. %s parsed to %ld seconds, or in local time: %s",
                    450:                str, (long) t, ctime(&t));
                    451:     return t;
1.1       timbl     452: }
2.23      frystyk   453: 
2.26      frystyk   454: /*
                    455: **     Returns a string pointer to a static area of the current calendar
                    456: **     time in RFC 1123 format, for example
                    457: **
                    458: **             Sun, 06 Nov 1994 08:49:37 GMT
                    459: **
                    460: **     The result can be given in both local and GMT dependent on the flag
                    461: */
2.27      frystyk   462: PUBLIC CONST char *HTDateTimeStr (time_t * calendar, BOOL local)
2.26      frystyk   463: {
                    464:     static char buf[40];
                    465: 
                    466: #ifndef NO_STRFTIME
                    467:     if (local) {
                    468:        /*
                    469:        ** Solaris 2.3 has a bug so we _must_ use reentrant version
                    470:        ** Thomas Maslen <tmaslen@verity.com>
                    471:        */
                    472: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    473:        struct tm loctime;
                    474:        localtime_r(calendar, &loctime);
                    475:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", &loctime);
                    476: #else
                    477:        struct tm *loctime = localtime(calendar);
                    478:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", loctime);
                    479: #endif /* SOLARIS || HT_REENTRANT */
                    480:     } else {
                    481: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    482:        struct tm gmt;
                    483:        gmtime_r(calendar, &gmt);
                    484:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", &gmt);
                    485: #else
                    486:        struct tm *gmt = gmtime(calendar);
                    487:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", gmt);
                    488: #endif /* SOLARIS || HT_REENTRANT */
                    489:     }
                    490: #else
                    491:     if (local) {
                    492: #if defined(HT_REENTRANT)
                    493:        struct tm loctime;
                    494:        localtime_r(calendar, &loctime);
                    495: #else
                    496:        struct tm *loctime = localtime(calendar);
                    497: #endif /* HT_REENTRANT */
                    498:        sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d",
                    499:                wkdays[gmt->tm_wday],
                    500:                gmt->tm_mday,
                    501:                months[gmt->tm_mon],
                    502:                gmt->tm_year % 100,
                    503:                gmt->tm_hour,
                    504:                gmt->tm_min,
                    505:                gmt->tm_sec);
                    506:     } else {
                    507: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    508:        struct tm gmt;
                    509:        gmtime_r(calendar, &gmt);
                    510: #else
                    511:        struct tm *gmt = gmtime(calendar);
                    512: #endif
                    513:        sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d GMT",
                    514:                wkdays[gmt->tm_wday],
                    515:                gmt->tm_mday,
                    516:                months[gmt->tm_mon],
                    517:                gmt->tm_year % 100,
                    518:                gmt->tm_hour,
                    519:                gmt->tm_min,
                    520:                gmt->tm_sec);
                    521:     }
                    522: #endif
                    523:     return buf;
                    524: }
                    525: 
                    526: /*     HTDateDirStr
                    527: **     ------------
                    528: **     Generates a date string used in directory listings
                    529: */
                    530: PUBLIC BOOL HTDateDirStr (time_t * time, char * str, int len)
                    531: {
                    532: #ifndef NO_STRFTIME
                    533: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    534:     struct tm loctime;
                    535:     localtime_r(time, &loctime);
                    536:     strftime(str, len, "%d-%b-%y %H:%M", &loctime);
                    537:     return YES;
                    538: #else
                    539:     strftime(str, len, "%d-%b-%y %H:%M", localtime(time));
                    540:     return YES;
                    541: #endif /* HT_REENTRANT || SOLARIS */
                    542: #else
                    543:     if (len >= 16) {
                    544:        struct tm *loctime = localtime(time);
                    545:        sprintf(bodyptr,"%02d-%s-%02d %02d:%02d",
                    546:                loctime->tm_mday,
                    547:                months[loctime->tm_mon],
                    548:                loctime->tm_year % 100,
                    549:                loctime->tm_hour,
                    550:                loctime->tm_min);
                    551:        return YES;
                    552:     }
                    553:     return NO;
                    554: #endif /* NO_STRFTIME */               
                    555: }
2.23      frystyk   556: 
                    557: /*     Strip white space off a string
                    558: **     ------------------------------
                    559: **
                    560: ** On exit,
                    561: **     Return value points to first non-white character, or to 0 if none.
                    562: **     All trailing white space is OVERWRITTEN with zero.
                    563: */
2.29      frystyk   564: PUBLIC char * HTStrip (char * s)
2.23      frystyk   565: {
                    566: #define SPACE(c) ((c==' ')||(c=='\t')||(c=='\n')) 
                    567:     char * p=s;
                    568:     if (!s) return NULL;       /* Doesn't dump core if NULL */
                    569:     for(p=s;*p;p++);           /* Find end of string */
                    570:     for(p--;p>=s;p--) {
                    571:        if(SPACE(*p)) *p=0;     /* Zap trailing blanks */
                    572:        else break;
                    573:     }
                    574:     while(SPACE(*s))s++;       /* Strip leading blanks */
                    575:     return s;
                    576: }
2.25      frystyk   577: 
                    578: 
                    579: /*                                                             HTNumToStr
                    580: **     Converts a long (byte count) to a string
                    581: **     ----------------------------------------
                    582: **     This function was a PAIN!  In computer-world 1K is 1024 bytes
                    583: **     and 1M is 1024K -- however, sprintf() still formats in base-10.
                    584: **     Therefore I output only until 999, and then start using the
                    585: **     next unit.  This doesn't work wrong, it's just a feature.
                    586: **     The "str" must be large enough to contain the result.
                    587: */
2.26      frystyk   588: PUBLIC void HTNumToStr (unsigned long n, char * str, int len)
2.25      frystyk   589: {
                    590:     double size = n/1024.0;
2.26      frystyk   591:     if (len < 6) {
                    592:        *str = '\0';
                    593:        return;
                    594:     }
2.25      frystyk   595:     if (n < 1000)
                    596:        sprintf(str, "%dK", n>0 ? 1 : 0);
                    597:     else if (size + 0.999 < 1000)
                    598:        sprintf(str, "%dK", (int)(size + 0.5));
                    599:     else if ((size /= 1024) < 9.9)
                    600:        sprintf(str, "%.1fM", (size + 0.05));
                    601:     else if (size < 1000)
                    602:        sprintf(str, "%dM", (int)(size + 0.5));
                    603:     else if ((size /= 1024) < 9.9)
                    604:        sprintf(str, "%.1fG", (size + 0.05));
                    605:     else
                    606:        sprintf(str, "%dG", (int)(size + 0.5));
                    607: }
                    608: 
2.26      frystyk   609: /*     Convert file URLs into a local representation
                    610: **     ---------------------------------------------
                    611: **     The URL has already been translated through the rules in get_physical
                    612: **     in HTAccess.c and all we need to do now is to map the path to a local
                    613: **     representation, for example if must translate '/' to the ones that
                    614: **     turn the wrong way ;-)
                    615: **     Returns:
                    616: **             OK:     local file (that must be freed by caller)
                    617: **             Error:  NULL
                    618: */
                    619: PUBLIC char * HTWWWToLocal (CONST char * url, CONST char * base)
                    620: {
                    621:     if (url) {
                    622:        char * access = HTParse(url, base, PARSE_ACCESS);
                    623:        char * host = HTParse(url, base, PARSE_HOST);
                    624:        char * path = HTParse(url, base, PARSE_PATH+PARSE_PUNCTUATION);
                    625:        CONST char *myhost = HTGetHostName();
                    626: 
                    627:        /* Find out if this is a reference to the local file system */
                    628:        if ((*access && strcmp(access, "file")) ||
                    629:            (*host && strcasecomp(host, "localhost") &&
                    630:             myhost && strcmp(host, myhost))) {
                    631:            if (PROT_TRACE)
2.30    ! frystyk   632:                TTYPrint(TDEST, "LocalName... Not on local file system\n");
2.26      frystyk   633:            free(access);
                    634:            free(host);
                    635:            free(path);
                    636:            return NULL;
                    637:        } else {
                    638:            char *ptr;
                    639:            if ((ptr = strchr(path, ';')) || (ptr = strchr(path, '?')))
                    640:                *ptr = '\0';
                    641:        
                    642:            /*
                    643:            ** Do whatever translation is required here in order to fit your
                    644:            ** platform _before_ the path is unescaped.
                    645:            */
                    646: #ifdef VMS
                    647:            HTVMS_checkDecnet(path);
                    648: #endif
                    649: #ifdef _WINDOWS
                    650:            /* an absolute pathname with logical drive */
                    651:            if (*path == '/' && path[2] == ':')    
                    652:                /* NB. need memmove because overlaps */
                    653:                memmove( path, path+1, strlen(path) + 1);
                    654: #endif
                    655:            
                    656:            HTUnEscape(path);             /* Take out the escaped characters */
                    657:            if (PROT_TRACE)
2.30    ! frystyk   658:                TTYPrint(TDEST, "Node........ `%s' means path `%s'\n",url,path);
2.26      frystyk   659:            free(access);
                    660:            free(host);
                    661:            return path;
                    662:        }
                    663:     }
                    664:     return NULL;
                    665: }
                    666: 
                    667: /*     Convert a local file name into a URL
                    668: **     ------------------------------------
                    669: **     Generates a WWW URL name from a local file name or NULL if error.
                    670: **     Returns:
                    671: **             OK:     local file (that must be freed by caller)
                    672: **             Error:  NULL
                    673: */
                    674: PUBLIC char * HTLocalToWWW (CONST char * local)
                    675: {
                    676:     char * result = NULL;
                    677:     if (local && *local) {
                    678:        StrAllocCopy(result, "file:");       /* We get an absolute file name */
                    679: #ifdef VMS 
                    680:        /* convert directory name to Unix-style syntax */
                    681:        {
                    682:            char * disk = strchr (local, ':');
                    683:            char * dir = strchr (local, '[');
                    684:            if (disk) {
                    685:                *disk = '\0';
                    686:                StrAllocCat(result, "/"); /* needs delimiter */
                    687:                StrAllocCat(result, local);
                    688:            }
                    689:            if (dir) {
                    690:                char *p;
                    691:                *dir = '/';     /* Convert leading '[' */
                    692:                for (p = dir ; *p != ']'; ++p)
                    693:                    if (*p == '.') *p = '/';
                    694:                *p = '\0';      /* Cut on final ']' */
                    695:                StrAllocCat(result, dir);
                    696:            }
                    697:        }
                    698: #else  /* not VMS */
                    699: #ifdef WIN32
                    700:        {
                    701:            char * p = local;                                     /* a colon */
                    702:            StrAllocCat(result, "/");
                    703:            while( *p != 0 ) { 
                    704:                if (*p == '\\')                  /* change to one true slash */
                    705:                    *p = '/' ;
                    706:                p++;
                    707:            }
                    708:            StrAllocCat(result, local);
                    709:        }
                    710: #else /* not WIN32 */
                    711:        StrAllocCat (result, local);
                    712: #endif /* not WIN32 */
                    713: #endif /* not VMS */
                    714:     }
                    715:     return result;
                    716: }

Webmaster