[BACK] Return to HTMulti.c CVS log [TXT] [DIR] Up to [Public] / libwww / Library / src

Annotation of libwww/Library/src/HTMulti.c, revision 2.34

2.29 frystyk 1: /*
 2: **   CONTENT NEGOTIATION
2.11 frystyk 3: **
2.15 frystyk 4: **   (c) COPYRIGHT MIT 1995.
2.11 frystyk 5: **   Please first read the full copyright statement in the file COPYRIGH.
2.34 ! frystyk 6: **   @(#) $Id: HTMulti.c,v 2.33 1998年11月24日 03:14:45 frystyk Exp $
2.1 luotonen 7: **
 8: ** History:
 9: **   March 94 AL  Separated from HTFile.c because
 10: **           multiformat handling would be a mess in VMS.
 11: */
 12: 
2.13 frystyk 13: /* Library include files */
2.32 frystyk 14: #include "wwwsys.h"
2.28 frystyk 15: #include "WWWUtil.h"
 16: #include "WWWCore.h"
2.2 duns 17: #include "HTMulti.h"
2.34 ! frystyk 18: #include "HTBind.h"
2.20 frystyk 19: #include "HTFile.h"
2.1 luotonen 20: 
2.29 frystyk 21: #define MULTI_SUFFIX  ".multi"/* Extension for scanning formats */
 22: #define MAX_SUFF    15   /* Maximum number of suffixes for a file */
 23: #define VARIANTS    4    /* We start with this array size */
 24: 
 25: typedef struct _HTContentDescription {
 26:   char *   filename;
 27:   HTFormat  content_type;
 28:   HTLanguage content_language;
 29:   HTEncoding content_encoding;
 30:   HTEncoding content_transfer;
 31:   int        content_length;
 32:   double   quality;
 33: } HTContentDescription;
 34: 
2.3 luotonen 35: PRIVATE HTList * welcome_names = NULL; /* Welcome.html, index.html etc. */
 36: 
2.29 frystyk 37: /* ------------------------------------------------------------------------- */
 38: 
 39: /*
 40: ** Sort the q values in descending order
 41: */
 42: PRIVATE int VariantSort (const void * a, const void * b)
 43: {
 44:   HTContentDescription * aa = *(HTContentDescription **) a;
 45:   HTContentDescription * bb = *(HTContentDescription **) b;
2.33 frystyk 46:   if (aa && bb) return (aa->quality > bb->quality) ? -1 : 1;
 47:   return bb - aa;
2.29 frystyk 48: }
 49: 
 50: /*
 51: * Added by takada@seraph.ntt.jp (94/04/08)
 52: */
 53: PRIVATE BOOL lang_match (HTAtom * tmplate, HTAtom * actual)
 54: {
 55:   const char *t, *a;
 56:   char *st, *sa;
 57:   BOOL match = NO;
 58: 
 59:   if (tmplate && actual &&
 60:    (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
 61:    st = strchr(t, '_');
 62:    sa = strchr(a, '_');
 63:    if ((st != NULL) && (sa != NULL)) {
 64:      if (!strcasecomp(t, a))
 65:       match = YES;
 66:      else
 67:       match = NO;
 68:    }
 69:    else {
 70:      if (st != NULL) *st = 0;
 71:      if (sa != NULL) *sa = 0;
 72:      if (!strcasecomp(t, a))
 73:       match = YES;
 74:      else
 75:       match = NO;
 76:      if (st != NULL) *st = '_';
 77:      if (sa != NULL) *sa = '_';
 78:    }
 79:   }
 80:   return match;
 81: }
 82: 
 83: PRIVATE double type_value (HTAtom * content_type, HTList * accepted)
 84: {
 85:   if (!content_type) return (1.0);
 86:   if (accepted) {
 87:    HTList * cur = accepted;
 88:    HTPresentation * pres;
 89:    HTPresentation * wild = NULL;
 90:    while ((pres = (HTPresentation *) HTList_nextObject(cur))) {
 91:      if (pres->rep == content_type)
 92:        return pres->quality;
2.30 frystyk 93:      else if (HTMIMEMatch(pres->rep, content_type))
2.29 frystyk 94:        wild = pres;
 95:    }
 96:    if (wild) return wild->quality;
 97:    else return (0.0);                /* Nothing matched */
 98:   }
 99:   return (1.0);                  /* We accept all types */
 100: }
 101: 
 102: PRIVATE double lang_value (HTAtom * language, HTList * accepted)
 103: {
 104:   if (!language) return (1.0);
 105:   if (accepted) {
 106:    HTList * cur = accepted;
 107:    HTAcceptNode * node;
 108:    HTAcceptNode * wild = NULL;
 109:    while ((node = (HTAcceptNode *) HTList_nextObject(cur))) {
 110:      if (node->atom == language)
 111:        return node->quality;
 112:      /*
 113:       * patch by takada@seraph.ntt.jp (94/04/08)
 114:       * the original line was
2.30 frystyk 115:       * else if (HTMIMEMatch(node->atom, language)) {
2.29 frystyk 116:       * and the new line is
 117:       */
 118:      else if (lang_match(node->atom, language))
 119:        wild = node;
 120:    }
 121:    if (wild) return wild->quality;
 122:    else return (0.0);                /* Nothing matched */
 123:   }
 124:   return (1.0);                /* We accept all languages */
 125: }
 126: 
 127: PRIVATE double encoding_value (HTAtom * encoding, HTList * accepted)
 128: {
 129:   if (!encoding) return (1.0);
 130:   if (accepted) {
 131:    HTList * cur = accepted;
 132:    HTAcceptNode * node;
 133:    HTAcceptNode * wild = NULL;
 134:    const char * e = HTAtom_name(encoding);
 135:    if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
 136:      return (1.0);
 137:    while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
 138:      if (node->atom == encoding)
 139:        return node->quality;
2.30 frystyk 140:      else if (HTMIMEMatch(node->atom, encoding))
2.29 frystyk 141:        wild = node;
 142:    }
 143:    if (wild) return wild->quality;
 144:    else return (0.0);                /* Nothing matched */
 145:   }
 146:   return (1.0);                /* We accept all encodings */
 147: }
 148: 
 149: PRIVATE BOOL HTRank (HTRequest * request, HTArray * variants)
 150: {
 151:   HTContentDescription * cd;
 152:   void ** data;
 153:   if (!variants) {
 154:    if (PROT_TRACE) HTTrace("Ranking..... No variants\n");
 155:    return NO;
 156:   }
 157:   /* 
 158:   ** Walk through the list of local and global preferences and find the
 159:   ** overall q factor for each variant
 160:   */
 161:   cd = (HTContentDescription *) HTArray_firstObject(variants, data);
 162:   while (cd) {
 163:    double ctq_local = type_value(cd->content_type, HTRequest_conversion(request));
 164:    double ctq_global = type_value(cd->content_type, HTFormat_conversion());
 165:    double clq_local = lang_value(cd->content_language, HTRequest_language(request));
 166:    double clq_global = lang_value(cd->content_language, HTFormat_language());
 167:    double ceq_local = encoding_value(cd->content_encoding, HTRequest_encoding(request));
 168:    double ceq_global = encoding_value(cd->content_encoding, HTFormat_contentCoding());
 169:    if (PROT_TRACE)
 170:      HTTrace("Qualities... Content type: %.3f, Content language: %.3f, Content encoding: %.3f\n",
 171:          HTMAX(ctq_local, ctq_global),
 172:          HTMAX(clq_local, clq_global),
 173:          HTMAX(ceq_local, ceq_global));
 174:    cd->quality *= (HTMAX(ctq_local, ctq_global) *
 175:            HTMAX(clq_local, clq_global) *
 176:            HTMAX(ceq_local, ceq_global));
 177:    cd = (HTContentDescription *) HTArray_nextObject(variants, data);
 178:   }
 179: 
 180:   /* Sort the array of all our accepted preferences */
 181:   HTArray_sort(variants, VariantSort);
 182: 
 183:   /* Write out the result */
 184:   if (PROT_TRACE) {
 185:    int cnt = 1;
 186:    cd = (HTContentDescription *) HTArray_firstObject(variants, data);
 187:    HTTrace("Ranking.....\n");
 188:    HTTrace("RANK QUALITY CONTENT-TYPE     LANGUAGE ENCODING FILE\n");
 189:    while (cd) {
 190:      HTTrace("%d.  %.4f %-20.20s %-8.8s %-10.10s %s\n",
 191:          cnt++,
 192:          cd->quality,
 193:          cd->content_type ? HTAtom_name(cd->content_type) : "-",
 194:          cd->content_language?HTAtom_name(cd->content_language):"-",
 195:          cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
 196:          cd->filename ? cd->filename :"-");
 197:      cd = (HTContentDescription *) HTArray_nextObject(variants, data);
 198:    }
 199:   }
 200:   return YES;
 201: }
2.3 luotonen 202: 
2.14 frystyk 203: /* PUBLIC                       HTSplitFilename()
 204: **
 205: **   Split the filename to an array of suffixes.
 206: **   Return the number of parts placed to the array.
 207: **   Array should have MAX_SUFF+1 items.
 208: */
2.23 frystyk 209: PRIVATE int HTSplitFilename (char * s_str, char ** s_arr)
2.14 frystyk 210: {
2.26 frystyk 211:   const char *delimiters = HTBind_delimiters();
2.14 frystyk 212:   char * start = s_str;
 213:   char * end;
 214:   char save;
 215:   int i;
 216: 
 217:   if (!s_str || !s_arr) return 0;
 218: 
 219:   for (i=0; i < MAX_SUFF && *start; i++) {
 220:    for(end=start+1; *end && !strchr(delimiters, *end); end++);
 221:    save = *end;
 222:    *end = 0;
 223:    StrAllocCopy(s_arr[i], start); /* Frees the previous value */
 224:    *end = save;
 225:    start = end;
 226:   }
2.24 frystyk 227:   HT_FREE(s_arr[i]);    /* Terminating NULL */
2.14 frystyk 228:   return i;
 229: }
 230: 
 231: 
2.3 luotonen 232: /*
 233: **   Set default file name for welcome page on each directory.
 234: */
2.23 frystyk 235: PUBLIC void HTAddWelcome (char * name)
2.3 luotonen 236: {
 237:   if (name) {
 238:    char * mycopy = NULL;
 239:    StrAllocCopy(mycopy,name);
 240: 
 241:    if (!welcome_names)
 242:      welcome_names = HTList_new();
 243:    HTList_addObject(welcome_names, (void*)mycopy);
 244:   }
 245: }
 246: 
 247: 
2.26 frystyk 248: #ifdef HAVE_READDIR
2.1 luotonen 249: 
 250: /* PRIVATE                       multi_match()
 251: **
 252: **   Check if actual filename (split in parts) fulfills
 253: **   the requirements.
 254: */
2.23 frystyk 255: PRIVATE BOOL multi_match (char ** required, int m, char ** actual, int n)
2.1 luotonen 256: {
 257:   int c;
 258:   int i,j;
 259: 
2.2 duns 260: #ifdef VMS
 261:   for(c=0; c<m && c<n && !strcasecomp(required[c], actual[c]); c++);
 262: #else /* not VMS */
2.1 luotonen 263:   for(c=0; c<m && c<n && !strcmp(required[c], actual[c]); c++);
2.2 duns 264: #endif /* not VMS */
2.1 luotonen 265: 
 266:   if (!c) return NO;     /* Names differ rigth from start */
 267: 
 268:   for(i=c; i<m; i++) {
 269:    BOOL found = NO;
 270:    for(j=c; j<n; j++) {
2.2 duns 271: #ifdef VMS
 272:      if (!strcasecomp(required[i], actual[j])) {
 273: #else /* not VMS */
2.1 luotonen 274:      if (!strcmp(required[i], actual[j])) {
2.2 duns 275: #endif /* not VMS */
2.1 luotonen 276:        found = YES;
 277:        break;
 278:      }
 279:    }
 280:    if (!found) return NO;
 281:   }
 282:   return YES;
 283: }
 284: 
 285: 
 286: /*
 287: **   Get multi-match possibilities for a given file
 288: **   ----------------------------------------------
 289: ** On entry:
 290: **   path  absolute path to one file in a directory,
 291: **       may end in .multi.
 292: ** On exit:
 293: **   returns a list of ContentDesription structures
 294: **       describing the mathing files.
 295: **
 296: */
2.29 frystyk 297: PRIVATE HTArray * dir_matches (char * path)
2.1 luotonen 298: {
 299:   static char * required[MAX_SUFF+1];
 300:   static char * actual[MAX_SUFF+1];
 301:   int m,n;
 302:   char * dirname = NULL;
 303:   char * basename = NULL;
 304:   int baselen;
 305:   char * multi = NULL;
 306:   DIR * dp;
2.26 frystyk 307:   struct dirent * dirbuf;
2.29 frystyk 308:   HTArray * matches = NULL;
2.16 frystyk 309: #ifdef HT_REENTRANT
2.31 frystyk 310:   struct dirent result;                    /* For readdir_r */
2.16 frystyk 311: #endif
2.1 luotonen 312: 
 313:   if (!path) return NULL;
 314: 
 315:   StrAllocCopy(dirname, path);
 316:   basename = (strrchr(dirname, '/'));
 317:   if (!basename)
 318:    goto dir_match_failed;
 319:   *basename++ = 0;
 320: 
 321:   multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2 duns 322:   if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1 luotonen 323:    *multi = 0;
 324:   baselen = strlen(basename);
 325: 
 326:   m = HTSplitFilename(basename, required);
 327: 
 328:   dp = opendir(dirname);
 329:   if (!dp) {
2.13 frystyk 330:    if (PROT_TRACE)
2.25 eric 331:      HTTrace("Warning..... Can't open directory %s\n", dirname);
2.1 luotonen 332:    goto dir_match_failed;
 333:   }
 334: 
2.29 frystyk 335:   matches = HTArray_new(VARIANTS);
2.16 frystyk 336: #ifdef HT_REENTRANT
2.31 frystyk 337:    while ((dirbuf = (struct dirent *) readdir_r(dp, &result))) {
2.16 frystyk 338: #else
 339:    while ((dirbuf = readdir(dp))) {
 340: #endif /* HT_REENTRANT */
2.1 luotonen 341:    if (!dirbuf->d_ino) continue;  /* Not in use */
2.3 luotonen 342:    if (!strcmp(dirbuf->d_name,".") ||
 343:      !strcmp(dirbuf->d_name,"..") ||
2.20 frystyk 344:      !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3 luotonen 345:      continue;
2.7 frystyk 346: 
2.13 frystyk 347:    /* Use of direct->namlen is only valid in BSD'ish system */
 348:    /* Thanks to chip@chinacat.unicom.com (Chip Rosenthal) */
 349:    /* if ((int)(dirbuf->d_namlen) >= baselen) { */
 350:    if ((int) strlen(dirbuf->d_name) >= baselen) {
2.1 luotonen 351:      n = HTSplitFilename(dirbuf->d_name, actual);
 352:      if (multi_match(required, m, actual, n)) {
 353:        HTContentDescription * cd;
2.29 frystyk 354:        if ((cd = (HTContentDescription *)
 355:           HT_CALLOC(1, sizeof(HTContentDescription))) == NULL)
 356:          HT_OUTOFMEM("dir_matches");
 357:        if (HTBind_getFormat(dirbuf->d_name,
 358:                   &cd->content_type,
 359:                   &cd->content_encoding,
 360:                   &cd->content_transfer,
 361:                   &cd->content_language,
 362:                   &cd->quality)) {
2.1 luotonen 363:          if (cd->content_type) {
2.24 frystyk 364:            if ((cd->filename = (char *) HT_MALLOC(strlen(dirname) + 2 + strlen(dirbuf->d_name))) == NULL)
 365:              HT_OUTOFMEM("dir_matches");
2.29 frystyk 366:            sprintf(cd->filename, "%s/%s", dirname, dirbuf->d_name);
 367:            HTArray_addObject(matches, (void *) cd);
 368:          } else {
 369:            HT_FREE(cd);
2.1 luotonen 370:          }
2.29 frystyk 371:        } else {
 372:          HT_FREE(cd);
2.1 luotonen 373:        }
 374:      }
 375:    }
 376:   }
 377:   closedir(dp);
 378: 
 379:  dir_match_failed:
2.24 frystyk 380:   HT_FREE(dirname);
2.1 luotonen 381:   return matches;
 382: }
 383: 
 384: 
 385: /*
 386: **   Get the best match for a given file
 387: **   -----------------------------------
 388: ** On entry:
 389: **   req->conversions accepted content-types
 390: **   req->encodings  accepted content-transfer-encodings
 391: **   req->languages  accepted content-languages
 392: **   path       absolute pathname of the filename for
 393: **            which the match is desired.
 394: ** On exit:
 395: **   returns a newly allocated absolute filepath.
 396: */
2.23 frystyk 397: PRIVATE char * HTGetBest (HTRequest * req, char * path)
2.1 luotonen 398: {
2.29 frystyk 399:   HTArray * variants = NULL;
 400:   char * representation = NULL;
2.1 luotonen 401: 
2.13 frystyk 402:   if (!path || !*path) return NULL;
2.1 luotonen 403: 
2.29 frystyk 404:   if ((variants = dir_matches(path)) == NULL) {
 405:    if (PROT_TRACE) HTTrace("No matches.. for \"%s\"\n", path);
2.13 frystyk 406:    return NULL;
2.1 luotonen 407:   }
 408: 
2.29 frystyk 409:   if (PROT_TRACE) {
 410:    void ** data;
 411:    HTContentDescription * cd = HTArray_firstObject(variants, data);
2.25 eric 412:    HTTrace("Multi....... Possibilities for \"%s\"\n", path);
2.29 frystyk 413:    HTTrace("   QUALITY CONTENT-TYPE     LANGUAGE ENCODING FILE\n");
 414:    while (cd) {
 415:      HTTrace("   %.4f %-20.20s %-8.8s %-10.10s %s\n",
 416:          cd->quality,
 417:          cd->content_type  ?HTAtom_name(cd->content_type) :"-\t",
 418:          cd->content_language?HTAtom_name(cd->content_language):"-",
 419:          cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
 420:          cd->filename    ?cd->filename          :"-");
 421:      cd = (HTContentDescription *) HTArray_nextObject(variants, data);
 422:    }
2.1 luotonen 423:   }
 424: 
 425:   /*
2.29 frystyk 426:   ** Finally get the best variant which is readable
2.1 luotonen 427:   */
2.29 frystyk 428:   if (HTRank(req, variants)) {
 429:    void ** data;
 430:    HTContentDescription * cd = HTArray_firstObject(variants, data);
 431:    while (cd) {
 432:      if (cd->filename) {
 433:        if (access(cd->filename, R_OK) != -1)
 434:          StrAllocCopy(representation, cd->filename);
 435:        else if (PROT_TRACE)
 436:          HTTrace("Multi....... `%s\' is not readable\n",
 437:              cd->filename);
2.1 luotonen 438:      }
2.29 frystyk 439:      HT_FREE(cd->filename);
 440:      HT_FREE(cd);
 441:      cd = (HTContentDescription *) HTArray_nextObject(variants, data);
2.1 luotonen 442:    }
 443:   }
2.29 frystyk 444:   HTArray_delete(variants);
 445:   return representation;
2.1 luotonen 446: }
 447: 
2.3 luotonen 448: 
 449: 
2.23 frystyk 450: PRIVATE int welcome_value (char * name)
2.3 luotonen 451: {
 452:   HTList * cur = welcome_names;
 453:   char * welcome;
 454:   int v = 0;
 455: 
 456:   while ((welcome = (char*)HTList_nextObject(cur))) {
 457:    v++;
 458:    if (!strcmp(welcome,name)) return v;
 459:   }
 460:   return 0;
 461: }
 462: 
 463: 
 464: 
2.23 frystyk 465: PRIVATE char * get_best_welcome (char * path)
2.3 luotonen 466: {
 467:   char * best_welcome = NULL;
 468:   int best_value = 0;
 469:   DIR * dp;
2.26 frystyk 470:   struct dirent * dirbuf;
2.3 luotonen 471:   char * last = strrchr(path, '/');
 472: 
 473:   if (!welcome_names) {
 474:    HTAddWelcome("Welcome.html");
 475:    HTAddWelcome("welcome.html");
2.5 luotonen 476: #if 0
2.3 luotonen 477:    HTAddWelcome("Index.html");
2.5 luotonen 478: #endif
2.3 luotonen 479:    HTAddWelcome("index.html");
 480:   }
 481: 
2.5 luotonen 482:   if (last && last!=path) *last = 0;
2.3 luotonen 483:   dp = opendir(path);
2.5 luotonen 484:   if (last && last!=path) *last='/';
2.3 luotonen 485:   if (!dp) {
2.13 frystyk 486:    if (PROT_TRACE)
2.25 eric 487:      HTTrace("Warning..... Can't open directory %s\n",path);
2.3 luotonen 488:    return NULL;
 489:   }
 490:   while ((dirbuf = readdir(dp))) {
2.13 frystyk 491:    if (!dirbuf->d_ino ||
2.3 luotonen 492:      !strcmp(dirbuf->d_name,".") ||
 493:      !strcmp(dirbuf->d_name,"..") ||
2.20 frystyk 494:      !strcmp(dirbuf->d_name, DEFAULT_DIR_FILE))
2.3 luotonen 495:      continue;
 496:    else {
 497:      int v = welcome_value(dirbuf->d_name);
 498:      if (v > best_value) {
 499:        best_value = v;
 500:        StrAllocCopy(best_welcome, dirbuf->d_name);
 501:      }
 502:    }
 503:   }
 504:   closedir(dp);
 505: 
 506:   if (best_welcome) {
2.24 frystyk 507:    char * welcome;
 508:    if ((welcome = (char *) HT_MALLOC(strlen(path) + strlen(best_welcome)+2)) == NULL)
 509:      HT_OUTOFMEM("get_best_welcome");
2.4 luotonen 510:    sprintf(welcome, "%s%s%s", path, last ? "" : "/", best_welcome);
2.24 frystyk 511:    HT_FREE(best_welcome);
2.13 frystyk 512:    if (PROT_TRACE)
2.25 eric 513:      HTTrace("Welcome..... \"%s\"\n",welcome);
2.3 luotonen 514:    return welcome;
 515:   }
 516:   return NULL;
 517: }
 518: 
2.26 frystyk 519: #endif /* HAVE_READDIR */
2.1 luotonen 520: 
 521: 
 522: /*
 523: **   Do multiformat handling
 524: **   -----------------------
 525: ** On entry:
 526: **   req->conversions accepted content-types
 527: **   req->encodings  accepted content-transfer-encodings
 528: **   req->languages  accepted content-languages
 529: **   path       absolute pathname of the filename for
 530: **            which the match is desired.
 531: **   stat_info     pointer to result space.
 532: **
 533: ** On exit:
 534: **   returns a newly allocated absolute filepath of the best
 535: **       match, or NULL if no match.
 536: **   stat_info     will contain inode information as
 537: **            returned by stat().
 538: */
2.23 frystyk 539: PUBLIC char * HTMulti (HTRequest *   req,
 540:            char *      path,
 541:            struct stat *  stat_info)
2.1 luotonen 542: {
 543:   char * new_path = NULL;
 544:   int stat_status = -1;
 545: 
2.3 luotonen 546:   if (!req || !path || !*path || !stat_info)
2.1 luotonen 547:    return NULL;
 548: 
2.26 frystyk 549: #ifdef HAVE_READDIR
2.19 frystyk 550:   if (*(path+strlen(path)-1) == '/') {    /* Find welcome page */
2.3 luotonen 551:    new_path = get_best_welcome(path);
 552:    if (new_path) path = new_path;
2.29 frystyk 553:   } else{
2.3 luotonen 554:    char * multi = strrchr(path, MULTI_SUFFIX[0]);
 555:    if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.13 frystyk 556:      if (PROT_TRACE)
2.25 eric 557:        HTTrace("Multi....... by %s suffix\n", MULTI_SUFFIX);
2.1 luotonen 558:      if (!(new_path = HTGetBest(req, path))) {
2.13 frystyk 559:        if (PROT_TRACE)
2.25 eric 560:          HTTrace("Multi....... failed -- giving up\n");
2.1 luotonen 561:        return NULL;
 562:      }
 563:      path = new_path;
2.29 frystyk 564:    } else {
2.18 frystyk 565:      stat_status = HT_STAT(path, stat_info);
2.3 luotonen 566:      if (stat_status == -1) {
2.13 frystyk 567:        if (PROT_TRACE)
2.29 frystyk 568:          HTTrace("AutoMulti... can't stat \"%s\"(errno %d)\n",
2.13 frystyk 569:              path, errno);
2.3 luotonen 570:        if (!(new_path = HTGetBest(req, path))) {
2.13 frystyk 571:          if (PROT_TRACE)
2.25 eric 572:            HTTrace("AutoMulti... failed -- giving up\n");
2.3 luotonen 573:          return NULL;
 574:        }
 575:        path = new_path;
 576:      }
2.1 luotonen 577:    }
 578:   }
2.26 frystyk 579: #endif /* HAVE_READDIR */
2.1 luotonen 580: 
 581:   if (stat_status == -1)
2.18 frystyk 582:    stat_status = HT_STAT(path, stat_info);
2.1 luotonen 583:   if (stat_status == -1) {
2.13 frystyk 584:    if (PROT_TRACE)
2.25 eric 585:      HTTrace("Stat fails.. on \"%s\" -- giving up (errno %d)\n",
2.13 frystyk 586:          path, errno);
2.1 luotonen 587:    return NULL;
2.29 frystyk 588:   } else {
2.1 luotonen 589:    if (!new_path) {
 590:      StrAllocCopy(new_path, path);
 591:      return new_path;
 592:    }
 593:    else return path;
 594:   }
 595: }
 596: 
 597: 

Webmaster

AltStyle によって変換されたページ (->オリジナル) /