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