HTDir.c
上传用户:zlh9724
上传日期:2007-01-04
资源大小:1991k
文件大小:13k
源码类别:

浏览器

开发平台:

Unix_Linux

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