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