Annotation of libwww/Library/src/HTDir.c, revision 2.1

2.1     ! frystyk     1: /*                                                                  HTDir.c
        !             2: **     DIRECTORY BROWSING
        !             3: **
        !             4: **     (c) COPYRIGHT MIT 1995.
        !             5: **     Please first read the full copyright statement in the file COPYRIGH.
        !             6: **
        !             7: **     This is unix-specific code in general
        !             8: **     The module is intended for use in HTFile.c and HTFTP.c where
        !             9: **     it replaces the old directory browsing routine.
        !            10: **     The module is only compiled if GOT_READ_DIR is defined
        !            11: **
        !            12: ** Authors:
        !            13: **             HF      Henrik Frystyk, CERN, <frystyk@w3.org>
        !            14: ** History:
        !            15: **        Sep 95  HFN  written
        !            16: **
        !            17: ** Note:
        !            18: **     It could be a HTML table instead
        !            19: */
        !            20: 
        !            21: /* Library include files */
        !            22: #include "tcp.h"
        !            23: #include "HTUtils.h"
        !            24: #include "HTString.h"
        !            25: #include "HTMLGen.h"
        !            26: #include "HTBind.h"
        !            27: #include "HTEscape.h"
        !            28: #include "HTParse.h"
        !            29: #include "HTFormat.h"
        !            30: #include "HTReq.h"
        !            31: #include "HTIcons.h"
        !            32: #include "HTStruct.h"
        !            33: #include "HTDescpt.h"
        !            34: #include "HTArray.h"
        !            35: #include "HTError.h"
        !            36: #include "HTDir.h"                                      /* Implemented here */
        !            37: 
        !            38: /* Macros and other defines */
        !            39: #define PUTC(c)                (*target->isa->put_character)(target, c)
        !            40: #define PUTS(s)                (*target->isa->put_string)(target, s)
        !            41: #define START(e)       (*target->isa->start_element)(target, e, 0, 0)
        !            42: #define END(e)         (*target->isa->end_element)(target, e)
        !            43: #define FREE_TARGET    (*target->isa->_free)(target)
        !            44: 
        !            45: #define DEFAULT_MINFW  15
        !            46: #define DEFAULT_MAXFW  22
        !            47: 
        !            48: /* Type definitions and global variables etc. local to this module */
        !            49: 
        !            50: struct _HTStructured {
        !            51:     CONST HTStructuredClass *  isa;
        !            52:     /* ... */
        !            53: };
        !            54: 
        !            55: struct _HTDir {
        !            56:     HTStructured *     target;
        !            57:     HTRequest *                request;
        !            58:     HTArray *          array;                  /* Array for sorted listings */
        !            59:     char *             fnbuf;                           /* File name buffer */
        !            60:     char *             lnbuf;                               /* Rest of line */
        !            61:     char *             base;                             /* base url is any */
        !            62:     HTDirShow          show;                     /* What do we want to show */
        !            63:     HTDirKey           key;                              /* Key for sorting */
        !            64:     int                        size;                             /* Number of files */
        !            65:     int                curfw;               /* Max file name length in list */
        !            66: };
        !            67: 
        !            68: typedef struct _HTDirNode {
        !            69:     char *     fname;
        !            70:     char *     date;
        !            71:     char *     size;
        !            72:     char *     note;
        !            73:     HTFileMode mode;
        !            74: } HTDirNode;
        !            75: 
        !            76: typedef enum _HTShowLength {                        /* Width of each collumn */
        !            77:     HT_DLEN_SIZE  = 6,
        !            78:     HT_DLEN_DATE  = 15,
        !            79:     HT_DLEN_SPACE = 1,
        !            80:     HT_DLEN_DES          = 25
        !            81: } HTShowLength;
        !            82: 
        !            83: PRIVATE int MinFileW = DEFAULT_MINFW;
        !            84: PRIVATE int MaxFileW = DEFAULT_MAXFW;
        !            85: 
        !            86: /* ------------------------------------------------------------------------- */
        !            87: /*                             LINE JUSTIFICATION                           */
        !            88: /* ------------------------------------------------------------------------- */
        !            89: 
        !            90: /*
        !            91: **     Left-justifies str_in into str_out expecting str_out having size length
        !            92: **     l is number of chars. No 0 termination, rest of line filled with ' '
        !            93: */
        !            94: PRIVATE void LeftStr (char **outstr, char * instr, int l)
        !            95: {
        !            96:     char *out = *outstr;
        !            97:     while (l-- > 0 && *instr && (*out++ = *instr++));
        !            98:     while (l-- > 0) *out++ = ' ';
        !            99:     *outstr = out;
        !           100: }
        !           101: 
        !           102: /*
        !           103: **     Like LeftStr(), but result is right-justified.
        !           104: **     l is number of chars. No 0 termination
        !           105: */
        !           106: PRIVATE void RightStr (char **outstr, char * instr, int l)
        !           107: {
        !           108:     char *start = *outstr+l-strlen(instr);
        !           109:     char *out = *outstr;
        !           110:     while (out<start) *out++ = ' ';
        !           111:     while (*instr && (*out++ = *instr++));
        !           112:     *outstr = out;
        !           113: }
        !           114: 
        !           115: /* ------------------------------------------------------------------------- */
        !           116: /*                             NODE  MANAGEMENT                             */
        !           117: /* ------------------------------------------------------------------------- */
        !           118: 
        !           119: /*
        !           120: **     Create a sort key node
        !           121: */
        !           122: PRIVATE HTDirNode * HTDirNode_new (void)
        !           123: {
        !           124:     HTDirNode *node;
        !           125:     if ((node = (HTDirNode *) calloc(1, sizeof(HTDirNode))) == NULL)
        !           126:        outofmem(__FILE__, "HTDirNode_new");
        !           127:     return node;
        !           128: }
        !           129: 
        !           130: /*
        !           131: **     Free a sort key node
        !           132: */
        !           133: PRIVATE BOOL HTDirNode_free (HTDirNode *node)
        !           134: {
        !           135:     if (node) {
        !           136:        FREE(node->fname);
        !           137:        FREE(node->date);
        !           138:        FREE(node->size);
        !           139:        FREE(node->note);
        !           140:        free(node);
        !           141:        return YES;
        !           142:     }
        !           143:     return NO;
        !           144: }
        !           145: 
        !           146: /*
        !           147: **     Output an element in HTML
        !           148: **     Returns YES if OK, else NO
        !           149: */
        !           150: PRIVATE BOOL HTDirNode_print (HTDir *dir, HTDirNode *node)
        !           151: {
        !           152:     char *tp = NULL;
        !           153:     HTStructured *target = dir->target;
        !           154:     if (dir->show & HT_DS_ICON) {
        !           155:        HTFormat format = NULL;
        !           156:        HTEncoding encoding = NULL;
        !           157:        double q=1.0;
        !           158:        HTIconNode *icon;
        !           159:        HTHrefNode *href;
        !           160:        if (node->mode == HT_IS_FILE)
        !           161:            HTBind_getFormat(node->fname, &format, &encoding, NULL, &q);
        !           162:        icon = HTGetIcon(node->mode, format, encoding);
        !           163:        href = HTGetHref(node->fname);
        !           164: 
        !           165:        /* Are we having a hot or a cold icon? */
        !           166:        if (!(dir->show & HT_DS_HOTI)) {
        !           167:            HTMLPutImg(target, icon->icon_url,
        !           168:                       HTIcon_alt_string(icon->icon_alt, YES), NULL);
        !           169:            PUTC(' ');
        !           170:        }
        !           171: 
        !           172:        /* Start the anchor element */
        !           173:        if (dir->base) {
        !           174:            char *escaped = HTEscape(node->fname, URL_XPALPHAS);
        !           175:            char *full = malloc(strlen(escaped)+strlen(dir->base)+1);
        !           176:            if (!full) outofmem(__FILE__, "HTDirNode_print");
        !           177:            strcpy(full, dir->base);
        !           178:            strcat(full, escaped);
        !           179:            HTStartAnchor(target, NULL, full);
        !           180:            free(escaped);
        !           181:            free(full);
        !           182:        } else {
        !           183:            char *escaped = HTEscape(node->fname, URL_XPALPHAS);
        !           184:            HTStartAnchor(target, NULL, escaped);
        !           185:            free(escaped);
        !           186:        }
        !           187: 
        !           188:        if (dir->show & HT_DS_HOTI) {
        !           189:            HTMLPutImg(target, icon->icon_url,
        !           190:                       HTIcon_alt_string(icon->icon_alt, YES), NULL);
        !           191:            PUTC(' ');
        !           192:        }
        !           193:     } else {
        !           194:        if (dir->base) {
        !           195:            char *escaped = HTEscape(node->fname, URL_XPALPHAS);
        !           196:            char *full = malloc(strlen(escaped)+strlen(dir->base)+1);
        !           197:            if (!full) outofmem(__FILE__, "HTDirNode_print");
        !           198:            strcpy(full, dir->base);
        !           199:            strcat(full, escaped);
        !           200:            HTStartAnchor(target, NULL, escaped);
        !           201:            free(escaped);
        !           202:            free(full);
        !           203:        } else {
        !           204:            char *escaped = HTEscape(node->fname, URL_XPALPHAS);
        !           205:            HTStartAnchor(target, NULL, escaped);
        !           206:            free(escaped);
        !           207:        }
        !           208:     }
        !           209:     
        !           210:     /* Insert the anchor text and end anchor */
        !           211:     {
        !           212:        char *in = node->fname;
        !           213:        char *out = dir->fnbuf;
        !           214:        int l = dir->curfw;
        !           215:        while (l-- > 0 && *in && (*out++ = *in++));
        !           216:        if (*in)
        !           217:            *(out-1) = '>';
        !           218:        else if (node->mode == HT_IS_DIR) {
        !           219:            *out++ = '/';
        !           220:            l--;
        !           221:        }
        !           222:        *out = '\0';
        !           223:        PUTS(dir->fnbuf);
        !           224:        END(HTML_A);
        !           225:        out = dir->fnbuf;
        !           226:        while (l-- >= 0) *out++ = ' ';
        !           227:        LeftStr(&out, " ", HT_DLEN_SPACE);
        !           228:        *out = '\0';
        !           229:        PUTS(dir->fnbuf);
        !           230:     }
        !           231: 
        !           232:     /* Print the rest of it */
        !           233:     tp = dir->lnbuf;
        !           234:     if (node->date) {
        !           235:        RightStr(&tp, node->date, HT_DLEN_DATE);
        !           236:        LeftStr(&tp, " ", HT_DLEN_SPACE);
        !           237:     }
        !           238:     if (node->size) {
        !           239:        RightStr(&tp, node->size, HT_DLEN_SIZE);
        !           240:        LeftStr(&tp, " ", HT_DLEN_SPACE);
        !           241:     }
        !           242:     if (node->note) {
        !           243:        LeftStr(&tp, node->note, HT_DLEN_DES);
        !           244:        LeftStr(&tp, " ", HT_DLEN_SPACE);
        !           245:     }
        !           246:     *tp = '\0';
        !           247:     PUTS(dir->lnbuf);
        !           248:     PUTC('\n');
        !           249:     return YES;
        !           250: }
        !           251: 
        !           252: /* ------------------------------------------------------------------------- */
        !           253: /*                             DIRECTORY MANAGEMENT                         */
        !           254: /* ------------------------------------------------------------------------- */
        !           255: 
        !           256: /*     HTDir_headLine
        !           257: **     --------------
        !           258: **     Puts out the header line of the list itself
        !           259: **     Returns YES if OK, else NO
        !           260: */
        !           261: PRIVATE BOOL HTDir_headLine (HTDir *dir)
        !           262: {
        !           263:     if (dir) {
        !           264:        char *tp;
        !           265:        HTStructured *target = dir->target;
        !           266:        START(HTML_PRE);
        !           267:        if (dir->show & HT_DS_ICON) {
        !           268:            HTIconNode *icon = HTGetIcon(HT_IS_BLANK, NULL, NULL);
        !           269:            HTMLPutImg(target, icon->icon_url,
        !           270:                       HTIcon_alt_string(icon->icon_alt, YES), NULL);
        !           271:            PUTC(' ');
        !           272:        }
        !           273: 
        !           274:        tp = dir->fnbuf;
        !           275:        LeftStr(&tp, "Name", dir->curfw);
        !           276:        LeftStr(&tp, " ", HT_DLEN_SPACE);
        !           277:        *tp = '\0';
        !           278:        PUTS(dir->fnbuf);
        !           279: 
        !           280:        tp = dir->lnbuf;
        !           281:        if (dir->show & HT_DS_DATE) {
        !           282:            LeftStr(&tp, "Date", HT_DLEN_DATE);
        !           283:            LeftStr(&tp, " ", HT_DLEN_SPACE);
        !           284:        }
        !           285:        if (dir->show & HT_DS_SIZE) {
        !           286:            RightStr(&tp, "Size", HT_DLEN_SIZE);
        !           287:            LeftStr(&tp, " ", HT_DLEN_SPACE);
        !           288:        }
        !           289:        if (dir->show & HT_DS_DES) {
        !           290:            LeftStr(&tp, "Description", HT_DLEN_DATE);
        !           291:            LeftStr(&tp, " ", HT_DLEN_SPACE);
        !           292:        }
        !           293:        *tp = '\0';
        !           294:        PUTS(dir->lnbuf);
        !           295:        START(HTML_HR);
        !           296:        PUTC('\n');
        !           297:        return YES;
        !           298:     }
        !           299:     return NO;
        !           300: }
        !           301: 
        !           302: /*     HTDir_setWidth
        !           303: **     --------------
        !           304: **     The module automatically ajusts the width of the directory listing as
        !           305: **     a function of the file name. The width can flows dynamically between
        !           306: **     an upper and a lower limit.
        !           307: */
        !           308: PUBLIC BOOL HTDir_setWidth (int minfile, int maxfile)
        !           309: {
        !           310:     MinFileW = (minfile>=0) ? minfile : 0;
        !           311:     MaxFileW = (maxfile>minfile) ? maxfile : minfile+1;
        !           312:     return YES;
        !           313: }
        !           314: 
        !           315: /*     HTDir_new
        !           316: **     ---------
        !           317: **     Creates a structured stream object and sets up the initial HTML stuff
        !           318: **     Returns the dir object if OK, else NULL
        !           319: */
        !           320: PUBLIC HTDir * HTDir_new (HTRequest * request, HTDirShow show, HTDirKey key)
        !           321: {    
        !           322:     HTDir *dir;
        !           323:     char *title = NULL;
        !           324:     if (!request) return NULL;
        !           325: 
        !           326:     /* Create object */
        !           327:     if ((dir = (HTDir *) calloc(1, sizeof (HTDir))) == NULL ||
        !           328:        (dir->fnbuf = (char *) malloc(MaxFileW+HT_DLEN_SPACE)) == NULL)
        !           329:        outofmem(__FILE__, "HTDir_new");
        !           330:     dir->target = HTMLGenerator(request, NULL, WWW_HTML,
        !           331:                               HTRequest_outputFormat(request),
        !           332:                               HTRequest_outputStream(request));
        !           333:     dir->request = request;
        !           334:     dir->show = show;
        !           335:     dir->key = key;
        !           336:     if (key==HT_DK_NONE)
        !           337:        dir->curfw = MaxFileW;
        !           338:     else {
        !           339:        dir->curfw = MinFileW;
        !           340:        dir->array = HTArray_new(256);
        !           341:     }
        !           342: 
        !           343:     /* Find the length of the fields */
        !           344:     {
        !           345:        int len = HT_DLEN_SPACE+1;
        !           346:        if (show & HT_DS_SIZE) len += (HT_DLEN_SIZE+HT_DLEN_SPACE);
        !           347:        if (show & HT_DS_DATE) len += (HT_DLEN_DATE+HT_DLEN_SPACE);
        !           348:        if (show & HT_DS_DES) len += HT_DLEN_DES;
        !           349:        if ((dir->lnbuf = (char *) malloc(len)) == NULL)
        !           350:            outofmem(__FILE__, "HTDir_new");
        !           351:     }
        !           352: 
        !           353:     /* Find the title and the base URL */
        !           354:     {
        !           355:        char *addr = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
        !           356:        char *path = HTParse(addr, "", PARSE_PATH+PARSE_PUNCTUATION);
        !           357:        char *ptr;
        !           358:        if ((ptr = strchr(path, ';')) || (ptr = strchr(path, '?')))
        !           359:            *ptr = '\0';
        !           360:        StrAllocCopy(title, path);
        !           361:        HTUnEscape(title);                                          /* Title */
        !           362:        if (PROT_TRACE) fprintf(TDEST, "TESTTESTTEST `%s\'\n", path);
        !           363:        if((ptr=strrchr(path, '/')) && (ptr<path+strlen(path)-1 || ptr==path)){
        !           364:            StrAllocCopy(dir->base, ++ptr);
        !           365:            StrAllocCat(dir->base, "/");
        !           366:        }
        !           367:        if (PROT_TRACE) fprintf(TDEST, "HTDir_new... base is `%s\'\n",
        !           368:                                dir->base ? dir->base : "");
        !           369:        free(addr);
        !           370:        free(path);
        !           371:     }
        !           372: 
        !           373:     /* Start the HTML stuff */
        !           374:     {
        !           375:        HTStructured *target = dir->target;
        !           376:        START(HTML_HTML);
        !           377:        START(HTML_HEAD);
        !           378:        START(HTML_TITLE);
        !           379:        PUTS("Current index is ");
        !           380:        PUTS(title);
        !           381:        END(HTML_TITLE);
        !           382:        END(HTML_HEAD);
        !           383:        START(HTML_BODY);
        !           384:        START(HTML_H1);
        !           385:        PUTS("Index of ");
        !           386:        PUTS(title);
        !           387:        END(HTML_H1);
        !           388:     }
        !           389:     FREE(title);
        !           390:     return dir;
        !           391: }
        !           392: 
        !           393: /*     HTDir_addElement
        !           394: **     ---------------
        !           395: **     This function accepts a directory line. "data" and "size", and
        !           396: **     "description" can all be NULL
        !           397: **     Returns YES if OK, else NO
        !           398: */
        !           399: PUBLIC BOOL HTDir_addElement (HTDir *dir, char *name, char *date, char *size,
        !           400:                              HTFileMode mode)
        !           401: {
        !           402:     HTDirNode *node = HTDirNode_new();
        !           403:     if (!dir || !name) return NO;
        !           404:     StrAllocCopy(node->fname, name);                           /* Mandatory */
        !           405:     if (dir->show & HT_DS_DATE && date) StrAllocCopy(node->date, date);
        !           406:     if (dir->show & HT_DS_SIZE && size) StrAllocCopy(node->size, size);
        !           407:     if (dir->show & HT_DS_DES) {
        !           408: #if 0
        !           409: 
        !           410:        /* FIND DESCRIPTION */
        !           411: 
        !           412: #endif
        !           413:     }
        !           414:     node->mode = mode;
        !           415:     if (dir->key == HT_DK_NONE) {
        !           416:        if (!dir->size++) HTDir_headLine(dir);
        !           417:        HTDirNode_print(dir, node);
        !           418:        HTDirNode_free(node);
        !           419:     } else {
        !           420:        int slen = strlen(name);
        !           421:        if (slen > dir->curfw)
        !           422:            dir->curfw = slen < MaxFileW ? slen : MaxFileW;
        !           423:        HTArray_addObject(dir->array, (void *) node);
        !           424:     }
        !           425:     return YES;
        !           426: }
        !           427: 
        !           428: PRIVATE int DirSort (CONST void *a, CONST void *b)
        !           429: {
        !           430:     HTDirNode *aa = *(HTDirNode **) a;
        !           431:     HTDirNode *bb = *(HTDirNode **) b;
        !           432:     return strcmp(aa->fname, bb->fname);
        !           433: #if 0
        !           434:     return strcmp((*(HTDirNode**)a)->fname, (*(HTDirNode**)a)->fname);
        !           435: #endif
        !           436: }
        !           437: 
        !           438: PRIVATE int DirCaseSort (CONST void *a, CONST void *b)
        !           439: {
        !           440:     HTDirNode *aa = *(HTDirNode **) a;
        !           441:     HTDirNode *bb = *(HTDirNode **) b;
        !           442:     return strcasecomp(aa->fname, bb->fname);
        !           443: #if 0
        !           444:     return strcasecomp((*(HTDirNode**)a)->fname, (*(HTDirNode**)a)->fname);
        !           445: #endif
        !           446: }
        !           447: 
        !           448: /*     HTDir_free
        !           449: **     ----------
        !           450: **     If we are sorting then do the sorting and put out the list,
        !           451: **     else just append the end of the list.
        !           452: */
        !           453: PUBLIC BOOL HTDir_free (HTDir * dir)
        !           454: {
        !           455:     if (!dir) return NO;
        !           456:     if (dir->key != HT_DK_NONE) {
        !           457:        HTArray *array = dir->array;
        !           458:        void **data;
        !           459:        HTDirNode *node;
        !           460:        HTDir_headLine(dir);    
        !           461:        HTArray_sort(array, (dir->key==HT_DK_CINS ? DirCaseSort : DirSort));
        !           462:        node = (HTDirNode *) HTArray_firstObject(array, data);
        !           463:        while (node) {
        !           464:            HTDirNode_print(dir, node);
        !           465:            HTDirNode_free(node);
        !           466:            node = (HTDirNode *) HTArray_nextObject(array, data);
        !           467:        }
        !           468:        dir->size = HTArray_size(array);
        !           469:        HTArray_delete(array);  
        !           470:     }
        !           471: 
        !           472:     /* Put out the end of the HTML stuff */
        !           473:     {
        !           474:        HTStructured *target = dir->target;
        !           475:        START(HTML_HR);
        !           476:        if (!dir->size)
        !           477:            PUTS("Empty directory");
        !           478:        else if (dir->size == 1)
        !           479:            PUTS("1 File");
        !           480:        else {
        !           481:            char buffer[20];
        !           482:            sprintf(buffer, "%u files", dir->size);
        !           483:            PUTS(buffer);
        !           484:        }
        !           485:        END(HTML_PRE);
        !           486:        END(HTML_BODY);
        !           487:        END(HTML_HTML);
        !           488:        FREE_TARGET;
        !           489:     }
        !           490: 
        !           491:     FREE(dir->fnbuf);
        !           492:     FREE(dir->lnbuf);
        !           493:     FREE(dir->base);
        !           494:     free(dir);
        !           495:     return YES;
        !           496: }

Webmaster