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

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.24      frystyk   214:        /*
                    215:        ** Solaris 2.3 has a bug so we _must_ use reentrant version
                    216:        ** Thomas Maslen <tmaslen@verity.com>
                    217:        */
                    218: #if defined(HT_REENTRANT) || defined(SOLARIS)
2.17      frystyk   219:        struct tm loctime;
                    220:        localtime_r(calendar, &loctime);
                    221:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", &loctime);
                    222: #else
2.13      frystyk   223:        struct tm *loctime = localtime(calendar);
                    224:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", loctime);
2.24      frystyk   225: #endif /* SOLARIS || HT_REENTRANT */
2.13      frystyk   226:     } else {
2.24      frystyk   227: #if defined(HT_REENTRANT) || defined(SOLARIS)
2.17      frystyk   228:        struct tm gmt;
                    229:        gmtime_r(calendar, &gmt);
                    230:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", &gmt);
                    231: #else
2.13      frystyk   232:        struct tm *gmt = gmtime(calendar);
                    233:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", gmt);
2.24      frystyk   234: #endif /* SOLARIS || HT_REENTRANT */
2.13      frystyk   235:     }
                    236: #else
                    237:     if (local) {
2.24      frystyk   238: #if defined(HT_REENTRANT)
                    239:        struct tm loctime;
                    240:        localtime_r(calendar, &loctime);
                    241: #else
2.13      frystyk   242:        struct tm *loctime = localtime(calendar);
2.24      frystyk   243: #endif /* HT_REENTRANT */
2.13      frystyk   244:        sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d",
                    245:                wkday[gmt->tm_wday],
                    246:                gmt->tm_mday,
                    247:                month[gmt->tm_mon],
                    248:                gmt->tm_year % 100,
                    249:                gmt->tm_hour,
                    250:                gmt->tm_min,
                    251:                gmt->tm_sec);
                    252:     } else {
2.24      frystyk   253: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    254:        struct tm gmt;
                    255:        gmtime_r(calendar, &gmt);
                    256: #else
2.13      frystyk   257:        struct tm *gmt = gmtime(calendar);
2.24      frystyk   258: #endif
2.13      frystyk   259:        sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d GMT",
                    260:                wkday[gmt->tm_wday],
                    261:                gmt->tm_mday,
                    262:                month[gmt->tm_mon],
                    263:                gmt->tm_year % 100,
                    264:                gmt->tm_hour,
                    265:                gmt->tm_min,
                    266:                gmt->tm_sec);
                    267:     }
                    268: #endif
                    269:     return buf;
                    270: }
                    271: 
                    272: 
                    273: /*
                    274: **     Returns a Message-ID string including the open '<' and the closing '>'.
                    275: **     The format of the string is:
                    276: **
                    277: **             "<" time-in-sec "Z" process-id "@" FQDN ">"
                    278: **
                    279: **     or on systems that doesn't have process-id:
                    280: **
                    281: **             "<" time-in-sec "Z" user "@" FQDN ">"
                    282: **
                    283: **     Returns a pointer to the MessageID
                    284: */
                    285: PUBLIC CONST char *HTMessageIdStr NOARGS
                    286: {
                    287:     static char buf[80];
                    288:     time_t sectime = time(NULL);
                    289: #ifndef NO_GETPID
                    290:     CONST char *address = HTGetDomainName();
                    291: #else
                    292:     CONST char *address = HTGetMailAddress();
                    293: #endif /* NO_GETPID */
                    294:     if (!address) address = tmpnam(NULL);
                    295:     if ((!address || !*address) && sectime < 0) {
                    296:        if (TRACE)
                    297:            fprintf(TDEST, "MessageID...  Can't make a unique MessageID\n");
                    298:        return "";
                    299:     }
                    300: #ifndef NO_GETPID
                    301:     sprintf(buf, "<%ldZ%d@%s>", sectime, getpid(), address ? address : "@@@");
                    302: #else
                    303:     sprintf(buf, "<%ldZ%s>", sectime, address ? address : "@@@");
                    304: #endif /* NO_GETPID */
                    305: 
                    306:     *(buf+79) = '\0';
                    307:     return buf;
                    308: }
                    309: 
                    310: 
                    311: /*     Date and Time Parser
                    312: **     --------------------
                    313: **     These functions are taken from the server written by Ari Luotonen
                    314: */
                    315: 
                    316: PRIVATE char * month_names[12] =
                    317: {
                    318:     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                    319:     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                    320: };
                    321: 
                    322: PRIVATE int make_num ARGS1(CONST char *, s)
                    323: {
                    324:     if (*s >= '0' && *s <= '9')
                    325:        return 10 * (*s - '0') + *(s+1) - '0';
                    326:     else
                    327:        return *(s+1) - '0';
                    328: }
                    329: 
                    330: PRIVATE int make_month ARGS1(CONST char *, s)
                    331: {
                    332:     int i;
                    333:     for (i=0; i<12; i++)
                    334:        if (!strncasecomp(month_names[i], s, 3))
                    335:            return i;
                    336:     return 0;
                    337: }
                    338: 
                    339: /*     Timezone Offset
                    340: **     ---------------
                    341: **     Calculates the offset from GMT in seconds
                    342: */
                    343: PUBLIC long HTGetTimeZoneOffset NOARGS
                    344: {
                    345: #ifndef NO_TIMEZONE
                    346:     {
                    347:        time_t cur_t = time(NULL);
2.24      frystyk   348: #ifdef HT_REENTRANT
                    349:        struct tm loctime;
                    350:        struct tm *local = (struct tm *) localtime_r(&cur_t, &loctime);
                    351: #else
                    352:        struct tm *local = localtime(&cur_t);
                    353: #endif /* HT_REENTRANT */
2.22      frystyk   354:        if (daylight && local->tm_isdst>0) {               /* daylight time? */
                    355: #ifndef NO_ALTZONE
                    356:            HTTimeZone = altzone;
                    357: #else
                    358:            /* Assumes a fixed DST offset of 1 hour, which is probably wrong */
                    359:            HTTimeZone = timezone - 3600;
                    360: #endif
                    361:        } else {                                                       /* no */
                    362:            HTTimeZone = timezone;
                    363:        }
2.13      frystyk   364:        HTTimeZone = -HTTimeZone;
                    365:        if (TRACE)
2.14      frystyk   366:            fprintf(TDEST,"TimeZone.... GMT + (%02d) hours (including DST)\n",
2.13      frystyk   367:                    (int) HTTimeZone/3600);
                    368:     }
2.14      frystyk   369: #else
                    370: #ifndef NO_GMTOFF
                    371:     {
                    372:        time_t cur_t = time(NULL);
2.24      frystyk   373: #ifdef HT_REENTRANT
                    374:        struct tm loctime;
                    375:        localtime_r(&cur_t, &loctime);
                    376: #else
2.14      frystyk   377:        struct tm * local = localtime(&cur_t);
2.24      frystyk   378: #endif /* HT_REENTRANT */
2.14      frystyk   379:        HTTimeZone = local->tm_gmtoff;
2.22      frystyk   380:        if (TRACE)
                    381:            fprintf(TDEST,"TimeZone.... GMT + (%02d) hours (including DST)\n",
                    382:                    (int)local->tm_gmtoff / 3600);
2.14      frystyk   383:     }
                    384: #else
                    385:     if (TRACE) fprintf(TDEST,"TimeZone.... Not defined\n");
2.13      frystyk   386: #endif /* !NO_TIMEZONE */
                    387: #endif /* !NO_GMTOFF */
                    388:     return HTTimeZone;
                    389: }
                    390: 
                    391: /*
                    392: **     Parse a str in GMT format to a local time time_t representation
2.19      frystyk   393: **     Four formats are accepted:
                    394: **
                    395: **             Wkd, 00 Mon 0000 00:00:00 GMT           (rfc1123)
                    396: **             Weekday, 00-Mon-00 00:00:00 GMT         (rfc850)
                    397: **             Wkd Mon 00 00:00:00 0000 GMT            (ctime)
                    398: **             1*DIGIT                                 (delta-seconds)
2.13      frystyk   399: */
                    400: PUBLIC time_t HTParseTime ARGS1(CONST char *, str)
                    401: {
                    402:     CONST char * s;
                    403:     struct tm tm;
                    404:     time_t t;
                    405: 
                    406:     if (!str) return 0;
                    407: 
2.19      frystyk   408:     if ((s = strchr(str, ','))) {       /* Thursday, 10-Jun-93 01:29:59 GMT */
2.13      frystyk   409:        s++;                            /* or: Thu, 10 Jan 1993 01:29:59 GMT */
                    410:        while (*s && *s==' ') s++;
2.19      frystyk   411:        if (strchr(s,'-')) {                                 /* First format */
2.13      frystyk   412:            if (TRACE)
                    413:                fprintf(TDEST, "Format...... Weekday, 00-Mon-00 00:00:00 GMT\n");
                    414:            if ((int)strlen(s) < 18) {
                    415:                if (TRACE)
                    416:                    fprintf(TDEST,
                    417:                            "ERROR....... Not a valid time format \"%s\"\n",s);
                    418:                return 0;
                    419:            }
                    420:            tm.tm_mday = make_num(s);
                    421:            tm.tm_mon = make_month(s+3);
                    422:            tm.tm_year = make_num(s+7);
                    423:            tm.tm_hour = make_num(s+10);
                    424:            tm.tm_min = make_num(s+13);
                    425:            tm.tm_sec = make_num(s+16);
2.19      frystyk   426:        } else {                                            /* Second format */
2.13      frystyk   427:            if (TRACE)
                    428:                fprintf(TDEST, "Format...... Wkd, 00 Mon 0000 00:00:00 GMT\n");
                    429:            if ((int)strlen(s) < 20) {
                    430:                if (TRACE)
                    431:                    fprintf(TDEST,
                    432:                            "ERROR....... Not a valid time format \"%s\"\n",s);
                    433:                return 0;
                    434:            }
                    435:            tm.tm_mday = make_num(s);
                    436:            tm.tm_mon = make_month(s+3);
                    437:            tm.tm_year = (100*make_num(s+7) - 1900) + make_num(s+9);
                    438:            tm.tm_hour = make_num(s+12);
                    439:            tm.tm_min = make_num(s+15);
                    440:            tm.tm_sec = make_num(s+18);
                    441: 
                    442:        }
2.19      frystyk   443:     } else if (isdigit(*str)) {                                    /* delta seconds */
                    444:        t = time(NULL) + atol(str);           /* Current local calendar time */
2.24      frystyk   445:        if (TRACE) {
                    446: #ifdef HT_REENTRANT
                    447:            char buffer[CTIME_MAX];
                    448:            fprintf(TDEST, "Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, (char *) ctime_r(&t, buffer, CTIME_MAX));
                    449: #else
2.19      frystyk   450:            fprintf(TDEST, "Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, ctime(&t));
2.24      frystyk   451: #endif
                    452:        }
2.19      frystyk   453:        return t;
                    454: 
                    455:     } else {         /* Try the other format:  Wed Jun  9 01:29:59 1993 GMT */
2.13      frystyk   456:        if (TRACE)
                    457:            fprintf(TDEST, "Format...... Wkd Mon 00 00:00:00 0000 GMT\n");
                    458:        s = str;
                    459:        while (*s && *s==' ') s++;
                    460:        if (TRACE)
                    461:            fprintf(TDEST, "Trying...... The Wrong time format: %s\n", s);
                    462:        if ((int)strlen(s) < 24) {
                    463:            if (TRACE)
                    464:                fprintf(TDEST, "ERROR....... Not a valid time format \"%s\"\n",s);
                    465:            return 0;
                    466:        }
                    467:        tm.tm_mday = make_num(s+8);
                    468:        tm.tm_mon = make_month(s+4);
                    469:        tm.tm_year = make_num(s+22);
                    470:        tm.tm_hour = make_num(s+11);
                    471:        tm.tm_min = make_num(s+14);
                    472:        tm.tm_sec = make_num(s+17);
                    473:     }
                    474:     if (tm.tm_sec  < 0  ||  tm.tm_sec  > 59  ||
                    475:        tm.tm_min  < 0  ||  tm.tm_min  > 59  ||
                    476:        tm.tm_hour < 0  ||  tm.tm_hour > 23  ||
                    477:        tm.tm_mday < 1  ||  tm.tm_mday > 31  ||
                    478:        tm.tm_mon  < 0  ||  tm.tm_mon  > 11  ||
                    479:        tm.tm_year <70  ||  tm.tm_year >120) {
                    480:        if (TRACE) fprintf(TDEST,
                    481:        "ERROR....... Parsed illegal time: %02d.%02d.%02d %02d:%02d:%02d\n",
                    482:               tm.tm_mday, tm.tm_mon+1, tm.tm_year,
                    483:               tm.tm_hour, tm.tm_min, tm.tm_sec);
                    484:        return 0;
                    485:     }
                    486: 
2.16      frystyk   487: #if !defined(NO_TIMEZONE) && !defined(NO_ALTZONE)
2.14      frystyk   488:     tm.tm_isdst = daylight;                   /* Already taken into account */
                    489: #else
                    490:     tm.tm_isdst = -1;
                    491: #endif
                    492: 
2.13      frystyk   493: #ifndef NO_MKTIME
                    494:     t = mktime(&tm);
2.18      frystyk   495:     t += (HTTimeZone);
2.13      frystyk   496: #else
                    497: #ifndef NO_TIMEGM
                    498:     t = timegm(&tm);
                    499: #else
2.18      frystyk   500:     if (TRACE) fprintf(TDEST,"Time String. Can not be parsed\n");
2.13      frystyk   501: #endif /* !NO_TIMEGM */
                    502: #endif /* !NO_MKTIME */
                    503: 
                    504:     if (TRACE)
                    505:        fprintf(TDEST,
                    506:                "Time string. %s parsed to %ld seconds, or in local time: %s",
                    507:                str, (long) t, ctime(&t));
                    508:     return t;
1.1       timbl     509: }
2.23      frystyk   510: 
                    511: 
                    512: /*     Strip white space off a string
                    513: **     ------------------------------
                    514: **
                    515: ** On exit,
                    516: **     Return value points to first non-white character, or to 0 if none.
                    517: **     All trailing white space is OVERWRITTEN with zero.
                    518: */
                    519: 
                    520: PUBLIC char * HTStrip ARGS1(char *, s)
                    521: {
                    522: #define SPACE(c) ((c==' ')||(c=='\t')||(c=='\n')) 
                    523:     char * p=s;
                    524:     if (!s) return NULL;       /* Doesn't dump core if NULL */
                    525:     for(p=s;*p;p++);           /* Find end of string */
                    526:     for(p--;p>=s;p--) {
                    527:        if(SPACE(*p)) *p=0;     /* Zap trailing blanks */
                    528:        else break;
                    529:     }
                    530:     while(SPACE(*s))s++;       /* Strip leading blanks */
                    531:     return s;
                    532: }
2.25    ! frystyk   533: 
        !           534: 
        !           535: /*                                                             HTNumToStr
        !           536: **     Converts a long (byte count) to a string
        !           537: **     ----------------------------------------
        !           538: **     This function was a PAIN!  In computer-world 1K is 1024 bytes
        !           539: **     and 1M is 1024K -- however, sprintf() still formats in base-10.
        !           540: **     Therefore I output only until 999, and then start using the
        !           541: **     next unit.  This doesn't work wrong, it's just a feature.
        !           542: **     The "str" must be large enough to contain the result.
        !           543: */
        !           544: PUBLIC void HTNumToStr ARGS2(unsigned long, n, char *, str)
        !           545: {
        !           546:     double size = n/1024.0;
        !           547:     if (n < 1000)
        !           548:        sprintf(str, "%dK", n>0 ? 1 : 0);
        !           549:     else if (size + 0.999 < 1000)
        !           550:        sprintf(str, "%dK", (int)(size + 0.5));
        !           551:     else if ((size /= 1024) < 9.9)
        !           552:        sprintf(str, "%.1fM", (size + 0.05));
        !           553:     else if (size < 1000)
        !           554:        sprintf(str, "%dM", (int)(size + 0.5));
        !           555:     else if ((size /= 1024) < 9.9)
        !           556:        sprintf(str, "%.1fG", (size + 0.05));
        !           557:     else
        !           558:        sprintf(str, "%dG", (int)(size + 0.5));
        !           559: }
        !           560: 

Webmaster