dtsr: Coverity fixes for string buffer issues
[oweals/cde.git] / cde / programs / dtsr / dtsrhan.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  *   COMPONENT_NAME: austext
25  *
26  *   FUNCTIONS: cleanup
27  *              flag_shutdown
28  *              is_blank
29  *              is_count
30  *              is_time
31  *              is_whitespace
32  *              main
33  *              mmm_to_digits
34  *              my_strtok
35  *              new_rec
36  *              open_outfile
37  *              process_infile
38  *              process_profile
39  *              process_record
40  *              segregate_dicname
41  *              token
42  *              usage_msg
43  *              user_arg_processor
44  *              validate_id
45  *              write_record
46  *
47  *   ORIGINS: 27
48  *
49  *
50  *   (C) COPYRIGHT International Business Machines Corp. 1993,1996
51  *   All Rights Reserved
52  *   Licensed Materials - Property of IBM
53  *   US Government Users Restricted Rights - Use, duplication or
54  *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
55  */
56 /************** DTSRHAN.C ***************
57  * $XConsortium: dtsrhan.c /main/9 1996/09/23 21:02:27 cde-ibm $
58  * Oct 1993.
59  * Modification of handel.c for CDE system.
60  * Converts free form text in accordance with a profile file
61  * into a formal .fzk file.
62  *
63  * $Log$
64  * Revision 2.8  1996/04/10  22:55:27  miker
65  * Removed ref to BETA.
66  *
67  * Revision 2.7  1996/04/10  19:48:52  miker
68  * Added support for null dates.
69  *
70  * Revision 2.6  1996/03/25  18:53:56  miker
71  * Changed FILENAME_MAX to _POSIX_PATH_MAX.
72  *
73  * Revision 2.5  1996/02/01  18:20:02  miker
74  * Changed parser/stemmer calls to new readchar format.
75  *
76  * Revision 2.4  1995/11/07  17:51:46  miker
77  * Fixed bug in progress dot processing.
78  * Added rec count to err msgs to facilitate finding bad recs.
79  *
80  * Revision 2.3  1995/10/25  18:57:27  miker
81  * Renamed from chandel.c.  Added prolog.
82  *
83  * Log: chandel.c,v
84  * Revision 2.2  1995/10/02  20:00:51  miker
85  * Added semantic analysis so original handel.c no longer required.
86  *
87  * Revision 2.1  1995/09/22  19:20:45  miker
88  * Freeze DtSearch 0.1, AusText 2.1.8
89  *
90  * Revision 1.7  1995/09/19  21:49:22  miker
91  * ifdef DTSEARCH, use DtSrVERSION instead of AUSAPI_VERSION in banner.
92  *
93  * Revision 1.6  1995/08/31  22:15:33  miker
94  * Added MMM fields for date processing like handel.c.
95  * Minor changes for DtSearch, mostly msg sets changes..
96  * Executable module renamed dtsrload for DtSearch.
97  *
98  * Revision 1.5  1995/06/08  00:32:43  miker
99  * 2.1.5f: Bug fix.  Segfault if constant string not enclosed in quotes.
100  * Enable negative field offsets.
101  */
102 #include "SearchP.h"
103 #include <limits.h>
104 #include <string.h>
105 #include <stdlib.h>
106 #include <errno.h>
107 #include <ctype.h>
108 #include <signal.h>
109 #include <time.h>
110 #include <locale.h>
111
112 #define PROGNAME        "DTSRHAN"
113 #define MS_chandel      5
114 #define RECS_PER_DOT    10L
115
116 /*-- Numerical codes for storing "undefined items" --*/
117 #define UNDEFINED 0
118 #define ANY -999
119
120 /*-- Codes for "modes" of text buffering --*/
121 #define INCLUDE 1
122 #define EXCLUDE 2
123 #define SET 3
124 #define CLEAR 4
125 #define DEFAULT 5
126 #define NONE 6
127
128 /*-- codes for abstract mode --*/
129 #define FIELDS 2
130 #define USER 3
131 #define GENERATE 4
132
133 /*-- Exit codes for errors --*/
134 #define USAGE 2
135 #define FILE_ERROR 3
136 #define SYNTAX_ERROR 4
137 #define BAD_ID 5
138 #define BAD_DIC 6
139 #define BAD_PROFILE 7
140 #define CRIT 9
141
142 /*-- Token types --*/
143 #define UNKNOWN 999
144 #define LINE 1
145 #define FIELD 2
146 #define TEXT 3
147 /****#define WORDS 4*****/
148 #define IMAGE 5
149 #define KEY 6
150 #define ABSTR 7
151 #define KEYCHAR 8
152 #define DELIMITER 9
153 #define TEXTINCLUDE 10
154 #define TEXTEXCLUDE 11
155 #define TFIELDINCLUDE 12
156 #define TFIELDEXCLUDE 13
157 #define DELBLANKLINES 14
158 #define IMAGEINCLUDE 15
159 #define IMAGEEXCLUDE 16
160 #define DISCARD 17
161 #define CONSTANT 18
162 #define UPPER 19
163 #define DATEFLD 20
164
165 /*-- General Defines --*/
166 #define EOLN -999
167 #define EOW -998
168 #define CNTRL_L 12
169 #define MAX_ALPHABET_SIZE 256
170
171 /*-- definitions of various data structures --*/
172 struct line_comp {              /*-- Individual components for line ids --*/
173     int             column_number;
174     char            text[80];
175     int             d[MAX_ALPHABET_SIZE];
176     int             text_length;
177     struct line_comp *next;
178 };
179
180 struct line_id {                /*-- list of line ids to be handled     --*/
181     char            name[80];
182     struct line_comp *comp;
183     struct line_comp *head;
184     struct line_id *next;
185     struct rec     *line;
186     int             word_action;
187     int             text_action;
188     int             image_action;
189 };
190
191 struct field_id {               /*-- list of field ids to be used       --*/
192     struct field_id *next;
193     char            name[80];
194     struct line_id *line;
195     int             offset;
196     int             defined_length;
197     int             length;
198     char            text[80];
199     int             d[MAX_ALPHABET_SIZE];
200     int             text_length;
201     char            value[80];
202     int             word_action;
203     int             text_action;
204     int             image_action;
205     char            line_id[80];
206     int             constant;
207     int             is_month;
208 };
209
210 struct rec {                    /*-- holds a complete image of a record --*/
211     struct rec     *next;
212     struct line_id *line;
213     int             line_num;
214     char            text[200];
215 };
216
217 struct date_id {
218     char            field_id[80];
219     struct date_id *next;
220     struct field_id *field;
221 };
222
223 struct key_id {
224     char            field_id[80];
225     struct key_id  *next;
226     struct field_id *field;
227 };
228
229 struct finclude {
230     char            field_id[80];
231     int             value;
232     struct finclude *next;
233 };
234
235 struct include {
236     char            line_id[80];
237     int             value;
238     struct include *next;
239 };
240
241 /************************************************/
242 /*                                              */
243 /*                   GLOBALS                    */
244 /*                                              */
245 /************************************************/
246 char            abstracter[100];
247 int             abstract =              GENERATE;
248 struct key_id  *abstract_table =        NULL;
249 /***nl_catd             dtsearch_catd = (nl_catd) -1;***/
250 int             bad_parm =              FALSE;
251 int             bad_profile =           FALSE;
252 int             bot_defined =           FALSE;
253 struct date_id *date_table =            NULL;
254 int             date_pos_defined =      FALSE;
255 static char    *del_string =            " +=,\t\n";
256 /****static char    *del_string = " +-=,\t\n";**allow neg nums***/
257 int             del_blanklines =        FALSE;
258 char            dicname[10] =           {0};
259 char            dicpath[_POSIX_PATH_MAX] =      {0};
260 int             discard =               TRUE;
261 int             discard_record =        FALSE;
262 struct finclude *finclude_tab =         NULL;
263 struct field_id *field_table =          NULL;
264 struct include *i_i_t =                 NULL;
265 int             imagemode =             INCLUDE;
266 int             imageflag =             INCLUDE;
267 struct include *include_tab =           NULL;
268 char           *infile;
269 static FILE    *instream =              NULL;
270 static long     key_count =             0;
271 struct key_id  *key_table =             NULL;
272 int             key_defined =           FALSE;
273 int             key_pos_defined =       FALSE;
274 char            key_char;
275 char            key_value[80];
276 static char    *line_mode =             "\f\ 2\ 6CTHULHU TOCOMA ZYYXY UTOPIA";
277 struct line_id *line_table =            NULL;
278 time_t          now;
279 char            now_str[24];
280 struct tm       nowtm;
281 static int      null_date_specified =   FALSE;
282 struct tm      *objdate_tmptr;
283 int             outcount =              0;
284 char            outmode[8] =            "w";
285 int             outmode_specified =     FALSE;
286 char           *outfile;
287 static FILE    *outstream =             NULL;
288 char           *profile;
289 static long     rec_count =             0L;     /* for err msgs */
290 struct rec     *record_head =           NULL;
291 struct tm       rectm;
292 int             screen_width =          79;
293 int             shutdown_now =          FALSE;
294 int             started =               FALSE;
295 int             textflag =              INCLUDE;
296 int             textmode =              INCLUDE;
297 int             top_defined =           FALSE;
298 struct line_id *top_rec;
299 char            top_rec_name[80];
300 int             uppercase =             FALSE;
301 int             uninit_line =           TRUE;
302 int             uninit_field =          TRUE;
303 int             warnings =              TRUE;
304 int             wordmode =              INCLUDE;
305
306
307 /****************************************************************
308     VALIDATE_ID - validates an indentifier (first character a
309 letter, then alpha-numeric, etc)
310 ****************************************************************/
311 int             validate_id (char *s)
312 {
313     int             i;
314
315     if (s==NULL)
316         return FALSE;
317     if (!isalpha (s[0])) {
318         return FALSE;
319     }
320     for (i = 1; i < strlen (s); i++)
321         if (!isalnum (s[i]) && s[i] != '_') {
322             return FALSE;
323         }
324     return TRUE;
325 }
326
327
328 /****************************************************************
329    OPEN_OUTFILE - open outputfile - if the file already exists,
330   and no mode was specified by the user, ask the user what to do.
331 ****************************************************************/
332 void            open_outfile ()
333 {
334     FILE           *temp;
335     int             i;
336
337     if (!outmode_specified)
338         if ((temp = fopen (outfile, "r")) != NULL) {
339             fclose (temp);
340             printf ( catgets(dtsearch_catd, MS_chandel, 3,
341                 "Output file '%s' already exists.\n") ,
342                 outfile);
343             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 4,
344                 "Append, overwrite, or quit? [a,o,q] ") );
345             i = tolower (getchar ());
346
347             if (i == 'a')
348                 strcpy (outmode, "a");
349             else if (i == 'o')
350                 strcpy (outmode, "w");
351             else
352                 exit (FILE_ERROR);
353         }
354     if (!strcmp (outfile, "-"))
355         outstream = stdout;
356     else {
357         if ((outstream = fopen (outfile, outmode)) == NULL) {
358             printf ( catgets(dtsearch_catd, MS_chandel, 7,
359                 "Unable to open output file '%s'.\n") , outfile);
360             exit (FILE_ERROR);
361         }
362     }
363     return;
364 }  /* open_outfile */
365
366
367 /****************************************************************
368     IS_TIME - returns TRUE if the passed string contains the
369 string "time" in any case (upper/lower) - without destroying the
370 original string, in case it was a field name.
371 ****************************************************************/
372 int             is_time (char *orig)
373 {
374     char           *s;
375     int             i;
376     /* copy original string to temp buffer, so we can manipulate */
377     s = (char *) malloc (sizeof (char) * strlen (orig) +5);
378     strcpy (s, orig);
379     for (i = 0; i < strlen (s); i++)
380         s[i] = tolower (s[i]);
381
382     if (strcmp (s, "time") == 0)
383         return TRUE;
384     else
385         return FALSE;
386 }
387
388 /****************************************************************
389     IS_COUNT - returns TRUE if the passed string contains the
390 string "count" in any case (upper/lower) - without destroying the
391 original string, in case it was a field name.
392 ****************************************************************/
393 int             is_count (char *orig)
394 {
395     char           *s;
396     int             i;
397     /* copy original string to temp buffer, so we can manipulate */
398     s = (char *) malloc (sizeof(char) * strlen(orig) +5);
399     strcpy (s, orig);
400     for (i = 0; i < strlen (s); i++)
401         s[i] = tolower (s[i]);
402
403     if (strcmp (s, "count") == 0)
404         return TRUE;
405     else
406         return FALSE;
407 }
408
409 /****************************************************************
410     MY_STRTOK - my own version of strtok - why? Because I need
411 a little flexibility when parsing out the string component -
412 what if it has quotes embedded? 
413
414 s1 = the line to be parsed (= start at beginning)
415         or NULL (= start where we last left off).
416
417 s2 = the 'delete' string or array of token separators.
418         Usually it is either the global 'del_string' (" +-=,\t\n")
419         or a string consisting of a single double-quote char.
420 ****************************************************************/
421 char           *my_strtok (char *s1, const char *s2)
422 {
423     char           *sbegin, *send;
424     static char     stringbuf[100];
425     static char    *ssave = "";
426     int             i = 0;
427
428     memset (stringbuf, 0, sizeof(stringbuf));
429     sbegin = (s1) ? s1 : ssave; /* start of string or where we last left off */
430
431     if (strcmp (s2, "\"") == 0) {       /* parsing for a string */
432         if (*sbegin == '\0') {
433             ssave = "";
434             return NULL;
435         }
436         while (*sbegin != '"' && *sbegin != '\0') {/*-- look for first " --*/
437             sbegin++;
438         }
439         if (*sbegin == '\0') {
440             ssave = "";
441             return NULL;
442         }
443         sbegin++;               /*-- skip past "      --*/
444         i = 0;
445         while (*sbegin != '"') {/*-- until other "    --*/
446             if (*sbegin == '\\')        /*-- escape sequence  --*/
447                 sbegin++;
448             if (*sbegin == '\0') {      /*-- end of line  --*/
449                 ssave = "";
450                 return NULL;
451             }
452             stringbuf[i++] = (*sbegin);
453             sbegin++;
454         }
455         send = sbegin;
456         *send++ = '\0';
457         ssave = send;
458         stringbuf[i] = 0;
459         sbegin = stringbuf;
460         return (sbegin);
461     }
462
463     else {      /* not parsing for a string */
464         sbegin += strspn (sbegin, s2);
465         if (*sbegin == '\0') {
466             ssave = "";
467             return NULL;
468         }                       /* if */
469         send = strpbrk (sbegin, s2);
470         if (*send != '\0')
471             *send++ = '\0';
472         ssave = send;
473         return (sbegin);
474     }                           /* else */
475 }                               /*-- my_strtok --*/
476
477 /****************************************************************
478     IS_BLANK - determines if a string contains nothing but
479    white space.
480 *****************************************************************/
481 int             is_blank (char *s)
482 {
483     int             i;
484     for (i = 0; i < strlen (s); i++)
485         if (!isspace (s[i]))
486             return 0;
487     return 1;
488 }                               /*-- is_blank --*/
489
490
491 /***********************************************************************
492    TOKEN - returns a numerical token for the defined identifier types
493 ************************************************************************/
494 int             token (char *s)
495 {
496     int             i;
497
498     if (s == NULL)
499         return UNKNOWN;
500
501     /*-- make token all lowercase --*/
502     for (i = 0; i < strlen (s); i++)
503         s[i] = tolower (s[i]);
504
505     if (!strcmp (s, "line"))
506         return LINE;
507     if (!strcmp (s, "field"))
508         return FIELD;
509     if (!strcmp (s, "key"))
510         return KEY;
511     if (!strcmp (s, "date"))
512         return DATEFLD;
513     if (!strcmp (s, "text"))
514         return TEXT;
515     if (!strcmp (s, "keychar"))
516         return KEYCHAR;
517     if (!strcmp (s, "delimiter"))
518         return DELIMITER;
519     if (!strcmp (s, "textinclude"))
520         return TEXTINCLUDE;
521     if (!strcmp (s, "textexclude"))
522         return TEXTEXCLUDE;
523     if (!strcmp (s, "tfieldinclude"))
524         return TFIELDINCLUDE;
525     if (!strcmp (s, "tfieldexclude"))
526         return TFIELDEXCLUDE;
527     if (!strcmp (s, "delblanklines"))
528         return DELBLANKLINES;
529     if (!strcmp (s, "abstract"))
530         return ABSTR;
531     if (!strcmp (s, "user"))
532         return USER;
533     if (!strcmp (s, "fields"))
534         return FIELDS;
535     if (!strcmp (s, "generate"))
536         return GENERATE;
537     if (!strcmp (s, "image"))
538         return IMAGE;
539     if (!strcmp (s, "imageinclude"))
540         return IMAGEINCLUDE;
541     if (!strcmp (s, "imageexclude"))
542         return IMAGEEXCLUDE;
543     if (!strcmp (s, "discard"))
544         return DISCARD;
545     if (!strcmp (s, "constant"))
546         return CONSTANT;
547     if (!strcmp (s, "upper"))
548         return UPPER;
549     return UNKNOWN;
550 }                               /*-- token --*/
551
552 /***********************************************************************
553     PROCESS_PROFILE - process 'profile' file.
554 ************************************************************************/
555 void            process_profile ()
556 {
557     FILE           *prof;
558     char            prof_line[200];
559     int             line_num = 0;
560     int             i;
561     char           *tok;
562     struct line_id *line_current;
563     struct field_id *field_current;
564     struct key_id  *key_current;
565     struct date_id *date_current;
566     struct key_id  *abstract_current;
567     struct finclude *finclude_current;
568     struct include *include_current;
569     struct include *i_i_current;
570     int             found;
571     int             tok_type;
572
573     /*-- open file --*/
574     if ((prof = fopen (profile, "r")) == NULL) {
575         printf ( catgets(dtsearch_catd, MS_chandel, 11,
576                 "\nError - unable to open profile file '%s'.\n") , profile);
577         exit (FILE_ERROR);
578     }
579     /*-- Get next line --*/
580     do {
581         char *ret = NULL;
582         ret = fgets (prof_line, 200, prof);
583         line_num++;
584         if (ret == NULL || feof (prof) )
585             break;
586         if (prof_line[0] == '#' || is_blank (prof_line))
587             continue;
588         tok = my_strtok (prof_line, del_string);
589         if (tok == NULL)
590             continue;   /* ignore blank line */
591         tok_type = token (tok);
592         switch (tok_type) {
593             case UPPER:
594                 uppercase = TRUE;
595                 break;
596
597             case LINE:
598                 /*-- build node --*/
599                 if (line_table == NULL) {
600                     line_table = (struct line_id *) malloc (
601                         sizeof (struct line_id));
602                     line_current = line_table;
603                     line_table->next = NULL;
604                     line_table->comp = (struct line_comp *) malloc (
605                         sizeof (struct line_comp));
606                     line_table->head = line_table->comp;
607                     line_table->comp->next = NULL;
608                 }
609                 /* if */
610                 else {
611                     line_current->next = (struct line_id *) malloc (
612                         sizeof (struct line_id));
613                     line_current = line_current->next;
614                     line_current->next = NULL;
615                     line_current->comp = (struct line_comp *) malloc (
616                         sizeof (struct line_comp));
617                     line_current->head = line_current->comp;
618                     line_current->comp->next = NULL;
619                 }               /* else */
620                 line_current->image_action = NONE;
621                 line_current->word_action = NONE;
622                 line_current->text_action = NONE;
623                 line_current->line = NULL;
624                 line_current->name[0] = 0;
625                 /*-- get identifier --*/
626                 tok = my_strtok ('\0', del_string);
627                 if (validate_id (tok))
628                     strcpy (line_current->name, tok);
629                 else {
630                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
631                         "Error line %d: invalid identifier '%s'.\n") ,
632                         line_num, NULLORSTR(tok));
633                     bad_profile = TRUE;
634                     break;
635                 }
636                 /*-- get first value token --*/
637                 tok = my_strtok ('\0', del_string);
638                 if (!tok) {
639                     printf ( catgets(dtsearch_catd, MS_chandel, 13,
640                         "Error line %d - identifier '%s' missing value(s).\n") ,
641                         line_num, line_current->name);
642                     bad_profile = TRUE;
643                     continue;
644                 }               /* if */
645                 if (!strcmp (tok, "*"))
646                     line_current->comp->column_number = ANY;
647                 else
648                     line_current->comp->column_number = atoi (tok);
649                 if (line_current->comp->column_number == 0) {
650                     printf ( catgets(dtsearch_catd, MS_chandel, 14,
651                         "Error line %d - zero or bad value for '%s'.\n"
652                         "  offensive token: %s.\n") ,
653                         line_num, line_current->name, tok);
654                     bad_profile = TRUE;
655                     continue;
656                 }               /* if */
657                 /* d d d-- get second token of pair -- */
658                 tok = my_strtok ('\0', "\"");
659                 if (!tok) {
660                     if (line_current->comp->column_number == ANY) {
661                         printf ( catgets(dtsearch_catd, MS_chandel, 15,
662                         "Error line %d - for identifier '%s', column has "
663                         "been set to ANY\n  but there is no "
664                         "identifying signature string.\n") , 
665                             line_num, line_current->name);
666                         bad_profile = TRUE;
667                         continue;
668                     }
669                     /* if (line.. */
670                     else {
671                         strcpy (line_current->comp->text, line_mode);
672                         continue;
673                     }           /* else */
674                 }
675                 /* if (!tok) */
676                 else {
677                     strcpy (line_current->comp->text, tok);
678                     line_current->comp->text_length =
679                         strlen (line_current->comp->text);
680                 }
681                 /*-- check for more tokens for LINE type of line --*/
682                 for(;;) {
683                     tok = my_strtok ('\0', del_string);
684                     if (!tok)
685                         break;
686                     /*-- build component node --*/
687                     line_current->comp->next = (struct line_comp *) malloc (
688                         sizeof (struct line_comp));
689                     line_current->comp = line_current->comp->next;
690                     line_current->comp->next = NULL;
691                     /*-- check # and store --*/
692                     if (!strcmp (tok, "*"))
693                         line_current->comp->column_number = ANY;
694                     else
695                         line_current->comp->column_number = atoi (tok);
696                     if (line_current->comp->column_number == 0) {
697                         printf ( catgets(dtsearch_catd, MS_chandel, 16,
698                         "Error line %d - zero or bad value for "
699                         "identifier '%s'\n  offensive token: %s.\n") ,
700                             line_num, line_current->name, tok);
701                         bad_profile = TRUE;
702                         continue;
703                     }           /* if (line.. */
704                     /* -  --- get second of pair -- */
705                     tok = my_strtok ('\0', "\"");
706                     if (!tok) {
707                         if (line_current->comp->column_number == ANY)
708                             printf ( catgets(dtsearch_catd, MS_chandel, 15,
709                                 "Error line %d - for identifier '%s', column has "
710                                 "been set to ANY\n  but there is no "
711                                 "identifying signature string.\n") , 
712                                 line_num, line_current->name);
713                         else
714                             printf ( catgets(dtsearch_catd, MS_chandel, 18,
715                                 "Error line %d - missing value for "
716                                 "identifier '%s'\n") ,
717                                 line_num, line_current->name);
718                         bad_profile = TRUE;
719                         continue;
720                     }           /* if (!tok) */
721                     strcpy (line_current->comp->text, tok);
722                     line_current->comp->text_length =
723                         strlen (line_current->comp->text);
724                 }  /* end for(;;) loop for continuing LINE token pairs */
725                 break;  /* end case LINE */
726
727             case CONSTANT:
728             case FIELD:
729                 if (field_table == NULL) {
730                     field_table = (struct field_id *)
731                         malloc (sizeof (struct field_id));
732                     field_current = field_table;
733                     field_table->next = NULL;
734                 }
735                 else {
736                     field_current->next = (struct field_id *) malloc (
737                         sizeof (struct field_id));
738                     field_current = field_current->next;
739                     field_current->next = NULL;
740                 }
741                 memset (field_current, 0, sizeof(struct field_id));
742                 field_current->word_action = NONE;
743                 field_current->image_action = NONE;
744                 field_current->text_action = NONE;
745                 if (tok_type == CONSTANT)
746                     field_current->constant = TRUE;
747
748                 /*-- get identifier --*/
749                 tok = my_strtok ('\0', del_string);
750                 if (validate_id (tok)) {
751                     strcpy (field_current->name, tok);
752                     if (strncmp (tok, "MMM", 3) == 0)
753                         field_current->is_month = TRUE;
754                 }
755                 else {
756                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
757                         "Error line %d: invalid identifier '%s'.\n") ,
758                         line_num, NULLORSTR(tok));
759                     bad_profile = TRUE;
760                     break;
761                 }
762                 if (field_current->constant) {
763                     /*-- get constant value --*/
764                     tok = my_strtok (NULL, "\"");
765                     if (!tok) {
766                         printf ( catgets(dtsearch_catd, MS_chandel, 93,
767                             "Error line %d - '%s' string not "
768                             "enclosed in double quotes.\n"),
769                             line_num, field_current->name);
770                         bad_profile = TRUE;
771                         continue;
772                     }
773                     strcpy (field_current->value, tok);
774                 }       /* end CONSTANT */
775
776                 else {  /* ...must be FIELD */
777                     /*-- get line id --*/
778                     tok = my_strtok ('\0', del_string);
779                     if (!tok) {
780                         printf ( catgets(dtsearch_catd, MS_chandel, 13,
781                             "Error line %d - identifier '%s' missing value(s).\n") ,
782                             line_num, line_current->name);
783                         bad_profile = TRUE;
784                         continue;
785                     }           /* if */
786                     strcpy (field_current->line_id, tok);
787
788                     /*-- get "string"  --*/
789                     tok = my_strtok ('\0', "\"");
790                     if (!tok) {
791                         printf ( catgets(dtsearch_catd, MS_chandel, 93,
792                             "Error line %d - '%s' string not "
793                             "enclosed in double quotes.\n"),
794                             line_num, field_current->name);
795                         bad_profile = TRUE;
796                         continue;
797                     }
798                     snprintf(field_current->text, sizeof(field_current->text), "%s", tok);
799                     field_current->text_length = strlen (field_current->text);
800
801                     /*-- get offset --*/
802                     tok = my_strtok ('\0', del_string);
803                     if (!tok) {
804                         printf ( catgets(dtsearch_catd, MS_chandel, 13,
805                         "Error line %d - identifier '%s' missing value(s).\n") ,
806                             line_num, line_current->name);
807                         bad_profile = TRUE;
808                         continue;
809                     }           /* if */
810                     field_current->offset = atoi (tok);
811
812                     /*-- get length --*/
813                     tok = my_strtok ('\0', del_string);
814         /*******if (!tok && field_current->length == ANY) ************/
815                     if (!tok) {
816                         printf ( catgets(dtsearch_catd, MS_chandel, 13,
817                         "Error line %d - identifier '%s' missing value(s).\n") ,
818                             line_num, line_current->name);
819                         bad_profile = TRUE;
820                         continue;
821                     }           /* if */
822                     if (!strcmp (tok, "eoln"))
823                         field_current->defined_length = EOLN;
824                     else if (!strcmp (tok, "eow"))
825                         field_current->defined_length = EOW;
826                     else
827                         field_current->defined_length = atoi (tok);
828                 } /* end FIELD */
829                 break;
830
831             case DELIMITER:
832                 /*-- get next token - should be name of line --*/
833                 if (warnings &&(bot_defined || top_defined))
834                     printf ( catgets(dtsearch_catd, MS_chandel, 23,
835                         "Warning line %d: Delimiter redefined.\n") ,
836                         line_num);
837                 tok = my_strtok ('\0', del_string);
838                 if (validate_id (tok))
839                     strcpy (top_rec_name, tok);
840                 else {
841                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
842                         "Error line %d: invalid identifier '%s'.\n"),
843                         line_num, NULLORSTR(tok));
844                     bad_profile = TRUE;
845                 }
846                 tok = my_strtok ('\0', del_string);
847                 if (tok == NULL)
848                     goto BAD_DELIM_VAL;
849                 /* convert tok to lowercase */
850                 for (i = 0; i < strlen (tok); i++)
851                     tok[i] = tolower (tok[i]);
852                 if (!strcmp (tok, "top")) {
853                     top_defined = TRUE;
854                     bot_defined = FALSE;
855                 } else if (!strcmp (tok, "bottom")) {
856                     top_defined = FALSE;
857                     bot_defined = TRUE;
858                 } else {
859 BAD_DELIM_VAL:
860                     printf ( catgets(dtsearch_catd, MS_chandel, 25,
861                         "Error line %d: delimiter not specified as "
862                         "'top' or 'bottom'.\n") ,
863                     line_num);
864                     bad_profile = TRUE;
865                 }
866                 break;
867
868             case TFIELDEXCLUDE:
869                 tok = my_strtok ('\0', del_string);
870                 if (validate_id (tok)) {
871                     if (finclude_tab == NULL) {
872                         finclude_tab = (struct finclude *) malloc (
873                             sizeof (struct finclude));
874                         finclude_current = finclude_tab;
875                     } else {
876                         finclude_current->next = (struct finclude *) malloc (
877                             sizeof (struct finclude));
878                         finclude_current = finclude_current->next;
879                     }
880                     finclude_current->next = NULL;
881                     strcpy (finclude_current->field_id, tok);
882                     finclude_current->value = EXCLUDE;
883                 }
884                 /* if it was a valid token */
885                 else {
886                     printf ( catgets(dtsearch_catd, MS_chandel, 26,
887                         "Error line %d: invalid token '%s'.\n") ,
888                         line_num, NULLORSTR(tok));
889                     bad_profile = TRUE;
890                 }
891                 break;
892
893             case TFIELDINCLUDE:
894                 tok = my_strtok ('\0', del_string);
895                 if (validate_id (tok)) {
896                     if (finclude_tab == NULL) {
897                         finclude_tab = (struct finclude *) malloc (
898                             sizeof (struct finclude));
899                         finclude_tab->next = NULL;
900                         finclude_current = finclude_tab;
901                     }
902                     /* if valid */
903                     else {
904                         finclude_current->next = (struct finclude *) malloc (
905                             sizeof (struct finclude));
906                         finclude_current = finclude_current->next;
907                         finclude_current->next = NULL;
908                     }           /* else valid */
909                     strcpy (finclude_current->field_id, tok);
910                     finclude_current->value = INCLUDE;
911                 }
912                 /* if it was a valid token */
913                 else {
914                     printf ( catgets(dtsearch_catd, MS_chandel, 27,
915                         "Error line %d: invalid token '%s'.\n") ,
916                         line_num, NULLORSTR(tok));
917                     bad_profile = TRUE;
918                 }
919                 break;
920
921             case TEXTEXCLUDE:
922                 tok = my_strtok ('\0', del_string);
923                 if (validate_id (tok)) {
924                     if (include_tab == NULL) {
925                         include_tab = (struct include *) malloc (
926                                 sizeof (struct include));
927                         include_tab->next = NULL;
928                         include_current = include_tab;
929                     }
930                     /* if valid */
931                     else {
932                         include_current->next = (struct include *) malloc (
933                             sizeof (struct include));
934                         include_current = include_current->next;
935                         include_current->next = NULL;
936                     }           /* else in valid */
937                     strcpy (include_current->line_id, tok);
938                     tok = my_strtok ('\0', del_string);
939                     if (tok == NULL)
940                         include_current->value = EXCLUDE;
941                     else {
942                         if (validate_id (tok)) {
943                             include_current->value = SET;
944                             include_current->next = (struct include *) malloc (
945                                 sizeof (struct include));
946                             include_current = include_current->next;
947                             include_current->next = NULL;
948                             strcpy (include_current->line_id, tok);
949                             include_current->value = DEFAULT;
950                         }
951                         /* if in else */
952                         else {
953                             printf ( catgets(dtsearch_catd, MS_chandel, 12,
954                                 "Error line %d: invalid identifier '%s'.\n") ,
955                                 line_num, tok);
956                             bad_profile = TRUE;
957                         }       /* else in else */
958                     }           /* else tok wasn't NULL */
959                 }
960                 /* if validate... */
961                 else {
962                     printf (catgets(dtsearch_catd, MS_chandel, 12,
963                         "Error line %d: invalid identifier '%s'.\n") ,
964                         line_num, NULLORSTR(tok));
965                     bad_profile = TRUE;
966                 }               /* else not a valid token */
967                 break;
968
969             case IMAGEEXCLUDE:
970                 tok = my_strtok ('\0', del_string);
971                 if (validate_id (tok)) {
972                     if (i_i_t == NULL) {
973                         i_i_t = (struct include *) malloc (
974                                 sizeof (struct include));
975                         i_i_t->next = NULL;
976                         i_i_current = i_i_t;
977                     }
978                     /* if in valid */
979                     else {
980                         i_i_current->next = (struct include *) malloc (
981                             sizeof (struct include));
982                         i_i_current = i_i_current->next;
983                         i_i_current->next = NULL;
984                     }           /* else in valid */
985                     strcpy (i_i_current->line_id, tok);
986                     tok = my_strtok ('\0', del_string);
987                     if (tok == NULL)
988                         i_i_current->value = EXCLUDE;
989                     else {
990                         if (validate_id (tok)) {
991                             i_i_current->value = SET;
992                             i_i_current->next = (struct include *) malloc (
993                                 sizeof (struct include));
994                             i_i_current = i_i_current->next;
995                             i_i_current->next = NULL;
996                             strcpy (i_i_current->line_id, tok);
997                             i_i_current->value = DEFAULT;
998                         }
999                         /* if in else */
1000                         else {
1001                             printf ( catgets(dtsearch_catd, MS_chandel, 12,
1002                                 "Error line %d: invalid identifier '%s'.\n") ,
1003                                 line_num, tok);
1004                             bad_profile = TRUE;
1005                         }       /* else in else */
1006                     }           /* else tok wasn't NULL */
1007                 }
1008                 /* if validate... */
1009                 else {
1010                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
1011                         "Error line %d: invalid identifier '%s'.\n") ,
1012                         line_num, NULLORSTR(tok));
1013                     bad_profile = TRUE;
1014                 }               /* else not a valid token */
1015                 break;
1016
1017             case IMAGEINCLUDE:
1018                 tok = my_strtok ('\0', del_string);
1019                 if (validate_id (tok)) {
1020                     if (i_i_t == NULL) {
1021                         i_i_t = (struct include *) malloc (
1022                                 sizeof (struct include));
1023                         i_i_t->next = NULL;
1024                         i_i_current = i_i_t;
1025                     }
1026                     /* if in valid */
1027                     else {
1028                         i_i_current->next = (struct include *) malloc (
1029                             sizeof (struct include));
1030                         i_i_current = i_i_current->next;
1031                         i_i_current->next = NULL;
1032                     }           /* else in valid */
1033                     strcpy (i_i_current->line_id, tok);
1034                     tok = my_strtok ('\0', del_string);
1035                     if (tok == NULL)
1036                         i_i_current->value = INCLUDE;
1037                     else {
1038                         if (validate_id (tok)) {
1039                             i_i_current->value = CLEAR;
1040                             i_i_current->next = (struct include *) malloc (
1041                                 sizeof (struct include));
1042                             i_i_current = i_i_current->next;
1043                             i_i_current->next = NULL;
1044                             strcpy (i_i_current->line_id, tok);
1045                             i_i_current->value = DEFAULT;
1046                         }
1047                         /* if in else */
1048                         else {
1049                             printf ( catgets(dtsearch_catd, MS_chandel, 12,
1050                                 "Error line %d: invalid identifier '%s'.\n") ,
1051                                 line_num, tok);
1052                             bad_profile = TRUE;
1053                         }       /* else in else */
1054                     }           /* else tok wasn't NULL */
1055                 }
1056                 /* if validate... */
1057                 else {
1058                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
1059                         "Error line %d: invalid identifier '%s'.\n") ,
1060                         line_num, NULLORSTR(tok));
1061                     bad_profile = TRUE;
1062                 }               /* else not a valid token */
1063                 break;
1064
1065             case TEXTINCLUDE:
1066                 tok = my_strtok ('\0', del_string);
1067                 if (validate_id (tok)) {
1068                     if (include_tab == NULL) {
1069                         include_tab = (struct include *) malloc (
1070                                 sizeof (struct include));
1071                         include_tab->next = NULL;
1072                         include_current = include_tab;
1073                     }
1074                     /* if in valid */
1075                     else {
1076                         include_current->next = (struct include *) malloc (
1077                             sizeof (struct include));
1078                         include_current = include_current->next;
1079                         include_current->next = NULL;
1080                     }           /* else in valid */
1081                     strcpy (include_current->line_id, tok);
1082                     tok = my_strtok ('\0', del_string);
1083                     if (tok == NULL)
1084                         include_current->value = INCLUDE;
1085                     else {
1086                         if (validate_id (tok)) {
1087                             include_current->value = CLEAR;
1088                             include_current->next = (struct include *) malloc (
1089                                 sizeof (struct include));
1090                             include_current = include_current->next;
1091                             include_current->next = NULL;
1092                             strcpy (include_current->line_id, tok);
1093                             include_current->value = DEFAULT;
1094                         }
1095                         /* if in else */
1096                         else {
1097                             printf ( catgets(dtsearch_catd, MS_chandel, 12,
1098                                 "Error line %d: invalid identifier '%s'.\n") ,
1099                                 line_num, tok);
1100                             bad_profile = TRUE;
1101                         }       /* else in else */
1102                     }           /* else tok wasn't NULL */
1103                 }
1104                 /* if validate... */
1105                 else {
1106                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
1107                         "Error line %d: invalid identifier '%s'.\n") ,
1108                         line_num, NULLORSTR(tok));
1109                     bad_profile = TRUE;
1110                 }               /* else not a valid token */
1111                 break;
1112
1113             case IMAGE:
1114                 tok = my_strtok ('\0', del_string);
1115                 if (tok == NULL)
1116                     goto BAD_IMAGE;
1117                 for (i = 0; i < strlen (tok); i++)
1118                     tok[i] = tolower (tok[i]);
1119                 if (strcmp (tok, catgets (dtsearch_catd, MS_chandel, 34,"all")) == 0)
1120                     imagemode = INCLUDE;
1121                 else if (strcmp (tok, catgets (dtsearch_catd, MS_chandel, 35, "none")) == 0)
1122                     imagemode = EXCLUDE;
1123                 else {
1124 BAD_IMAGE:
1125                     printf ( catgets(dtsearch_catd, MS_chandel, 36,
1126                         "Error line %d: image mode must be 'all' or "
1127                         "'none' -'%s' not recognized.\n") ,
1128                         NULLORSTR(tok));
1129                     bad_profile = TRUE;
1130                 }
1131                 imageflag = imagemode;
1132                 break;
1133
1134             case TEXT:
1135                 tok = my_strtok ('\0', del_string);
1136                 if (tok == NULL)
1137                     goto BAD_TEXT;
1138                 for (i = 0; i < strlen (tok); i++)
1139                     tok[i] = tolower (tok[i]);
1140                 if (strcmp (tok, "all") == 0)
1141                     textmode = INCLUDE;
1142                 else if (strcmp (tok, "none") == 0)
1143                     textmode = EXCLUDE;
1144                 else {
1145 BAD_TEXT:
1146                     printf ( catgets(dtsearch_catd, MS_chandel, 37,
1147                         "Error line %d: text mode must be 'all' or "
1148                         "'none' - '%s' not recognized.\n") , NULLORSTR(tok));
1149                     bad_profile = TRUE;
1150                 }
1151                 textflag = textmode;
1152                 break;
1153
1154             case KEYCHAR:
1155                 /*-- get next token - should be character for key type --*/
1156                 if (warnings && key_defined)
1157                     printf ( catgets(dtsearch_catd, MS_chandel, 38,
1158                         "Warning line %d: Key character redefined.\n") ,
1159                         line_num);
1160                 tok = my_strtok ('\0', del_string);
1161                 if (validate_id (tok))
1162                     key_char = tok[0];
1163                 else {
1164                     printf ( catgets(dtsearch_catd, MS_chandel, 39,
1165                         "Error line %d: invalid Key Character:'%c'.\n") ,
1166                         line_num, (tok)?tok[0]:'?');
1167                     bad_profile = TRUE;
1168                 }
1169                 key_defined = TRUE;
1170                 break;
1171
1172
1173             case DATEFLD:
1174                 if (date_pos_defined) {
1175                     printf ( catgets(dtsearch_catd, MS_chandel, 110,
1176                         "Warning line %d - date field redefined.\n") ,
1177                         line_num);
1178                     null_date_specified = FALSE;
1179                 }
1180                 date_table = (struct date_id *) malloc
1181                         (sizeof (struct date_id));
1182                 date_current = date_table;
1183                 date_current->next = NULL;
1184                 tok = my_strtok ('\0', del_string);
1185                 /* validate_id() just does syntax chk on name string */
1186                 if (validate_id (tok))
1187                     strcpy (date_current->field_id, tok);
1188                 else {
1189                     /* Msg #111 used two places */
1190                     printf ( catgets(dtsearch_catd, MS_chandel, 111,
1191                         "Error line %d - bad identifier '%s' for date.\n") ,
1192                         line_num, NULLORSTR(tok));
1193                     bad_profile = TRUE;
1194                     break;
1195                 }
1196
1197                 /* Test for special "null" date value */
1198                 if (strcmp (date_current->field_id, "null") == 0) {
1199                     date_pos_defined = TRUE;
1200                     null_date_specified = TRUE;
1201                     break;
1202                 }
1203
1204                 tok = my_strtok ('\0', del_string);
1205                 while (tok != NULL) {
1206                     date_current->next = (struct date_id *) malloc
1207                         (sizeof (struct date_id));
1208                     date_current = date_current->next;
1209                     date_current->next = NULL;
1210                     if (validate_id (tok))
1211                         strcpy (date_current->field_id, tok);
1212                     else {
1213                         /* Msg #111 used two places */
1214                         printf ( catgets(dtsearch_catd, MS_chandel, 111,
1215                             "Error line %d - bad identifier '%s' for date.\n"),
1216                             line_num, NULLORSTR(tok));
1217                         bad_profile = TRUE;
1218                         break;
1219                     }
1220                     tok = my_strtok ('\0', del_string);
1221                 }
1222                 date_pos_defined = TRUE;
1223                 break;          /* end case DATEFLD */
1224
1225             case KEY:
1226                 /*-- building the key --*/
1227                 if (warnings && key_pos_defined)
1228                     printf ( catgets(dtsearch_catd, MS_chandel, 40,
1229                         "Warning line %d - key field redefined.\n") ,
1230                         line_num);
1231                 key_table = (struct key_id *) malloc (sizeof (struct key_id));
1232                 key_current = key_table;
1233                 key_current->next = NULL;
1234                 tok = my_strtok ('\0', del_string);
1235                 if (validate_id (tok)) {
1236                     if (is_time (tok)) {
1237                         strcpy (key_current->field_id, "time");
1238                         key_pos_defined = TRUE;
1239                         break;
1240                     } else if (is_count (tok)) {
1241                         strcpy (key_current->field_id, "count");
1242                         key_pos_defined = TRUE;
1243                         break;
1244                     } else
1245                         strcpy (key_current->field_id, tok);
1246                 }
1247                 else {
1248                     printf ( catgets(dtsearch_catd, MS_chandel, 43,
1249                         "Error line %d - bad identifier '%s' for key.\n") ,
1250                         line_num, NULLORSTR(tok));
1251                     bad_profile = TRUE;
1252                     break;
1253                 }
1254                 tok = my_strtok ('\0', del_string);
1255                 while (tok != NULL) {
1256                     key_current->next = (struct key_id *) malloc (
1257                         sizeof (struct key_id));
1258                     key_current = key_current->next;
1259                     key_current->next = NULL;
1260                     if (validate_id (tok))
1261                         strcpy (key_current->field_id, tok);
1262                     else {
1263                         printf ( catgets(dtsearch_catd, MS_chandel, 43,
1264                             "Error line %d - bad identifier '%s' for key.\n") ,
1265                             line_num, tok);
1266                         bad_profile = TRUE;
1267                         break;
1268                     }
1269                     tok = my_strtok ('\0', del_string);
1270                 }
1271                 key_pos_defined = TRUE;
1272                 break;
1273
1274             case DISCARD:
1275                 tok = my_strtok ('\0', del_string);
1276                 if (tok == NULL)
1277                     goto BAD_DISCARD;
1278                 for (i = 0; i < strlen (tok); i++)
1279                     tok[i] = toupper (tok[i]);
1280                 if (!strcmp (tok, "TRUE"))
1281                     discard = TRUE;
1282                 else if (!strcmp (tok, "FALSE"))
1283                     discard = FALSE;
1284                 else {
1285 BAD_DISCARD:
1286                     printf ( catgets(dtsearch_catd, MS_chandel, 45,
1287                         "Error line %d: unknown option for 'discard': "
1288                         "'%s'.\n") , line_num, NULLORSTR(tok));
1289                     bad_profile = TRUE;
1290                 }
1291                 break;
1292
1293             case DELBLANKLINES:
1294                 tok = my_strtok ('\0', del_string);
1295                 if (tok == NULL)
1296                     goto BAD_DELBLANKLINES;
1297                 for (i = 0; i < strlen (tok); i++)
1298                     tok[i] = toupper (tok[i]);
1299                 if (!strcmp (tok, "TRUE"))
1300                     del_blanklines = TRUE;
1301                 else if (!strcmp (tok, "FALSE"))
1302                     del_blanklines = FALSE;
1303                 else {
1304 BAD_DELBLANKLINES:
1305                     printf ( catgets(dtsearch_catd, MS_chandel, 46,
1306                         "Error line %d: unknown option for "
1307                         "'delblanklines': '%s'.\n") ,
1308                         line_num, NULLORSTR(tok));
1309                     bad_profile = TRUE;
1310                 }
1311                 break;
1312
1313             case ABSTR:
1314                 tok = my_strtok ('\0', del_string);
1315                 abstract = token (tok);
1316                 switch (abstract) {
1317                     case GENERATE:
1318                         break;
1319                     case USER:
1320                         tok = my_strtok ('\0', del_string);
1321                         if (tok == NULL)
1322                             goto BAD_ABSTR;
1323                         strcpy (abstracter, tok);
1324                         break;
1325                     case FIELDS:
1326                         tok = my_strtok ('\0', del_string);
1327                         while (tok != NULL) {
1328                             if (abstract_table == NULL) {
1329                                 abstract_table = (struct key_id *) malloc
1330                                     (sizeof (struct key_id));
1331                                 abstract_current = abstract_table;
1332                             } else {
1333                                 abstract_current->next =
1334                                     (struct key_id *) malloc (
1335                                         sizeof (struct key_id));
1336                                 abstract_current = abstract_current->next;
1337                             }
1338                             strcpy (abstract_current->field_id, tok);
1339                             abstract_current->next = NULL;
1340                             tok = my_strtok ('\0', del_string);
1341                         }
1342                         break;
1343                     default:
1344 BAD_ABSTR:
1345                         printf ( catgets(dtsearch_catd, MS_chandel, 47,
1346                         "Error line %d: Unknown option for abstract :'%s'\n"),
1347                         line_num, NULLORSTR(tok));
1348                         bad_profile = TRUE;
1349                         break;
1350                 }               /* 'abstract' subswitch */
1351                 break;
1352
1353             default:
1354                 printf ( catgets(dtsearch_catd, MS_chandel, 48,
1355                         "Error line %d -unknown identifier type '%s'.\n") ,
1356                     line_num,  NULLORSTR(tok));
1357                 bad_profile = TRUE;
1358                 break;
1359         }                       /* main switch for each line in profile */
1360     } while (TRUE);             /* read-a-line do loop */
1361     if (!date_pos_defined)
1362         fprintf (aa_stderr,  catgets(dtsearch_catd, MS_chandel, 115,
1363             "%s Default object dates will be '%s'.\n") ,
1364             PROGNAME"1288", now_str);
1365     if (bad_profile)
1366         return;
1367
1368     /*---- Process tables, and check for identifiers referenced ----*/
1369     if (!top_defined && !bot_defined) {
1370         bad_profile = TRUE;
1371         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 49,
1372                 "Error - delimiter not defined.\n") );
1373     }
1374     if (!key_defined) {
1375         bad_profile = TRUE;
1376         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 50,
1377                 "Error - key-type character never defined.\n") );
1378     }
1379     if (!key_pos_defined) {
1380         bad_profile = TRUE;
1381         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 51,
1382                 "Error - key never defined.\n") );
1383     }
1384     if (bad_profile)
1385         return;
1386
1387     top_rec = NULL;
1388     line_current = line_table;
1389     while (line_current != NULL) {
1390         if (strcmp (line_current->name, top_rec_name) == 0)
1391             top_rec = line_current;
1392         line_current = line_current->next;
1393     }
1394     if (top_rec_name[0] != 0 && top_rec == NULL) {
1395         printf ( catgets(dtsearch_catd, MS_chandel, 52,
1396                 "Error - delimiter defined as '%s' was never found.\n") ,
1397             top_rec_name);
1398         bad_profile = TRUE;
1399     } else if (strcmp (top_rec->head->text, line_mode) == 0) {
1400         printf ( catgets(dtsearch_catd, MS_chandel, 53,
1401             "Error - delimiter defined as '%s' references a physical "
1402             "line in the record.\n   Since the delimiter defines the "
1403             "physical lines\n  it cannot be referenced as a physical line.\n"),
1404             top_rec_name);
1405         bad_profile = TRUE;
1406     }
1407     field_current = field_table;
1408     while (field_current != NULL) {
1409         found = FALSE;
1410         line_current = line_table;
1411         while (line_current != NULL) {
1412             if (!strcmp (field_current->line_id, line_current->name)) {
1413                 found = TRUE;
1414                 field_current->line = line_current;
1415             }
1416             line_current = line_current->next;
1417         }
1418         if (!found && !field_current->constant) {
1419             printf ( catgets(dtsearch_catd, MS_chandel, 54,
1420                 "Error - for field '%s', no line identifier matches '%s'.\n") ,
1421                 field_current->name, field_current->line_id);
1422             bad_profile = TRUE;
1423         }
1424         field_current = field_current->next;
1425     }
1426     finclude_current = finclude_tab;
1427     while (finclude_current != NULL) {
1428         /* find field, and set text_value */
1429         field_current = field_table;
1430         found = FALSE;
1431         while (field_current != NULL) {
1432             if (!strcmp (field_current->name, finclude_current->field_id)) {
1433                 field_current->text_action = finclude_current->value;
1434                 found = TRUE;
1435             }
1436             field_current = field_current->next;
1437         }
1438         if (!found) {
1439             printf ( catgets(dtsearch_catd, MS_chandel, 55,
1440                 "Error - field include/exclude list included\n"
1441                 "  the field '%s', which was never defined.\n") ,
1442                 finclude_current->field_id);
1443             bad_profile = TRUE;
1444         }
1445         finclude_current = finclude_current->next;
1446     }
1447     i_i_current = i_i_t;
1448     while (i_i_current != NULL) {
1449         /* find line, and set text_action */
1450         line_current = line_table;
1451         found = FALSE;
1452         while (line_current != NULL) {
1453             if (!strcmp (line_current->name, i_i_current->line_id)) {
1454                 line_current->image_action = i_i_current->value;
1455                 found = TRUE;
1456             }
1457             line_current = line_current->next;
1458         }
1459         if (!found) {
1460             printf ( catgets(dtsearch_catd, MS_chandel, 56,
1461                 "Error - image include/exclude list included\n"
1462                 "  the line '%s', which was never defined.\n") ,
1463                 include_current->line_id);
1464             bad_profile = TRUE;
1465         }
1466         i_i_current = i_i_current->next;
1467     }
1468     include_current = include_tab;
1469     while (include_current != NULL) {
1470         /* find line, and set text_action */
1471         line_current = line_table;
1472         found = FALSE;
1473         while (line_current != NULL) {
1474             if (!strcmp (line_current->name, include_current->line_id)) {
1475                 line_current->text_action = include_current->value;
1476                 found = TRUE;
1477             }
1478             line_current = line_current->next;
1479         }
1480         if (!found) {
1481             printf ( catgets(dtsearch_catd, MS_chandel, 57,
1482                 "Error - text include/exclude list included\n"
1483                 "  the line '%s', which was never defined.\n") ,
1484                 include_current->line_id);
1485             bad_profile = TRUE;
1486         }
1487         include_current = include_current->next;
1488     }
1489
1490     /* If "null" dates specified, no need to look for other date fields */
1491     if (null_date_specified) 
1492         goto END_DATE_TABLE;
1493
1494     /* loop thru date table and link each field id to its structure */
1495     for (date_current = date_table; date_current != NULL;
1496         date_current = date_current->next) {
1497         found = FALSE;
1498
1499         for (field_current = field_table; field_current != NULL;
1500             field_current = field_current->next) {
1501             if (strcmp (field_current->name, date_current->field_id) == 0) {
1502                 date_current->field = field_current;
1503                 found = TRUE;
1504                 break;
1505             }
1506         }
1507         if (!found) {
1508             printf ( catgets(dtsearch_catd, MS_chandel, 116,
1509                 "Error - date references undefined field '%s'.\n"),
1510                 date_current->field_id);
1511             bad_profile = TRUE;
1512         }
1513     }
1514 END_DATE_TABLE:
1515
1516     key_current = key_table;
1517     while (key_current != NULL) {
1518         field_current = field_table;
1519         found = FALSE;
1520         if (!strcmp ("time", key_current->field_id)) {
1521             found = TRUE;
1522             key_current->field = NULL;
1523         } else if (!strcmp ("count", key_current->field_id)) {
1524             found = TRUE;
1525             key_current->field = NULL;
1526         }
1527         while (field_current != NULL) {
1528             if (!strcmp (field_current->name, key_current->field_id)) {
1529                 found = TRUE;
1530                 key_current->field = field_current;
1531             } else if (!strcmp ("time", key_current->field_id)) {
1532                 found = TRUE;
1533                 key_current->field = NULL;
1534             } else if (!strcmp ("count", key_current->field_id)) {
1535                 found = TRUE;
1536                 key_current->field = NULL;
1537             }
1538             field_current = field_current->next;
1539         }
1540         if (!found) {
1541             printf ( catgets(dtsearch_catd, MS_chandel, 58,
1542                 "Error - key definition references field '%s'\n"
1543                 "  which was never defined.\n") ,
1544                 key_current->field_id);
1545             bad_profile = TRUE;
1546         }
1547         key_current = key_current->next;
1548     }
1549     abstract_current = abstract_table;
1550     while (abstract_current != NULL) {
1551         field_current = field_table;
1552         found = FALSE;
1553         while (field_current != NULL) {
1554             if (!strcmp (field_current->name, abstract_current->field_id)) {
1555                 found = TRUE;
1556                 abstract_current->field = field_current;
1557             }
1558             field_current = field_current->next;
1559         }
1560         if (!found) {
1561             printf ( catgets(dtsearch_catd, MS_chandel, 59,
1562                 "Error - abstract definition references field '%s'\n"
1563                 "  which was never defined.\n") ,
1564                 abstract_current->field_id);
1565             bad_profile = TRUE;
1566         }
1567         abstract_current = abstract_current->next;
1568     }
1569
1570 } /*--process_profile--*/
1571
1572 /**********************************************************************
1573    CLEANUP - frees memory used by record
1574 ***********************************************************************/
1575 void            cleanup ()
1576 {
1577     struct line_id *line_current;
1578     struct field_id *field_current;
1579     struct rec     *record;
1580
1581     /*-- Reset line_table --*/
1582     line_current = line_table;
1583     while (line_current != NULL) {
1584         line_current->line = UNDEFINED;
1585         line_current = line_current->next;
1586     }
1587
1588     /*-- Reset field table --*/
1589     field_current = field_table;
1590     while (field_current != NULL) {
1591         if (field_current->constant == FALSE)
1592             field_current->value[0] = 0;
1593         field_current = field_current->next;
1594     }
1595
1596     /*-- clean up record, free memory for reuse --*/
1597     record = record_head;
1598     while (record_head != NULL) {
1599         record_head = record->next;
1600         free (record);
1601         record = record_head;
1602     }
1603 }
1604
1605 /**************************************************************************
1606    WRITE_RECORD - writes the final form of the record - key, fzkey, abstract,
1607  and image.
1608 **************************************************************************/
1609 void            write_record ()
1610 {
1611     static int      dotcount = 0;
1612     char           *ptr;
1613     struct key_id  *abst;
1614     struct rec     *record;
1615     char            value[200];
1616     int             lvalue;
1617     int             i;
1618     int             good = FALSE;
1619     char            buffer[200];
1620
1621     /* Line #1 is fzkey */
1622     fprintf (outstream, " 0,2\n"); /* hardcoded null fzkey */
1623
1624     /* Line #2 is abstract */
1625     value[0] = 0;
1626     if (abstract == FIELDS) {
1627         abst = abstract_table;
1628         while (abst != NULL) {
1629             strcat (value, abst->field->value);
1630             abst = abst->next;
1631         }
1632         for (i = 0; i < strlen (value); i++)
1633             if (value[i] == '\n')
1634                 value[i] = ' ';
1635     }
1636     fprintf (outstream, "ABSTRACT: %s\n", value);
1637
1638     /* Line #3 is unique database key */
1639     if (key_value[strlen (key_value) - 1] == '\n')
1640         key_value[strlen (key_value) - 1] = 0;
1641     if (uppercase)
1642         strupr (key_value);
1643     fprintf (outstream, "%c%s\n", key_char, key_value);
1644
1645     /* Line #4 is object date in objdate string format.
1646      * Prior to version 2.0.8 this would be the first line of text.
1647      */
1648     if (null_date_specified)
1649         fputs (NULLDATESTR"\n", outstream);
1650     else
1651         fprintf (outstream, "%s\n",
1652             objdate2fzkstr (tm2objdate (objdate_tmptr)));
1653
1654     /* Lines #5 and thereafter (text) of .fzk rec */
1655     record = record_head;
1656     while (record != NULL) {
1657         /*
1658          * Strip out any control-l's, as we put our own later,
1659          * and any extras might freak out something that wants
1660          * a control-l as a delimeter.
1661          */
1662         for (i = 0; i < strlen (record->text); i++)
1663             if (record->text[i] == CNTRL_L)
1664                 record->text[i] = ' ';
1665
1666         lvalue = (record->line)? record->line->image_action : 0;
1667         switch (lvalue) {
1668             case CLEAR:
1669                 imageflag = INCLUDE;
1670                 break;
1671             case SET:
1672                 imageflag = EXCLUDE;
1673                 break;
1674             default:
1675                 break;
1676         }
1677         if ((imageflag == INCLUDE && lvalue != EXCLUDE)
1678                 || (lvalue == INCLUDE)) {
1679             /* trim to fit in screen */
1680             strcpy (buffer, record->text);
1681             if (strlen (buffer) > screen_width) {
1682                 buffer[screen_width] = '\n';
1683                 buffer[screen_width + 1] = 0;
1684             }
1685             fprintf (outstream, "%s", buffer);
1686         }
1687         record = record->next;
1688         if (lvalue == DEFAULT)
1689             imageflag = imagemode;
1690     }
1691
1692     /* Test final record write to check for full filesystem */
1693     if (fprintf (outstream, "%c\n", CNTRL_L) <= 0) {
1694         printf ( catgets(dtsearch_catd, MS_chandel, 124,
1695             "%s Unable to write to output file '%s':\n  %s\n") ,
1696             PROGNAME"1663", outfile, strerror(errno));
1697         DtSearchExit (2);
1698     }
1699     return;
1700 } /* write_record */
1701
1702
1703 /************************************************/
1704 /*                                              */
1705 /*                mmm_to_digits                 */
1706 /*                                              */
1707 /************************************************/
1708 /* Translates a field value which is a recognizable month
1709  * name string into a two-char digit string from "01" to "12".
1710  */
1711 static void     mmm_to_digits (struct field_id *fld)
1712 {
1713     static char valbuf[8];
1714     static char *months = NULL;
1715     int         i;
1716
1717     if (months == NULL)
1718         months = strdup (catgets(dtsearch_catd, MS_chandel, 125,
1719             "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"));
1720     for (i=0; i<3; i++)
1721         valbuf[i] = toupper (fld->value[i]);
1722     for (i=0; i<12; i++)
1723         if (strncmp (valbuf, months + (i*3), 3) == 0) {
1724             sprintf (fld->value, "%02d", ++i);
1725             break;
1726         }
1727 return;
1728 } /* mmm_to_digits() */
1729
1730
1731 /************************************************/
1732 /*                                              */
1733 /*                process_record                */
1734 /*                                              */
1735 /************************************************/
1736 /* PROCESS_RECORD - does all processing for the record currently stored
1737  * in the data structure pointed to by record_head.  If record_head points
1738  * to NULL, it can safely be assumed that no record is currently awaiting
1739  * processing.
1740  */
1741 void    process_record (void)
1742 {
1743     struct field_id
1744                 *field_current;
1745     struct key_id
1746                 *key_current;
1747     struct date_id
1748                 *date_current;
1749     struct rec  *record;
1750     char        *pos;
1751     char        value[200];
1752     int         lvalue;
1753     int         i;
1754     int         linelen;
1755     char        date_value[256];
1756     int         dummy;
1757     int         meaningless;
1758     static int  dotcount = 0;
1759
1760     if (record_head == NULL)
1761         return;
1762
1763     /* Print progress dots and messages */
1764     rec_count++;
1765     if (rec_count % RECS_PER_DOT == 0L) {
1766         putchar('.');
1767         if (++dotcount % 10 == 0)
1768             putchar(' ');
1769         if (dotcount % 50 == 0) {
1770             putchar('\n');
1771             dotcount = 0;
1772         }
1773         fflush(stdout);
1774     }
1775
1776     discard_record = FALSE;
1777     meaningless = FALSE;
1778
1779     /* Main loop on every line in record */
1780     record = record_head;
1781     while (record != NULL) {
1782         lvalue = (record->line)? record->line->text_action : 0;
1783         switch (lvalue) {
1784             case CLEAR:
1785                 textflag = INCLUDE;
1786                 break;
1787             case SET:
1788                 textflag = EXCLUDE;
1789                 break;
1790             default:
1791                 break;
1792         }                       /* switch */
1793
1794         field_current = field_table;
1795         while (field_current != NULL) {
1796             if (field_current->line == record->line) {
1797                 /* this field is defined within this line */
1798                 memset (value, 0, sizeof(value));
1799
1800                 /* If profile pattern str was empty ("") ...*/
1801                 if (field_current->text[0] == 0) {
1802                     if (field_current->defined_length == EOLN)
1803                         strncpy (value, record->text +
1804                             (field_current->offset - 1), sizeof(value)-1);
1805                     else if (field_current->defined_length == EOW)
1806                         /* copy until end of word only */
1807                         for (dummy = 0;
1808                              (!isspace ((record->text +
1809                                 (field_current->offset - 1))[dummy]))
1810                                 &&  dummy < sizeof(value);
1811                              dummy++
1812                              )
1813                                 value[dummy] = (record->text +
1814                                     (field_current->offset - 1))[dummy];
1815                     else {
1816                         i = (field_current->defined_length < sizeof(value))?
1817                             field_current->defined_length : sizeof(value)-1;
1818                         strncpy (value,
1819                             record->text + (field_current->offset - 1),
1820                             i);
1821                     }
1822                 }
1823
1824                 /* ...else if profile pattern str was not empty ("xxx") */
1825                 else {
1826                     pos = strstr (record->text, field_current->text);
1827                     if (pos != NULL) {  /* pattern found... */
1828                         if (field_current->defined_length == EOLN)
1829                             strncpy (value,
1830                                 pos + (field_current->offset - 1),
1831                                 sizeof(value) - 1);
1832                         else if (field_current->defined_length == EOW)
1833                             /* copy until end of word only */
1834                             for (dummy = 0;
1835                                  (!isspace ((pos +
1836                                     (field_current->offset - 1))[dummy]))
1837                                     &&  dummy < sizeof(value);
1838                                  dummy++
1839                                  )
1840                                     value[dummy] = (pos +
1841                                         (field_current->offset - 1))[dummy];
1842                         else {
1843                             i = (field_current->defined_length<sizeof(value))?
1844                                 field_current->defined_length : sizeof(value)-1;
1845                             strncpy (value,
1846                                 pos + (field_current->offset - 1),
1847                                 i);
1848                         }
1849                     }   /* end pattern found */
1850                 } /* end else where pattern str not empty */
1851
1852                 /* strip \n's out of value */
1853                 for (i = 0; i < strlen (value); i++)
1854                     if (value[i] == '\n')
1855                         value[i] = 0;
1856                 if (field_current->constant == FALSE) {
1857                     strncpy (field_current->value, value,
1858                         sizeof(field_current->value));
1859                     field_current->value [sizeof(field_current->value)-1] = 0;
1860                     field_current->length = strlen (field_current->value);
1861                     if (field_current->is_month)
1862                         mmm_to_digits (field_current);
1863                 }
1864             }
1865             field_current = field_current->next;
1866         } /* end while loop on each field within each line */
1867
1868         if (lvalue == DEFAULT)
1869             textflag = textmode;
1870         record = record->next;
1871     } /* end while loop on each record line */
1872
1873
1874     /* Build a handel date_value string from specified fields.
1875      * If 'date' was not specified, uses current date/time.
1876      * If 'date = null' was specified, uses special constant string.
1877      * If value error in specified date fields,
1878      * uses current date/time and prints err msg. 
1879      */
1880     objdate_tmptr = &nowtm;             /* default */
1881     if (date_pos_defined && !null_date_specified) {
1882         date_value[0] = 0;
1883         for (date_current = date_table; date_current != NULL;
1884             date_current = date_current->next) {
1885             if (date_current->field->value[0] != 0) {
1886                 strcat (date_value, date_current->field->value);
1887             }
1888             else {
1889                 date_value[0] = 0;      /* flags error msg */
1890                 break;
1891             }
1892         }
1893
1894         /*
1895          * Validate format for date_value of this record.
1896          * Date value format: YYYYMMDDhhmm (exactly 12 digits).
1897          * The area at date_value + 100 is just a little atoi buffer. 
1898          */
1899         if (date_value[0] == 0)
1900             goto BAD_DATE_VALUE;
1901         if (strlen (date_value) != 12)
1902             goto BAD_DATE_VALUE;
1903         for (i = 0; i < 12; i++)
1904             if (!isdigit (date_value[i]))
1905                 goto BAD_DATE_VALUE;
1906
1907         /* year = YYYY */
1908         strncpy (date_value + 100, date_value, 4);
1909         date_value[104] = 0;
1910         i = atoi (date_value + 100);
1911         if (i < 1900 || i > 5995)       /* valid OBJDATE years */
1912             goto BAD_DATE_VALUE;
1913         else
1914             rectm.tm_year = i - 1900;
1915
1916         /* month = MM */
1917         strncpy (date_value + 100, date_value + 4, 2);
1918         date_value[102] = 0;
1919         i = atoi (date_value + 100);
1920         if (i < 1 || i > 12)
1921             goto BAD_DATE_VALUE;
1922         else
1923             rectm.tm_mon = i - 1;       /* tm values = 0 - 11 */
1924
1925         /* day = DD */
1926         strncpy (date_value + 100, date_value + 6, 2);
1927         date_value[102] = 0;
1928         i = atoi (date_value + 100);
1929         if (i < 1 || i > 31)
1930             goto BAD_DATE_VALUE;
1931         else
1932             rectm.tm_mday = i;
1933
1934         /* hours = hh */
1935         strncpy (date_value + 100, date_value + 8, 2);
1936         date_value[102] = 0;
1937         i = atoi (date_value + 100);
1938         if (i < 0 || i > 23)
1939             goto BAD_DATE_VALUE;
1940         else
1941             rectm.tm_hour = i;
1942
1943         /* minutes = mm */
1944         strncpy (date_value + 100, date_value + 10, 2);
1945         date_value[102] = 0;
1946         i = atoi (date_value + 100);
1947         if (i < 0 || i > 59)
1948             goto BAD_DATE_VALUE;
1949         else
1950             rectm.tm_min = i;
1951
1952         objdate_tmptr = &rectm;
1953         goto GOOD_DATE_VALUE;
1954
1955     BAD_DATE_VALUE:
1956         objdate_tmptr = &nowtm;
1957         printf ( catgets(dtsearch_catd, MS_chandel, 133,
1958             "Warning - '%s' is invalid date specification.\n"
1959             "  Using '%s' date for record number %ld that began: %.30s\n") ,
1960             date_value, now_str, rec_count, record_head->text);
1961     GOOD_DATE_VALUE:
1962         ;
1963     }   /* end if (date_pos_defined) */
1964
1965     key_current = key_table;
1966     key_count++;
1967     for (dummy = 0; dummy < 80; dummy++)
1968         key_value[dummy] = 0;
1969     dummy = FALSE;
1970     while (key_current != NULL) {
1971         if (key_current->field == NULL) {
1972             if (strcmp (key_current->field_id, "time") == 0)
1973                 sprintf (key_value, "%ld%06ld", now, key_count);
1974             else        /* must be 'count' */
1975                 sprintf (key_value, "%09ld", key_count);
1976         } else if (key_current->field->value[0] != 0) {
1977             strcat (key_value, key_current->field->value);
1978         } else {
1979             dummy = TRUE;
1980         }
1981         key_current = key_current->next;
1982     }
1983     if (dummy && warnings) {
1984         printf ( catgets(dtsearch_catd, MS_chandel, 68,
1985                 "Warning - fields necessary for key not found.\n"
1986                 "  discarding record #%ld that began:\n  %s\n") ,
1987             rec_count, record_head->text);
1988     } else if (discard && meaningless && warnings) {
1989         printf ( catgets(dtsearch_catd, MS_chandel, 69,
1990                 "Warning - record #ld deemed meaningless, discarding...\n"
1991                 "  record began: %.60s\n") ,
1992             rec_count, record_head->text);
1993     } else {
1994         outcount++;
1995         write_record ();
1996     }
1997     cleanup ();
1998 } /*--process_record--*/
1999
2000
2001 /**************************************************************************
2002    NEW_REC - determines if the string sent represents a new record or
2003   not.
2004 **************************************************************************/
2005 int             new_rec (char *buffer)
2006 {
2007     int             cant_be = FALSE;
2008     top_rec->comp = top_rec->head;
2009     while (top_rec->comp != NULL) {
2010         if (strcmp (top_rec->comp->text, line_mode) != 0) {
2011             if (top_rec->comp->column_number == ANY) {
2012             if (strstr(buffer,top_rec->comp->text)==NULL) 
2013                     cant_be = TRUE;
2014             }
2015             /* if */
2016             else if (strncmp (buffer + (top_rec->comp->column_number - 1),
2017                         top_rec->comp->text,
2018                     strlen (top_rec->comp->text)) != 0)
2019                 cant_be = TRUE;
2020         }                       /* if */
2021         top_rec->comp = top_rec->comp->next;
2022     }                           /* while */
2023     if (cant_be == FALSE) {
2024         return TRUE;
2025     } else
2026         return FALSE;
2027 }                               /*--new_rec--*/
2028
2029 /**************************************************************************
2030    IS_WHITESPACE - returns true if the string passed contains only
2031  whitespace
2032 **************************************************************************/
2033 int             is_whitespace (char *s)
2034 {
2035     int             i;
2036     for (i = 0; i < strlen (s); i++)
2037         if (!isspace (s[i]) || s[i] == 12)
2038             return FALSE;
2039     return TRUE;
2040 }
2041
2042 /**************************************************************************
2043    PROCESS_INFILE - processes the input file, 1 record at a time.  For each
2044 record, the lines must first be compared against the line id's we have, to
2045 try and identify each line.  Then fields are processed against these lines,
2046 and finally fzk processing can begin on any lines that are indicated being
2047 important.
2048 ***************************************************************************/
2049 void            process_infile ()
2050 {
2051     int             line_num = 0;
2052     struct line_id *line_current;
2053     struct rec     *record;
2054     char            buffer[200];
2055     int             cant_be;
2056     time_t          startime = 0L;
2057     int             i;
2058     int             rc;
2059
2060     if (!strcmp (infile, "-"))
2061         instream = stdin;
2062     else {
2063         if ((instream = fopen (infile, "rt")) == NULL) {
2064             printf ( catgets(dtsearch_catd, MS_chandel, 70,
2065                 " Unable to open input file '%s'.\n") , infile);
2066             exit (FILE_ERROR);
2067         }
2068     }
2069
2070     record_head = NULL;
2071     time (&startime);
2072     while (fgets (buffer, sizeof (buffer) - 1, instream) != NULL) {
2073         /* clean any non ASCII characters out of buffer */
2074         delete_whitespace (buffer);
2075         if (feof (instream))
2076             continue;           /*-* end of file *-*/
2077         if (del_blanklines && is_whitespace (buffer))
2078             continue;
2079         if (new_rec (buffer)) {
2080             if (bot_defined) {
2081                 if (record_head == NULL) {
2082                     record_head = (struct rec *) malloc (sizeof (struct rec));
2083                     record = record_head;
2084                 } else {
2085                     record->next = (struct rec *) malloc (sizeof (struct rec));
2086                     record = record->next;
2087                 }
2088                 record->next = NULL;
2089                 line_num++;
2090                 record->line_num = line_num;
2091                 strcpy (record->text, buffer);
2092                 record->line = NULL;
2093                 /*-- search list of line_id's for a possible match --*/
2094                 line_current = line_table;
2095                 while (line_current != NULL) {
2096                     cant_be = FALSE;
2097                     line_current->comp = line_current->head;
2098                     while (line_current->comp != NULL) {
2099                         if (strcmp (line_current->comp->text, line_mode) != 0) {
2100                             if (line_current->comp->column_number == ANY) {
2101                                 if (strstr(buffer,line_current->comp->text)
2102                                         == NULL)
2103                                     cant_be = TRUE;
2104                             } else if (
2105                                     strncmp (buffer +
2106                                         (line_current->comp->column_number - 1),
2107                                         line_current->comp->text,
2108                                     strlen (line_current->comp->text)) != 0)
2109                                 cant_be = TRUE;
2110                         } else if (line_current->comp->column_number
2111                                 != line_num)
2112                             cant_be = TRUE;
2113                         line_current->comp = line_current->comp->next;
2114                     }
2115                     if (cant_be == FALSE) {
2116                         /* found a hit, set pointers */
2117                         line_current->line = record;
2118                         record->line = line_current;
2119                     }           /* if */
2120                     line_current = line_current->next;
2121                 }               /* while - line_current loop */
2122             }                   /* if bot_defined */
2123             process_record ();
2124             if (shutdown_now)
2125                 break;
2126             line_num = 0;
2127             started = TRUE;
2128             if (bot_defined)
2129                 continue;
2130         }
2131         if (record_head == NULL) {
2132             record_head = (struct rec *) malloc (sizeof (struct rec));
2133             record = record_head;
2134         } else {
2135             record->next = (struct rec *) malloc (sizeof (struct rec));
2136             record = record->next;
2137         }
2138         record->next = NULL;
2139         line_num++;
2140         record->line_num = line_num;
2141         strcpy (record->text, buffer);
2142         record->line = NULL;
2143         /*-- search list of line_id's for a possible match --*/
2144         line_current = line_table;
2145         while (line_current != NULL) {
2146             cant_be = FALSE;
2147             line_current->comp = line_current->head;
2148             while (line_current->comp != NULL) {
2149                 if (strcmp (line_current->comp->text, line_mode) != 0) {
2150                     if (line_current->comp->column_number == ANY) {
2151                   if (strstr(buffer,line_current->comp->text)==NULL){
2152                             cant_be = TRUE;
2153                         }
2154                     } else if (strncmp (buffer +
2155                                     (line_current->comp->column_number - 1),
2156                                 line_current->comp->text,
2157                             strlen (line_current->comp->text)) != 0) {
2158                         cant_be = TRUE;
2159                     }
2160                 } else if (line_current->comp->column_number != line_num) {
2161                     cant_be = TRUE;
2162                 }
2163                 line_current->comp = line_current->comp->next;
2164             }
2165             if (cant_be == FALSE) {
2166                 /* found a hit, set pointers */
2167                 line_current->line = record;
2168                 record->line = line_current;
2169             }                   /* if */
2170             line_current = line_current->next;
2171         }                       /* while - line_current loop */
2172         for (rc = 0; rc < 200; rc++)
2173             buffer[rc] = 0;
2174     }                           /* while - buffer read loop */
2175     /*- check for any leftover records -*/
2176     process_record ();
2177 }   /*-- process_infile --*/
2178
2179
2180 /************************************************/
2181 /*                                              */
2182 /*                  usage_msg                   */
2183 /*                                              */
2184 /************************************************/
2185 static void     usage_msg (void)
2186 {
2187     static char       *default_text =
2188       "\nUSAGE: %s [options] <profile> <infile> [<outfile>]\n"
2189       "  -m         Turn off all but error messages.\n"
2190       "  -wN        Change target screen width to <N>.\n"
2191       "  -oo        Preapprove overwrite of outfile.\n"
2192       "  -oa        Preapprove append to outfile.\n"
2193       "  <profile>  Input file containing profile of records\n"
2194       "             to be processed.\n"
2195       "  <infile>   Input file containing actual records.\n"
2196       "  <outfile>  Output file name, .fzk format (%s).\n\n";
2197
2198     if (!warnings)
2199         return;
2200     printf (catgets (dtsearch_catd, MS_chandel, 71, default_text),
2201       aa_argv0, EXT_FZKEY);
2202     return;
2203 } /* usage_msg() */
2204
2205
2206 /************************************************/
2207 /*                                              */
2208 /*              user_arg_processor              */
2209 /*                                              */
2210 /************************************************/
2211 /* Process any user arguments passed thru the command line parameters. */
2212 static void     user_arg_processor (int argc, char **argv)
2213 {
2214     char        *cptr, *argptr;
2215     char        *pos;
2216
2217     if (argc <= 1) {
2218         bad_parm = TRUE;
2219         return;
2220     }                           /* if */
2221     while (--argc > 0 && (*++argv)[0] == '-') {
2222         argptr = argv[0];
2223         argptr[1] = tolower (argptr[1]);
2224         switch (argptr[1]) {
2225
2226             case 'w':
2227                 if ((screen_width = atoi (argptr + 2)) == 0) {
2228                     printf ( "%s", catgets(dtsearch_catd, MS_chandel, 72,
2229                         "Invalid screen width specified.\n") );
2230                     bad_parm = TRUE;
2231                 }
2232                 break;
2233
2234             case 'm':
2235                 warnings = FALSE;
2236                 break;
2237
2238             case 'o':
2239                 argptr[2] = tolower (argptr[2]);
2240                 if (argptr[2] == 'o')
2241                     strcpy (outmode, "w");
2242                 else if (argptr[2] == 'a')
2243                     strcpy (outmode, "a");
2244                 else {
2245                     printf ( catgets(dtsearch_catd, MS_chandel, 75,
2246                         "'%s' is invalid output mode.\n") , argptr);
2247                     bad_parm = TRUE;
2248                 }               /* else */
2249                 outmode_specified = TRUE;
2250                 break;
2251
2252             default:
2253                 printf ( catgets(dtsearch_catd, MS_chandel, 76,
2254                         "Unknown command line argument '%s'.\n") , argptr);
2255                 bad_parm = TRUE;
2256         }                       /*--switch--*/
2257     }                           /*--while--*/
2258
2259     if (argc-- <= 0) {
2260         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 77,
2261                 "Missing required profile-file name.\n") );
2262         bad_parm = TRUE;
2263     }
2264     /* if */
2265     else {
2266 /******
2267     strcpy(profile,argv[0]);
2268     profile=argv[0];
2269 *******/
2270         profile = (char *) malloc (sizeof (char) * (strlen (argv[0])) +10);
2271         strcpy (profile, argv[0]);
2272         if (strchr (profile, '.') == NULL)
2273             strcat (profile, EXT_HANDEL);
2274     }
2275
2276     if (argc-- <= 0) {
2277         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 78,
2278                 "Missing required input-file name.\n") );
2279         bad_parm = TRUE;
2280     }
2281     /* if */
2282     else
2283 /********    strcpy(infile,argv[1]); ********/
2284         infile = argv[1];
2285
2286     if (argc-- <= 0) {
2287 /*****************
2288       strcpy(outfile,infile);
2289       if (strchr(outfile,'.')!=NULL)
2290          strcpy(strchr(outfile,'.'), EXT_FZKEY);
2291       else
2292          strcat(outfile,EXT_FZKEY);
2293 *****************/
2294         if (strcmp (infile, "-") == 0) {
2295             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 79, "Error - using "
2296                 "stdin as input, output filename is required!\n") );
2297             exit (FILE_ERROR);
2298         } else {
2299             outfile = (char *) malloc (sizeof (char) * (strlen (infile) + 10));
2300             strcpy (outfile, infile);
2301             pos = strrchr (outfile, (int) '.');
2302             if (pos == NULL)
2303                 strcat (outfile, EXT_FZKEY);
2304             else {
2305                 pos++;
2306                 pos[0] = 'f';
2307                 pos++;
2308                 pos[0] = 'z';
2309                 pos++;
2310                 pos[0] = 'k';
2311                 pos++;
2312                 pos[0] = 0;
2313             }
2314         }
2315     }
2316     /* if */
2317     else
2318 /*    strcpy(outfile,argv[2]); */
2319         outfile = argv[2];
2320
2321 /*-- Sanity checks --*/
2322     /*-- duplicates? --*/
2323     if (strcmp (infile, profile) == 0) {
2324         printf ( catgets(dtsearch_catd, MS_chandel, 80,
2325                 "Profile file and input file have same name:'%s'.\n") ,
2326             infile);
2327         bad_parm = TRUE;
2328     }                           /* if */
2329     if (strcmp (infile, outfile) == 0 && strcmp (infile, "-")) {
2330         printf ( catgets(dtsearch_catd, MS_chandel, 81,
2331                 "Input file and output file have same name:'%s'.\n") ,
2332             infile);
2333         bad_parm = TRUE;
2334     }                           /* if */
2335     if (strcmp (profile, outfile) == 0) {
2336         printf ( catgets(dtsearch_catd, MS_chandel, 82,
2337                 "Profile file and output file have same name:'%s'.\n") ,
2338             profile);
2339         bad_parm = TRUE;
2340     }                           /* if */
2341     if(warnings)
2342         {
2343         printf ( catgets(dtsearch_catd, MS_chandel, 83,
2344                 "        Profile file: %s\n") , profile);
2345         if (strcmp (infile, "-") == 0)
2346             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 84,
2347                 "          Input file: stdin\n") );
2348         else
2349             printf ( catgets(dtsearch_catd, MS_chandel, 85,
2350                 "          Input file: %s\n") , infile);
2351         if (strcmp (outfile, "-") == 0)
2352             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 86,
2353                 "         Output file: stdout\n") );
2354         else
2355             printf ( catgets(dtsearch_catd, MS_chandel, 87,
2356                 "         Output file: %s\n") , outfile);
2357         }
2358 }                               /*--user_args_processor--*/
2359
2360 /****************************************************************************
2361      FLAG_SHUTDOWN - signal handler - to allow for graceful exiting
2362 ****************************************************************************/
2363 static void     flag_shutdown (int sig)
2364 {
2365                     shutdown_now = TRUE;
2366 }
2367
2368 /****************************************************************************
2369      MAIN - Body of Handel.  Checks user parameters, processes the profile
2370  file, and then goes into the main loop, running each record from the input
2371  file against the profile and thru the text processor.  
2372 *****************************************************************************/
2373 int             main (int argc, char **argv)
2374 {
2375     int         oops;
2376
2377     /*-- Initialization --*/
2378     aa_argv0 = argv[0];
2379     setlocale (LC_ALL, "");
2380     dtsearch_catd = catopen (FNAME_DTSRCAT, 0);
2381     printf ( catgets(dtsearch_catd, MS_chandel, 88,
2382         "%s. %s %s Text Filter.\n") ,
2383         aa_argv0, PRODNAME, DtSrVERSION);
2384
2385     time (&now);
2386     memcpy (&nowtm, localtime(&now), sizeof(struct tm));
2387     strftime (now_str, sizeof(now_str), "%y/%m/%d~%H:%M", &nowtm);
2388     memset (&rectm, 0, sizeof(struct tm));
2389
2390     /* check user arguments */
2391     user_arg_processor (argc, argv);
2392     if (bad_parm) {
2393         usage_msg ();
2394         exit (USAGE);
2395     }
2396
2397     process_profile ();
2398     if (warnings && !bad_profile) {
2399         signal (SIGINT, flag_shutdown);
2400         signal (SIGTERM, flag_shutdown);
2401         open_outfile ();
2402         printf ( catgets(dtsearch_catd, MS_chandel, 89,
2403                 "\nInterrupt with CTRL-C to exit gracefully "
2404                 "at record boundary.\n  Each dot is %ld records...\n"),
2405             RECS_PER_DOT);
2406         process_infile ();      /* process the input file */
2407         oops = fclose (outstream);
2408         fclose (instream);
2409         if (oops < 0) {
2410             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 90,
2411                 "\nError closing output file - disk full?\n") );
2412             exit (FILE_ERROR);
2413         }
2414     }
2415     else {
2416         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 91,
2417                 "Quitting due to errors in profile file.\n") );
2418         exit (BAD_PROFILE);
2419     }
2420     printf ( catgets(dtsearch_catd, MS_chandel, 92,
2421         "\n%s: Normal completion.  %ld records processed.  Exit code = 0.\n"),
2422         aa_argv0, rec_count);
2423     return 0;
2424 }
2425 /*************** DTSRHAN.C ****************/