Annotation of Amaya/amaya/AHTURLTools.c, revision 1.62

1.7       cvs         1: /*
                      2:  *
                      3:  *  (c) COPYRIGHT MIT and INRIA, 1996.
                      4:  *  Please first read the full copyright statement in file COPYRIGHT.
                      5:  *
                      6:  */
1.9       cvs         7: 
1.10      cvs         8: /*
                      9:  * AHTURLTools.c: contains all the functions for testing, manipulating,
1.25      cvs        10:  * and normalizing URLs. It also contains a local copy of the libWWW
                     11:  * URL parsing functions.
1.10      cvs        12:  *
                     13:  * Authors: J. Kahan, I. Vatton
1.45      cvs        14:  *          R. Guetari (Stuff related to Windows).
1.10      cvs        15:  *
                     16:  */
1.7       cvs        17:  
1.15      cvs        18: #define THOT_EXPORT extern
1.3       cvs        19: #include "amaya.h"
                     20: 
1.8       cvs        21: #include "init_f.h"
                     22: #include "AHTURLTools_f.h"
                     23: 
1.24      cvs        24: #define MAX_PRINT_URL_LENGTH 50
1.29      cvs        25: typedef struct _HTURI {
                     26:     char * access;             /* Now known as "scheme" */
                     27:     char * host;
                     28:     char * absolute;
                     29:     char * relative;
                     30:     char * fragment;
                     31: } HTURI;
1.24      cvs        32: 
1.28      cvs        33: 
                     34: /*----------------------------------------------------------------------
                     35:   ConvertToLowerCase
                     36:   Converts a string to lowercase.
                     37:   ----------------------------------------------------------------------*/
1.22      cvs        38: #ifdef __STDC__
1.38      cvs        39: void         ConvertToLowerCase (char *string)
1.28      cvs        40: #else  /* __STDC__ */
1.38      cvs        41: void         ConvertToLowerCase (string)
1.28      cvs        42: char                *string;
                     43: 
                     44: #endif /* __STDC__ */
                     45: {
                     46:  int i;
                     47: 
                     48:  if (!string)
                     49:    return;
                     50: 
                     51:  for (i = 0; string[i] != EOS; i++)
                     52:    string[i] = tolower (string[i]);
                     53: }
1.22      cvs        54: 
1.8       cvs        55: /*----------------------------------------------------------------------
1.11      cvs        56:   ExplodeURL 
1.8       cvs        57:   ----------------------------------------------------------------------*/
                     58: #ifdef __STDC__
                     59: void                ExplodeURL (char *url, char **proto, char **host, char **dir, char **file)
                     60: #else
                     61: void                ExplodeURL (url, proto, host, dir, file)
                     62: char               *url;
                     63: char              **proto;
                     64: char              **host;
                     65: char              **dir;
                     66: char              **file;
                     67: 
                     68: #endif
                     69: {
1.33      cvs        70:    char            *curr, *temp;
                     71:    char             used_sep;
1.32      cvs        72: 
1.33      cvs        73:    if (url && strchr (url, URL_SEP))
                     74:      used_sep = URL_SEP;
                     75:    else
                     76:      used_sep = DIR_SEP;
1.8       cvs        77: 
                     78:    if ((url == NULL) || (proto == NULL) || (host == NULL) ||
                     79:        (dir == NULL) || (file == NULL))
                     80:       return;
                     81: 
                     82:    /* initialize every pointer */
                     83:    *proto = *host = *dir = *file = NULL;
                     84: 
                     85:    /* skip any leading space */
                     86:    while ((*url == SPACE) || (*url == TAB))
                     87:       url++;
1.9       cvs        88:    curr = url;
                     89:    if (*curr == 0)
1.8       cvs        90:       goto finished;
                     91: 
                     92:    /* go to the end of the URL */
1.9       cvs        93:    while ((*curr != 0) && (*curr != SPACE) && (*curr != '\b') &&
                     94:          (*curr != '\r') && (*curr != EOL))
                     95:       curr++;
1.8       cvs        96: 
                     97:    /* mark the end of the chain */
1.9       cvs        98:    *curr = EOS;
                     99:    curr--;
                    100:    if (curr <= url)
1.8       cvs       101:       goto finished;
                    102: 
                    103:    /* search the next DIR_SEP indicating the beginning of the file name */
                    104:    do
1.11      cvs       105:      curr--;
1.33      cvs       106:    while ((curr >= url) && (*curr != used_sep));
1.11      cvs       107: 
1.9       cvs       108:    if (curr < url)
1.8       cvs       109:       goto finished;
1.9       cvs       110:    *file = curr + 1;
1.8       cvs       111: 
                    112:    /* mark the end of the dir */
1.9       cvs       113:    *curr = EOS;
                    114:    curr--;
                    115:    if (curr < url)
1.8       cvs       116:       goto finished;
                    117: 
1.29      cvs       118:    /* search for the DIR_STR indicating the host name start */
1.33      cvs       119:    while ((curr > url) && ((*curr != used_sep) || (*(curr + 1) != used_sep)))
1.9       cvs       120:       curr--;
1.8       cvs       121: 
                    122:    /* if we found it, separate the host name from the directory */
1.33      cvs       123:    if ((*curr == DIR_SEP) && (*(curr + 1) == used_sep))
1.8       cvs       124:      {
1.9       cvs       125:        *host = temp = curr + 2;
1.33      cvs       126:        while ((*temp != 0) && (*temp != used_sep))
1.8       cvs       127:           temp++;
1.33      cvs       128:        if (*temp == used_sep)
1.8       cvs       129:          {
                    130:             *temp = EOS;
                    131:             *dir = temp + 1;
                    132:          }
                    133:      }
                    134:    else
1.11      cvs       135:      *dir = curr;
                    136: 
1.9       cvs       137:    if (curr <= url)
1.8       cvs       138:       goto finished;
                    139: 
                    140:    /* mark the end of the proto */
1.9       cvs       141:    *curr = EOS;
                    142:    curr--;
                    143:    if (curr < url)
1.8       cvs       144:       goto finished;
                    145: 
1.32      cvs       146:    if (*curr == ':')
1.8       cvs       147:      {
1.9       cvs       148:        *curr = EOS;
                    149:        curr--;
1.8       cvs       150:      }
                    151:    else
                    152:       goto finished;
1.11      cvs       153: 
1.9       cvs       154:    if (curr < url)
1.8       cvs       155:       goto finished;
1.9       cvs       156:    while ((curr > url) && (isalpha (*curr)))
                    157:       curr--;
                    158:    *proto = curr;
1.8       cvs       159: 
                    160:  finished:;
                    161: 
                    162: #ifdef AMAYA_DEBUG
                    163:    fprintf (stderr, "ExplodeURL(%s)\n\t", url);
                    164:    if (*proto)
                    165:       fprintf (stderr, "proto : %s, ", *proto);
                    166:    if (*host)
                    167:       fprintf (stderr, "host : %s, ", *host);
                    168:    if (*dir)
                    169:       fprintf (stderr, "dir : %s, ", *dir);
                    170:    if (*file)
                    171:       fprintf (stderr, "file : %s ", *file);
                    172:    fprintf (stderr, "\n");
                    173: #endif
                    174: 
                    175: }
1.3       cvs       176: 
1.61      cvs       177: 
                    178: /*----------------------------------------------------------------------
                    179:    ExtractSuffix extract suffix from document nane.                
                    180:   ----------------------------------------------------------------------*/
                    181: #ifdef __STDC__
                    182: void                ExtractSuffix (STRING aName, STRING aSuffix)
                    183: #else
                    184: void                ExtractSuffix (aName, aSuffix)
                    185: STRING              aName;
                    186: STRING              aSuffix;
                    187: 
                    188: #endif
                    189: {
                    190:    int                 lg, i;
                    191:    STRING              ptr, oldptr;
                    192: 
                    193:    if (!aSuffix || !aName)
                    194:      /* bad suffix */
                    195:      return;
                    196: 
                    197:    aSuffix[0] = EOS;
                    198:    lg = ustrlen (aName);
                    199:    if (lg)
                    200:      {
                    201:        /* the name is not empty */
                    202:        oldptr = ptr = &aName[0];
                    203:        do
                    204:          {
                    205:             ptr = ustrrchr (oldptr, '.');
                    206:             if (ptr)
                    207:                oldptr = &ptr[1];
                    208:          }
                    209:        while (ptr);
                    210: 
                    211:        i = (int) (oldptr) - (int) (aName);     /* name length */
                    212:        if (i > 1)
                    213:          {
                    214:             aName[i - 1] = EOS;
                    215:             if (i != lg)
                    216:                ustrcpy (aSuffix, oldptr);
                    217:          }
                    218:      }
                    219: }
                    220: 
1.4       cvs       221: /*----------------------------------------------------------------------
1.9       cvs       222:   IsHTMLName                                                         
                    223:   returns TRUE if path points to an HTML resource.
1.4       cvs       224:   ----------------------------------------------------------------------*/
1.3       cvs       225: #ifdef __STDC__
1.34      cvs       226: boolean             IsHTMLName (const char *path)
1.3       cvs       227: #else  /* __STDC__ */
                    228: boolean             IsHTMLName (path)
1.34      cvs       229: const char         *path;
1.3       cvs       230: #endif /* __STDC__ */
                    231: {
1.5       cvs       232:    char                temppath[MAX_LENGTH];
                    233:    char                suffix[MAX_LENGTH];
                    234:    char                nsuffix[MAX_LENGTH];
                    235:    int                 i;
                    236: 
                    237:    if (!path)
1.37      cvs       238:       return (FALSE);
1.5       cvs       239: 
                    240:    strcpy (temppath, path);
                    241:    ExtractSuffix (temppath, suffix);
                    242: 
                    243:    /* Normalize the suffix */
                    244:    i = 0;
1.39      cvs       245:    while (suffix[i] != EOS && i < MAX_LENGTH -1)
1.13      cvs       246:      {
1.25      cvs       247:        nsuffix[i] = tolower (suffix[i]);
1.13      cvs       248:        i++;
                    249:      }
1.5       cvs       250:    nsuffix[i] = EOS;
1.60      cvs       251:    if (!strcmp (nsuffix, "html") ||
                    252:        !strcmp (nsuffix, "htm") ||
1.62    ! cvs       253:        !strcmp (nsuffix, "xhtl") ||
1.60      cvs       254:        !strcmp (nsuffix, "shtml"))
1.39      cvs       255:      return (TRUE);
1.22      cvs       256:    else if (!strcmp (nsuffix, "gz"))
1.13      cvs       257:      {
1.39      cvs       258:        /* take into account compressed files */
1.13      cvs       259:        ExtractSuffix (temppath, suffix);       
                    260:        /* Normalize the suffix */
                    261:        i = 0;
1.39      cvs       262:        while (suffix[i] != EOS && i < MAX_LENGTH -1)
1.13      cvs       263:         {
1.25      cvs       264:           nsuffix[i] = tolower (suffix[i]);
1.13      cvs       265:           i++;
                    266:         }
                    267:        nsuffix[i] = EOS;
1.60      cvs       268:        if (!strcmp (nsuffix, "html") ||
                    269:           !strcmp (nsuffix, "htm") ||
1.62    ! cvs       270:           !strcmp (nsuffix, "xhtl") ||
1.60      cvs       271:           !strcmp (nsuffix, "shtml"))
1.39      cvs       272:         return (TRUE);
                    273:        else
1.13      cvs       274:         return (FALSE);
                    275:      }
                    276:    else
1.39      cvs       277:      return (FALSE);
1.3       cvs       278: }
                    279: 
1.4       cvs       280: /*----------------------------------------------------------------------
1.56      cvs       281:   IsXMLName                                                         
                    282:   returns TRUE if path points to an XML resource.
                    283:   ----------------------------------------------------------------------*/
                    284: #ifdef __STDC__
                    285: boolean             IsXMLName (const char *path)
                    286: #else  /* __STDC__ */
                    287: boolean             IsXMLName (path)
                    288: const char         *path;
                    289: #endif /* __STDC__ */
                    290: {
                    291:    char                temppath[MAX_LENGTH];
                    292:    char                suffix[MAX_LENGTH];
                    293: 
                    294:    if (!path)
                    295:       return (FALSE);
                    296: 
                    297:    strcpy (temppath, path);
                    298:    ExtractSuffix (temppath, suffix);
                    299: 
                    300:    if (!strcasecmp (suffix, "xml"))
                    301:      return (TRUE);
                    302:    else if (!strcmp (suffix, "gz"))
                    303:      {
                    304:        /* take into account compressed files */
                    305:        ExtractSuffix (temppath, suffix);       
                    306:        if (!strcasecmp (suffix, "xml"))
1.60      cvs       307:         return (TRUE);
                    308:        else
                    309:         return (FALSE);
                    310:      }
                    311:    else
                    312:      return (FALSE);
                    313: }
                    314: 
                    315: /*----------------------------------------------------------------------
                    316:   IsCSSName                                                         
                    317:   returns TRUE if path points to an XML resource.
                    318:   ----------------------------------------------------------------------*/
                    319: #ifdef __STDC__
                    320: boolean             IsCSSName (const char *path)
                    321: #else  /* __STDC__ */
                    322: boolean             IsCSSName (path)
                    323: const char         *path;
                    324: #endif /* __STDC__ */
                    325: {
                    326:    char                temppath[MAX_LENGTH];
                    327:    char                suffix[MAX_LENGTH];
                    328: 
                    329:    if (!path)
                    330:       return (FALSE);
                    331: 
                    332:    strcpy (temppath, path);
                    333:    ExtractSuffix (temppath, suffix);
                    334: 
                    335:    if (!strcasecmp (suffix, "css"))
                    336:      return (TRUE);
                    337:    else if (!strcmp (suffix, "gz"))
                    338:      {
                    339:        /* take into account compressed files */
                    340:        ExtractSuffix (temppath, suffix);       
                    341:        if (!strcasecmp (suffix, "css"))
1.56      cvs       342:         return (TRUE);
                    343:        else
                    344:         return (FALSE);
                    345:      }
                    346:    else
                    347:      return (FALSE);
                    348: }
                    349: 
                    350: /*----------------------------------------------------------------------
1.9       cvs       351:   IsImageName                                
                    352:   returns TRUE if path points to an image resource.
1.4       cvs       353:   ----------------------------------------------------------------------*/
1.3       cvs       354: #ifdef __STDC__
1.34      cvs       355: boolean             IsImageName (const char *path)
1.3       cvs       356: #else  /* __STDC__ */
                    357: boolean             IsImageName (path)
1.34      cvs       358: const char         *path;
1.3       cvs       359: #endif /* __STDC__ */
                    360: {
1.5       cvs       361:    char                temppath[MAX_LENGTH];
                    362:    char                suffix[MAX_LENGTH];
                    363:    char                nsuffix[MAX_LENGTH];
                    364:    int                 i;
                    365: 
                    366:    if (!path)
1.13      cvs       367:       return (FALSE);
1.5       cvs       368: 
                    369:    strcpy (temppath, path);
                    370:    ExtractSuffix (temppath, suffix);
                    371: 
                    372:    /* Normalize the suffix */
                    373:    i = 0;
1.39      cvs       374:    while (suffix[i] != EOS && i < MAX_LENGTH -1)
1.13      cvs       375:      {
1.25      cvs       376:        nsuffix[i] = tolower (suffix[i]);
1.13      cvs       377:        i++;
                    378:      }
1.5       cvs       379:    nsuffix[i] = EOS;
1.39      cvs       380:    if ((!strcmp (nsuffix, "gif")) || (!strcmp (nsuffix, "xbm")) ||
                    381:        (!strcmp (nsuffix, "xpm")) || (!strcmp (nsuffix, "jpg")) ||
                    382:        (!strcmp (nsuffix, "png")) || (!strcmp (nsuffix, "au")))
                    383:       return (TRUE);
                    384:    return (FALSE);
1.3       cvs       385: }
                    386: 
1.4       cvs       387: /*----------------------------------------------------------------------
1.58      cvs       388:   IsImageType                                
                    389:   returns TRUE if type points to an image resource.
                    390:   ----------------------------------------------------------------------*/
                    391: #ifdef __STDC__
                    392: boolean             IsImageType (const char *type)
                    393: #else  /* __STDC__ */
                    394: boolean             IsImageType (type)
                    395: const char         *type;
                    396: #endif /* __STDC__ */
                    397: {
                    398:    char                temptype[MAX_LENGTH];
                    399:    int                 i;
                    400: 
                    401:    if (!type)
                    402:       return (FALSE);
                    403: 
                    404:    strcpy (temptype, type);
                    405:    /* Normalize the type */
                    406:    i = 0;
                    407:    while (temptype[i] != EOS)
                    408:      {
                    409:        temptype[i] = tolower (temptype[i]);
                    410:        i++;
                    411:      }
                    412:    if ((!strcmp (temptype, "gif")) || (!strcmp (temptype, "x-xbitmap")) ||
                    413:        (!strcmp (temptype, "x-xpixmap")) || (!strcmp (temptype, "jpeg")) ||
                    414:        (!strcmp (temptype, "png")))
                    415:       return (TRUE);
                    416:    return (FALSE);
                    417: }
                    418: 
                    419: /*----------------------------------------------------------------------
1.9       cvs       420:   IsTextName                                                         
1.4       cvs       421:   ----------------------------------------------------------------------*/
1.3       cvs       422: #ifdef __STDC__
1.34      cvs       423: boolean             IsTextName (const char *path)
1.3       cvs       424: #else  /* __STDC__ */
                    425: boolean             IsTextName (path)
1.34      cvs       426: const char         *path;
1.3       cvs       427: 
                    428: #endif /* __STDC__ */
                    429: {
1.5       cvs       430:    char                temppath[MAX_LENGTH];
                    431:    char                suffix[MAX_LENGTH];
                    432:    char                nsuffix[MAX_LENGTH];
                    433:    int                 i;
                    434: 
                    435:    if (!path)
1.13      cvs       436:      return (FALSE);
1.5       cvs       437: 
                    438:    strcpy (temppath, path);
                    439:    ExtractSuffix (temppath, suffix);
                    440: 
                    441:    /* Normalize the suffix */
                    442:    i = 0;
1.39      cvs       443:    while (suffix[i] != EOS && i < MAX_LENGTH -1)
1.5       cvs       444:      {
1.25      cvs       445:        nsuffix[i] = tolower (suffix[i]);
1.5       cvs       446:        i++;
                    447:      }
                    448:    nsuffix[i] = EOS;
                    449: 
1.39      cvs       450:    if ((!strcmp (nsuffix, "txt")) || (!strcmp (nsuffix, "dtd")))
1.13      cvs       451:       return (TRUE);
1.22      cvs       452:    else if (!strcmp (nsuffix, "gz"))
1.13      cvs       453:      {
1.39      cvs       454:        /* take into account compressed files */
1.13      cvs       455:        ExtractSuffix (temppath, suffix);       
                    456:        /* Normalize the suffix */
                    457:        i = 0;
1.39      cvs       458:        while (suffix[i] != EOS && i < MAX_LENGTH -1)
1.13      cvs       459:         {
1.25      cvs       460:           nsuffix[i] = tolower (suffix[i]);
1.13      cvs       461:           i++;
                    462:         }
                    463:        nsuffix[i] = EOS;
1.39      cvs       464:        if ((!strcmp (nsuffix, "txt")) || (!strcmp (nsuffix, "dtd")))
1.13      cvs       465:         return (TRUE);
                    466:        else
                    467:         return (FALSE);
                    468:      }
                    469:    else
                    470:      return (FALSE);
1.3       cvs       471: }
                    472: 
1.4       cvs       473: /*----------------------------------------------------------------------
1.9       cvs       474:   IsHTTPPath                                     
                    475:   returns TRUE if path is in fact an http URL.
1.4       cvs       476:   ----------------------------------------------------------------------*/
1.3       cvs       477: #ifdef __STDC__
1.34      cvs       478: boolean             IsHTTPPath (const char *path)
1.3       cvs       479: #else  /* __STDC__ */
                    480: boolean             IsHTTPPath (path)
1.34      cvs       481: const char         *path;
1.3       cvs       482: #endif /* __STDC__ */
                    483: {
1.5       cvs       484:    if (!path)
                    485:       return FALSE;
1.3       cvs       486: 
1.58      cvs       487:    if ((!strncmp (path, "http:", 5) != 0)
                    488:        || !strncmp (path, "internal:", 9))
                    489:       return TRUE;
                    490:    return FALSE;
1.3       cvs       491: }
                    492: 
1.4       cvs       493: /*----------------------------------------------------------------------
1.9       cvs       494:   IsWithParameters                           
                    495:   returns TRUE if url has a concatenated query string.
1.4       cvs       496:   ----------------------------------------------------------------------*/
1.3       cvs       497: #ifdef __STDC__
1.34      cvs       498: boolean             IsWithParameters (const char *url)
1.3       cvs       499: #else  /* __STDC__ */
1.9       cvs       500: boolean             IsWithParameters (url)
1.34      cvs       501: const char         *url;
1.3       cvs       502: #endif /* __STDC__ */
                    503: {
1.5       cvs       504:    int                 i;
1.3       cvs       505: 
1.9       cvs       506:    if ((!url) || (url[0] == EOS))
1.5       cvs       507:       return FALSE;
1.3       cvs       508: 
1.9       cvs       509:    i = strlen (url) - 1;
                    510:    while (i > 0 && url[i--] != '?')
1.5       cvs       511:       if (i < 0)
                    512:         return FALSE;
1.3       cvs       513: 
1.5       cvs       514:    /* There is a parameter */
                    515:    return TRUE;
1.3       cvs       516: }
                    517: 
1.4       cvs       518: /*----------------------------------------------------------------------
1.9       cvs       519:   IsW3Path                                           
                    520:   returns TRUE if path is in fact a URL.
1.4       cvs       521:   ----------------------------------------------------------------------*/
1.3       cvs       522: #ifdef __STDC__
1.34      cvs       523: boolean             IsW3Path (const char *path)
1.3       cvs       524: #else  /* __STDC__ */
                    525: boolean             IsW3Path (path)
1.34      cvs       526: const char               *path;
1.3       cvs       527: #endif /* __STDC__ */
                    528: {
1.5       cvs       529:    if ((strncmp (path, "http:", 5)) && (strncmp (path, "ftp:", 4)) &&
                    530:        (strncmp (path, "telnet:", 7)) && (strncmp (path, "wais:", 5)) &&
                    531:        (strncmp (path, "news:", 5)) && (strncmp (path, "gopher:", 7)) &&
                    532:        (strncmp (path, "mailto:", 7)) && (strncmp (path, "archie:", 7)))
                    533:       return FALSE;
                    534:    return TRUE;
1.3       cvs       535: }
                    536: 
1.4       cvs       537: /*----------------------------------------------------------------------
1.9       cvs       538:   IsValidProtocol                                                    
                    539:   returns true if the url protocol is supported by Amaya.
1.4       cvs       540:   ----------------------------------------------------------------------*/
1.3       cvs       541: #ifdef __STDC__
1.34      cvs       542: boolean             IsValidProtocol (const char *url)
1.3       cvs       543: #else  /* __STDC__ */
1.9       cvs       544: boolean             IsValidProtocol (url)
1.34      cvs       545: const char         *url;
1.3       cvs       546: #endif /* __STDC__ */
                    547: {
1.58      cvs       548:    if (!strncmp (url, "http:", 5)
                    549:       || !strncmp (url, "internal:", 9))
1.22      cvs       550:        /* experimental */
1.58      cvs       551:       /***  || !strncmp (url, "ftp:", 4) ***/
1.24      cvs       552:      /*** || !strncmp (path, "news:", 5)***/ 
1.8       cvs       553:       return (TRUE);
1.5       cvs       554:    else
1.8       cvs       555:       return (FALSE);
1.3       cvs       556: }
                    557: 
1.31      cvs       558: 
                    559: /*----------------------------------------------------------------------
                    560:    GetBaseURL
                    561:    normalizes orgName according to a base associated with doc, and
                    562:    following the standard URL format rules.
                    563:    The function returns the base used to solve relative URL and SRC:
                    564:       - the base of the document,
                    565:       - or the document path (without document name).
                    566:   ----------------------------------------------------------------------*/
                    567: #ifdef __STDC__
                    568: char               *GetBaseURL (Document doc)
                    569: #else  /* __STDC__ */
                    570: char               *GetBaseURL (doc)
                    571: Document            doc;
                    572: #endif /* __STDC__ */
                    573: {
                    574:   Element             el;
                    575:   ElementType         elType;
                    576:   AttributeType       attrType;
                    577:   Attribute           attr;
                    578:   char               *ptr, *basename;
                    579:   int                 length;
                    580: 
1.57      cvs       581:   /* @@@ irene */
                    582:   if (!DocumentURLs[doc])
                    583:          return NULL;
1.31      cvs       584:   basename = TtaGetMemory (MAX_LENGTH);
1.39      cvs       585:   strncpy (basename, DocumentURLs[doc], MAX_LENGTH-1);
                    586:   basename[MAX_LENGTH-1] = EOS;
1.31      cvs       587:   length = MAX_LENGTH -1;
                    588:   /* get the root element    */
                    589:   el = TtaGetMainRoot (doc);
                    590:   /* search the BASE element */
                    591:   elType.ElSSchema = TtaGetDocumentSSchema (doc);
                    592:   elType.ElTypeNum = HTML_EL_BASE;
                    593:   el = TtaSearchTypedElement (elType, SearchInTree, el);
                    594:   if (el)
                    595:     {
                    596:       /*  The document has a BASE element -> Get the HREF attribute */
                    597:       attrType.AttrSSchema = elType.ElSSchema;
                    598:       attrType.AttrTypeNum = HTML_ATTR_HREF_;
                    599:       attr = TtaGetAttribute (el, attrType);
                    600:       if (attr)
                    601:        {
                    602:          /* Use the base path of the document */
                    603:          TtaGiveTextAttributeValue (attr, basename, &length);
                    604:          /* base and orgName have to be separated by a DIR_SEP */
                    605:          length--;
1.43      cvs       606:          if (basename[0] != EOS && basename[length] != URL_SEP && basename[length] != DIR_SEP) 
1.31      cvs       607:            /* verify if the base has the form "protocol://server:port" */
                    608:            {
1.33      cvs       609:              ptr = AmayaParseUrl (basename, "", AMAYA_PARSE_ACCESS |
                    610:                                                 AMAYA_PARSE_HOST |
                    611:                                                 AMAYA_PARSE_PUNCTUATION);
1.31      cvs       612:              if (ptr && !strcmp (ptr, basename))
                    613:                {
1.43      cvs       614:                  /* it has this form, we complete it by adding a URL_STR  */
                    615:                  if (strchr (basename, DIR_SEP))
                    616:                    strcat (basename, DIR_STR);
                    617:                  else
                    618:                    strcat (basename, URL_STR);
1.31      cvs       619:                  length++;
                    620:                }
                    621:              if (ptr)
                    622:                TtaFreeMemory (ptr);
                    623:            }
                    624:        }
1.33      cvs       625:       }
                    626:   
1.31      cvs       627:   /* Remove anything after the last DIR_SEP char. If no such char is found,
                    628:    * then search for the first ":" char, hoping that what's before that is a
                    629:    * protocol. If found, end the string there. If neither char is found,
                    630:    * then discard the whole base element.
                    631:    */
                    632:   length = strlen (basename) - 1;
                    633:   /* search for the last DIR_SEP char */
1.43      cvs       634:   while (length >= 0  && basename[length] != URL_SEP && basename[length] != DIR_SEP)
1.31      cvs       635:     length--;
                    636:   if (length >= 0)
                    637:     /* found the last DIR_SEP char, end the string there */
                    638:     basename[length + 1] = EOS;                   
                    639:   else
                    640:     /* search for the first PATH_STR char */
                    641:     {
1.32      cvs       642:       for (length = 0; basename[length] != ':' && 
1.31      cvs       643:             basename[length] != EOS; length ++);
1.32      cvs       644:       if (basename[length] == ':')
1.31      cvs       645:        /* found, so end the string there */
                    646:        basename[length + 1] = EOS;
                    647:       else
                    648:        /* not found, discard the base */
                    649:        basename[0] = EOS;
                    650:     }
                    651:   return (basename);
                    652: }
                    653: 
                    654: 
1.4       cvs       655: /*----------------------------------------------------------------------
1.40      cvs       656:    GetLocalPath
                    657:    Allocate and return the local document path associated to the url
                    658:   ----------------------------------------------------------------------*/
                    659: #ifdef __STDC__
                    660: char      *GetLocalPath (Document doc, char *url)
                    661: #else  /* __STDC__ */
                    662: char      *GetLocalPath (doc, url)
                    663: Document   doc;
                    664: char      *url;
                    665: #endif /* __STDC__ */
                    666: {
1.46      cvs       667:   char    *ptr, *n;
1.40      cvs       668:   char    *documentname;
1.41      cvs       669:   char     url_sep;
1.40      cvs       670:   int      len;
                    671:   boolean  noFile;
                    672: 
                    673:   if (url != NULL)
                    674:     {
                    675:       /* check whether the file name exists */
                    676:       len = strlen (url) - 1;
1.41      cvs       677:       if (IsW3Path)
                    678:        url_sep = '/';
                    679:       else 
                    680:        url_sep = DIR_SEP;
                    681:       noFile = (url[len] == url_sep);
1.40      cvs       682:       if (noFile)
                    683:        url[len] = EOS;
1.47      cvs       684:       ptr = TtaGetMemory (MAX_LENGTH);
                    685:       documentname = TtaGetMemory (MAX_LENGTH);
1.40      cvs       686:       TtaExtractName (url, ptr, documentname);
                    687:       sprintf (ptr, "%s%s%d%s", TempFileDirectory, DIR_STR, doc, DIR_STR);
                    688:       if (!TtaCheckDirectory (ptr))
                    689:        /* directory did not exist */
1.59      cvs       690: #   ifdef _WINDOWS
                    691:        _mkdir (ptr);
                    692: #   else  /* !_WINDOWS */
1.40      cvs       693:        mkdir (ptr, S_IRWXU);
1.59      cvs       694: #   endif /* !_WINDOWS */
1.47      cvs       695: 
                    696:       /* don't include the query string within document name */
                    697:       n = strrchr(documentname, '?');
                    698:       if (n != NULL)
                    699:        *n = EOS;
1.46      cvs       700:       /* don't include ':' within document name */
                    701:       n = strchr (documentname, ':');
                    702:       if (n != NULL)
                    703:        *n = EOS;
1.40      cvs       704:       strcat (ptr, documentname);
                    705:       TtaFreeMemory (documentname);
                    706:       /* restore the url */
                    707:       if (noFile)
1.41      cvs       708:        url[len] = url_sep;
1.40      cvs       709:       return (ptr);
                    710:     }
                    711:   else
                    712:     return (NULL);
                    713: }
                    714: 
                    715: 
                    716: /*----------------------------------------------------------------------
1.9       cvs       717:    NormalizeURL
                    718:    normalizes orgName according to a base associated with doc, and
                    719:    following the standard URL format rules.
1.53      cvs       720:    if doc is 0 and otherPath not NULL, normalizes orgName according to this
                    721:    other path.
1.9       cvs       722:    The function returns the new complete and normalized URL 
1.12      cvs       723:    or file name path (newName) and the name of the document (docName).        
1.9       cvs       724:    N.B. If the function can't find out what's the docName, it assigns
                    725:    the name "noname.html".
1.4       cvs       726:   ----------------------------------------------------------------------*/
1.3       cvs       727: #ifdef __STDC__
1.53      cvs       728: void                NormalizeURL (char *orgName, Document doc, char *newName, char *docName, char *otherPath)
1.3       cvs       729: #else  /* __STDC__ */
1.53      cvs       730: void                NormalizeURL (orgName, doc, newName, docName, otherPath)
1.3       cvs       731: char               *orgName;
                    732: Document            doc;
                    733: char               *newName;
                    734: char               *docName;
1.53      cvs       735: char               *otherPath;
1.3       cvs       736: #endif /* __STDC__ */
                    737: {
1.31      cvs       738:    char               *basename;
1.18      cvs       739:    char                tempOrgName[MAX_LENGTH];
1.5       cvs       740:    char               *ptr;
1.49      cvs       741:    char                used_sep;
1.5       cvs       742:    int                 length;
1.49      cvs       743:    boolean             check;
1.5       cvs       744: 
1.44      cvs       745: #  ifdef _WINDOWS
                    746:    int ndx;
                    747: #  endif /* _WINDOWS */
                    748: 
1.5       cvs       749:    if (!newName || !docName)
                    750:       return;
1.18      cvs       751: 
1.32      cvs       752:    if (doc != 0)
1.53      cvs       753:      basename = GetBaseURL (doc);
                    754:    else if (otherPath != NULL)
                    755:      basename = TtaStrdup (otherPath);
1.32      cvs       756:    else
1.53      cvs       757:      basename = NULL;
1.32      cvs       758: 
1.18      cvs       759:    /*
1.31      cvs       760:     * Clean orgName
                    761:     * Make sure we have a complete orgName, without any leading or trailing
                    762:     * white spaces, or trailinbg new lines
                    763:     */
1.5       cvs       764:    ptr = orgName;
1.18      cvs       765:    /* skip leading white space and new line characters */
1.19      cvs       766:    while ((*ptr == ' ' || *ptr == EOL) && *ptr++ != EOS);
1.39      cvs       767:    strncpy (tempOrgName, ptr, MAX_LENGTH -1);
                    768:    tempOrgName[MAX_LENGTH -1] = EOS;
1.18      cvs       769:    /*
1.31      cvs       770:     * Make orgName a complete URL
                    771:     * If the URL does not include a protocol, then try to calculate
                    772:     * one using the doc's base element (if it exists),
                    773:     */
1.53      cvs       774:    if (tempOrgName[0] == EOS)
                    775:      {
                    776:        newName[0] = EOS;
                    777:        TtaFreeMemory (basename);
                    778:        return;
                    779:      }
1.49      cvs       780: 
                    781:    /* clean trailing white space */
                    782:    length = strlen (tempOrgName) - 1;
1.53      cvs       783:    while (tempOrgName[length] == SPACE && tempOrgName[length] == EOL)
                    784:      {
                    785:        tempOrgName[length] = EOS;
                    786:        length--;
                    787:      }
1.50      cvs       788: 
1.55      cvs       789:    /* remove extra dot (which dot???) */
                    790:    /* ugly, but faster than a strcmp */
                    791:    if (tempOrgName[length] == '.'
                    792:        && (length == 0 || tempOrgName[length-1] != '.'))
                    793:         tempOrgName[length] = EOS;
1.50      cvs       794: 
1.53      cvs       795:    if (IsW3Path (tempOrgName))
                    796:      {
                    797:        /* the name is complete, go to the Sixth Step */
                    798:        strcpy (newName, tempOrgName);
                    799:        SimplifyUrl (&newName);
                    800:        /* verify if the URL has the form "protocol://server:port" */
                    801:        ptr = AmayaParseUrl (newName, "", AMAYA_PARSE_ACCESS | AMAYA_PARSE_HOST | AMAYA_PARSE_PUNCTUATION);
                    802:        if (ptr && !strcmp (ptr, newName)) /* it has this form, we complete it by adding a DIR_STR  */
1.50      cvs       803:          strcat (newName, URL_STR);
1.49      cvs       804: 
1.53      cvs       805:        if (ptr)
1.50      cvs       806:          TtaFreeMemory (ptr);
1.53      cvs       807:      }
                    808:    else if ( basename == NULL)
                    809:      /* the name is complete, go to the Sixth Step */
1.18      cvs       810:      strcpy (newName, tempOrgName);
1.53      cvs       811:    else
                    812:      {
1.31      cvs       813:        /* Calculate the absolute URL, using the base or document URL */
1.44      cvs       814: #      ifdef _WINDOWS
1.53      cvs       815:        if (!IsW3Path (basename))
                    816:         {
                    817:           length = strlen (tempOrgName);
                    818:           for (ndx = 0; ndx < length; ndx++)
                    819:             if (tempOrgName [ndx] == '/')
                    820:               tempOrgName [ndx] = '\\';
                    821:         }
1.44      cvs       822: #      endif /* _WINDOWS */
1.25      cvs       823:        ptr = AmayaParseUrl (tempOrgName, basename, AMAYA_PARSE_ALL);
1.53      cvs       824:        if (ptr)
                    825:         {
                    826:           SimplifyUrl (&ptr);
                    827:           strcpy (newName, ptr);
                    828:           TtaFreeMemory (ptr);
                    829:         }
                    830:        else
                    831:         newName[0] = EOS;
                    832:      }
1.36      cvs       833: 
                    834:    TtaFreeMemory (basename);
1.18      cvs       835:    /*
1.31      cvs       836:     * Prepare the docname that will refer to this ressource in the
                    837:     * .amaya directory. If the new URL finishes on DIR_SEP, then use
                    838:     * noname.html as a default ressource name
1.18      cvs       839:    */
1.53      cvs       840:    if (newName[0] != EOS)
                    841:      {
                    842:        length = strlen (newName) - 1;
                    843:        if (newName[length] == URL_SEP || newName[length] == DIR_SEP)
                    844:         {
                    845:           used_sep = newName[length];
                    846:           check = TRUE;
                    847:           while (check)
                    848:             {
1.50      cvs       849:                length--;
                    850:                while (length >= 0 && newName[length] != used_sep)
1.53      cvs       851:                 length--;
                    852:                if (!strncmp (&newName[length+1], "..", 2))
                    853:                 {
                    854:                   newName[length+1] = EOS;
                    855:                   /* remove also previous directory */
                    856:                   length--;
                    857:                   while (length >= 0 && newName[length] != used_sep)
                    858:                     length--;
                    859:                   if (strncmp (&newName[length+1], "//", 2))
                    860:                     /* don't remove server name */
1.50      cvs       861:                      newName[length+1] = EOS;
1.53      cvs       862:                 }
                    863:               else if (!strncmp (&newName[length+1], ".", 1))
                    864:                 newName[length+1] = EOS;
1.50      cvs       865:                else
1.53      cvs       866:                 check = FALSE;
                    867:             }
                    868:           strcpy (docName, "noname.html");            
                    869:           /* docname was not comprised inside the URL, so let's */
                    870:           /* assign the default ressource name */
                    871:           strcpy (docName, "noname.html");
                    872:         }
                    873:        else
                    874:         { /* docname is comprised inside the URL */
1.50      cvs       875:            while (length >= 0 && newName[length] != URL_SEP && newName[length] != DIR_SEP)
1.53      cvs       876:             length--;
                    877:           if (length < 0)
1.50      cvs       878:              strcpy (docName, newName);
1.53      cvs       879:           else
                    880:             strcpy (docName, &newName[length+1]);
                    881:         }
                    882:      }
                    883:    else
                    884:      docName[0] = EOS;
1.18      cvs       885: } 
1.3       cvs       886: 
1.4       cvs       887: /*----------------------------------------------------------------------
1.9       cvs       888:   IsSameHost                                                         
1.4       cvs       889:   ----------------------------------------------------------------------*/
1.3       cvs       890: #ifdef __STDC__
1.34      cvs       891: boolean             IsSameHost (const char *url1, const char *url2)
1.3       cvs       892: #else  /* __STDC__ */
                    893: boolean             IsSameHost (url1, url2)
1.34      cvs       894: const char         *url1;
                    895: const char         *url2;
1.3       cvs       896: #endif /* __STDC__ */
                    897: {
1.34      cvs       898:    char            *basename_ptr1, *basename_ptr2;
                    899:    boolean          result;
1.3       cvs       900: 
1.25      cvs       901:    basename_ptr1 = AmayaParseUrl (url1, "", AMAYA_PARSE_ACCESS | AMAYA_PARSE_HOST | AMAYA_PARSE_PUNCTUATION);
                    902:    basename_ptr2 = AmayaParseUrl (url2, "", AMAYA_PARSE_ACCESS | AMAYA_PARSE_HOST | AMAYA_PARSE_PUNCTUATION);
1.3       cvs       903: 
1.5       cvs       904:    if (strcmp (basename_ptr1, basename_ptr2))
1.8       cvs       905:       result = FALSE;
1.5       cvs       906:    else
1.8       cvs       907:       result = TRUE;
1.3       cvs       908: 
1.25      cvs       909:    TtaFreeMemory (basename_ptr1);
                    910:    TtaFreeMemory (basename_ptr2);
1.5       cvs       911:    return (result);
1.3       cvs       912: }
                    913: 
                    914: 
1.4       cvs       915: /*----------------------------------------------------------------------
1.22      cvs       916:   HasKnownFileSuffix
                    917:   returns TRUE if path points to a file ending with a suffix.
                    918:   ----------------------------------------------------------------------*/
                    919: #ifdef __STDC__
1.34      cvs       920: boolean             HasKnownFileSuffix (const char *path)
1.22      cvs       921: #else  /* __STDC__ */
                    922: boolean             HasKnownFileSuffix (path)
1.34      cvs       923: const char         *path;
1.22      cvs       924: #endif /* __STDC__ */
                    925: {
1.29      cvs       926:    char            *root;
                    927:    char             temppath[MAX_LENGTH];
                    928:    char             suffix[MAX_LENGTH];
1.22      cvs       929: 
1.24      cvs       930:    if (!path || path[0] == EOS || path[strlen(path)] == DIR_SEP)
1.22      cvs       931:      return (FALSE);
                    932: 
1.29      cvs       933:    root = AmayaParseUrl(path, "", AMAYA_PARSE_PATH | AMAYA_PARSE_PUNCTUATION);
1.22      cvs       934: 
                    935:    if (root) 
                    936:      {
                    937:        strcpy (temppath, root);
1.25      cvs       938:        TtaFreeMemory (root);
1.22      cvs       939:        /* Get the suffix */
                    940:        ExtractSuffix (temppath, suffix); 
                    941: 
                    942:        if( suffix[0] == EOS)
                    943:         /* no suffix */
                    944:         return (FALSE);
                    945: 
                    946:        /* Normalize the suffix */
                    947:        ConvertToLowerCase (suffix);
                    948: 
1.23      cvs       949:        if (!strcmp (suffix, "gz"))
1.22      cvs       950:         /* skip the compressed suffix */
                    951:         {
                    952:         ExtractSuffix (temppath, suffix);
                    953:         if(suffix[0] == EOS)
                    954:           /* no suffix */
                    955:           return (FALSE);
                    956:          /* Normalize the suffix */
                    957:          ConvertToLowerCase (suffix);
                    958:         }
                    959: 
                    960:        if ((strcmp (suffix, "gif")) && (strcmp (suffix, "xbm")) &&
                    961:           (strcmp (suffix, "xpm")) && (strcmp (suffix, "jpg")) &&
                    962:           (strcmp (suffix, "pdf")) && (strcmp (suffix, "png")) &&
                    963:           (strcmp (suffix, "tgz")) && (strcmp (suffix, "xpg")) &&
                    964:           (strcmp (suffix, "xpd")) && (strcmp (suffix, "ps")) &&
                    965:           (strcmp (suffix, "au"))  && (strcmp (suffix, "html")) &&
                    966:           (strcmp (suffix, "htm")) && (strcmp (suffix, "shtml")) &&
                    967:           (strcmp (suffix, "txt")) && (strcmp (suffix, "css")) &&
                    968:           (strcmp (suffix, "eps")))
                    969:         return (FALSE);
                    970:        else
                    971:         return (TRUE);
                    972:      }
                    973:    else
                    974:      return (FALSE);
                    975: }
                    976: 
                    977: 
                    978: /*----------------------------------------------------------------------
1.24      cvs       979:   ChopURL
                    980:   Gives back a URL no longer than MAX_PRINT_URL_LENGTH chars (outputURL). 
                    981:   If inputURL is  bigger than that size, outputURL receives
                    982:   MAX_PRINT_URL_LENGTH / 2 chars from the beginning of inputURL, "...", 
                    983:   and MAX_PRINT_URL_LENGTH / 2 chars from the end of inputURL.
                    984:   If inputURL is not longer than MAX_PRINT_URL_LENGTH chars, it gets
                    985:   copied into outputURL. 
                    986:   N.B.: outputURL must point to a memory block of MAX_PRINT_URL_LENGTH
                    987:   chars.
                    988:   ----------------------------------------------------------------------*/
                    989: #ifdef __STDC__
1.34      cvs       990: void ChopURL (char *outputURL, const char *inputURL)
1.24      cvs       991: #else
                    992: void ChopURL (outputURL, inputURL)
1.34      cvs       993: char       *outputURL;
                    994: const char *inputURL;
1.24      cvs       995: #endif
1.22      cvs       996: 
1.24      cvs       997: {
                    998:   int len;
1.9       cvs       999: 
1.24      cvs      1000:   len = strlen (inputURL);
                   1001:   if (len <= MAX_PRINT_URL_LENGTH) 
1.29      cvs      1002:     strcpy (outputURL, inputURL);
1.24      cvs      1003:   else
                   1004:     /* make a truncated urlName on the status window */
                   1005:     {
                   1006:       strncpy (outputURL, inputURL, MAX_PRINT_URL_LENGTH / 2);
                   1007:       outputURL [MAX_PRINT_URL_LENGTH / 2] = EOS;
                   1008:       strcat (outputURL, "...");
                   1009:       strcat (outputURL, &(inputURL[len - MAX_PRINT_URL_LENGTH / 2 ]));
                   1010:     }
1.25      cvs      1011: }
                   1012: 
                   1013: 
                   1014: /*----------------------------------------------------------------------
                   1015:    scan
1.47      cvs      1016:        Scan a filename for its constituents
1.25      cvs      1017:        -----------------------------------
                   1018:   
                   1019:    On entry,
                   1020:        name    points to a document name which may be incomplete.
                   1021:    On exit,
                   1022:         absolute or relative may be nonzero (but not both).
                   1023:        host, fragment and access may be nonzero if they were specified.
                   1024:        Any which are nonzero point to zero terminated strings.
                   1025:   ----------------------------------------------------------------------*/
                   1026: #ifdef __STDC__
                   1027: static void scan (char * name, HTURI * parts)
                   1028: #else  /* __STDC__ */
                   1029: static void scan (name, parts)
                   1030: char                *name;
                   1031: HTURI               *parts;
                   1032: 
                   1033: #endif /* __STDC__ */
                   1034: {
1.43      cvs      1035:   char      *p;
                   1036:   char      *after_access = name;
1.32      cvs      1037: 
1.43      cvs      1038:   memset (parts, '\0', sizeof (HTURI));
1.28      cvs      1039:   /* Look for fragment identifier */
1.52      cvs      1040:   if ((p = strchr(name, '#')) != NULL)
1.28      cvs      1041:     {
                   1042:       *p++ = '\0';
                   1043:       parts->fragment = p;
1.25      cvs      1044:     }
                   1045:     
1.28      cvs      1046:   for (p=name; *p; p++)
                   1047:     {
1.43      cvs      1048:       if (*p == URL_SEP || *p == DIR_SEP || *p=='#' || *p=='?')
1.28      cvs      1049:        break;
1.32      cvs      1050:       if (*p==':')
1.28      cvs      1051:        {
                   1052:          *p = 0;
                   1053:          parts->access = after_access; /* Scheme has been specified */
                   1054: 
                   1055:          /* The combination of gcc, the "-O" flag and the HP platform is
                   1056:             unhealthy. The following three lines is a quick & dirty fix, but is
                   1057:             not recommended. Rather, turn off "-O". */
                   1058: 
                   1059:          /*            after_access = p;*/
                   1060:          /*            while (*after_access == 0)*/
                   1061:          /*                after_access++;*/
                   1062:          after_access = p+1;
1.43      cvs      1063:          if (!strcasecmp("URL", parts->access))
1.28      cvs      1064:            /* Ignore IETF's URL: pre-prefix */
                   1065:            parts->access = NULL;
                   1066:          else
1.25      cvs      1067:            break;
                   1068:        }
                   1069:     }
                   1070:     
                   1071:     p = after_access;
1.43      cvs      1072:     if (*p == URL_SEP || *p == DIR_SEP)
1.28      cvs      1073:       {
1.43      cvs      1074:        if (p[1] == URL_SEP)
1.28      cvs      1075:          {
1.25      cvs      1076:            parts->host = p+2;          /* host has been specified      */
1.28      cvs      1077:            *p = 0;                     /* Terminate access             */
                   1078:            /* look for end of host name if any */
1.43      cvs      1079:            p = strchr (parts->host, URL_SEP);
1.28      cvs      1080:            if (p)
                   1081:              {
1.43      cvs      1082:                *p = EOS;                       /* Terminate host */
1.25      cvs      1083:                parts->absolute = p+1;          /* Root has been found */
1.28      cvs      1084:              }
                   1085:          }
                   1086:        else
                   1087:          /* Root found but no host */
                   1088:          parts->absolute = p+1;
                   1089:       }
                   1090:     else
                   1091:       {
1.25      cvs      1092:         parts->relative = (*after_access) ? after_access : 0; /* zero for "" */
1.28      cvs      1093:       }
1.25      cvs      1094: }
                   1095: 
                   1096: 
                   1097: /*----------------------------------------------------------------------
1.28      cvs      1098:   AmayaParseUrl: parse a Name relative to another name
                   1099: 
                   1100:   This returns those parts of a name which are given (and requested)
                   1101:   substituting bits from the related name where necessary.
1.25      cvs      1102:   
1.28      cvs      1103:   On entry,
1.25      cvs      1104:        aName           A filename given
                   1105:         relatedName     A name relative to which aName is to be parsed. Give
                   1106:                         it an empty string if aName is absolute.
                   1107:         wanted          A mask for the bits which are wanted.
                   1108:   
1.28      cvs      1109:   On exit,
1.25      cvs      1110:        returns         A pointer to a malloc'd string which MUST BE FREED
                   1111:   ----------------------------------------------------------------------*/
                   1112: #ifdef __STDC__
1.34      cvs      1113: char          *AmayaParseUrl (const char *aName, char *relatedName, int wanted)
1.25      cvs      1114: #else  /* __STDC__ */
1.28      cvs      1115: char          *AmayaParseUrl (aName, relatedName, wanted)
1.34      cvs      1116: const char    *aName;
1.28      cvs      1117: char          *relatedName;
                   1118: int            wanted;
1.25      cvs      1119: 
                   1120: #endif /* __STDC__ */
                   1121: {
1.29      cvs      1122:   char      *return_value;
                   1123:   char       result[MAX_LENGTH];
                   1124:   char       name[MAX_LENGTH];
                   1125:   char       rel[MAX_LENGTH];
                   1126:   char      *p, *access;
                   1127:   HTURI      given, related;
                   1128:   int        len;
1.33      cvs      1129:   char       used_sep;
                   1130:   char      *used_str;
1.32      cvs      1131: 
1.43      cvs      1132:   if (strchr (aName, DIR_SEP) || strchr (relatedName, DIR_SEP))
1.33      cvs      1133:     {
1.42      cvs      1134:       used_str = DIR_STR;
                   1135:       used_sep = DIR_SEP;
1.33      cvs      1136:     }
1.32      cvs      1137:   else
1.33      cvs      1138:     {
1.42      cvs      1139:       used_str = URL_STR;
                   1140:       used_sep = URL_SEP;
1.33      cvs      1141:     }
1.32      cvs      1142: 
1.29      cvs      1143:   /* Make working copies of input strings to cut up: */
                   1144:   return_value = NULL;
                   1145:   result[0] = 0;               /* Clear string  */
                   1146:   strcpy (name, aName);
                   1147:   if (relatedName != NULL)  
                   1148:     strcpy (rel, relatedName);
                   1149:   else
                   1150:     relatedName[0] = EOS;
                   1151:   
                   1152:   scan (name, &given);
                   1153:   scan (rel,  &related); 
                   1154:   access = given.access ? given.access : related.access;
                   1155:   if (wanted & AMAYA_PARSE_ACCESS)
                   1156:     if (access)
                   1157:       {
                   1158:        strcat (result, access);
                   1159:        if(wanted & AMAYA_PARSE_PUNCTUATION)
1.32      cvs      1160:                strcat (result, ":");
1.29      cvs      1161:       }
                   1162:   
                   1163:   if (given.access && related.access)
                   1164:     /* If different, inherit nothing. */
                   1165:     if (strcmp (given.access, related.access) != 0)
                   1166:       {
                   1167:        related.host = 0;
                   1168:        related.absolute = 0;
                   1169:        related.relative = 0;
                   1170:        related.fragment = 0;
                   1171:       }
                   1172:   
                   1173:   if (wanted & AMAYA_PARSE_HOST)
                   1174:     if(given.host || related.host)
                   1175:       {
                   1176:        if(wanted & AMAYA_PARSE_PUNCTUATION)
                   1177:          strcat (result, "//");
                   1178:        strcat (result, given.host ? given.host : related.host);
                   1179:       }
                   1180:   
                   1181:   if (given.host && related.host)
                   1182:     /* If different hosts, inherit no path. */
                   1183:     if (strcmp(given.host, related.host) != 0)
                   1184:       {
                   1185:        related.absolute = 0;
                   1186:        related.relative = 0;
                   1187:        related.fragment = 0;
                   1188:       }
                   1189:   
                   1190:   if (wanted & AMAYA_PARSE_PATH)
                   1191:     {
                   1192:       if (given.absolute)
                   1193:        {
                   1194:          /* All is given */
                   1195:          if (wanted & AMAYA_PARSE_PUNCTUATION)
1.33      cvs      1196:            strcat (result, used_str);
1.29      cvs      1197:          strcat (result, given.absolute);
1.25      cvs      1198:        }
1.29      cvs      1199:       else if (related.absolute)
                   1200:        {
                   1201:          /* Adopt path not name */
1.33      cvs      1202:          strcat (result, used_str);
1.29      cvs      1203:          strcat (result, related.absolute);
                   1204:          if (given.relative)
                   1205:            {
                   1206:              /* Search part? */
                   1207:              p = strchr (result, '?');
                   1208:              if (!p)
                   1209:                p=result+strlen(result)-1;
1.33      cvs      1210:              for (; *p!=used_sep; p--);        /* last / */
1.29      cvs      1211:              /* Remove filename */
                   1212:              p[1]=0;
                   1213:              /* Add given one */
                   1214:              strcat (result, given.relative);
1.25      cvs      1215:            }
                   1216:        }
1.29      cvs      1217:       else if (given.relative)
                   1218:        /* what we've got */
                   1219:        strcat (result, given.relative);
                   1220:       else if (related.relative)
                   1221:        strcat (result, related.relative);
                   1222:       else
                   1223:        /* No inheritance */
1.33      cvs      1224:        strcat (result, used_str);
1.25      cvs      1225:     }
1.29      cvs      1226:   
                   1227:   if (wanted & AMAYA_PARSE_ANCHOR)
                   1228:     if (given.fragment || related.fragment)
                   1229:       {
                   1230:        if (given.absolute && given.fragment)
                   1231:          {
                   1232:            /*Fixes for relURLs...*/
                   1233:            if (wanted & AMAYA_PARSE_PUNCTUATION)
                   1234:              strcat (result, "#");
                   1235:            strcat (result, given.fragment); 
                   1236:          }
                   1237:        else if (!(given.absolute) && !(given.fragment))
                   1238:          strcat (result, "");
                   1239:        else
                   1240:          {
                   1241:            if (wanted & AMAYA_PARSE_PUNCTUATION)
                   1242:              strcat (result, "#");
                   1243:            strcat (result, given.fragment ? given.fragment : related.fragment); 
                   1244:          }
                   1245:       }
                   1246:   len = strlen (result);
                   1247:   if ((return_value = (char *) TtaGetMemory (len + 1)) != NULL)
                   1248:     strcpy (return_value, result);
                   1249:   return (return_value);               /* exactly the right length */
1.25      cvs      1250: }
                   1251: 
                   1252: /*----------------------------------------------------------------------
                   1253:      HTCanon
                   1254:        Canonicalizes the URL in the following manner starting from the host
                   1255:        pointer:
                   1256:   
                   1257:        1) The host name is converted to lowercase
                   1258:        2) Chop off port if `:80' (http), `:70' (gopher), or `:21' (ftp)
                   1259:   
                   1260:        Return: OK      The position of the current path part of the URL
                   1261:                        which might be the old one or a new one.
                   1262:   
                   1263:   ----------------------------------------------------------------------*/
                   1264: #ifdef __STDC__
1.28      cvs      1265: static char *HTCanon (char ** filename, char * host)
1.25      cvs      1266: #else  /* __STDC__ */
1.28      cvs      1267: static char *HTCanon (filename, host)
                   1268: char       **filename;
                   1269: char        *host;
1.25      cvs      1270: #endif /* __STDC__ */
                   1271: {
                   1272:     char *newname = NULL;
                   1273:     char *port;
                   1274:     char *strptr;
                   1275:     char *path;
                   1276:     char *access = host-3;
1.33      cvs      1277:     char       used_sep;
1.32      cvs      1278: 
                   1279:   
1.33      cvs      1280:      if (*filename && strchr (*filename, URL_SEP))
                   1281:        {
                   1282:         used_sep = URL_SEP;
                   1283:        }
                   1284:      else
                   1285:        {
                   1286:         used_sep = DIR_SEP;
                   1287:        }
1.32      cvs      1288:   
1.33      cvs      1289:     while (access>*filename && *(access-1)!= used_sep)       /* Find access method */
1.25      cvs      1290:        access--;
1.33      cvs      1291:     if ((path = strchr(host, used_sep)) == NULL)                       /* Find path */
1.25      cvs      1292:        path = host + strlen(host);
                   1293:     if ((strptr = strchr(host, '@')) != NULL && strptr<path)      /* UserId */
                   1294:        host = strptr;
1.32      cvs      1295:     if ((port = strchr(host, ':')) != NULL && port>path)      /* Port number */
1.25      cvs      1296:        port = NULL;
                   1297: 
                   1298:     strptr = host;                                 /* Convert to lower-case */
1.33      cvs      1299:     while (strptr<path)
                   1300:       {
1.25      cvs      1301:        *strptr = tolower(*strptr);
                   1302:        strptr++;
1.33      cvs      1303:       }
1.25      cvs      1304:     
                   1305:     /* Does the URL contain a full domain name? This also works for a
                   1306:        numerical host name. The domain name is already made lower-case
                   1307:        and without a trailing dot. */
                   1308:     {
1.33      cvs      1309:       char *dot = port ? port : path;
                   1310:       if (dot > *filename && *--dot=='.')
                   1311:        {
                   1312:          char *orig=dot, *dest=dot+1;
                   1313:          while((*orig++ = *dest++));
                   1314:          if (port) port--;
                   1315:          path--;
1.25      cvs      1316:        }
                   1317:     }
                   1318:     /* Chop off port if `:', `:80' (http), `:70' (gopher), or `:21' (ftp) */
1.33      cvs      1319:     if (port)
                   1320:       {
                   1321:        if (!*(port+1) || *(port+1)==used_sep)
                   1322:          {
                   1323:            if (!newname)
                   1324:              {
1.25      cvs      1325:                char *orig=port, *dest=port+1;
                   1326:                while((*orig++ = *dest++));
1.33      cvs      1327:              }
                   1328:          }
                   1329:        else if ((!strncmp(access, "http", 4) &&
                   1330:                  (*(port+1)=='8'&&*(port+2)=='0'&&(*(port+3)==used_sep||!*(port+3)))) ||
                   1331:                 (!strncmp(access, "gopher", 6) &&
                   1332:                  (*(port+1)=='7'&&*(port+2)=='0'&&(*(port+3)==used_sep||!*(port+3)))) ||
                   1333:                 (!strncmp(access, "ftp", 3) &&
                   1334:                  (*(port+1)=='2'&&*(port+2)=='1'&&(*(port+3)==used_sep||!*(port+3))))) {
                   1335:          if (!newname)
                   1336:            {
                   1337:              char *orig=port, *dest=port+3;
                   1338:              while((*orig++ = *dest++));
                   1339:              /* Update path position, Henry Minsky */
                   1340:              path -= 3;
1.25      cvs      1341:            }
1.33      cvs      1342:        }
                   1343:        else if (newname)
                   1344:          strncat(newname, port, (int) (path-port));
                   1345:       }
1.25      cvs      1346: 
1.33      cvs      1347:     if (newname)
                   1348:       {
1.25      cvs      1349:        char *newpath = newname+strlen(newname);
                   1350:        strcat(newname, path);
                   1351:        path = newpath;
1.28      cvs      1352:        /* Free old copy */
                   1353:        TtaFreeMemory(*filename);
1.25      cvs      1354:        *filename = newname;
1.33      cvs      1355:       }
1.25      cvs      1356:     return path;
                   1357: }
                   1358: 
                   1359: 
                   1360: /*----------------------------------------------------------------------
1.29      cvs      1361:   SimplifyUrl: simplify a URI
1.32      cvs      1362:   A URI is allowed to contain the sequence xxx/../ which may be
                   1363:   replaced by "" , and the sequence "/./" which may be replaced by DIR_STR.
1.28      cvs      1364:   Simplification helps us recognize duplicate URIs. 
1.25      cvs      1365:   
1.28      cvs      1366:   Thus,        /etc/junk/../fred       becomes /etc/fred
                   1367:                 /etc/junk/./fred       becomes /etc/junk/fred
1.25      cvs      1368:   
1.28      cvs      1369:   but we should NOT change
                   1370:                 http://fred.xxx.edu/../..
1.25      cvs      1371:   
                   1372:        or      ../../albert.html
                   1373:   
1.28      cvs      1374:   In order to avoid empty URLs the following URLs become:
1.25      cvs      1375:   
                   1376:                /fred/..                becomes /fred/..
                   1377:                /fred/././..            becomes /fred/..
                   1378:                /fred/.././junk/.././   becomes /fred/..
                   1379:   
1.28      cvs      1380:   If more than one set of `://' is found (several proxies in cascade) then
                   1381:   only the part after the last `://' is simplified.
1.25      cvs      1382:   
1.28      cvs      1383:   Returns: A string which might be the old one or a new one.
1.25      cvs      1384:   ----------------------------------------------------------------------*/
                   1385: #ifdef __STDC__
1.29      cvs      1386: void         SimplifyUrl (char ** url)
1.25      cvs      1387: #else  /* __STDC__ */
1.29      cvs      1388: void         SimplifyUrl (url)
1.28      cvs      1389: char        **url;
1.25      cvs      1390: #endif /* __STDC__ */
                   1391: {
1.28      cvs      1392:   char *path, *p;
                   1393:   char *newptr, *access;
                   1394:   char *orig, *dest, *end;
                   1395: 
1.33      cvs      1396:   char       used_sep;
1.32      cvs      1397: 
                   1398: 
1.28      cvs      1399:   if (!url || !*url)
                   1400:     return;
                   1401: 
1.33      cvs      1402:   if (strchr (*url, URL_SEP))
                   1403:     {
                   1404:       used_sep = URL_SEP;
                   1405:     }
1.32      cvs      1406:   else
1.33      cvs      1407:     {
                   1408:       used_sep = DIR_SEP;
                   1409:     }
1.32      cvs      1410: 
1.28      cvs      1411:   /* Find any scheme name */
                   1412:   if ((path = strstr(*url, "://")) != NULL)
1.33      cvs      1413:     {
                   1414:       /* Find host name */
1.28      cvs      1415:       access = *url;
                   1416:       while (access<path && (*access=tolower(*access)))
                   1417:        access++;
                   1418:       path += 3;
                   1419:       while ((newptr = strstr(path, "://")) != NULL)
                   1420:         /* For proxies */
                   1421:        path = newptr+3;
                   1422:       /* We have a host name */
                   1423:       path = HTCanon(url, path);
1.25      cvs      1424:     }
1.28      cvs      1425:   else if ((path = strstr(*url, ":/")) != NULL)
                   1426:     path += 2;
                   1427:   else
                   1428:     path = *url;
1.25      cvs      1429: 
1.33      cvs      1430:   if (*path == used_sep && *(path+1)==used_sep)
1.28      cvs      1431:     /* Some URLs start //<foo> */
                   1432:     path += 1;
                   1433:   else if (!strncmp(path, "news:", 5))
                   1434:     {
                   1435:       newptr = strchr(path+5, '@');
                   1436:       if (!newptr)
                   1437:        newptr = path + 5;
                   1438:       while (*newptr)
                   1439:        {
                   1440:          /* Make group or host lower case */
                   1441:          *newptr = tolower (*newptr);
                   1442:          newptr++;
1.25      cvs      1443:        }
1.28      cvs      1444:       /* Doesn't need to do any more */
                   1445:       return;
1.25      cvs      1446:     }
1.28      cvs      1447: 
                   1448:   if ((p = path))
                   1449:     {
                   1450:       if (!((end = strchr (path, ';')) || (end = strchr (path, '?')) ||
                   1451:            (end = strchr (path, '#'))))
                   1452:        end = path + strlen (path);
                   1453:       
                   1454:       /* Parse string second time to simplify */
                   1455:       p = path;
                   1456:       while (p < end)
                   1457:        {
1.33      cvs      1458:          if (*p==used_sep)
1.28      cvs      1459:            {
1.33      cvs      1460:              if (p > *url && *(p+1) == '.' && (*(p+2) == used_sep || !*(p+2)))
1.28      cvs      1461:                {
                   1462:                  orig = p + 1;
1.33      cvs      1463:                  dest = (*(p+2)!=used_sep) ? p+2 : p+3;
1.52      cvs      1464:                  while ((*orig++ = *dest++)); /* Remove a used_sep and a dot*/
1.28      cvs      1465:                  end = orig - 1;
                   1466:                }
1.33      cvs      1467:              else if (*(p+1)=='.' && *(p+2)=='.' && (*(p+3)==used_sep || !*(p+3)))
1.28      cvs      1468:                {
                   1469:                  newptr = p;
1.52      cvs      1470:                  while (newptr>path && *--newptr!=used_sep); /* prev used_sep */
                   1471:                  if (*newptr == used_sep)
                   1472:                    orig = newptr + 1;
1.28      cvs      1473:                  else
1.52      cvs      1474:                    orig = newptr;
                   1475: 
                   1476:                  dest = (*(p+3) != used_sep) ? p+3 : p+4;
                   1477:                  while ((*orig++ = *dest++)); /* Remove /xxx/.. */
                   1478:                  end = orig-1;
                   1479:                  /* Start again with prev slash */
                   1480:                  p = newptr;
1.28      cvs      1481:                }
1.33      cvs      1482:              else if (*(p+1) == used_sep)
1.28      cvs      1483:                {
1.33      cvs      1484:                  while (*(p+1) == used_sep)
1.28      cvs      1485:                    {
                   1486:                      orig = p;
                   1487:                      dest = p + 1;
                   1488:                      while ((*orig++ = *dest++));  /* Remove multiple /'s */
                   1489:                      end = orig-1;
                   1490:                    }
                   1491:                }
                   1492:              else
1.25      cvs      1493:                p++;
1.28      cvs      1494:            }
                   1495:          else
                   1496:            p++;
1.25      cvs      1497:        }
                   1498:     }
1.51      cvs      1499: 
                   1500:     /*
                   1501:     **  Check for host/../.. kind of things
                   1502:     */
1.52      cvs      1503:     if (*path==used_sep && *(path+1)=='.' && *(path+2)=='.' && (!*(path+3) || *(path+3)==used_sep))
1.51      cvs      1504:        *(path+1) = EOS;
                   1505: 
1.28      cvs      1506:   return;
                   1507: }
                   1508: 
                   1509: 
                   1510: /*----------------------------------------------------------------------
                   1511:    NormalizeFile normalizes  local names.                             
                   1512:    Return TRUE if target and src differ.                           
                   1513:   ----------------------------------------------------------------------*/
                   1514: #ifdef __STDC__
                   1515: boolean             NormalizeFile (char *src, char *target)
                   1516: #else
                   1517: boolean             NormalizeFile (src, target)
                   1518: char               *src;
                   1519: char               *target;
                   1520: 
                   1521: #endif
                   1522: {
                   1523:    char               *s;
                   1524:    boolean             change;
                   1525: 
1.54      cvs      1526:    change = FALSE;
1.53      cvs      1527:    if (strncmp (src, "file:", 5) == 0)
1.28      cvs      1528:      {
                   1529:        /* remove the prefix file: */
                   1530:        if (src[5] == EOS)
                   1531:           strcpy (target, DIR_STR);
                   1532:        else if (src[0] == '~')
                   1533:          {
                   1534:            /* replace ~ */
                   1535:            s = (char *) TtaGetEnvString ("HOME");
                   1536:            strcpy (target, s);
                   1537:            strcat (target, &src[5]);
                   1538:          }
                   1539:        else
                   1540:           strcpy (target, &src[5]);
1.54      cvs      1541:        change = TRUE;
1.28      cvs      1542:      }
1.53      cvs      1543: #  ifndef _WINDOWS
                   1544:    else if (src[0] == '~')
                   1545:      {
                   1546:        /* replace ~ */
                   1547:        s = (char *) TtaGetEnvString ("HOME");
                   1548:        strcpy (target, s);
                   1549:        if (src[1] != DIR_SEP)
                   1550:          strcat (target, DIR_STR);
                   1551:        strcat (target, &src[1]);
1.54      cvs      1552:        change = TRUE;
1.53      cvs      1553:      }
                   1554: #   endif /* _WINDOWS */
1.28      cvs      1555:    else
                   1556:       strcpy (target, src);
                   1557: 
                   1558:    /* remove /../ and /./ */
1.29      cvs      1559:    SimplifyUrl (&target);
1.54      cvs      1560:    if (!change)
                   1561:      change = strcmp (src, target);
1.28      cvs      1562:    return (change);
1.25      cvs      1563: }
                   1564: 
1.28      cvs      1565: 
1.25      cvs      1566: /*----------------------------------------------------------------------
1.31      cvs      1567:   MakeRelativeURL: make relative name
1.25      cvs      1568:   
1.28      cvs      1569:   This function creates and returns a string which gives an expression of
                   1570:   one address as related to another. Where there is no relation, an absolute
                   1571:   address is retured.
1.25      cvs      1572:   
1.28      cvs      1573:   On entry,
1.25      cvs      1574:        Both names must be absolute, fully qualified names of nodes
                   1575:        (no fragment bits)
                   1576:   
1.28      cvs      1577:   On exit,
1.25      cvs      1578:        The return result points to a newly allocated name which, if
                   1579:        parsed by AmayaParseUrl relative to relatedName, will yield aName.
                   1580:        The caller is responsible for freeing the resulting name later.
                   1581:   ----------------------------------------------------------------------*/
                   1582: #ifdef __STDC__
1.31      cvs      1583: char            *MakeRelativeURL (char *aName, char *relatedName)
1.25      cvs      1584: #else  /* __STDC__ */
1.31      cvs      1585: char            *MakeRelativeURL (aName, relatedName)
1.28      cvs      1586: char            *aName;
                   1587: char            *relatedName;
1.25      cvs      1588: #endif  /* __STDC__ */
                   1589: {
1.39      cvs      1590:   char          *return_value;
                   1591:   char           result[MAX_LENGTH];
1.29      cvs      1592:   char          *p;
1.34      cvs      1593:   char          *q;
1.29      cvs      1594:   char          *after_access;
                   1595:   char          *last_slash = NULL;
                   1596:   int            slashes, levels, len;
                   1597: 
1.44      cvs      1598: # ifdef _WINDOWS
                   1599:   int ndx;
                   1600: # endif /* _WINDOWS */
                   1601: 
1.29      cvs      1602:   if (aName == NULL || relatedName == NULL)
                   1603:     return (NULL);
                   1604: 
                   1605:   slashes = 0;
                   1606:   after_access = NULL;
                   1607:   p = aName;
                   1608:   q = relatedName;
                   1609:   for (; *p && (*p == *q); p++, q++)
1.27      cvs      1610:     {
                   1611:       /* Find extent of match */
1.32      cvs      1612:       if (*p == ':')
1.29      cvs      1613:        after_access = p + 1;
1.28      cvs      1614:       if (*p == DIR_SEP)
1.27      cvs      1615:        {
1.29      cvs      1616:          /* memorize the last slash position and count them */
1.27      cvs      1617:          last_slash = p;
                   1618:          slashes++;
1.25      cvs      1619:        }
                   1620:     }
                   1621:     
1.31      cvs      1622:   /* q, p point to the first non-matching character or zero */
                   1623:   if (*q == EOS)
                   1624:     {
                   1625:       /* New name is a subset of the related name */
                   1626:       /* exactly the right length */
                   1627:       len = strlen (p);
                   1628:       if ((return_value = (char *) TtaGetMemory (len + 1)) != NULL)
                   1629:        strcpy (return_value, p);
                   1630:     }
                   1631:   else if ((slashes < 2 && after_access == NULL)
                   1632:       || (slashes < 3 && after_access != NULL))
                   1633:     {
                   1634:       /* Two names whitout common path */
                   1635:       /* exactly the right length */
                   1636:       len = strlen (aName);
                   1637:       if ((return_value = (char *) TtaGetMemory (len + 1)) != NULL)
                   1638:        strcpy (return_value, aName);
                   1639:     }
                   1640:   else
                   1641:     {
                   1642:       /* Some path in common */
                   1643:       if (slashes == 3 && strncmp (aName, "http:", 5) == 0)
                   1644:        /* just the same server */
                   1645:        strcpy (result, last_slash);
                   1646:       else
                   1647:        {
                   1648:          levels= 0; 
1.52      cvs      1649:          for (; *q && *q != '#' && *q!=';' && *q!='?'; q++)
1.31      cvs      1650:            if (*q == DIR_SEP)
                   1651:              levels++;
                   1652:          
1.52      cvs      1653:          result[0] = EOS;
1.31      cvs      1654:          for (;levels; levels--)
                   1655:            strcat (result, "../");
                   1656:          strcat (result, last_slash+1);
                   1657:        } 
1.52      cvs      1658: 
                   1659:       if (!*result)
                   1660:        strcat (result, "./");
                   1661: 
1.31      cvs      1662:       /* exactly the right length */
                   1663:       len = strlen (result);
                   1664:       if ((return_value = (char *) TtaGetMemory (len + 1)) != NULL)
                   1665:        strcpy (return_value, result);
1.52      cvs      1666: 
1.25      cvs      1667:     }
1.44      cvs      1668: # ifdef _WINDOWS
                   1669:   len = strlen (return_value);
                   1670:   for (ndx = 0; ndx < len; ndx ++)
                   1671:          if (return_value[ndx] == '\\')
                   1672:             return_value[ndx] = '/' ;
                   1673: # endif /* _WINDOWS */
1.29      cvs      1674:   return (return_value);
1.24      cvs      1675: }
1.35      cvs      1676: 
                   1677: 

Webmaster