Annotation of libwww/Library/src/HTWWWStr.c, revision 2.6

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.
                      6: **
                      7: **      Now 13 95      Spwaned from HTString.c
                      8: */
                      9: 
                     10: /* Library include files */
                     11: #include "tcp.h"
                     12: #include "HTUtils.h"
                     13: #include "HTString.h"
                     14: #include "HTTCP.h"
                     15: #include "HTParse.h"
                     16: #include "HTWWWStr.h"                                   /* Implemented here */
                     17: 
                     18: PRIVATE long HTTimeZone = 0L;                 /* Offset from GMT in seconds */
                     19: PRIVATE char * months[12] = {
                     20:     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
                     21: };
                     22: 
                     23: #ifdef NO_STRFTIME
                     24: PRIVATE char * wkdays[7] = {
                     25:     "Mon","Tue","Wed","Thu","Fri","Sat","Sun"
                     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.4       frystyk    51:     if (!*pstr) return NULL;
2.1       frystyk    52:     while (1) {
                     53:        /* Strip white space and other delimiters */
                     54:        while (*p && (WHITE(*p) || *p==',' || *p==';' || *p=='=')) p++;
                     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;
                     76:            while(*p && !WHITE(*p) && *p!=',' && *p!=';' && *p!='=')
                     77:                p++;
                     78:            break;                                                 /* Got it */
                     79:        }
                     80:     }
                     81:     if (*p) *p++ = '\0';
                     82:     *pstr = p;
                     83:     return start;
                     84: }
                     85: 
                     86: /*
                     87: **     Returns a Message-ID string including the open '<' and the closing '>'.
                     88: **     The format of the string is:
                     89: **
                     90: **             "<" time-in-sec "Z" process-id "@" FQDN ">"
                     91: **
                     92: **     or on systems that doesn't have process-id:
                     93: **
                     94: **             "<" time-in-sec "Z" user "@" FQDN ">"
                     95: **
                     96: **     Returns a pointer to the MessageID
                     97: */
                     98: PUBLIC CONST char *HTMessageIdStr (void)
                     99: {
                    100:     static char buf[80];
                    101:     time_t sectime = time(NULL);
                    102: #ifndef NO_GETPID
                    103:     CONST char *address = HTGetDomainName();
                    104: #else
                    105:     CONST char *address = HTGetMailAddress();
                    106: #endif /* NO_GETPID */
                    107:     if (!address) address = tmpnam(NULL);
                    108:     if ((!address || !*address) && sectime < 0) {
                    109:        if (WWWTRACE)
2.6     ! eric      110:            HTTrace("MessageID...  Can't make a unique MessageID\n");
2.1       frystyk   111:        return "";
                    112:     }
                    113: #ifndef NO_GETPID
                    114:     sprintf(buf, "<%ldZ%d@%s>", sectime, getpid(), address ? address : "@@@");
                    115: #else
                    116:     sprintf(buf, "<%ldZ%s>", sectime, address ? address : "@@@");
                    117: #endif /* NO_GETPID */
                    118: 
                    119:     *(buf+79) = '\0';
                    120:     return buf;
                    121: }
                    122: 
                    123: /*     Date and Time Parser
                    124: **     --------------------
                    125: **     These functions are taken from the server written by Ari Luotonen
                    126: */
                    127: 
                    128: PRIVATE int make_num (CONST char *  s)
                    129: {
                    130:     if (*s >= '0' && *s <= '9')
                    131:        return 10 * (*s - '0') + *(s+1) - '0';
                    132:     else
                    133:        return *(s+1) - '0';
                    134: }
                    135: 
                    136: PRIVATE int make_month (CONST char *  s)
                    137: {
                    138:     int i;
                    139:     for (i=0; i<12; i++)
                    140:        if (!strncasecomp(months[i], s, 3))
                    141:            return i;
                    142:     return 0;
                    143: }
                    144: 
                    145: /*     Timezone Offset
                    146: **     ---------------
                    147: **     Calculates the offset from GMT in seconds
                    148: */
                    149: PUBLIC long HTGetTimeZoneOffset (void)
                    150: {
                    151: #ifndef NO_TIMEZONE
                    152:     {
                    153:        time_t cur_t = time(NULL);
                    154: #ifdef HT_REENTRANT
                    155:        struct tm loctime;
                    156:        struct tm *local = (struct tm *) localtime_r(&cur_t, &loctime);
                    157: #else
                    158:        struct tm *local = localtime(&cur_t);
                    159: #endif /* HT_REENTRANT */
                    160:        if (daylight && local->tm_isdst>0) {               /* daylight time? */
                    161: #ifndef NO_ALTZONE
                    162:            HTTimeZone = altzone;
                    163: #else
                    164:            /* Assumes a fixed DST offset of 1 hour, which is probably wrong */
                    165:            HTTimeZone = timezone - 3600;
                    166: #endif
                    167:        } else {                                                       /* no */
                    168:            HTTimeZone = timezone;
                    169:        }
                    170:        HTTimeZone = -HTTimeZone;
                    171:        if (WWWTRACE)
2.6     ! eric      172:            HTTrace("TimeZone.... GMT + (%02d) hours (including DST)\n",
2.1       frystyk   173:                    (int) HTTimeZone/3600);
                    174:     }
                    175: #else
                    176: #ifndef NO_GMTOFF
                    177:     {
                    178:        time_t cur_t = time(NULL);
                    179: #ifdef HT_REENTRANT
                    180:        struct tm loctime;
                    181:        localtime_r(&cur_t, &loctime);
                    182: #else
                    183:        struct tm * local = localtime(&cur_t);
                    184: #endif /* HT_REENTRANT */
                    185:        HTTimeZone = local->tm_gmtoff;
                    186:        if (WWWTRACE)
2.6     ! eric      187:            HTTrace("TimeZone.... GMT + (%02d) hours (including DST)\n",
2.1       frystyk   188:                    (int)local->tm_gmtoff / 3600);
                    189:     }
                    190: #else
2.6     ! eric      191:     if (WWWTRACE) HTTrace("TimeZone.... Not defined\n");
2.1       frystyk   192: #endif /* !NO_TIMEZONE */
                    193: #endif /* !NO_GMTOFF */
                    194:     return HTTimeZone;
                    195: }
                    196: 
                    197: /*
                    198: **     Parse a str in GMT format to a local time time_t representation
                    199: **     Four formats are accepted:
                    200: **
                    201: **             Wkd, 00 Mon 0000 00:00:00 GMT           (rfc1123)
                    202: **             Weekday, 00-Mon-00 00:00:00 GMT         (rfc850)
                    203: **             Wkd Mon 00 00:00:00 0000 GMT            (ctime)
                    204: **             1*DIGIT                                 (delta-seconds)
                    205: */
                    206: PUBLIC time_t HTParseTime (CONST char *  str)
                    207: {
                    208:     CONST char * s;
                    209:     struct tm tm;
                    210:     time_t t;
                    211: 
                    212:     if (!str) return 0;
                    213: 
                    214:     if ((s = strchr(str, ','))) {       /* Thursday, 10-Jun-93 01:29:59 GMT */
                    215:        s++;                            /* or: Thu, 10 Jan 1993 01:29:59 GMT */
                    216:        while (*s && *s==' ') s++;
                    217:        if (strchr(s,'-')) {                                 /* First format */
                    218:            if (WWWTRACE)
2.6     ! eric      219:                HTTrace("Format...... Weekday, 00-Mon-00 00:00:00 GMT\n");
2.1       frystyk   220:            if ((int)strlen(s) < 18) {
                    221:                if (WWWTRACE)
2.6     ! eric      222:                    HTTrace(
2.1       frystyk   223:                            "ERROR....... Not a valid time format \"%s\"\n",s);
                    224:                return 0;
                    225:            }
                    226:            tm.tm_mday = make_num(s);
                    227:            tm.tm_mon = make_month(s+3);
                    228:            tm.tm_year = make_num(s+7);
                    229:            tm.tm_hour = make_num(s+10);
                    230:            tm.tm_min = make_num(s+13);
                    231:            tm.tm_sec = make_num(s+16);
                    232:        } else {                                            /* Second format */
                    233:            if (WWWTRACE)
2.6     ! eric      234:                HTTrace("Format...... Wkd, 00 Mon 0000 00:00:00 GMT\n");
2.1       frystyk   235:            if ((int)strlen(s) < 20) {
                    236:                if (WWWTRACE)
2.6     ! eric      237:                    HTTrace(
2.1       frystyk   238:                            "ERROR....... Not a valid time format \"%s\"\n",s);
                    239:                return 0;
                    240:            }
                    241:            tm.tm_mday = make_num(s);
                    242:            tm.tm_mon = make_month(s+3);
                    243:            tm.tm_year = (100*make_num(s+7) - 1900) + make_num(s+9);
                    244:            tm.tm_hour = make_num(s+12);
                    245:            tm.tm_min = make_num(s+15);
                    246:            tm.tm_sec = make_num(s+18);
                    247: 
                    248:        }
                    249:     } else if (isdigit(*str)) {                                    /* delta seconds */
                    250:        t = time(NULL) + atol(str);           /* Current local calendar time */
                    251:        if (WWWTRACE) {
                    252: #ifdef HT_REENTRANT
                    253:            char buffer[CTIME_MAX];
2.6     ! eric      254:            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   255: #else
2.6     ! eric      256:            HTTrace("Time string. Delta-time %s parsed to %ld seconds, or in local time: %s", str, (long) t, ctime(&t));
2.1       frystyk   257: #endif
                    258:        }
                    259:        return t;
                    260: 
                    261:     } else {         /* Try the other format:  Wed Jun  9 01:29:59 1993 GMT */
                    262:        if (WWWTRACE)
2.6     ! eric      263:            HTTrace("Format...... Wkd Mon 00 00:00:00 0000 GMT\n");
2.1       frystyk   264:        s = str;
                    265:        while (*s && *s==' ') s++;
                    266:        if (WWWTRACE)
2.6     ! eric      267:            HTTrace("Trying...... The Wrong time format: %s\n", s);
2.1       frystyk   268:        if ((int)strlen(s) < 24) {
                    269:            if (WWWTRACE)
2.6     ! eric      270:                HTTrace("ERROR....... Not a valid time format \"%s\"\n",s);
2.1       frystyk   271:            return 0;
                    272:        }
                    273:        tm.tm_mday = make_num(s+8);
                    274:        tm.tm_mon = make_month(s+4);
                    275:        tm.tm_year = make_num(s+22);
                    276:        tm.tm_hour = make_num(s+11);
                    277:        tm.tm_min = make_num(s+14);
                    278:        tm.tm_sec = make_num(s+17);
                    279:     }
                    280:     if (tm.tm_sec  < 0  ||  tm.tm_sec  > 59  ||
                    281:        tm.tm_min  < 0  ||  tm.tm_min  > 59  ||
                    282:        tm.tm_hour < 0  ||  tm.tm_hour > 23  ||
                    283:        tm.tm_mday < 1  ||  tm.tm_mday > 31  ||
                    284:        tm.tm_mon  < 0  ||  tm.tm_mon  > 11  ||
                    285:        tm.tm_year <70  ||  tm.tm_year >120) {
2.6     ! eric      286:        if (WWWTRACE) HTTrace(
2.1       frystyk   287:        "ERROR....... Parsed illegal time: %02d.%02d.%02d %02d:%02d:%02d\n",
                    288:               tm.tm_mday, tm.tm_mon+1, tm.tm_year,
                    289:               tm.tm_hour, tm.tm_min, tm.tm_sec);
                    290:        return 0;
                    291:     }
                    292: 
                    293: #if !defined(NO_TIMEZONE) && !defined(NO_ALTZONE)
                    294:     tm.tm_isdst = daylight;                   /* Already taken into account */
                    295: #else
                    296:     tm.tm_isdst = -1;
                    297: #endif
                    298: 
                    299: #ifndef NO_MKTIME
                    300:     t = mktime(&tm);
                    301:     t += (HTTimeZone);
                    302: #else
                    303: #ifndef NO_TIMEGM
                    304:     t = timegm(&tm);
                    305: #else
2.6     ! eric      306:     if (WWWTRACE) HTTrace("Time String. Can not be parsed\n");
2.1       frystyk   307: #endif /* !NO_TIMEGM */
                    308: #endif /* !NO_MKTIME */
                    309: 
                    310:     if (WWWTRACE)
2.6     ! eric      311:        HTTrace(
2.1       frystyk   312:                "Time string. %s parsed to %ld seconds, or in local time: %s",
                    313:                str, (long) t, ctime(&t));
                    314:     return t;
                    315: }
                    316: 
                    317: /*
                    318: **     Returns a string pointer to a static area of the current calendar
                    319: **     time in RFC 1123 format, for example
                    320: **
                    321: **             Sun, 06 Nov 1994 08:49:37 GMT
                    322: **
                    323: **     The result can be given in both local and GMT dependent on the flag
                    324: */
                    325: PUBLIC CONST char *HTDateTimeStr (time_t * calendar, BOOL local)
                    326: {
                    327:     static char buf[40];
                    328: 
                    329: #ifndef NO_STRFTIME
                    330:     if (local) {
                    331:        /*
                    332:        ** Solaris 2.3 has a bug so we _must_ use reentrant version
                    333:        ** Thomas Maslen <tmaslen@verity.com>
                    334:        */
                    335: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    336:        struct tm loctime;
                    337:        localtime_r(calendar, &loctime);
                    338:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", &loctime);
                    339: #else
                    340:        struct tm *loctime = localtime(calendar);
                    341:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", loctime);
                    342: #endif /* SOLARIS || HT_REENTRANT */
                    343:     } else {
                    344: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    345:        struct tm gmt;
                    346:        gmtime_r(calendar, &gmt);
                    347:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", &gmt);
                    348: #else
                    349:        struct tm *gmt = gmtime(calendar);
                    350:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", gmt);
                    351: #endif /* SOLARIS || HT_REENTRANT */
                    352:     }
                    353: #else
                    354:     if (local) {
                    355: #if defined(HT_REENTRANT)
                    356:        struct tm loctime;
                    357:        localtime_r(calendar, &loctime);
                    358: #else
                    359:        struct tm *loctime = localtime(calendar);
                    360: #endif /* HT_REENTRANT */
                    361:        sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d",
                    362:                wkdays[gmt->tm_wday],
                    363:                gmt->tm_mday,
                    364:                months[gmt->tm_mon],
                    365:                gmt->tm_year % 100,
                    366:                gmt->tm_hour,
                    367:                gmt->tm_min,
                    368:                gmt->tm_sec);
                    369:     } else {
                    370: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    371:        struct tm gmt;
                    372:        gmtime_r(calendar, &gmt);
                    373: #else
                    374:        struct tm *gmt = gmtime(calendar);
                    375: #endif
                    376:        sprintf(buf,"%s, %02d %s 19%02d %02d:%02d:%02d GMT",
                    377:                wkdays[gmt->tm_wday],
                    378:                gmt->tm_mday,
                    379:                months[gmt->tm_mon],
                    380:                gmt->tm_year % 100,
                    381:                gmt->tm_hour,
                    382:                gmt->tm_min,
                    383:                gmt->tm_sec);
                    384:     }
                    385: #endif
                    386:     return buf;
                    387: }
                    388: 
                    389: /*     HTDateDirStr
                    390: **     ------------
                    391: **     Generates a date string used in directory listings
                    392: */
                    393: PUBLIC BOOL HTDateDirStr (time_t * time, char * str, int len)
                    394: {
                    395: #ifndef NO_STRFTIME
                    396: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    397:     struct tm loctime;
                    398:     localtime_r(time, &loctime);
                    399:     strftime(str, len, "%d-%b-%y %H:%M", &loctime);
                    400:     return YES;
                    401: #else
                    402:     strftime(str, len, "%d-%b-%y %H:%M", localtime(time));
                    403:     return YES;
                    404: #endif /* HT_REENTRANT || SOLARIS */
                    405: #else
                    406:     if (len >= 16) {
                    407:        struct tm *loctime = localtime(time);
                    408:        sprintf(bodyptr,"%02d-%s-%02d %02d:%02d",
                    409:                loctime->tm_mday,
                    410:                months[loctime->tm_mon],
                    411:                loctime->tm_year % 100,
                    412:                loctime->tm_hour,
                    413:                loctime->tm_min);
                    414:        return YES;
                    415:     }
                    416:     return NO;
                    417: #endif /* NO_STRFTIME */               
                    418: }
                    419: 
                    420: /*                                                             HTNumToStr
                    421: **     Converts a long (byte count) to a string
                    422: **     ----------------------------------------
                    423: **     This function was a PAIN!  In computer-world 1K is 1024 bytes
                    424: **     and 1M is 1024K -- however, sprintf() still formats in base-10.
                    425: **     Therefore I output only until 999, and then start using the
                    426: **     next unit.  This doesn't work wrong, it's just a feature.
                    427: **     The "str" must be large enough to contain the result.
                    428: */
                    429: PUBLIC void HTNumToStr (unsigned long n, char * str, int len)
                    430: {
                    431:     double size = n/1024.0;
                    432:     if (len < 6) {
                    433:        *str = '\0';
                    434:        return;
                    435:     }
                    436:     if (n < 1000)
                    437:        sprintf(str, "%dK", n>0 ? 1 : 0);
                    438:     else if (size + 0.999 < 1000)
                    439:        sprintf(str, "%dK", (int)(size + 0.5));
                    440:     else if ((size /= 1024) < 9.9)
                    441:        sprintf(str, "%.1fM", (size + 0.05));
                    442:     else if (size < 1000)
                    443:        sprintf(str, "%dM", (int)(size + 0.5));
                    444:     else if ((size /= 1024) < 9.9)
                    445:        sprintf(str, "%.1fG", (size + 0.05));
                    446:     else
                    447:        sprintf(str, "%dG", (int)(size + 0.5));
                    448: }
                    449: 
                    450: /*     Convert file URLs into a local representation
                    451: **     ---------------------------------------------
                    452: **     The URL has already been translated through the rules in get_physical
                    453: **     in HTAccess.c and all we need to do now is to map the path to a local
                    454: **     representation, for example if must translate '/' to the ones that
                    455: **     turn the wrong way ;-)
                    456: **     Returns:
                    457: **             OK:     local file (that must be freed by caller)
                    458: **             Error:  NULL
                    459: */
                    460: PUBLIC char * HTWWWToLocal (CONST char * url, CONST char * base)
                    461: {
                    462:     if (url) {
                    463:        char * access = HTParse(url, base, PARSE_ACCESS);
                    464:        char * host = HTParse(url, base, PARSE_HOST);
                    465:        char * path = HTParse(url, base, PARSE_PATH+PARSE_PUNCTUATION);
                    466:        CONST char *myhost = HTGetHostName();
                    467: 
                    468:        /* Find out if this is a reference to the local file system */
                    469:        if ((*access && strcmp(access, "file")) ||
                    470:            (*host && strcasecomp(host, "localhost") &&
                    471:             myhost && strcmp(host, myhost))) {
                    472:            if (PROT_TRACE)
2.6     ! eric      473:                HTTrace("LocalName... Not on local file system\n");
2.5       frystyk   474:            HT_FREE(access);
                    475:            HT_FREE(host);
                    476:            HT_FREE(path);
2.1       frystyk   477:            return NULL;
                    478:        } else {
                    479:            char *ptr;
                    480:            if ((ptr = strchr(path, ';')) || (ptr = strchr(path, '?')))
                    481:                *ptr = '\0';
                    482:        
                    483:            /*
                    484:            ** Do whatever translation is required here in order to fit your
                    485:            ** platform _before_ the path is unescaped.
                    486:            */
                    487: #ifdef VMS
                    488:            HTVMS_checkDecnet(path);
                    489: #endif
2.3       frystyk   490: #ifdef WWW_MSWINDOWS
2.1       frystyk   491:            /* an absolute pathname with logical drive */
                    492:            if (*path == '/' && path[2] == ':')    
                    493:                /* NB. need memmove because overlaps */
                    494:                memmove( path, path+1, strlen(path) + 1);
                    495: #endif
                    496:            
                    497:            HTUnEscape(path);             /* Take out the escaped characters */
                    498:            if (PROT_TRACE)
2.6     ! eric      499:                HTTrace("Node........ `%s' means path `%s'\n",url,path);
2.5       frystyk   500:            HT_FREE(access);
                    501:            HT_FREE(host);
2.1       frystyk   502:            return path;
                    503:        }
                    504:     }
                    505:     return NULL;
                    506: }
                    507: 
                    508: /*     Convert a local file name into a URL
                    509: **     ------------------------------------
                    510: **     Generates a WWW URL name from a local file name or NULL if error.
                    511: **     Returns:
                    512: **             OK:     local file (that must be freed by caller)
                    513: **             Error:  NULL
                    514: */
                    515: PUBLIC char * HTLocalToWWW (CONST char * local)
                    516: {
                    517:     char * result = NULL;
                    518:     if (local && *local) {
                    519:        StrAllocCopy(result, "file:");       /* We get an absolute file name */
                    520: #ifdef VMS 
                    521:        /* convert directory name to Unix-style syntax */
                    522:        {
                    523:            char * disk = strchr (local, ':');
                    524:            char * dir = strchr (local, '[');
                    525:            if (disk) {
                    526:                *disk = '\0';
                    527:                StrAllocCat(result, "/"); /* needs delimiter */
                    528:                StrAllocCat(result, local);
                    529:            }
                    530:            if (dir) {
                    531:                char *p;
                    532:                *dir = '/';     /* Convert leading '[' */
                    533:                for (p = dir ; *p != ']'; ++p)
                    534:                    if (*p == '.') *p = '/';
                    535:                *p = '\0';      /* Cut on final ']' */
                    536:                StrAllocCat(result, dir);
                    537:            }
                    538:        }
                    539: #else  /* not VMS */
                    540: #ifdef WIN32
                    541:        {
2.2       frystyk   542:            char * p;
2.1       frystyk   543:            StrAllocCat(result, "/");
2.2       frystyk   544:            StrAllocCat(result, local);     
                    545:            p = result;
                    546:            while (*p) { 
2.1       frystyk   547:                if (*p == '\\')                  /* change to one true slash */
2.2       frystyk   548:                    *p = '/';
2.1       frystyk   549:                p++;
                    550:            }
                    551:        }
                    552: #else /* not WIN32 */
                    553:        StrAllocCat (result, local);
                    554: #endif /* not WIN32 */
                    555: #endif /* not VMS */
                    556:     }
                    557:     return result;
                    558: }

Webmaster