1 /* HTIcon.c
2 ** ICON MANAGEMENT
3 **
4 ** (c) COPYRIGHT MIT 1995.
5 ** Please first read the full copyright statement in the file COPYRIGH.
6 ** @(#) $Id$
7 **
8 ** This module contains the functions for initializing, adding
9 ** and selecting the icon for local directory listings, FTP and Gopher.
10 **
11 ** History:
12 ** Mar 94 Written by Ari Luotonen, luotonen@dxcern.cern.ch
13 ** Henrik Frystyk, frystyk@w3.org
14 **
15 */
16
17 /* Library include files */
18 #include "wwwsys.h"
19 #include "WWWUtil.h"
20 #include "WWWCore.h"
21 #include "HTIcons.h" /* Implemented here */
22
23 struct _HTIconNode {
24 char * icon_url;
25 char * icon_alt;
26 char * type_templ;
27 };
28
29 /* Globals */
30 PRIVATE HTIconNode * icon_unknown = NULL; /* Unknown file type */
31 PRIVATE HTIconNode * icon_blank = NULL; /* Blank icon in heading */
32 PRIVATE HTIconNode * icon_parent = NULL; /* Parent directory icon */
33 PRIVATE HTIconNode * icon_dir = NULL; /* Directory icon */
34
35 /* Type definitions and global variables etc. local to this module */
36 PRIVATE HTList * icons = NULL;
37 PRIVATE int alt_len = 0; /* Longest ALT text */
38
39 /* ------------------------------------------------------------------------- */
40
alt_resize(char * alt)41 PRIVATE void alt_resize (char * alt)
42 {
43 if (alt) {
44 int len = strlen(alt);
45 if (len > alt_len) alt_len = len;
46 }
47 }
48
match(char * templ,const char * actual)49 PRIVATE BOOL match (char * templ,
50 const char * actual)
51 {
52 static char * c1 = NULL;
53 static char * c2 = NULL;
54 char * slash1;
55 char * slash2;
56
57 StrAllocCopy(c1,templ);
58 StrAllocCopy(c2,actual);
59
60 slash1 = strchr(c1,'/');
61 slash2 = strchr(c2,'/');
62
63 if (slash1 && slash2) {
64 *slash1++ = 0;
65 *slash2++ = 0;
66 return HTStrMatch(c1,c2) && HTStrMatch(slash1,slash2);
67 }
68 else if (!slash1 && !slash2)
69 return HTStrMatch(c1,c2) ? YES : NO;
70 else
71 return NO;
72 }
73
74
prefixed(const char * name,const char * prefix)75 PRIVATE char * prefixed (const char * name, const char * prefix)
76 {
77 char * ret = NULL;
78 if (name) {
79 int len = prefix ? strlen(prefix) : 0;
80 if ((ret = (char *) HT_MALLOC(len + strlen(name) + 2)) == NULL)
81 HT_OUTOFMEM("prefixed");
82 if (prefix) {
83 strcpy(ret, prefix);
84 if (*prefix && prefix[len-1] != '/') strcat(ret, "/");
85 strcat(ret, name);
86 } else
87 strcpy(ret, name);
88 }
89 return ret;
90 }
91
HTIcon_url(HTIconNode * node)92 PUBLIC char * HTIcon_url (HTIconNode * node)
93 {
94 return node ? node->icon_url : NULL;
95 }
96
97 /*
98 ** Returned string must be freed by caller
99 */
HTIcon_alternative(HTIconNode * node,BOOL brackets)100 PUBLIC char * HTIcon_alternative (HTIconNode * node, BOOL brackets)
101 {
102 char * ret = NULL;
103 if (node) {
104 char * p = NULL;
105 int len = node->icon_alt ? strlen(node->icon_alt) : 0;
106 if ((p = ret = (char *) HT_MALLOC(alt_len + 3)) == NULL)
107 HT_OUTOFMEM("HTIcon_alt_string");
108 *p++ = brackets ? '[' : ' ';
109 if (node->icon_alt) strcpy(p, node->icon_alt);
110 p += len;
111 while (len++ < alt_len) *p++=' ';
112 *p++ = brackets ? ']' : ' ';
113 *p = 0;
114 }
115 return ret;
116 }
117
118 /*
119 ** HTAddIcon(url, alt, type_templ) adds icon:
120 **
121 ** <IMG SRC="url" ALT="[alt]">
122 **
123 ** for files for which content-type or content-encoding matches
124 ** type_templ. If type_templ contains a slash, it is taken to be
125 ** a content-type template. Otherwise, it is a content-encoding
126 ** template.
127 */
HTIcon_add(const char * url,const char * prefix,char * alt,char * type_templ)128 PUBLIC BOOL HTIcon_add (const char * url, const char * prefix,
129 char * alt, char * type_templ)
130 {
131 if (url && type_templ) {
132 HTIconNode * node;
133 if ((node = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode))) == NULL)
134 HT_OUTOFMEM("HTAddIcon");
135 if (url) node->icon_url = prefixed(url, prefix);
136 if (alt) StrAllocCopy(node->icon_alt, alt);
137 if (type_templ) StrAllocCopy(node->type_templ, type_templ);
138 if (!icons) icons = HTList_new();
139 HTList_addObject(icons, (void *) node);
140 alt_resize(alt);
141 HTTRACE(PROT_TRACE, "AddIcon..... %s => SRC=\"%s\" ALT=\"%s\"\n" _
142 type_templ _ url _ alt ? alt : "");
143 return YES;
144 }
145 return NO;
146 }
147
148 /*
149 ** Add the icon used for files for which
150 ** no other icon seems appropriate (unknown type).
151 */
HTIcon_addUnknown(const char * url,const char * prefix,char * alt)152 PUBLIC BOOL HTIcon_addUnknown (const char * url, const char * prefix,
153 char * alt)
154 {
155 if ((icon_unknown = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode)))==NULL)
156 HT_OUTOFMEM("HTAddUnknownIcon");
157 if (url) icon_unknown->icon_url = prefixed(url, prefix);
158 if (alt) StrAllocCopy(icon_unknown->icon_alt, alt);
159 alt_resize(alt);
160 HTTRACE(PROT_TRACE, "Icon add.... UNKNOWN => SRC=\"%s\" ALT=\"%s\"\n" _ url _
161 alt ? alt : "");
162 return YES;
163 }
164
165
166 /*
167 ** Add the blank icon used in the heading of the listing.
168 */
HTIcon_addBlank(const char * url,const char * prefix,char * alt)169 PUBLIC BOOL HTIcon_addBlank (const char * url, const char * prefix, char * alt)
170 {
171 if ((icon_blank = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode))) == NULL)
172 HT_OUTOFMEM("HTAddBlankIcon");
173 if (url) icon_blank->icon_url = prefixed(url, prefix);
174 if (alt) StrAllocCopy(icon_blank->icon_alt, alt);
175 alt_resize(alt);
176 HTTRACE(PROT_TRACE, "Icon add.... BLANK => SRC=\"%s\" ALT=\"%s\"\n" _ url _
177 alt ? alt : "");
178 return YES;
179 }
180
181
182 /*
183 ** Add the parent directory icon.
184 */
HTIcon_addParent(const char * url,const char * prefix,char * alt)185 PUBLIC BOOL HTIcon_addParent (const char * url, const char * prefix, char * alt)
186 {
187 if ((icon_parent = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode))) == NULL)
188 HT_OUTOFMEM("HTAddBlankIcon");
189 if (url) icon_parent->icon_url = prefixed(url, prefix);
190 if (alt) StrAllocCopy(icon_parent->icon_alt, alt);
191 alt_resize(alt);
192 HTTRACE(PROT_TRACE, "Icon add.... PARENT => SRC=\"%s\" ALT=\"%s\"\n" _ url _
193 alt ? alt : "");
194 return YES;
195 }
196
197
198 /*
199 ** Add the directory icon.
200 */
HTIcon_addDir(const char * url,const char * prefix,char * alt)201 PUBLIC BOOL HTIcon_addDir (const char * url, const char * prefix, char * alt)
202 {
203 if ((icon_dir = (HTIconNode *) HT_CALLOC(1,sizeof(HTIconNode))) == NULL)
204 HT_OUTOFMEM("HTAddBlankIcon");
205 if (url) icon_dir->icon_url = prefixed(url, prefix);
206 if (alt) StrAllocCopy(icon_dir->icon_alt, alt);
207 alt_resize(alt);
208 HTTRACE(PROT_TRACE, "Icon add.... DIRECTORY => SRC=\"%s\" ALT=\"%s\"\n" _ url _
209 alt ? alt : "");
210 return YES;
211 }
212
213 /*
214 ** Returns the icon corresponding to content_type or content_encoding.
215 ** If no match is found then use "unknown icon"
216 */
HTIcon_find(HTFileMode mode,HTFormat content_type,HTEncoding content_encoding)217 PUBLIC HTIconNode * HTIcon_find (HTFileMode mode,
218 HTFormat content_type,
219 HTEncoding content_encoding)
220 {
221 if (!icon_unknown) icon_unknown = icon_blank;
222 if (mode == HT_IS_FILE) {
223 const char * ct = content_type ? HTAtom_name(content_type) : NULL;
224 const char * ce = content_encoding ? HTAtom_name(content_encoding) : NULL;
225 HTList * cur = icons;
226 HTIconNode * node;
227
228 while ((node = (HTIconNode*)HTList_nextObject(cur))) {
229 char * slash = strchr(node->type_templ,'/');
230 if ((ct && slash && match(node->type_templ,ct)) ||
231 (ce && !slash && HTStrMatch(node->type_templ,ce))) {
232 return node;
233 }
234 }
235 } else if (mode == HT_IS_DIR) {
236 return icon_dir ? icon_dir : icon_unknown;
237 } else if (mode == HT_IS_BLANK) {
238 return icon_blank ? icon_blank : icon_unknown;
239 } else if (mode == HT_IS_PARENT) {
240 return icon_parent ? icon_parent : icon_unknown;
241 }
242 return icon_unknown;
243 }
244
HTIconNode_delete(HTIconNode * pNode)245 PRIVATE void HTIconNode_delete (HTIconNode* pNode)
246 {
247 if (pNode) {
248 HT_FREE(pNode->icon_url);
249 HT_FREE(pNode->icon_alt);
250 HT_FREE(pNode->type_templ);
251 HT_FREE(pNode);
252 }
253 }
254 /*
255 ** cleans up all memory used by icons. Should be called by
256 ** HTLibTerminate() (but it isn't)
257 **
258 */
HTIcon_deleteAll(void)259 PUBLIC void HTIcon_deleteAll (void)
260 {
261 if(icons != NULL) {
262 HTList * iconList = icons;
263 HTIconNode * node;
264 while((node = (HTIconNode*)HTList_removeLastObject(iconList))) {
265 HTIconNode_delete(node);
266 }
267 /* delete the list as well */
268 HTList_delete(icons);
269 icons = NULL;
270 }
271 HTIconNode_delete(icon_unknown);
272 icon_unknown = NULL;
273 HTIconNode_delete(icon_blank);
274 icon_blank = NULL;
275 HTIconNode_delete(icon_parent);
276 icon_parent = NULL;
277 HTIconNode_delete(icon_dir);
278 icon_dir = NULL;
279 }
280