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