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

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

Webmaster