Annotation of libwww/Library/src/HTFormat.c, revision 1.68
1.55 frystyk 1: /* HTFormat.c
2: ** MANAGE DIFFERENT FILE FORMATS
3: **
1.62 frystyk 4: ** (c) COPYRIGHT MIT 1995.
1.55 frystyk 5: ** Please first read the full copyright statement in the file COPYRIGH.
1.1 timbl 6: **
7: ** Bugs:
8: ** Assumes the incoming stream is ASCII, rather than a local file
9: ** format, and so ALWAYS converts from ASCII on non-ASCII machines.
10: ** Therefore, non-ASCII machines can't read local files.
1.2 timbl 11: **
1.45 duns 12: ** HISTORY:
1.52 frystyk 13: ** 8 Jul 94 FM Insulate free() from _free structure element.
14: ** 8 Nov 94 HFN Changed a lot to make reentrant
1.2 timbl 15: */
16:
1.58 frystyk 17: /* Library Include files */
18: #include "tcp.h"
1.52 frystyk 19: #include "HTUtils.h"
1.58 frystyk 20: #include "HTString.h"
1.52 frystyk 21: #include "HTTCP.h"
1.58 frystyk 22: #include "HTFWrite.h"
1.52 frystyk 23: #include "HTGuess.h"
1.68 ! frystyk 24: #include "HTNetMan.h"
1.52 frystyk 25: #include "HTError.h"
1.67 frystyk 26: #include "HTReqMan.h"
1.52 frystyk 27: #include "HTFormat.h" /* Implemented here */
1.2 timbl 28:
1.52 frystyk 29: /* Public variables */
30: PUBLIC HTList * HTConversions = NULL;
1.63 frystyk 31: PUBLIC HTList * HTCharsets = NULL;
32: PUBLIC HTList * HTEncodings = NULL;
33: PUBLIC HTList * HTLanguages = NULL;
34:
35: #define NO_VALUE_FOUND -1e30 /* Stream Stack Value if none found */
36:
37: /* Varlables and typedefs local to this moduel */
38: PRIVATE double HTMaxSecs = 1e10; /* No effective limit */
1.64 frystyk 39: #if 0
1.63 frystyk 40: PRIVATE double HTMaxLength = 1e10; /* No effective limit */
1.64 frystyk 41: #endif
1.17 luotonen 42:
1.60 frystyk 43: struct _HTStream {
44: CONST HTStreamClass * isa;
45: };
46:
1.66 frystyk 47: /*
48: ** A bug in the Pyramid compiler requires this
49: */
50: #ifdef pyramid
51: extern HTConverter HTSaveAndExecute;
52: #endif /* pyramid */
53:
1.52 frystyk 54: /* ------------------------------------------------------------------------- */
1.63 frystyk 55: /* ACCEPT LISTS OF CONVERSIONS, ENCODINGS, LANGUAGE, AND CHARSET */
1.61 frystyk 56: /* ------------------------------------------------------------------------- */
1.17 luotonen 57:
1.52 frystyk 58: /*
1.63 frystyk 59: ** For all `accept lists' there is a local list and a global list. The
60: ** local list is a part of the request structure and the global list is
61: ** internal to the HTFormat module. The global lists can be used when
62: ** specifying accept lists for ALL requests and the local list can be
63: ** used to add specific accept headers to the request.
64: */
65:
66: /*
67: ** Cleanup memory after the LOCAL list of converters, language,
68: ** charset, and encoding in the HTRequest structure. Note that
69: ** all these also have a global representation.
1.2 timbl 70: */
1.52 frystyk 71: PUBLIC void HTFormatDelete ARGS1(HTRequest *, request)
1.31 frystyk 72: {
1.63 frystyk 73: if (!request)
74: return;
75:
76: /* List of converters and presenters */
77: if (request->conversions) {
1.56 frystyk 78: HTList *cur = request->conversions;
79: HTPresentation *pres;
80: while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
81: FREE(pres->command); /* Leak fixed AL 6 Feb 1994 */
82: free(pres);
83: }
84: HTList_delete(request->conversions);
85: request->conversions = NULL;
1.31 frystyk 86: }
1.63 frystyk 87:
88: /* List of encoders (or decoders) */
89: if (request->encodings) {
90: HTList *cur = request->encodings;
91: HTAcceptNode *pres;
92: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
93: free(pres);
94: }
95: HTList_delete(request->encodings);
96: request->encodings = NULL;
97: }
98:
99: /* List of natural languages */
100: if (request->languages) {
101: HTList *cur = request->languages;
102: HTAcceptNode *pres;
103: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
104: free(pres);
105: }
106: HTList_delete(request->languages);
107: request->languages = NULL;
108: }
109:
110: /* List of charsets */
111: if (request->charsets) {
112: HTList *cur = request->charsets;
113: HTAcceptNode *pres;
114: while ((pres = (HTAcceptNode *) HTList_nextObject(cur))) {
115: free(pres);
116: }
117: HTList_delete(request->charsets);
118: request->charsets = NULL;
119: }
1.31 frystyk 120: }
121:
1.2 timbl 122:
1.61 frystyk 123: /*
1.63 frystyk 124: ** Cleanup memory after the GLOBAL list of converters, encodings,
125: ** languages, charsets etc. Note that there
1.61 frystyk 126: ** is also a LOCAL conversion list associated with each HTRequest
127: ** structure. Written by Eric Sink, eric@spyglass.com
128: */
129: PUBLIC void HTDisposeConversions NOARGS
130: {
1.63 frystyk 131: /* List of converters/preenters */
1.61 frystyk 132: if (HTConversions) {
133: HTList *cur = HTConversions;
134: HTPresentation *pres;
135: while ((pres = (HTPresentation*) HTList_nextObject(cur))) {
136: FREE(pres->command);
137: free(pres);
138: }
139: HTList_delete(HTConversions);
140: HTConversions = NULL;
141: }
1.63 frystyk 142:
143: /* List of encoders */
144: if (HTEncodings) {
145: HTList *cur = HTEncodings;
146: HTAcceptNode *pres;
147: while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
148: free(pres);
149: }
150: HTList_delete(HTEncodings);
151: HTEncodings = NULL;
152: }
153:
154: /* List of Languages */
155: if (HTLanguages) {
156: HTList *cur = HTLanguages;
157: HTAcceptNode *pres;
158: while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
159: free(pres);
160: }
161: HTList_delete(HTLanguages);
162: HTLanguages = NULL;
163: }
164:
165: /* List of Charsets */
166: if (HTCharsets) {
167: HTList *cur = HTCharsets;
168: HTAcceptNode *pres;
169: while ((pres = (HTAcceptNode*) HTList_nextObject(cur))) {
170: free(pres);
171: }
172: HTList_delete(HTCharsets);
173: HTCharsets = NULL;
174: }
1.61 frystyk 175: }
176:
177:
1.2 timbl 178: /* Define a presentation system command for a content-type
179: ** -------------------------------------------------------
1.52 frystyk 180: ** INPUT:
181: ** conversions: The list of conveters and presenters
182: ** representation: the MIME-style format name
183: ** command: the MAILCAP-style command template
184: ** quality: A degradation faction [0..1]
185: ** maxbytes: A limit on the length acceptable as input (0 infinite)
186: ** maxsecs: A limit on the time user will wait (0 for infinity)
1.2 timbl 187: */
1.49 howcome 188: PUBLIC void HTSetPresentation ARGS7(
1.12 timbl 189: HTList *, conversions,
190: CONST char *, representation,
191: CONST char *, command,
1.52 frystyk 192: CONST char *, test_command, /* HWL 27/9/94: mailcap functionality */
1.59 frystyk 193: double, quality,
194: double, secs,
195: double, secs_per_byte)
1.52 frystyk 196: {
1.63 frystyk 197: HTPresentation * pres = (HTPresentation *)calloc(1,sizeof(HTPresentation));
1.2 timbl 198: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
199:
200: pres->rep = HTAtom_for(representation);
201: pres->rep_out = WWW_PRESENT; /* Fixed for now ... :-) */
202: pres->converter = HTSaveAndExecute; /* Fixed for now ... */
203: pres->quality = quality;
204: pres->secs = secs;
205: pres->secs_per_byte = secs_per_byte;
206: pres->rep = HTAtom_for(representation);
1.49 howcome 207: pres->command = NULL;
1.2 timbl 208: StrAllocCopy(pres->command, command);
1.49 howcome 209: pres->test_command = NULL;
210: StrAllocCopy(pres->test_command, test_command);
1.12 timbl 211: HTList_addObject(conversions, pres);
1.2 timbl 212: }
213:
214:
215: /* Define a built-in function for a content-type
216: ** ---------------------------------------------
217: */
1.12 timbl 218: PUBLIC void HTSetConversion ARGS7(
219: HTList *, conversions,
220: CONST char *, representation_in,
221: CONST char *, representation_out,
1.6 timbl 222: HTConverter*, converter,
1.59 frystyk 223: double, quality,
224: double, secs,
225: double, secs_per_byte)
1.52 frystyk 226: {
1.63 frystyk 227: HTPresentation * pres = (HTPresentation *)calloc(1,sizeof(HTPresentation));
1.2 timbl 228: if (pres == NULL) outofmem(__FILE__, "HTSetPresentation");
229:
230: pres->rep = HTAtom_for(representation_in);
231: pres->rep_out = HTAtom_for(representation_out);
232: pres->converter = converter;
233: pres->command = NULL; /* Fixed */
1.49 howcome 234: pres->test_command = NULL;
1.2 timbl 235: pres->quality = quality;
236: pres->secs = secs;
237: pres->secs_per_byte = secs_per_byte;
1.12 timbl 238: HTList_addObject(conversions, pres);
1.56 frystyk 239: }
240:
241:
1.17 luotonen 242: PUBLIC void HTAcceptEncoding ARGS3(HTList *, list,
1.63 frystyk 243: CONST char *,enc,
1.59 frystyk 244: double, quality)
1.17 luotonen 245: {
246: HTAcceptNode * node;
1.63 frystyk 247: if (!list || !enc || !*enc) {
248: if (TRACE)
249: fprintf(TDEST, "Encodings... Bad argument\n");
250: return;
251: }
1.17 luotonen 252: node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
253: if (!node) outofmem(__FILE__, "HTAcceptEncoding");
254: HTList_addObject(list, (void*)node);
255:
256: node->atom = HTAtom_for(enc);
257: node->quality = quality;
258: }
259:
260:
261: PUBLIC void HTAcceptLanguage ARGS3(HTList *, list,
1.63 frystyk 262: CONST char *,lang,
1.59 frystyk 263: double, quality)
1.17 luotonen 264: {
265: HTAcceptNode * node;
1.63 frystyk 266: if (!list || !lang || !*lang) {
267: if (TRACE)
268: fprintf(TDEST, "Languages... Bad argument\n");
269: return;
270: }
271: node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
272: if (!node) outofmem(__FILE__, "HTAcceptLanguage");
273:
274: HTList_addObject(list, (void*)node);
275: node->atom = HTAtom_for(lang);
276: node->quality = quality;
277: }
1.17 luotonen 278:
279:
1.63 frystyk 280: PUBLIC void HTAcceptCharset ARGS3(HTList *, list,
281: CONST char *, charset,
282: double, quality)
283: {
284: HTAcceptNode * node;
285: if (!list || !charset || !*charset) {
286: if (TRACE)
287: fprintf(TDEST, "Charset..... Bad argument\n");
288: return;
289: }
1.17 luotonen 290: node = (HTAcceptNode*)calloc(1, sizeof(HTAcceptNode));
1.63 frystyk 291: if (!node) outofmem(__FILE__, "HTAcceptCharsetuage");
1.17 luotonen 292:
293: HTList_addObject(list, (void*)node);
1.63 frystyk 294: node->atom = HTAtom_for(charset);
1.17 luotonen 295: node->quality = quality;
296: }
297:
298:
1.63 frystyk 299: /* ------------------------------------------------------------------------- */
300: /* FORMAT NEGOTIATION */
301: /* ------------------------------------------------------------------------- */
302:
303: PRIVATE BOOL better_match ARGS2(HTFormat, f,
304: HTFormat, g)
305: {
306: CONST char *p, *q;
307:
308: if (f && g && (p = HTAtom_name(f)) && (q = HTAtom_name(g))) {
309: int i,j;
310: for(i=0 ; *p; p++) if (*p == '*') i++;
311: for(j=0 ; *q; q++) if (*q == '*') j++;
312: if (i < j) return YES;
313: }
314: return NO;
315: }
316:
317:
1.48 frystyk 318: PRIVATE BOOL wild_match ARGS2(HTAtom *, tmplate,
1.17 luotonen 319: HTAtom *, actual)
320: {
321: char *t, *a, *st, *sa;
322: BOOL match = NO;
323:
1.48 frystyk 324: if (tmplate && actual && (t = HTAtom_name(tmplate))) {
1.22 luotonen 325: if (!strcmp(t, "*"))
326: return YES;
1.17 luotonen 327:
1.22 luotonen 328: if (strchr(t, '*') &&
329: (a = HTAtom_name(actual)) &&
330: (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
1.17 luotonen 331:
1.22 luotonen 332: *sa = 0;
333: *st = 0;
334:
335: if ((*(st-1)=='*' &&
336: (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
337: (*(st+1)=='*' && !strcasecomp(t,a)))
338: match = YES;
339:
340: *sa = '/';
341: *st = '/';
342: }
343: }
1.23 luotonen 344: return match;
1.17 luotonen 345: }
346:
1.36 luotonen 347: /*
348: * Added by takada@seraph.ntt.jp (94/04/08)
349: */
1.48 frystyk 350: PRIVATE BOOL lang_match ARGS2(HTAtom *, tmplate,
1.36 luotonen 351: HTAtom *, actual)
352: {
353: char *t, *a, *st, *sa;
354: BOOL match = NO;
355:
1.48 frystyk 356: if (tmplate && actual &&
357: (t = HTAtom_name(tmplate)) && (a = HTAtom_name(actual))) {
1.36 luotonen 358: st = strchr(t, '_');
359: sa = strchr(a, '_');
360: if ((st != NULL) && (sa != NULL)) {
361: if (!strcasecomp(t, a))
362: match = YES;
363: else
364: match = NO;
365: }
366: else {
367: if (st != NULL) *st = 0;
368: if (sa != NULL) *sa = 0;
369: if (!strcasecomp(t, a))
370: match = YES;
371: else
372: match = NO;
373: if (st != NULL) *st = '_';
374: if (sa != NULL) *sa = '_';
375: }
376: }
377: return match;
378: }
379: /* end of addition */
380:
381:
1.17 luotonen 382:
1.59 frystyk 383: PRIVATE double type_value ARGS2(HTAtom *, content_type,
1.17 luotonen 384: HTList *, accepted)
385: {
386: HTList * cur = accepted;
387: HTPresentation * pres;
388: HTPresentation * wild = NULL;
389:
390: if (!content_type || !accepted) return -1;
391:
392: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
393: if (pres->rep == content_type)
394: return pres->quality;
395: else if (wild_match(pres->rep, content_type))
396: wild = pres;
397: }
398: if (wild) return wild->quality;
399: else return -1;
400: }
401:
402:
1.59 frystyk 403: PRIVATE double lang_value ARGS2(HTAtom *, language,
1.17 luotonen 404: HTList *, accepted)
405: {
406: HTList * cur = accepted;
407: HTAcceptNode * node;
408: HTAcceptNode * wild = NULL;
409:
410: if (!language || !accepted || HTList_isEmpty(accepted)) {
411: return 0.1;
412: }
413:
414: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
415: if (node->atom == language) {
416: return node->quality;
417: }
1.36 luotonen 418: /*
419: * patch by takada@seraph.ntt.jp (94/04/08)
420: * the original line was
421: * else if (wild_match(node->atom, language)) {
422: * and the new line is
423: */
424: else if (lang_match(node->atom, language)) {
1.17 luotonen 425: wild = node;
426: }
427: }
428:
429: if (wild) {
430: return wild->quality;
431: }
432: else {
433: return 0.1;
434: }
435: }
436:
437:
1.59 frystyk 438: PRIVATE double encoding_value ARGS2(HTAtom *, encoding,
1.17 luotonen 439: HTList *, accepted)
440: {
441: HTList * cur = accepted;
442: HTAcceptNode * node;
443: HTAcceptNode * wild = NULL;
444: char * e;
445:
446: if (!encoding || !accepted || HTList_isEmpty(accepted))
447: return 1;
448:
449: e = HTAtom_name(encoding);
450: if (!strcmp(e, "7bit") || !strcmp(e, "8bit") || !strcmp(e, "binary"))
451: return 1;
452:
453: while ((node = (HTAcceptNode*)HTList_nextObject(cur))) {
454: if (node->atom == encoding)
455: return node->quality;
456: else if (wild_match(node->atom, encoding))
457: wild = node;
458: }
459: if (wild) return wild->quality;
460: else return 1;
461: }
462:
463:
464: PUBLIC BOOL HTRank ARGS4(HTList *, possibilities,
465: HTList *, accepted_content_types,
466: HTList *, accepted_languages,
467: HTList *, accepted_encodings)
468: {
469: int accepted_cnt = 0;
470: HTList * accepted;
471: HTList * sorted;
472: HTList * cur;
473: HTContentDescription * d;
474:
475: if (!possibilities) return NO;
476:
477: accepted = HTList_new();
478: cur = possibilities;
479: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
1.59 frystyk 480: double tv = type_value(d->content_type, accepted_content_types);
481: double lv = lang_value(d->content_language, accepted_languages);
482: double ev = encoding_value(d->content_encoding, accepted_encodings);
1.17 luotonen 483:
484: if (tv > 0) {
485: d->quality *= tv * lv * ev;
486: HTList_addObject(accepted, d);
487: accepted_cnt++;
488: }
1.18 luotonen 489: else {
490: if (d->filename) free(d->filename);
491: free(d);
492: }
1.17 luotonen 493: }
494:
1.58 frystyk 495: if (PROT_TRACE) fprintf(TDEST, "Ranking.....\n");
496: if (PROT_TRACE) fprintf(TDEST,
1.18 luotonen 497: "\nRANK QUALITY CONTENT-TYPE LANGUAGE ENCODING FILE\n");
1.17 luotonen 498:
499: sorted = HTList_new();
500: while (accepted_cnt-- > 0) {
501: HTContentDescription * worst = NULL;
502: cur = accepted;
503: while ((d = (HTContentDescription*)HTList_nextObject(cur))) {
504: if (!worst || d->quality < worst->quality)
505: worst = d;
506: }
507: if (worst) {
1.58 frystyk 508: if (PROT_TRACE)
509: fprintf(TDEST, "%d. %.4f %-20.20s %-8.8s %-10.10s %s\n",
510: accepted_cnt+1,
511: worst->quality,
512: (worst->content_type
1.17 luotonen 513: ? HTAtom_name(worst->content_type) : "-"),
1.58 frystyk 514: (worst->content_language
1.17 luotonen 515: ? HTAtom_name(worst->content_language) :"-"),
1.58 frystyk 516: (worst->content_encoding
1.17 luotonen 517: ? HTAtom_name(worst->content_encoding) :"-"),
1.58 frystyk 518: (worst->filename
1.17 luotonen 519: ? worst->filename :"-"));
520: HTList_removeObject(accepted, (void*)worst);
521: HTList_addObject(sorted, (void*)worst);
522: }
523: }
1.58 frystyk 524: if (PROT_TRACE) fprintf(TDEST, "\n");
1.17 luotonen 525: HTList_delete(accepted);
526: HTList_delete(possibilities->next);
527: possibilities->next = sorted->next;
528: sorted->next = NULL;
529: HTList_delete(sorted);
530:
531: if (!HTList_isEmpty(possibilities)) return YES;
532: else return NO;
533: }
534:
535:
1.2 timbl 536: /* Create a filter stack
537: ** ---------------------
538: **
1.7 secret 539: ** If a wildcard match is made, a temporary HTPresentation
1.2 timbl 540: ** structure is made to hold the destination format while the
541: ** new stack is generated. This is just to pass the out format to
542: ** MIME so far. Storing the format of a stream in the stream might
543: ** be a lot neater.
1.10 timbl 544: **
1.29 frystyk 545: ** The star/star format is special, in that if you can take
1.40 frystyk 546: ** that you can take anything.
1.2 timbl 547: */
1.52 frystyk 548: PUBLIC HTStream * HTStreamStack ARGS5(HTFormat, rep_in,
549: HTFormat, rep_out,
550: HTStream *, output_stream,
1.34 luotonen 551: HTRequest *, request,
552: BOOL, guess)
1.2 timbl 553: {
1.14 timbl 554: HTList * conversion[2];
555: int which_list;
1.59 frystyk 556: double best_quality = -1e30; /* Pretty bad! */
1.65 frystyk 557: HTPresentation *pres, *best_match=NULL;
1.14 timbl 558:
1.65 frystyk 559: if (STREAM_TRACE) {
560: fprintf(TDEST, "StreamStack. Constructing stream stack for %s to %s\n",
561: HTAtom_name(rep_in), HTAtom_name(rep_out));
562: }
1.34 luotonen 563: if (guess && rep_in == WWW_UNKNOWN) {
1.58 frystyk 564: if (PROT_TRACE) fprintf(TDEST, "Returning... guessing stream\n");
1.52 frystyk 565: return HTGuess_new(request, NULL, rep_in, rep_out, output_stream);
1.34 luotonen 566: }
567:
1.47 frystyk 568: if (rep_out == WWW_SOURCE || rep_out == rep_in) {
1.52 frystyk 569: return output_stream;
1.47 frystyk 570: }
1.2 timbl 571:
1.14 timbl 572: conversion[0] = request->conversions;
573: conversion[1] = HTConversions;
1.17 luotonen 574:
1.15 luotonen 575: for(which_list = 0; which_list<2; which_list++) {
576: HTList * cur = conversion[which_list];
577:
578: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
1.65 frystyk 579: if ((pres->rep==rep_in || wild_match(pres->rep, rep_in)) &&
580: (pres->rep_out==rep_out || wild_match(pres->rep_out,rep_out))){
581: if (!best_match || better_match(pres->rep, best_match->rep) ||
1.33 luotonen 582: (!better_match(best_match->rep, pres->rep) &&
583: pres->quality > best_quality)) {
1.58 frystyk 584: #ifdef GOT_SYSTEM
1.65 frystyk 585: int result=0;
586: if (pres->test_command) {
587: result = system(pres->test_command);
588: if (STREAM_TRACE)
589: fprintf(TDEST, "StreamStack. system(%s) returns %d\n", pres->test_command, result);
590: }
591: if (!result) {
1.49 howcome 592: best_match = pres;
593: best_quality = pres->quality;
594: }
1.65 frystyk 595: #else
596: best_match = pres;
597: best_quality = pres->quality;
1.58 frystyk 598: #endif /* GOT_SYSTEM */
1.10 timbl 599: }
600: }
1.2 timbl 601: }
602: }
1.65 frystyk 603: if (best_match)
604: return (*best_match->converter)(request, best_match->command,
605: rep_in, rep_out, output_stream);
606: if (STREAM_TRACE)
607: fprintf(TDEST, "StreamStack. No match found, dumping to local file\n");
608: return HTSaveLocally(request, NULL, rep_in, rep_out, output_stream);
1.2 timbl 609: }
610:
611:
612: /* Find the cost of a filter stack
613: ** -------------------------------
614: **
615: ** Must return the cost of the same stack which StreamStack would set up.
616: **
617: ** On entry,
618: ** length The size of the data to be converted
619: */
1.59 frystyk 620: PUBLIC double HTStackValue ARGS5(
1.14 timbl 621: HTList *, theseConversions,
1.10 timbl 622: HTFormat, rep_in,
1.2 timbl 623: HTFormat, rep_out,
1.59 frystyk 624: double, initial_value,
1.2 timbl 625: long int, length)
626: {
1.14 timbl 627: int which_list;
628: HTList* conversion[2];
629:
1.65 frystyk 630: if (STREAM_TRACE) {
631: fprintf(TDEST, "StackValue.. Evaluating stream stack for %s worth %.3f to %s\n",
632: HTAtom_name(rep_in), initial_value,
633: HTAtom_name(rep_out));
634: }
1.2 timbl 635: if (rep_out == WWW_SOURCE ||
1.10 timbl 636: rep_out == rep_in) return 0.0;
1.2 timbl 637:
1.14 timbl 638: conversion[0] = theseConversions;
639: conversion[1] = HTConversions;
640:
641: for(which_list = 0; which_list<2; which_list++)
642: if (conversion[which_list]) {
1.15 luotonen 643: HTList * cur = conversion[which_list];
1.2 timbl 644: HTPresentation * pres;
1.15 luotonen 645: while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
646: if (pres->rep == rep_in &&
1.17 luotonen 647: (pres->rep_out == rep_out || wild_match(pres->rep_out, rep_out))) {
1.59 frystyk 648: double value = initial_value * pres->quality;
1.2 timbl 649: if (HTMaxSecs != 0.0)
1.15 luotonen 650: value = value - (length*pres->secs_per_byte + pres->secs)
1.2 timbl 651: /HTMaxSecs;
652: return value;
653: }
654: }
655: }
1.63 frystyk 656: return NO_VALUE_FOUND; /* Really bad */
1.1 timbl 657: }
1.2 timbl 658:
1.10 timbl 659:
Webmaster