Annotation of libwww/Library/src/HTMulti.c, revision 2.2
2.1 luotonen 1:
2: /*
3: ** Multiformat handling
4: **
5: ** History:
6: ** March 94 AL Separated from HTFile.c because
7: ** multiformat handling would be a mess in VMS.
8: **
9: **
10: */
11:
2.2 ! duns 12: #include "HTMulti.h"
2.1 luotonen 13: #include "HTFile.h"
14: #include "HTList.h"
15:
2.2 ! duns 16: #ifdef VMS
! 17: #define USE_DIRENT
! 18: #define GOT_READ_DIR
! 19: #include "dirent.h"
! 20: #define R_OK 3
! 21: #endif
! 22:
2.1 luotonen 23: #ifdef USE_DIRENT /* Set this for Sys V systems */
24: #define STRUCT_DIRENT struct dirent
25: #else
26: #define STRUCT_DIRENT struct direct
27: #endif
28:
29:
30: #ifdef GOT_READ_DIR
31:
32: /* PRIVATE multi_match()
33: **
34: ** Check if actual filename (split in parts) fulfills
35: ** the requirements.
36: */
37: PRIVATE BOOL multi_match ARGS4(char **, required,
38: int, m,
39: char **, actual,
40: int, n)
41: {
42: int c;
43: int i,j;
44:
2.2 ! duns 45: #ifdef VMS
! 46: for(c=0; c<m && c<n && !strcasecomp(required[c], actual[c]); c++);
! 47: #else /* not VMS */
2.1 luotonen 48: for(c=0; c<m && c<n && !strcmp(required[c], actual[c]); c++);
2.2 ! duns 49: #endif /* not VMS */
2.1 luotonen 50:
51: if (!c) return NO; /* Names differ rigth from start */
52:
53: for(i=c; i<m; i++) {
54: BOOL found = NO;
55: for(j=c; j<n; j++) {
2.2 ! duns 56: #ifdef VMS
! 57: if (!strcasecomp(required[i], actual[j])) {
! 58: #else /* not VMS */
2.1 luotonen 59: if (!strcmp(required[i], actual[j])) {
2.2 ! duns 60: #endif /* not VMS */
2.1 luotonen 61: found = YES;
62: break;
63: }
64: }
65: if (!found) return NO;
66: }
67: return YES;
68: }
69:
70:
71: /*
72: ** Get multi-match possibilities for a given file
73: ** ----------------------------------------------
74: ** On entry:
75: ** path absolute path to one file in a directory,
76: ** may end in .multi.
77: ** On exit:
78: ** returns a list of ContentDesription structures
79: ** describing the mathing files.
80: **
81: */
82: PRIVATE HTList * dir_matches ARGS1(char *, path)
83: {
84: static char * required[MAX_SUFF+1];
85: static char * actual[MAX_SUFF+1];
86: int m,n;
87: char * dirname = NULL;
88: char * basename = NULL;
89: int baselen;
90: char * multi = NULL;
91: DIR * dp;
92: STRUCT_DIRENT * dirbuf;
93: HTList * matches = NULL;
94:
95: if (!path) return NULL;
96:
97: StrAllocCopy(dirname, path);
98: basename = (strrchr(dirname, '/'));
99: if (!basename)
100: goto dir_match_failed;
101: *basename++ = 0;
102:
103: multi = strrchr(basename, MULTI_SUFFIX[0]);
2.2 ! duns 104: if (multi && !strcasecomp(multi, MULTI_SUFFIX))
2.1 luotonen 105: *multi = 0;
106: baselen = strlen(basename);
107:
108: m = HTSplitFilename(basename, required);
109:
110: dp = opendir(dirname);
111: if (!dp) {
112: CTRACE(stderr,"Warning..... Can't open directory %s\n",
113: dirname);
114: goto dir_match_failed;
115: }
116:
117: matches = HTList_new();
118: while ((dirbuf = readdir(dp))) {
119: if (!dirbuf->d_ino) continue; /* Not in use */
120: if ((int)(dirbuf->d_namlen) >= baselen) {
121: n = HTSplitFilename(dirbuf->d_name, actual);
122: if (multi_match(required, m, actual, n)) {
123: HTContentDescription * cd;
124: cd = HTGetContentDescription(actual, n);
125: if (cd) {
126: if (cd->content_type) {
127: cd->filename = (char*)malloc(strlen(dirname) + 2 +
128: strlen(dirbuf->d_name));
129: if (!cd->filename) outofmem(__FILE__, "dir_matches");
130: sprintf(cd->filename, "%s/%s",
131: dirname, dirbuf->d_name);
132: HTList_addObject(matches, (void*)cd);
133: }
134: else free(cd);
135: }
136: }
137: }
138: }
139: closedir(dp);
140:
141: dir_match_failed:
142: free(dirname);
143: return matches;
144: }
145:
146:
147: /*
148: ** Get the best match for a given file
149: ** -----------------------------------
150: ** On entry:
151: ** req->conversions accepted content-types
152: ** req->encodings accepted content-transfer-encodings
153: ** req->languages accepted content-languages
154: ** path absolute pathname of the filename for
155: ** which the match is desired.
156: ** On exit:
157: ** returns a newly allocated absolute filepath.
158: */
159: PRIVATE char * HTGetBest ARGS2(HTRequest *, req,
160: char *, path)
161: {
162: HTList * matches;
163: HTList * cur;
164: HTContentDescription * cd;
165: HTContentDescription * best = NULL;
166: char * best_path = NULL;
167:
168:
169: if (!path || !*path) return NO;
170:
171: matches = dir_matches(path);
172: if (!matches) {
173: CTRACE(stderr, "No matches.. for \"%s\"\n", path);
174: return NO;
175: }
176:
177: /* BEGIN DEBUG */
178: cur = matches;
179: CTRACE(stderr, "Multi....... Possibilities for \"%s\"\n", path);
180: CTRACE(stderr, "\nCONTENT-TYPE LANGUAGE ENCODING QUALITY FILE\n");
181: while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
182: CTRACE(stderr, "%s\t%s\t%s\t %.5f %s\n",
183: cd->content_type ?HTAtom_name(cd->content_type) :"-\t",
184: cd->content_language?HTAtom_name(cd->content_language):"-",
185: cd->content_encoding?HTAtom_name(cd->content_encoding):"-",
186: cd->quality,
187: cd->filename ?cd->filename :"-");
188: }
189: CTRACE(stderr, "\n");
190: /* END DEBUG */
191:
192: /*
193: ** Finally get best that is readable
194: */
195: if (HTRank(matches, req->conversions, req->languages, req->encodings)) {
196: cur = matches;
197: while ((best = (HTContentDescription*)HTList_nextObject(cur))) {
198: if (best && best->filename) {
199: if (access(best->filename, R_OK) != -1) {
200: StrAllocCopy(best_path, best->filename);
201: break;
202: }
203: else CTRACE(stderr, "Bad News.... \"%s\" is not readable\n",
204: best->filename);
205: }
206: }
207: } /* Select best */
208:
209: cur = matches;
210: while ((cd = (HTContentDescription*)HTList_nextObject(cur))) {
211: if (cd->filename) free(cd->filename);
212: free(cd);
213: }
214: HTList_delete(matches);
215:
216: return best_path;
217: }
218:
2.2 ! duns 219: #endif /* GOT_READ_DIR */
2.1 luotonen 220:
221:
222: /*
223: ** Do multiformat handling
224: ** -----------------------
225: ** On entry:
226: ** req->conversions accepted content-types
227: ** req->encodings accepted content-transfer-encodings
228: ** req->languages accepted content-languages
229: ** path absolute pathname of the filename for
230: ** which the match is desired.
231: ** stat_info pointer to result space.
232: **
233: ** On exit:
234: ** returns a newly allocated absolute filepath of the best
235: ** match, or NULL if no match.
236: ** stat_info will contain inode information as
237: ** returned by stat().
238: */
239: PUBLIC char * HTMulti ARGS3(HTRequest *, req,
240: char *, path,
241: struct stat *, stat_info)
242: {
243: char * multi;
244: char * new_path = NULL;
245: int stat_status = -1;
246:
247: if (!req || !path || !stat_info)
248: return NULL;
249:
2.2 ! duns 250: #ifdef GOT_READ_DIR
2.1 luotonen 251: multi = strrchr(path, MULTI_SUFFIX[0]);
2.2 ! duns 252: if (multi && !strcasecomp(multi, MULTI_SUFFIX)) {
2.1 luotonen 253: CTRACE(stderr, "Multi....... by %s suffix\n", MULTI_SUFFIX);
254: if (!(new_path = HTGetBest(req, path))) {
255: CTRACE(stderr, "Multi....... failed -- giving up\n");
256: return NULL;
257: }
258: path = new_path;
259: }
260: else {
261: stat_status = stat(path, stat_info);
262: if (stat_status == -1) {
263: CTRACE(stderr,
264: "AutoMulti... because couldn't stat \"%s\" (errno %d)\n",
265: path, errno);
266: if (!(new_path = HTGetBest(req, path))) {
267: CTRACE(stderr, "AutoMulti... failed -- giving up\n");
268: return NULL;
269: }
270: path = new_path;
271: }
272: }
2.2 ! duns 273: #endif /* GOT_READ_DIR */
2.1 luotonen 274:
275: if (stat_status == -1)
276: stat_status = stat(path, stat_info);
277: if (stat_status == -1) {
278: CTRACE(stderr, "Stat fails.. on \"%s\" -- giving up (errno %d)\n",
279: path, errno);
280: return NULL;
281: }
282: else {
283: if (!new_path) {
284: StrAllocCopy(new_path, path);
285: return new_path;
286: }
287: else return path;
288: }
289: }
290:
291:
Webmaster