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