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

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
                     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
2.20      frystyk   152: **             by white white space "," ";" or "=". The word
2.13      frystyk   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) {
2.20      frystyk   169:        /* Strip white space and other delimiters */
                    170:        while (*p && (WHITE(*p) || *p==',' || *p==';' || *p=='=')) p++;
2.13      frystyk   171:        if (!*p) {
                    172:            *pstr = p;
                    173:            return NULL;                                         /* No field */
                    174:        }
2.20      frystyk   175: 
2.13      frystyk   176:        if (*p == '"') {                                     /* quoted field */
                    177:            start = ++p;
                    178:            for(;*p && *p!='"'; p++)
                    179:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    180:        } else if (*p == '<') {                              /* quoted field */
                    181:            for(;*p && *p!='>'; p++)
                    182:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    183:        } else if (*p == '(') {                                   /* Comment */
                    184:            for(;*p && *p!=')'; p++)
                    185:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    186:            p++;
2.20      frystyk   187:        } else {                                              /* Spool field */
2.13      frystyk   188:            start = p;
2.20      frystyk   189:            while(*p && !WHITE(*p) && *p!=',' && *p!=';' && *p!='=')
2.13      frystyk   190:                p++;
                    191:            break;                                                 /* Got it */
2.6       timbl     192:        }
                    193:     }
2.13      frystyk   194:     if (*p) *p++ = '\0';
2.6       timbl     195:     *pstr = p;
                    196:     return start;
2.13      frystyk   197: }
                    198: 
                    199: 
                    200: /*
                    201: **     Returns a string pointer to a static area of the current calendar
                    202: **     time in RFC 1123 format, for example
                    203: **
                    204: **             Sun, 06 Nov 1994 08:49:37 GMT
                    205: **
                    206: **     The result can be given in both local and GMT dependent on the flag
                    207: */
                    208: PUBLIC CONST char *HTDateTimeStr ARGS2(time_t *, calendar, BOOL, local)
                    209: {
                    210:     static char buf[40];
                    211: 
                    212: #ifndef NO_STRFTIME
                    213:     if (local) {
2.18      frystyk   214: #ifdef SOLARIS                        /* Thomas Maslen <tmaslen@verity.com> */
2.17      frystyk   215:        struct tm loctime;
                    216:        localtime_r(calendar, &loctime);
                    217:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", &loctime);
                    218: #else
2.13      frystyk   219:        struct tm *loctime = localtime(calendar);
                    220:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", loctime);
2.17      frystyk   221: #endif /* SOLARIS */
2.13      frystyk   222:     } else {
2.17      frystyk   223: #ifdef SOLARIS
                    224:        struct tm gmt;
                    225:        gmtime_r(calendar, &gmt);
                    226:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", &gmt);
                    227: #else
2.13      frystyk   228:        struct tm *gmt = gmtime(calendar);
                    229:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", gmt);
2.17      frystyk   230: #endif /* SOLARIS */
2.13      frystyk   231:     }
                    232: #else
                    233:     if (local) {
                    234:        struct tm *loctime = localtime(calendar);
                    235:        sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d",
                    236:                wkday[gmt->tm_wday],
                    237:                gmt->tm_mday,
                    238:                month[gmt->tm_mon],
                    239:                gmt->tm_year % 100,
                    240:                gmt->tm_hour,
                    241:                gmt->tm_min,
                    242:                gmt->tm_sec);
                    243:     } else {
                    244:        struct tm *gmt = gmtime(calendar);
                    245:        sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d GMT",
                    246:                wkday[gmt->tm_wday],
                    247:                gmt->tm_mday,
                    248:                month[gmt->tm_mon],
                    249:                gmt->tm_year % 100,
                    250:                gmt->tm_hour,
                    251:                gmt->tm_min,
                    252:                gmt->tm_sec);
                    253:     }
                    254: #endif
                    255:     return buf;
                    256: }
                    257: 
                    258: 
                    259: /*
                    260: **     Returns a Message-ID string including the open '<' and the closing '>'.
                    261: **     The format of the string is:
                    262: **
                    263: **             "<" time-in-sec "Z" process-id "@" FQDN ">"
                    264: **
                    265: **     or on systems that doesn't have process-id:
                    266: **
                    267: **             "<" time-in-sec "Z" user "@" FQDN ">"
                    268: **
                    269: **     Returns a pointer to the MessageID
                    270: */
                    271: PUBLIC CONST char *HTMessageIdStr NOARGS
                    272: {
                    273:     static char buf[80];
                    274:     time_t sectime = time(NULL);
                    275: #ifndef NO_GETPID
                    276:     CONST char *address = HTGetDomainName();
                    277: #else
                    278:     CONST char *address = HTGetMailAddress();
                    279: #endif /* NO_GETPID */
                    280:     if (!address) address = tmpnam(NULL);
                    281:     if ((!address || !*address) && sectime < 0) {
                    282:        if (TRACE)
                    283:            fprintf(TDEST, "MessageID...  Can't make a unique MessageID\n");
                    284:        return "";
                    285:     }
                    286: #ifndef NO_GETPID
                    287:     sprintf(buf, "<%ldZ%d@%s>", sectime, getpid(), address ? address : "@@@");
                    288: #else
                    289:     sprintf(buf, "<%ldZ%s>", sectime, address ? address : "@@@");
                    290: #endif /* NO_GETPID */
                    291: 
                    292:     *(buf+79) = '\0';
                    293:     return buf;
                    294: }
                    295: 
                    296: 
                    297: /*     Date and Time Parser
                    298: **     --------------------
                    299: **     These functions are taken from the server written by Ari Luotonen
                    300: */
                    301: 
                    302: PRIVATE char * month_names[12] =
                    303: {
                    304:     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                    305:     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                    306: };
                    307: 
                    308: PRIVATE int make_num ARGS1(CONST char *, s)
                    309: {
                    310:     if (*s >= '0' && *s <= '9')
                    311:        return 10 * (*s - '0') + *(s+1) - '0';
                    312:     else
                    313:        return *(s+1) - '0';
                    314: }
                    315: 
                    316: PRIVATE int make_month ARGS1(CONST char *, s)
                    317: {
                    318:     int i;
                    319:     for (i=0; i<12; i++)
                    320:        if (!strncasecomp(month_names[i], s, 3))
                    321:            return i;
                    322:     return 0;
                    323: }
                    324: 
                    325: /*     Timezone Offset
                    326: **     ---------------
                    327: **     Calculates the offset from GMT in seconds
                    328: */
                    329: PUBLIC long HTGetTimeZoneOffset NOARGS
                    330: {
                    331: #ifndef NO_TIMEZONE
                    332:     {
2.15      frystyk   333: #ifndef NO_ALTZONE
2.13      frystyk   334:        time_t cur_t = time(NULL);
                    335:        struct tm * local = localtime(&cur_t);
                    336:        if (daylight && local->tm_isdst==1)     /* daylight time? */
                    337:            HTTimeZone = altzone;               /* yes */
                    338:        else
                    339:            HTTimeZone = timezone;              /* no */
                    340:        HTTimeZone = -HTTimeZone;
                    341:        if (TRACE)
2.14      frystyk   342:            fprintf(TDEST,"TimeZone.... GMT + (%02d) hours (including DST)\n",
2.13      frystyk   343:                    (int) HTTimeZone/3600);
2.14      frystyk   344: #else
                    345:        HTTimeZone = -timezone;
                    346:        if (TRACE)
                    347:            fprintf(TDEST,"TimeZone.... GMT + (%02d) hours (excluding DST)\n",
                    348:                    (int) HTTimeZone/3600);
                    349: #endif
2.13      frystyk   350:     }
2.14      frystyk   351: #else
                    352: #ifndef NO_GMTOFF
                    353:     {
                    354:        time_t cur_t = time(NULL);
                    355:        struct tm * local = localtime(&cur_t);
                    356:        HTTimeZone = local->tm_gmtoff;
                    357:        if (TRACE) fprintf(TDEST,"TimeZone.... GMT + (%02d) hours\n",
                    358:                           (int)local->tm_gmtoff / 3600);
                    359:     }
                    360: #else
                    361:     if (TRACE) fprintf(TDEST,"TimeZone.... Not defined\n");
2.13      frystyk   362: #endif /* !NO_TIMEZONE */
                    363: #endif /* !NO_GMTOFF */
                    364:     return HTTimeZone;
                    365: }
                    366: 
                    367: /*
                    368: **     Parse a str in GMT format to a local time time_t representation
2.19      frystyk   369: **     Four formats are accepted:
                    370: **
                    371: **             Wkd, 00 Mon 0000 00:00:00 GMT           (rfc1123)
                    372: **             Weekday, 00-Mon-00 00:00:00 GMT         (rfc850)
                    373: **             Wkd Mon 00 00:00:00 0000 GMT            (ctime)
                    374: **             1*DIGIT                                 (delta-seconds)
2.13      frystyk   375: */
                    376: PUBLIC time_t HTParseTime ARGS1(CONST char *, str)
                    377: {
                    378:     CONST char * s;
                    379:     struct tm tm;
                    380:     time_t t;
                    381: 
                    382:     if (!str) return 0;
                    383: 
2.19      frystyk   384:     if ((s = strchr(str, ','))) {       /* Thursday, 10-Jun-93 01:29:59 GMT */
2.13      frystyk   385:        s++;                            /* or: Thu, 10 Jan 1993 01:29:59 GMT */
                    386:        while (*s && *s==' ') s++;
2.19      frystyk   387:        if (strchr(s,'-')) {                                 /* First format */
2.13      frystyk   388:            if (TRACE)
                    389:                fprintf(TDEST, "Format...... Weekday, 00-Mon-00 00:00:00 GMT\n");
                    390:            if ((int)strlen(s) < 18) {
                    391:                if (TRACE)
                    392:                    fprintf(TDEST,
                    393:                            "ERROR....... Not a valid time format \"%s\"\n",s);
                    394:                return 0;
                    395:            }
                    396:            tm.tm_mday = make_num(s);
                    397:            tm.tm_mon = make_month(s+3);
                    398:            tm.tm_year = make_num(s+7);
                    399:            tm.tm_hour = make_num(s+10);
                    400:            tm.tm_min = make_num(s+13);
                    401:            tm.tm_sec = make_num(s+16);
2.19      frystyk   402:        } else {                                            /* Second format */
2.13      frystyk   403:            if (TRACE)
                    404:                fprintf(TDEST, "Format...... Wkd, 00 Mon 0000 00:00:00 GMT\n");
                    405:            if ((int)strlen(s) < 20) {
                    406:                if (TRACE)
                    407:                    fprintf(TDEST,
                    408:                            "ERROR....... Not a valid time format \"%s\"\n",s);
                    409:                return 0;
                    410:            }
                    411:            tm.tm_mday = make_num(s);
                    412:            tm.tm_mon = make_month(s+3);
                    413:            tm.tm_year = (100*make_num(s+7) - 1900) + make_num(s+9);
                    414:            tm.tm_hour = make_num(s+12);
                    415:            tm.tm_min = make_num(s+15);
                    416:            tm.tm_sec = make_num(s+18);
                    417: 
                    418:        }
2.19      frystyk   419:     } else if (isdigit(*str)) {                                    /* delta seconds */
                    420:        t = time(NULL) + atol(str);           /* Current local calendar time */
                    421:        if (TRACE)
                    422:            fprintf(TDEST, "Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, ctime(&t));
                    423:        return t;
                    424: 
                    425:     } else {         /* Try the other format:  Wed Jun  9 01:29:59 1993 GMT */
2.13      frystyk   426:        if (TRACE)
                    427:            fprintf(TDEST, "Format...... Wkd Mon 00 00:00:00 0000 GMT\n");
                    428:        s = str;
                    429:        while (*s && *s==' ') s++;
                    430:        if (TRACE)
                    431:            fprintf(TDEST, "Trying...... The Wrong time format: %s\n", s);
                    432:        if ((int)strlen(s) < 24) {
                    433:            if (TRACE)
                    434:                fprintf(TDEST, "ERROR....... Not a valid time format \"%s\"\n",s);
                    435:            return 0;
                    436:        }
                    437:        tm.tm_mday = make_num(s+8);
                    438:        tm.tm_mon = make_month(s+4);
                    439:        tm.tm_year = make_num(s+22);
                    440:        tm.tm_hour = make_num(s+11);
                    441:        tm.tm_min = make_num(s+14);
                    442:        tm.tm_sec = make_num(s+17);
                    443:     }
                    444:     if (tm.tm_sec  < 0  ||  tm.tm_sec  > 59  ||
                    445:        tm.tm_min  < 0  ||  tm.tm_min  > 59  ||
                    446:        tm.tm_hour < 0  ||  tm.tm_hour > 23  ||
                    447:        tm.tm_mday < 1  ||  tm.tm_mday > 31  ||
                    448:        tm.tm_mon  < 0  ||  tm.tm_mon  > 11  ||
                    449:        tm.tm_year <70  ||  tm.tm_year >120) {
                    450:        if (TRACE) fprintf(TDEST,
                    451:        "ERROR....... Parsed illegal time: %02d.%02d.%02d %02d:%02d:%02d\n",
                    452:               tm.tm_mday, tm.tm_mon+1, tm.tm_year,
                    453:               tm.tm_hour, tm.tm_min, tm.tm_sec);
                    454:        return 0;
                    455:     }
                    456: 
2.16      frystyk   457: #if !defined(NO_TIMEZONE) && !defined(NO_ALTZONE)
2.14      frystyk   458:     tm.tm_isdst = daylight;                   /* Already taken into account */
                    459: #else
                    460:     tm.tm_isdst = -1;
                    461: #endif
                    462: 
2.13      frystyk   463: #ifndef NO_MKTIME
                    464:     t = mktime(&tm);
2.18      frystyk   465:     t += (HTTimeZone);
2.13      frystyk   466: #else
                    467: #ifndef NO_TIMEGM
                    468:     t = timegm(&tm);
                    469: #else
2.18      frystyk   470:     if (TRACE) fprintf(TDEST,"Time String. Can not be parsed\n");
2.13      frystyk   471: #endif /* !NO_TIMEGM */
                    472: #endif /* !NO_MKTIME */
                    473: 
                    474:     if (TRACE)
                    475:        fprintf(TDEST,
                    476:                "Time string. %s parsed to %ld seconds, or in local time: %s",
                    477:                str, (long) t, ctime(&t));
                    478:     return t;
1.1       timbl     479: }

Webmaster