1 |
/* |
2 |
$Id: result_output.c,v 1.60 2002/08/20 22:24:09 whmoseley Exp $ |
3 |
** |
4 |
** This program and library is free software; you can redistribute it and/or |
5 |
** modify it under the terms of the GNU (Library) General Public License |
6 |
** as published by the Free Software Foundation; either version 2 |
7 |
** of the License, or any later version. |
8 |
** |
9 |
** This program is distributed in the hope that it will be useful, |
10 |
** but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 |
** GNU (Library) General Public License for more details. |
13 |
** |
14 |
** You should have received a copy of the GNU (Library) General Public License |
15 |
** along with this program; if not, write to the Free Software |
16 |
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
17 |
|
18 |
-- This module does result output for swish-e |
19 |
-- This module implements some methods about the |
20 |
-- "-x fmt" cmd option. |
21 |
-- basically: handle output fmts like: -x "%c|<swishtitle fmt=/%20s/>\n" |
22 |
-- |
23 |
-- License: see swish licence file |
24 |
|
25 |
-- 2001-01 R. Scherg (rasc) initial coding |
26 |
|
27 |
-- 2001-02-09 rasc make propertynames always lowercase! (may change) |
28 |
this is get same handling as metanames... |
29 |
-- 2001-02-28 rasc -b and counter corrected... |
30 |
-- 2001-03-13 rasc result header output routine -H <n> |
31 |
-- 2001-04-12 rasc Module init rewritten |
32 |
|
33 |
*/ |
34 |
|
35 |
|
36 |
//** should really "compile" the -x format string for each index, which means |
37 |
// basically looking up the properties only once for each index. |
38 |
|
39 |
|
40 |
/* Prints the final results of a search. |
41 |
2001-01-01 rasc Standard is swish 1.x default output |
42 |
|
43 |
if option extended format string is set, an alternate |
44 |
userdefined result output is possible (format like strftime or printf) |
45 |
in this case -d (delimiter is obsolete) |
46 |
e.g. : -x "result: COUNT:%c \t URL:%u\n" |
47 |
*/ |
48 |
|
49 |
|
50 |
/* $$$ Remark / ToDO: |
51 |
-- The code is a prototype and needs optimizing: |
52 |
-- format control string is parsed on each result entry. (very bad!) |
53 |
-- ToDO: build an "action array" from an initial parsing of fmt |
54 |
-- ctrl string. |
55 |
-- on each entry step thru this action output list |
56 |
-- seems to be simple, but has to be done. |
57 |
-- but for now: get this stuff running on the easy way. |
58 |
-- (rasc 2000-12) |
59 |
$$$ |
60 |
*/ |
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
#include <ctype.h> |
67 |
#include <string.h> |
68 |
#include <time.h> |
69 |
#include <stdio.h> |
70 |
#include <stdarg.h> |
71 |
|
72 |
#include "swish.h" |
73 |
#include "mem.h" |
74 |
#include "string.h" |
75 |
#include "merge.h" |
76 |
#include "docprop.h" |
77 |
#include "error.h" |
78 |
#include "search.h" |
79 |
#include "result_output.h" |
80 |
#include "no_better_place_module.h" |
81 |
#include "parse_conffile.h" // for the fuzzy to string function |
82 |
|
83 |
|
84 |
/* private module prototypes */ |
85 |
|
86 |
static void printExtResultEntry(SWISH * sw, FILE * f, char *fmt, RESULT * r); |
87 |
static char *printResultControlChar(FILE * f, char *s); |
88 |
static char *printTagAbbrevControl(SWISH * sw, FILE * f, char *s, RESULT * r); |
89 |
static char *parsePropertyResultControl(char *s, char **propertyname, char **subfmt); |
90 |
static void printPropertyResultControl(SWISH * sw, FILE * f, char *propname, char *subfmt, RESULT * r); |
91 |
|
92 |
static struct ResultExtFmtStrList *addResultExtFormatStr(struct ResultExtFmtStrList *rp, char *name, char *fmtstr); |
93 |
|
94 |
|
95 |
/* |
96 |
** ---------------------------------------------- |
97 |
** |
98 |
** Module management code starts here |
99 |
** |
100 |
** ---------------------------------------------- |
101 |
*/ |
102 |
|
103 |
|
104 |
|
105 |
/* |
106 |
-- init structures for this module |
107 |
*/ |
108 |
|
109 |
void initModule_ResultOutput(SWISH * sw) |
110 |
{ |
111 |
struct MOD_ResultOutput *md; |
112 |
|
113 |
md = (struct MOD_ResultOutput *) emalloc(sizeof(struct MOD_ResultOutput)); |
114 |
|
115 |
sw->ResultOutput = md; |
116 |
|
117 |
md->resultextfmtlist = NULL; |
118 |
|
119 |
/* cmd options */ |
120 |
md->extendedformat = NULL; /* -x :cmd param */ |
121 |
md->headerOutVerbose = 1; /* default = standard header */ |
122 |
md->stdResultFieldDelimiter = NULL; /* -d :old 1.x result output delimiter */ |
123 |
|
124 |
return; |
125 |
} |
126 |
|
127 |
|
128 |
/* |
129 |
-- release all wired memory for this module |
130 |
-- 2001-04-11 rasc |
131 |
*/ |
132 |
|
133 |
void freeModule_ResultOutput(SWISH * sw) |
134 |
{ |
135 |
struct MOD_ResultOutput *md = sw->ResultOutput; |
136 |
struct ResultExtFmtStrList *l, |
137 |
*ln; |
138 |
|
139 |
|
140 |
if (md->stdResultFieldDelimiter) |
141 |
efree(md->stdResultFieldDelimiter); /* -d :free swish 1.x delimiter */ |
142 |
/* was not emalloc!# efree (md->extendedformat); -x stuff */ |
143 |
|
144 |
|
145 |
l = md->resultextfmtlist; /* free ResultExtFormatName */ |
146 |
while (l) |
147 |
{ |
148 |
efree(l->name); |
149 |
efree(l->fmtstr); |
150 |
ln = l->next; |
151 |
efree(l); |
152 |
l = ln; |
153 |
} |
154 |
md->resultextfmtlist = NULL; |
155 |
|
156 |
/* free module data */ |
157 |
efree(sw->ResultOutput); |
158 |
sw->ResultOutput = NULL; |
159 |
|
160 |
return; |
161 |
} |
162 |
|
163 |
|
164 |
|
165 |
/* |
166 |
** ---------------------------------------------- |
167 |
** |
168 |
** Module config code starts here |
169 |
** |
170 |
** ---------------------------------------------- |
171 |
*/ |
172 |
|
173 |
|
174 |
/* |
175 |
-- Config Directives |
176 |
-- Configuration directives for this Module |
177 |
-- return: 0/1 = none/config applied |
178 |
*/ |
179 |
|
180 |
int configModule_ResultOutput(SWISH * sw, StringList * sl) |
181 |
{ |
182 |
struct MOD_ResultOutput *md = sw->ResultOutput; |
183 |
char *w0 = sl->word[0]; |
184 |
int retval = 1; |
185 |
|
186 |
|
187 |
|
188 |
/* $$$ this will not work unless swish is reading the config file also for search ... */ |
189 |
|
190 |
if (strcasecmp(w0, "ResultExtFormatName") == 0) |
191 |
{ /* 2001-02-15 rasc */ |
192 |
/* ResultExt... name fmtstring */ |
193 |
if (sl->n == 3) |
194 |
{ |
195 |
md->resultextfmtlist = (struct ResultExtFmtStrList *) addResultExtFormatStr(md->resultextfmtlist, sl->word[1], sl->word[2]); |
196 |
} |
197 |
else |
198 |
progerr("%s: requires \"name\" \"fmtstr\"", w0); |
199 |
} |
200 |
else |
201 |
{ |
202 |
retval = 0; /* not a module directive */ |
203 |
} |
204 |
|
205 |
return retval; |
206 |
} |
207 |
|
208 |
|
209 |
|
210 |
/* |
211 |
-- cmdline settings |
212 |
-- return: # of args read |
213 |
*/ |
214 |
|
215 |
int cmdlineModule_ResultOutput(SWISH * sw, char opt, char **args) |
216 |
{ |
217 |
|
218 |
//$$$ still to do... |
219 |
//$$$ move code from swish.c |
220 |
return 0; /* quiet a warning */ |
221 |
|
222 |
|
223 |
} |
224 |
|
225 |
|
226 |
|
227 |
|
228 |
/* |
229 |
** ---------------------------------------------- |
230 |
** |
231 |
** Module code starts here |
232 |
** |
233 |
** ---------------------------------------------- |
234 |
*/ |
235 |
|
236 |
|
237 |
|
238 |
/* |
239 |
-- Init the print of result entry in extented output format. |
240 |
-- The parsed propertynames will be stored for result handling |
241 |
-- Only user properties will be stored. |
242 |
-- Routine has to be executed prior to search/result storing... |
243 |
-- (This behavior is for historic reasons and may change) |
244 |
-- ($$ this routine may build the print action list in the future...) |
245 |
2001-02-07 rasc |
246 |
*/ |
247 |
|
248 |
void initPrintExtResult(SWISH * sw, char *fmt) |
249 |
{ |
250 |
FILE *f; |
251 |
char *propname; |
252 |
char *subfmt; |
253 |
|
254 |
f = (FILE *) NULL; /* no output, just parsing!!! */ |
255 |
|
256 |
|
257 |
while (*fmt) |
258 |
{ /* loop fmt string */ |
259 |
|
260 |
switch (*fmt) |
261 |
{ |
262 |
|
263 |
case '%': /* swish abbrevation controls */ |
264 |
/* ignore (dummy param), because autoprop */ |
265 |
fmt = printTagAbbrevControl(sw, f, fmt, NULL); |
266 |
break; |
267 |
|
268 |
case '<': |
269 |
/* -- Property - Control: read Property Tag <name> */ |
270 |
/* -- Save User PropertyNames for result handling */ |
271 |
// Oct 16, 2001 - moseley: Seem like this should lookup the property |
272 |
// and error if not found, plus, it should cache the propID to avoid lookups |
273 |
// when returning results. Would parse the -x format for each index. |
274 |
fmt = parsePropertyResultControl(fmt, &propname, &subfmt); |
275 |
|
276 |
efree(subfmt); |
277 |
efree(propname); |
278 |
break; |
279 |
|
280 |
case '\\': /* format controls */ |
281 |
fmt = printResultControlChar(f, fmt); |
282 |
break; |
283 |
|
284 |
|
285 |
default: /* a output character in fmt string */ |
286 |
fmt++; |
287 |
break; |
288 |
} |
289 |
|
290 |
} |
291 |
|
292 |
} |
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
/* ------------------------------------------------------------ */ |
299 |
|
300 |
|
301 |
|
302 |
|
303 |
/* |
304 |
-- Output the resuult entries in the given order |
305 |
-- outputformat depends on some cmd opt settings |
306 |
This frees memory as it goes along, so this can't be called from the library. |
307 |
*/ |
308 |
|
309 |
void printSortedResults(SWISH * sw) |
310 |
{ |
311 |
struct MOD_ResultOutput *md = sw->ResultOutput; |
312 |
RESULT *r = NULL; |
313 |
FileRec *fi; |
314 |
int resultmaxhits; |
315 |
int resultbeginhits; |
316 |
int counter; |
317 |
char *delimiter; |
318 |
FILE *f_out; |
319 |
|
320 |
|
321 |
f_out = stdout; |
322 |
resultmaxhits = sw->Search->maxhits; |
323 |
resultbeginhits = (sw->Search->beginhits > 0) ? sw->Search->beginhits - 1 : 0; |
324 |
delimiter = (md->stdResultFieldDelimiter) ? md->stdResultFieldDelimiter : " "; |
325 |
counter = resultbeginhits; |
326 |
|
327 |
|
328 |
/* jmruiz 02/2001 SwishSeek is faster because it does not read the |
329 |
** unused data */ |
330 |
SwishSeek(sw, resultbeginhits); |
331 |
|
332 |
|
333 |
/* -- resultmaxhits: >0 or -1 (all hits) */ |
334 |
while ((r = SwishNext(sw)) && (resultmaxhits != 0)) |
335 |
{ |
336 |
fi = &r->fi; /* get address of FileRec to store properties and pointers */ |
337 |
|
338 |
r->count = ++counter; /* set rec. counter for output */ |
339 |
|
340 |
|
341 |
/* This may or may not be an optimization */ |
342 |
// not really any more -- used to be able to read all the props, now this just reads them using ReadSingle... |
343 |
// ReadAllDocPropertiesFromDisk( sw, r->indexf, r->filenum); |
344 |
|
345 |
|
346 |
if (md->extendedformat) |
347 |
printExtResultEntry(sw, f_out, md->extendedformat, r); |
348 |
|
349 |
else |
350 |
{ |
351 |
char *format; |
352 |
|
353 |
if ((delimiter = (md->stdResultFieldDelimiter)) ) |
354 |
{ |
355 |
format = emalloc( (3* strlen( delimiter )) + 100 ); |
356 |
sprintf( format, "%%r%s%%p%s%%t%s%%l", delimiter, delimiter, delimiter ); |
357 |
} |
358 |
else |
359 |
format = estrdup( "%r %p \"%t\" %l" ); |
360 |
|
361 |
printExtResultEntry(sw, f_out, format, r); |
362 |
printStandardResultProperties(sw, f_out, r); |
363 |
|
364 |
fprintf(f_out, "\n"); |
365 |
efree( format ); |
366 |
} |
367 |
|
368 |
|
369 |
/* might as well free the memory as we go */ |
370 |
freefileinfo( fi ); |
371 |
|
372 |
if (resultmaxhits > 0) |
373 |
resultmaxhits--; |
374 |
} |
375 |
|
376 |
} |
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 |
/* |
383 |
-- print a result entry in extented output format |
384 |
-- Format characters: see switch cases... |
385 |
-- f_out == NULL, use STDOUT |
386 |
-- fmt = output format |
387 |
-- count = current result record counter |
388 |
2001-01-01 rasc |
389 |
*/ |
390 |
|
391 |
static void printExtResultEntry(SWISH * sw, FILE * f_out, char *fmt, RESULT * r) |
392 |
{ |
393 |
FILE *f; |
394 |
char *propname; |
395 |
char *subfmt; |
396 |
|
397 |
|
398 |
f = (f_out) ? f_out : stdout; |
399 |
|
400 |
while (*fmt) |
401 |
{ /* loop fmt string */ |
402 |
|
403 |
switch (*fmt) |
404 |
{ |
405 |
|
406 |
case '%': /* swish abbrevation controls */ |
407 |
fmt = printTagAbbrevControl(sw, f, fmt, r); |
408 |
break; |
409 |
|
410 |
case '<': |
411 |
/* Property - Control: read and print Property Tag <name> */ |
412 |
fmt = parsePropertyResultControl(fmt, &propname, &subfmt); |
413 |
printPropertyResultControl(sw, f, propname, subfmt, r); |
414 |
efree(subfmt); |
415 |
efree(propname); |
416 |
break; |
417 |
|
418 |
case '\\': /* print format controls */ |
419 |
fmt = printResultControlChar(f, fmt); |
420 |
break; |
421 |
|
422 |
|
423 |
default: /* just output the character in fmt string */ |
424 |
if (f) |
425 |
fputc(*fmt, f); |
426 |
fmt++; |
427 |
break; |
428 |
} |
429 |
|
430 |
} |
431 |
|
432 |
|
433 |
} |
434 |
|
435 |
|
436 |
|
437 |
|
438 |
|
439 |
|
440 |
|
441 |
/* -- parse print control and print it |
442 |
-- output on file <f> |
443 |
-- *s = "\....." |
444 |
-- return: string ptr to char after control sequence. |
445 |
*/ |
446 |
|
447 |
static char *printResultControlChar(FILE * f, char *s) |
448 |
{ |
449 |
char c, |
450 |
*se; |
451 |
|
452 |
if (*s != '\\') |
453 |
return s; |
454 |
|
455 |
c = charDecode_C_Escape(s, &se); |
456 |
if (f) |
457 |
fputc(c, f); |
458 |
return se; |
459 |
} |
460 |
|
461 |
|
462 |
|
463 |
|
464 |
|
465 |
/* -- parse % control and print it |
466 |
-- in fact expand shortcut to fullnamed autoproperty tag |
467 |
-- output on file <f>, NULL = parse only mode |
468 |
-- *s = "%..... |
469 |
-- return: string ptr to char after control sequence. |
470 |
*/ |
471 |
|
472 |
static char *printTagAbbrevControl(SWISH * sw, FILE * f, char *s, RESULT * r) |
473 |
{ |
474 |
char *t; |
475 |
char buf[MAXWORDLEN]; |
476 |
|
477 |
if (*s != '%') |
478 |
return s; |
479 |
t = NULL; |
480 |
|
481 |
switch (*(++s)) |
482 |
{ |
483 |
case 'c': |
484 |
t = AUTOPROPERTY_REC_COUNT; |
485 |
break; |
486 |
case 'd': |
487 |
t = AUTOPROPERTY_SUMMARY; |
488 |
break; |
489 |
case 'D': |
490 |
t = AUTOPROPERTY_LASTMODIFIED; |
491 |
break; |
492 |
case 'I': |
493 |
t = AUTOPROPERTY_INDEXFILE; |
494 |
break; |
495 |
case 'p': |
496 |
t = AUTOPROPERTY_DOCPATH; |
497 |
break; |
498 |
case 'r': |
499 |
t = AUTOPROPERTY_RESULT_RANK; |
500 |
break; |
501 |
case 'l': |
502 |
t = AUTOPROPERTY_DOCSIZE; |
503 |
break; |
504 |
case 'S': |
505 |
t = AUTOPROPERTY_STARTPOS; |
506 |
break; |
507 |
case 't': |
508 |
t = AUTOPROPERTY_TITLE; |
509 |
break; |
510 |
|
511 |
case '%': |
512 |
if (f) |
513 |
fputc('%', f); |
514 |
break; |
515 |
default: |
516 |
progerr("Formatstring: unknown abbrev '%%%c'", *s); |
517 |
break; |
518 |
|
519 |
} |
520 |
|
521 |
if (t) |
522 |
{ |
523 |
sprintf(buf, "<%s>", t); /* create <...> tag */ |
524 |
if (f) |
525 |
printExtResultEntry(sw, f, buf, r); |
526 |
else |
527 |
initPrintExtResult(sw, buf); /* parse only ! */ |
528 |
} |
529 |
return ++s; |
530 |
} |
531 |
|
532 |
|
533 |
|
534 |
|
535 |
/* -- parse <tag fmt="..."> control |
536 |
-- *s = "<....." format control string |
537 |
-- possible subformat: fmt="...", fmt=/..../, etc. |
538 |
-- return: string ptr to char after control sequence. |
539 |
-- **propertyname = Tagname (or NULL) |
540 |
-- **subfmt = NULL or subformat |
541 |
*/ |
542 |
|
543 |
static char *parsePropertyResultControl(char *s, char **propertyname, char **subfmt) |
544 |
{ |
545 |
char *s1; |
546 |
char c; |
547 |
int len; |
548 |
|
549 |
|
550 |
*propertyname = NULL; |
551 |
*subfmt = NULL; |
552 |
|
553 |
s = str_skip_ws(s); |
554 |
if (*s != '<') |
555 |
return s; |
556 |
s = str_skip_ws(++s); |
557 |
|
558 |
|
559 |
/* parse propertyname */ |
560 |
|
561 |
s1 = s; |
562 |
while (*s) |
563 |
{ /* read to end of propertyname */ |
564 |
if ((*s == '>') || isspace((unsigned char) *s)) |
565 |
{ /* delim > or whitespace ? */ |
566 |
break; /* break on delim */ |
567 |
} |
568 |
s++; |
569 |
} |
570 |
len = s - s1; |
571 |
*propertyname = (char *) emalloc(len + 1); |
572 |
strncpy(*propertyname, s1, len); |
573 |
*(*propertyname + len) = '\0'; |
574 |
|
575 |
|
576 |
if (*s == '>') |
577 |
return ++s; /* no fmt, return */ |
578 |
s = str_skip_ws(s); |
579 |
|
580 |
|
581 |
/* parse optional fmt=<c>...<c> e.g. fmt="..." */ |
582 |
|
583 |
if (!strncmp(s, "fmt=", 4)) |
584 |
{ |
585 |
s += 4; /* skip "fmt=" */ |
586 |
c = *(s++); /* string delimiter */ |
587 |
s1 = s; |
588 |
while (*s) |
589 |
{ /* read to end of delim. char */ |
590 |
if (*s == c) |
591 |
{ /* c or \c */ |
592 |
if (*(s - 1) != '\\') |
593 |
break; /* break on delim c */ |
594 |
} |
595 |
s++; |
596 |
} |
597 |
|
598 |
len = s - s1; |
599 |
*subfmt = (char *) emalloc(len + 1); |
600 |
strncpy(*subfmt, s1, len); |
601 |
*(*subfmt + len) = '\0'; |
602 |
} |
603 |
|
604 |
|
605 |
/* stupid "find end of tag" */ |
606 |
|
607 |
while (*s && *s != '>') |
608 |
s++; |
609 |
if (*s == '>') |
610 |
s++; |
611 |
|
612 |
return s; |
613 |
} |
614 |
|
615 |
|
616 |
|
617 |
|
618 |
/* |
619 |
-- Print the result value of propertytag <name> on file <f> |
620 |
-- if a format is given use it (data type dependend) |
621 |
-- string and numeric types are using printfcontrols formatstrings |
622 |
-- date formats are using strftime fromat strings. |
623 |
*/ |
624 |
|
625 |
|
626 |
static void printPropertyResultControl(SWISH * sw, FILE * f, char *propname, char *subfmt, RESULT * r) |
627 |
{ |
628 |
char *fmt; |
629 |
PropValue *pv; |
630 |
char *s; |
631 |
int n; |
632 |
|
633 |
|
634 |
pv = getResultPropValue(sw, r, propname, 0); |
635 |
|
636 |
if (!pv) |
637 |
{ |
638 |
if (f) |
639 |
fprintf(f, "(NULL)"); /* Null value, no propname */ |
640 |
return; |
641 |
} |
642 |
|
643 |
#ifdef USE_DOCPATH_AS_TITLE |
644 |
if ( strcmp( AUTOPROPERTY_TITLE, propname ) == 0 && strcmp( "", pv->value.v_str ) == 0 ) |
645 |
{ |
646 |
char *c; |
647 |
efree( pv ); |
648 |
pv = getResultPropValue(sw, r, AUTOPROPERTY_DOCPATH, 0); |
649 |
|
650 |
/* Just display the base name */ |
651 |
if ( pv ) |
652 |
{ |
653 |
c = estrdup( str_basename( pv->value.v_str ) ); |
654 |
efree( pv->value.v_str ); |
655 |
pv->value.v_str = c; |
656 |
} |
657 |
} |
658 |
#endif |
659 |
|
660 |
|
661 |
|
662 |
|
663 |
switch (pv->datatype) |
664 |
{ |
665 |
/* use passed or default fmt */ |
666 |
|
667 |
case PROP_INTEGER: |
668 |
fmt = (subfmt) ? subfmt : "%d"; |
669 |
if (f) |
670 |
fprintf(f, fmt, pv->value.v_int); |
671 |
break; |
672 |
|
673 |
case PROP_ULONG: |
674 |
fmt = (subfmt) ? subfmt : "%lu"; |
675 |
if (f) |
676 |
fprintf(f, fmt, pv->value.v_ulong); |
677 |
break; |
678 |
|
679 |
|
680 |
|
681 |
case PROP_STRING: |
682 |
fmt = (subfmt) ? subfmt : "%s"; |
683 |
|
684 |
/* -- get rid of \n\r in string! */ // there shouldn't be any in the first place, I believe |
685 |
for (s = pv->value.v_str; *s; s++) |
686 |
{ |
687 |
if (isspace((unsigned char) *s)) |
688 |
*s = ' '; |
689 |
} |
690 |
|
691 |
/* $$$ ToDo: escaping of delimiter characters $$$ */ |
692 |
/* $$$ Also ToDo, escapeHTML entities (need config directive) */ |
693 |
|
694 |
if (f) |
695 |
fprintf(f, fmt, (char *) pv->value.v_str); |
696 |
|
697 |
break; |
698 |
|
699 |
|
700 |
case PROP_DATE: |
701 |
fmt = (subfmt) ? subfmt : "%Y-%m-%d %H:%M:%S %Z"; |
702 |
if (!strcmp(fmt, "%ld")) |
703 |
{ |
704 |
/* special: Print date as serial int (for Bill) */ |
705 |
if (f) |
706 |
fprintf(f, fmt, (long) pv->value.v_date); |
707 |
} |
708 |
else |
709 |
{ |
710 |
/* fmt is strftime format control! */ |
711 |
s = (char *) emalloc(MAXWORDLEN + 1); |
712 |
n = strftime(s, (size_t) MAXWORDLEN, fmt, localtime(&(pv->value.v_date))); |
713 |
if (n && f) |
714 |
fprintf(f, s); |
715 |
efree(s); |
716 |
} |
717 |
break; |
718 |
|
719 |
case PROP_FLOAT: |
720 |
fmt = (subfmt) ? subfmt : "%f"; |
721 |
if (f) |
722 |
fprintf(f, fmt, (double) pv->value.v_float); |
723 |
break; |
724 |
|
725 |
default: |
726 |
fprintf(stdout, "err:(unknown datatype <%s>)\n", propname); |
727 |
break; |
728 |
|
729 |
|
730 |
} |
731 |
freeResultPropValue(pv); |
732 |
} |
733 |
|
734 |
|
735 |
|
736 |
/* |
737 |
------------------------------------------- |
738 |
Result config stuff |
739 |
------------------------------------------- |
740 |
*/ |
741 |
|
742 |
|
743 |
/* |
744 |
-- some code for -x fmtByName: |
745 |
-- e.g. ResultExtendedFormat myformat "<swishtitle>|....\n" |
746 |
-- ResultExtendedFormat yourformat "%c|%t|%p|<author fmt=/%20s/>\n" |
747 |
-- |
748 |
-- swish -w ... -x myformat ... |
749 |
-- |
750 |
-- 2001-02-15 rasc |
751 |
*/ |
752 |
|
753 |
|
754 |
/* |
755 |
-- add name and string to list |
756 |
*/ |
757 |
|
758 |
static struct ResultExtFmtStrList *addResultExtFormatStr(struct ResultExtFmtStrList *rp, char *name, char *fmtstr) |
759 |
{ |
760 |
struct ResultExtFmtStrList *newnode; |
761 |
|
762 |
|
763 |
newnode = (struct ResultExtFmtStrList *) emalloc(sizeof(struct ResultExtFmtStrList)); |
764 |
|
765 |
newnode->name = (char *) estrdup(name); |
766 |
newnode->fmtstr = (char *) estrdup(fmtstr); |
767 |
|
768 |
newnode->next = NULL; |
769 |
|
770 |
if (rp == NULL) |
771 |
rp = newnode; |
772 |
else |
773 |
rp->nodep->next = newnode; |
774 |
|
775 |
rp->nodep = newnode; |
776 |
return rp; |
777 |
} |
778 |
|
779 |
|
780 |
|
781 |
/* |
782 |
-- check if name is a predefined format |
783 |
-- case sensitive |
784 |
-- return fmtstring for formatname or NULL |
785 |
*/ |
786 |
|
787 |
|
788 |
char *hasResultExtFmtStr(SWISH * sw, char *name) |
789 |
{ |
790 |
struct ResultExtFmtStrList *rfl; |
791 |
|
792 |
rfl = sw->ResultOutput->resultextfmtlist; |
793 |
if (!rfl) |
794 |
return (char *) NULL; |
795 |
|
796 |
while (rfl) |
797 |
{ |
798 |
if (!strcmp(name, rfl->name)) |
799 |
return rfl->fmtstr; |
800 |
rfl = rfl->next; |
801 |
} |
802 |
|
803 |
return (char *) NULL; |
804 |
} |
805 |
|
806 |
|
807 |
|
808 |
|
809 |
|
810 |
/* |
811 |
------------------------------------------- |
812 |
result header stuff |
813 |
------------------------------------------- |
814 |
*/ |
815 |
|
816 |
|
817 |
|
818 |
|
819 |
/* |
820 |
-- print a line for the result output header |
821 |
-- the verbose level is checked for output |
822 |
-- <min_verbose> has to be >= sw->...headerOutVerbose |
823 |
-- outherwise nothing is outputted |
824 |
-- return: 0/1 (not printed/printed) |
825 |
-- 2001-03-13 rasc |
826 |
*/ |
827 |
|
828 |
int resultHeaderOut(SWISH * sw, int min_verbose, char *printfmt, ...) |
829 |
{ |
830 |
va_list args; |
831 |
|
832 |
/* min_verbose to low, no output */ |
833 |
if (min_verbose > sw->ResultOutput->headerOutVerbose) |
834 |
return 0; |
835 |
|
836 |
/* print header info... */ |
837 |
va_start(args, printfmt); |
838 |
vfprintf(stdout, printfmt, args); |
839 |
va_end(args); |
840 |
return 1; |
841 |
} |
842 |
|
843 |
|
844 |
|
845 |
|
846 |
/* |
847 |
-- print a standard result header (according to -H <n>) |
848 |
-- for the header of an index file |
849 |
*/ |
850 |
|
851 |
void resultPrintHeader(SWISH * sw, int min_verbose, INDEXDATAHEADER * h, char *pathname, int merged) |
852 |
{ |
853 |
char *fname; |
854 |
int v; |
855 |
|
856 |
v = min_verbose; |
857 |
fname = str_basename(pathname); |
858 |
|
859 |
resultHeaderOut(sw, v, "%s\n", INDEXVERSION); |
860 |
/* why the blank merge header? */ |
861 |
resultHeaderOut(sw, v, "# %s\n", (merged) ? "MERGED INDEX" : ""); |
862 |
resultHeaderOut(sw, v, "%s %s\n", NAMEHEADER, (h->indexn[0] == '\0') ? "(no name)" : h->indexn); |
863 |
resultHeaderOut(sw, v, "%s %s\n", SAVEDASHEADER, fname); |
864 |
resultHeaderOut(sw, v, "%s %d words, %d files\n", COUNTSHEADER, h->totalwords, h->totalfiles); |
865 |
resultHeaderOut(sw, v, "%s %s\n", INDEXEDONHEADER, h->indexedon); |
866 |
resultHeaderOut(sw, v, "%s %s\n", DESCRIPTIONHEADER, (h->indexd[0] == '\0') ? "(no description)" : h->indexd); |
867 |
resultHeaderOut(sw, v, "%s %s\n", POINTERHEADER, (h->indexp[0] == '\0') ? "(no pointer)" : h->indexp); |
868 |
resultHeaderOut(sw, v, "%s %s\n", MAINTAINEDBYHEADER, (h->indexa[0] == '\0') ? "(no maintainer)" : h->indexa); |
869 |
resultHeaderOut(sw, v, "%s %s\n", DOCPROPENHEADER, "Enabled"); |
870 |
|
871 |
|
872 |
resultHeaderOut(sw, v, "%s %d\n", STEMMINGHEADER, h->fuzzy_mode == FUZZY_STEMMING ? 1 : 0 ); |
873 |
resultHeaderOut(sw, v, "%s %d\n", SOUNDEXHEADER, h->fuzzy_mode == FUZZY_SOUNDEX ? 1 : 0 ); |
874 |
resultHeaderOut(sw, v, "%s %s\n", FUZZYMODE_HEADER, fuzzy_mode_to_string( h->fuzzy_mode ) ); |
875 |
|
876 |
|
877 |
resultHeaderOut(sw, v, "%s %d\n", IGNORETOTALWORDCOUNTWHENRANKING, h->ignoreTotalWordCountWhenRanking); |
878 |
resultHeaderOut(sw, v, "%s %s\n", WORDCHARSHEADER, h->wordchars); |
879 |
resultHeaderOut(sw, v, "%s %d\n", MINWORDLIMHEADER, h->minwordlimit); |
880 |
resultHeaderOut(sw, v, "%s %d\n", MAXWORDLIMHEADER, h->maxwordlimit); |
881 |
resultHeaderOut(sw, v, "%s %s\n", BEGINCHARSHEADER, h->beginchars); |
882 |
resultHeaderOut(sw, v, "%s %s\n", ENDCHARSHEADER, h->endchars); |
883 |
resultHeaderOut(sw, v, "%s %s\n", IGNOREFIRSTCHARHEADER, h->ignorefirstchar); |
884 |
resultHeaderOut(sw, v, "%s %s\n", IGNORELASTCHARHEADER, h->ignorelastchar); |
885 |
/* |
886 |
resultHeaderOut (sw,v, "%s %d\n", FILEINFOCOMPRESSION, h->applyFileInfoCompression); |
887 |
*/ |
888 |
translatecharHeaderOut(sw, v, h); |
889 |
|
890 |
|
891 |
return; |
892 |
} |