Annotation of libwww/Library/src/HTDir.c, revision 2.2
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) {
2.2 ! frystyk 282: LeftStr(&tp, "Last Modified", HT_DLEN_DATE);
2.1 frystyk 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