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