Don't use fstat for readable pipe chars in dtexec.
[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         fgets (prof_line, 200, prof);
582         line_num++;
583         if (feof (prof))
584             break;
585         if (prof_line[0] == '#' || is_blank (prof_line))
586             continue;
587         tok = my_strtok (prof_line, del_string);
588         if (tok == NULL)
589             continue;   /* ignore blank line */
590         tok_type = token (tok);
591         switch (tok_type) {
592             case UPPER:
593                 uppercase = TRUE;
594                 break;
595
596             case LINE:
597                 /*-- build node --*/
598                 if (line_table == NULL) {
599                     line_table = (struct line_id *) malloc (
600                         sizeof (struct line_id));
601                     line_current = line_table;
602                     line_table->next = NULL;
603                     line_table->comp = (struct line_comp *) malloc (
604                         sizeof (struct line_comp));
605                     line_table->head = line_table->comp;
606                     line_table->comp->next = NULL;
607                 }
608                 /* if */
609                 else {
610                     line_current->next = (struct line_id *) malloc (
611                         sizeof (struct line_id));
612                     line_current = line_current->next;
613                     line_current->next = NULL;
614                     line_current->comp = (struct line_comp *) malloc (
615                         sizeof (struct line_comp));
616                     line_current->head = line_current->comp;
617                     line_current->comp->next = NULL;
618                 }               /* else */
619                 line_current->image_action = NONE;
620                 line_current->word_action = NONE;
621                 line_current->text_action = NONE;
622                 line_current->line = NULL;
623                 line_current->name[0] = 0;
624                 /*-- get identifier --*/
625                 tok = my_strtok ('\0', del_string);
626                 if (validate_id (tok))
627                     strcpy (line_current->name, tok);
628                 else {
629                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
630                         "Error line %d: invalid identifier '%s'.\n") ,
631                         line_num, NULLORSTR(tok));
632                     bad_profile = TRUE;
633                     break;
634                 }
635                 /*-- get first value token --*/
636                 tok = my_strtok ('\0', del_string);
637                 if (!tok) {
638                     printf ( catgets(dtsearch_catd, MS_chandel, 13,
639                         "Error line %d - identifier '%s' missing value(s).\n") ,
640                         line_num, line_current->name);
641                     bad_profile = TRUE;
642                     continue;
643                 }               /* if */
644                 if (!strcmp (tok, "*"))
645                     line_current->comp->column_number = ANY;
646                 else
647                     line_current->comp->column_number = atoi (tok);
648                 if (line_current->comp->column_number == 0) {
649                     printf ( catgets(dtsearch_catd, MS_chandel, 14,
650                         "Error line %d - zero or bad value for '%s'.\n"
651                         "  offensive token: %s.\n") ,
652                         line_num, line_current->name, tok);
653                     bad_profile = TRUE;
654                     continue;
655                 }               /* if */
656                 /* d d d-- get second token of pair -- */
657                 tok = my_strtok ('\0', "\"");
658                 if (!tok) {
659                     if (line_current->comp->column_number == ANY) {
660                         printf ( catgets(dtsearch_catd, MS_chandel, 15,
661                         "Error line %d - for identifier '%s', column has "
662                         "been set to ANY\n  but there is no "
663                         "identifying signature string.\n") , 
664                             line_num, line_current->name);
665                         bad_profile = TRUE;
666                         continue;
667                     }
668                     /* if (line.. */
669                     else {
670                         strcpy (line_current->comp->text, line_mode);
671                         continue;
672                     }           /* else */
673                 }
674                 /* if (!tok) */
675                 else {
676                     strcpy (line_current->comp->text, tok);
677                     line_current->comp->text_length =
678                         strlen (line_current->comp->text);
679                 }
680                 /*-- check for more tokens for LINE type of line --*/
681                 for(;;) {
682                     tok = my_strtok ('\0', del_string);
683                     if (!tok)
684                         break;
685                     /*-- build component node --*/
686                     line_current->comp->next = (struct line_comp *) malloc (
687                         sizeof (struct line_comp));
688                     line_current->comp = line_current->comp->next;
689                     line_current->comp->next = NULL;
690                     /*-- check # and store --*/
691                     if (!strcmp (tok, "*"))
692                         line_current->comp->column_number = ANY;
693                     else
694                         line_current->comp->column_number = atoi (tok);
695                     if (line_current->comp->column_number == 0) {
696                         printf ( catgets(dtsearch_catd, MS_chandel, 16,
697                         "Error line %d - zero or bad value for "
698                         "identifier '%s'\n  offensive token: %s.\n") ,
699                             line_num, line_current->name, tok);
700                         bad_profile = TRUE;
701                         continue;
702                     }           /* if (line.. */
703                     /* -  --- get second of pair -- */
704                     tok = my_strtok ('\0', "\"");
705                     if (!tok) {
706                         if (line_current->comp->column_number == ANY)
707                             printf ( catgets(dtsearch_catd, MS_chandel, 15,
708                                 "Error line %d - for identifier '%s', column has "
709                                 "been set to ANY\n  but there is no "
710                                 "identifying signature string.\n") , 
711                                 line_num, line_current->name);
712                         else
713                             printf ( catgets(dtsearch_catd, MS_chandel, 18,
714                                 "Error line %d - missing value for "
715                                 "identifier '%s'\n") ,
716                                 line_num, line_current->name);
717                         bad_profile = TRUE;
718                         continue;
719                     }           /* if (!tok) */
720                     strcpy (line_current->comp->text, tok);
721                     line_current->comp->text_length =
722                         strlen (line_current->comp->text);
723                 }  /* end for(;;) loop for continuing LINE token pairs */
724                 break;  /* end case LINE */
725
726             case CONSTANT:
727             case FIELD:
728                 if (field_table == NULL) {
729                     field_table = (struct field_id *)
730                         malloc (sizeof (struct field_id));
731                     field_current = field_table;
732                     field_table->next = NULL;
733                 }
734                 else {
735                     field_current->next = (struct field_id *) malloc (
736                         sizeof (struct field_id));
737                     field_current = field_current->next;
738                     field_current->next = NULL;
739                 }
740                 memset (field_current, 0, sizeof(struct field_id));
741                 field_current->word_action = NONE;
742                 field_current->image_action = NONE;
743                 field_current->text_action = NONE;
744                 if (tok_type == CONSTANT)
745                     field_current->constant = TRUE;
746
747                 /*-- get identifier --*/
748                 tok = my_strtok ('\0', del_string);
749                 if (validate_id (tok)) {
750                     strcpy (field_current->name, tok);
751                     if (strncmp (tok, "MMM", 3) == 0)
752                         field_current->is_month = TRUE;
753                 }
754                 else {
755                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
756                         "Error line %d: invalid identifier '%s'.\n") ,
757                         line_num, NULLORSTR(tok));
758                     bad_profile = TRUE;
759                     break;
760                 }
761                 if (field_current->constant) {
762                     /*-- get constant value --*/
763                     tok = my_strtok (NULL, "\"");
764                     if (!tok) {
765                         printf ( catgets(dtsearch_catd, MS_chandel, 93,
766                             "Error line %d - '%s' string not "
767                             "enclosed in double quotes.\n"),
768                             line_num, field_current->name);
769                         bad_profile = TRUE;
770                         continue;
771                     }
772                     strcpy (field_current->value, tok);
773                 }       /* end CONSTANT */
774
775                 else {  /* ...must be FIELD */
776                     /*-- get line id --*/
777                     tok = my_strtok ('\0', del_string);
778                     if (!tok) {
779                         printf ( catgets(dtsearch_catd, MS_chandel, 13,
780                             "Error line %d - identifier '%s' missing value(s).\n") ,
781                             line_num, line_current->name);
782                         bad_profile = TRUE;
783                         continue;
784                     }           /* if */
785                     strcpy (field_current->line_id, tok);
786
787                     /*-- get "string"  --*/
788                     tok = my_strtok ('\0', "\"");
789                     if (!tok) {
790                         printf ( catgets(dtsearch_catd, MS_chandel, 93,
791                             "Error line %d - '%s' string not "
792                             "enclosed in double quotes.\n"),
793                             line_num, field_current->name);
794                         bad_profile = TRUE;
795                         continue;
796                     }
797                     strcpy (field_current->text, tok);
798                     field_current->text_length = strlen (field_current->text);
799
800                     /*-- get offset --*/
801                     tok = my_strtok ('\0', del_string);
802                     if (!tok) {
803                         printf ( catgets(dtsearch_catd, MS_chandel, 13,
804                         "Error line %d - identifier '%s' missing value(s).\n") ,
805                             line_num, line_current->name);
806                         bad_profile = TRUE;
807                         continue;
808                     }           /* if */
809                     field_current->offset = atoi (tok);
810
811                     /*-- get length --*/
812                     tok = my_strtok ('\0', del_string);
813         /*******if (!tok && field_current->length == ANY) ************/
814                     if (!tok) {
815                         printf ( catgets(dtsearch_catd, MS_chandel, 13,
816                         "Error line %d - identifier '%s' missing value(s).\n") ,
817                             line_num, line_current->name);
818                         bad_profile = TRUE;
819                         continue;
820                     }           /* if */
821                     if (!strcmp (tok, "eoln"))
822                         field_current->defined_length = EOLN;
823                     else if (!strcmp (tok, "eow"))
824                         field_current->defined_length = EOW;
825                     else
826                         field_current->defined_length = atoi (tok);
827                 } /* end FIELD */
828                 break;
829
830             case DELIMITER:
831                 /*-- get next token - should be name of line --*/
832                 if (warnings &&(bot_defined || top_defined))
833                     printf ( catgets(dtsearch_catd, MS_chandel, 23,
834                         "Warning line %d: Delimiter redefined.\n") ,
835                         line_num);
836                 tok = my_strtok ('\0', del_string);
837                 if (validate_id (tok))
838                     strcpy (top_rec_name, tok);
839                 else {
840                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
841                         "Error line %d: invalid identifier '%s'.\n"),
842                         line_num, NULLORSTR(tok));
843                     bad_profile = TRUE;
844                 }
845                 tok = my_strtok ('\0', del_string);
846                 if (tok == NULL)
847                     goto BAD_DELIM_VAL;
848                 /* convert tok to lowercase */
849                 for (i = 0; i < strlen (tok); i++)
850                     tok[i] = tolower (tok[i]);
851                 if (!strcmp (tok, "top")) {
852                     top_defined = TRUE;
853                     bot_defined = FALSE;
854                 } else if (!strcmp (tok, "bottom")) {
855                     top_defined = FALSE;
856                     bot_defined = TRUE;
857                 } else {
858 BAD_DELIM_VAL:
859                     printf ( catgets(dtsearch_catd, MS_chandel, 25,
860                         "Error line %d: delimiter not specified as "
861                         "'top' or 'bottom'.\n") ,
862                     line_num);
863                     bad_profile = TRUE;
864                 }
865                 break;
866
867             case TFIELDEXCLUDE:
868                 tok = my_strtok ('\0', del_string);
869                 if (validate_id (tok)) {
870                     if (finclude_tab == NULL) {
871                         finclude_tab = (struct finclude *) malloc (
872                             sizeof (struct finclude));
873                         finclude_current = finclude_tab;
874                     } else {
875                         finclude_current->next = (struct finclude *) malloc (
876                             sizeof (struct finclude));
877                         finclude_current = finclude_current->next;
878                     }
879                     finclude_current->next = NULL;
880                     strcpy (finclude_current->field_id, tok);
881                     finclude_current->value = EXCLUDE;
882                 }
883                 /* if it was a valid token */
884                 else {
885                     printf ( catgets(dtsearch_catd, MS_chandel, 26,
886                         "Error line %d: invalid token '%s'.\n") ,
887                         line_num, NULLORSTR(tok));
888                     bad_profile = TRUE;
889                 }
890                 break;
891
892             case TFIELDINCLUDE:
893                 tok = my_strtok ('\0', del_string);
894                 if (validate_id (tok)) {
895                     if (finclude_tab == NULL) {
896                         finclude_tab = (struct finclude *) malloc (
897                             sizeof (struct finclude));
898                         finclude_tab->next = NULL;
899                         finclude_current = finclude_tab;
900                     }
901                     /* if valid */
902                     else {
903                         finclude_current->next = (struct finclude *) malloc (
904                             sizeof (struct finclude));
905                         finclude_current = finclude_current->next;
906                         finclude_current->next = NULL;
907                     }           /* else valid */
908                     strcpy (finclude_current->field_id, tok);
909                     finclude_current->value = INCLUDE;
910                 }
911                 /* if it was a valid token */
912                 else {
913                     printf ( catgets(dtsearch_catd, MS_chandel, 27,
914                         "Error line %d: invalid token '%s'.\n") ,
915                         line_num, NULLORSTR(tok));
916                     bad_profile = TRUE;
917                 }
918                 break;
919
920             case TEXTEXCLUDE:
921                 tok = my_strtok ('\0', del_string);
922                 if (validate_id (tok)) {
923                     if (include_tab == NULL) {
924                         include_tab = (struct include *) malloc (
925                                 sizeof (struct include));
926                         include_tab->next = NULL;
927                         include_current = include_tab;
928                     }
929                     /* if valid */
930                     else {
931                         include_current->next = (struct include *) malloc (
932                             sizeof (struct include));
933                         include_current = include_current->next;
934                         include_current->next = NULL;
935                     }           /* else in valid */
936                     strcpy (include_current->line_id, tok);
937                     tok = my_strtok ('\0', del_string);
938                     if (tok == NULL)
939                         include_current->value = EXCLUDE;
940                     else {
941                         if (validate_id (tok)) {
942                             include_current->value = SET;
943                             include_current->next = (struct include *) malloc (
944                                 sizeof (struct include));
945                             include_current = include_current->next;
946                             include_current->next = NULL;
947                             strcpy (include_current->line_id, tok);
948                             include_current->value = DEFAULT;
949                         }
950                         /* if in else */
951                         else {
952                             printf ( catgets(dtsearch_catd, MS_chandel, 12,
953                                 "Error line %d: invalid identifier '%s'.\n") ,
954                                 line_num, tok);
955                             bad_profile = TRUE;
956                         }       /* else in else */
957                     }           /* else tok wasn't NULL */
958                 }
959                 /* if validate... */
960                 else {
961                     printf (catgets(dtsearch_catd, MS_chandel, 12,
962                         "Error line %d: invalid identifier '%s'.\n") ,
963                         line_num, NULLORSTR(tok));
964                     bad_profile = TRUE;
965                 }               /* else not a valid token */
966                 break;
967
968             case IMAGEEXCLUDE:
969                 tok = my_strtok ('\0', del_string);
970                 if (validate_id (tok)) {
971                     if (i_i_t == NULL) {
972                         i_i_t = (struct include *) malloc (
973                                 sizeof (struct include));
974                         i_i_t->next = NULL;
975                         i_i_current = i_i_t;
976                     }
977                     /* if in valid */
978                     else {
979                         i_i_current->next = (struct include *) malloc (
980                             sizeof (struct include));
981                         i_i_current = i_i_current->next;
982                         i_i_current->next = NULL;
983                     }           /* else in valid */
984                     strcpy (i_i_current->line_id, tok);
985                     tok = my_strtok ('\0', del_string);
986                     if (tok == NULL)
987                         i_i_current->value = EXCLUDE;
988                     else {
989                         if (validate_id (tok)) {
990                             i_i_current->value = SET;
991                             i_i_current->next = (struct include *) malloc (
992                                 sizeof (struct include));
993                             i_i_current = i_i_current->next;
994                             i_i_current->next = NULL;
995                             strcpy (i_i_current->line_id, tok);
996                             i_i_current->value = DEFAULT;
997                         }
998                         /* if in else */
999                         else {
1000                             printf ( catgets(dtsearch_catd, MS_chandel, 12,
1001                                 "Error line %d: invalid identifier '%s'.\n") ,
1002                                 line_num, tok);
1003                             bad_profile = TRUE;
1004                         }       /* else in else */
1005                     }           /* else tok wasn't NULL */
1006                 }
1007                 /* if validate... */
1008                 else {
1009                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
1010                         "Error line %d: invalid identifier '%s'.\n") ,
1011                         line_num, NULLORSTR(tok));
1012                     bad_profile = TRUE;
1013                 }               /* else not a valid token */
1014                 break;
1015
1016             case IMAGEINCLUDE:
1017                 tok = my_strtok ('\0', del_string);
1018                 if (validate_id (tok)) {
1019                     if (i_i_t == NULL) {
1020                         i_i_t = (struct include *) malloc (
1021                                 sizeof (struct include));
1022                         i_i_t->next = NULL;
1023                         i_i_current = i_i_t;
1024                     }
1025                     /* if in valid */
1026                     else {
1027                         i_i_current->next = (struct include *) malloc (
1028                             sizeof (struct include));
1029                         i_i_current = i_i_current->next;
1030                         i_i_current->next = NULL;
1031                     }           /* else in valid */
1032                     strcpy (i_i_current->line_id, tok);
1033                     tok = my_strtok ('\0', del_string);
1034                     if (tok == NULL)
1035                         i_i_current->value = INCLUDE;
1036                     else {
1037                         if (validate_id (tok)) {
1038                             i_i_current->value = CLEAR;
1039                             i_i_current->next = (struct include *) malloc (
1040                                 sizeof (struct include));
1041                             i_i_current = i_i_current->next;
1042                             i_i_current->next = NULL;
1043                             strcpy (i_i_current->line_id, tok);
1044                             i_i_current->value = DEFAULT;
1045                         }
1046                         /* if in else */
1047                         else {
1048                             printf ( catgets(dtsearch_catd, MS_chandel, 12,
1049                                 "Error line %d: invalid identifier '%s'.\n") ,
1050                                 line_num, tok);
1051                             bad_profile = TRUE;
1052                         }       /* else in else */
1053                     }           /* else tok wasn't NULL */
1054                 }
1055                 /* if validate... */
1056                 else {
1057                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
1058                         "Error line %d: invalid identifier '%s'.\n") ,
1059                         line_num, NULLORSTR(tok));
1060                     bad_profile = TRUE;
1061                 }               /* else not a valid token */
1062                 break;
1063
1064             case TEXTINCLUDE:
1065                 tok = my_strtok ('\0', del_string);
1066                 if (validate_id (tok)) {
1067                     if (include_tab == NULL) {
1068                         include_tab = (struct include *) malloc (
1069                                 sizeof (struct include));
1070                         include_tab->next = NULL;
1071                         include_current = include_tab;
1072                     }
1073                     /* if in valid */
1074                     else {
1075                         include_current->next = (struct include *) malloc (
1076                             sizeof (struct include));
1077                         include_current = include_current->next;
1078                         include_current->next = NULL;
1079                     }           /* else in valid */
1080                     strcpy (include_current->line_id, tok);
1081                     tok = my_strtok ('\0', del_string);
1082                     if (tok == NULL)
1083                         include_current->value = INCLUDE;
1084                     else {
1085                         if (validate_id (tok)) {
1086                             include_current->value = CLEAR;
1087                             include_current->next = (struct include *) malloc (
1088                                 sizeof (struct include));
1089                             include_current = include_current->next;
1090                             include_current->next = NULL;
1091                             strcpy (include_current->line_id, tok);
1092                             include_current->value = DEFAULT;
1093                         }
1094                         /* if in else */
1095                         else {
1096                             printf ( catgets(dtsearch_catd, MS_chandel, 12,
1097                                 "Error line %d: invalid identifier '%s'.\n") ,
1098                                 line_num, tok);
1099                             bad_profile = TRUE;
1100                         }       /* else in else */
1101                     }           /* else tok wasn't NULL */
1102                 }
1103                 /* if validate... */
1104                 else {
1105                     printf ( catgets(dtsearch_catd, MS_chandel, 12,
1106                         "Error line %d: invalid identifier '%s'.\n") ,
1107                         line_num, NULLORSTR(tok));
1108                     bad_profile = TRUE;
1109                 }               /* else not a valid token */
1110                 break;
1111
1112             case IMAGE:
1113                 tok = my_strtok ('\0', del_string);
1114                 if (tok == NULL)
1115                     goto BAD_IMAGE;
1116                 for (i = 0; i < strlen (tok); i++)
1117                     tok[i] = tolower (tok[i]);
1118                 if (strcmp (tok, catgets (dtsearch_catd, MS_chandel, 34,"all")) == 0)
1119                     imagemode = INCLUDE;
1120                 else if (strcmp (tok, catgets (dtsearch_catd, MS_chandel, 35, "none")) == 0)
1121                     imagemode = EXCLUDE;
1122                 else {
1123 BAD_IMAGE:
1124                     printf ( catgets(dtsearch_catd, MS_chandel, 36,
1125                         "Error line %d: image mode must be 'all' or "
1126                         "'none' -'%s' not recognized.\n") ,
1127                         NULLORSTR(tok));
1128                     bad_profile = TRUE;
1129                 }
1130                 imageflag = imagemode;
1131                 break;
1132
1133             case TEXT:
1134                 tok = my_strtok ('\0', del_string);
1135                 if (tok == NULL)
1136                     goto BAD_TEXT;
1137                 for (i = 0; i < strlen (tok); i++)
1138                     tok[i] = tolower (tok[i]);
1139                 if (strcmp (tok, "all") == 0)
1140                     textmode = INCLUDE;
1141                 else if (strcmp (tok, "none") == 0)
1142                     textmode = EXCLUDE;
1143                 else {
1144 BAD_TEXT:
1145                     printf ( catgets(dtsearch_catd, MS_chandel, 37,
1146                         "Error line %d: text mode must be 'all' or "
1147                         "'none' - '%s' not recognized.\n") , NULLORSTR(tok));
1148                     bad_profile = TRUE;
1149                 }
1150                 textflag = textmode;
1151                 break;
1152
1153             case KEYCHAR:
1154                 /*-- get next token - should be character for key type --*/
1155                 if (warnings && key_defined)
1156                     printf ( catgets(dtsearch_catd, MS_chandel, 38,
1157                         "Warning line %d: Key character redefined.\n") ,
1158                         line_num);
1159                 tok = my_strtok ('\0', del_string);
1160                 if (validate_id (tok))
1161                     key_char = tok[0];
1162                 else {
1163                     printf ( catgets(dtsearch_catd, MS_chandel, 39,
1164                         "Error line %d: invalid Key Character:'%c'.\n") ,
1165                         line_num, (tok)?tok[0]:'?');
1166                     bad_profile = TRUE;
1167                 }
1168                 key_defined = TRUE;
1169                 break;
1170
1171
1172             case DATEFLD:
1173                 if (date_pos_defined) {
1174                     printf ( catgets(dtsearch_catd, MS_chandel, 110,
1175                         "Warning line %d - date field redefined.\n") ,
1176                         line_num);
1177                     null_date_specified = FALSE;
1178                 }
1179                 date_table = (struct date_id *) malloc
1180                         (sizeof (struct date_id));
1181                 date_current = date_table;
1182                 date_current->next = NULL;
1183                 tok = my_strtok ('\0', del_string);
1184                 /* validate_id() just does syntax chk on name string */
1185                 if (validate_id (tok))
1186                     strcpy (date_current->field_id, tok);
1187                 else {
1188                     /* Msg #111 used two places */
1189                     printf ( catgets(dtsearch_catd, MS_chandel, 111,
1190                         "Error line %d - bad identifier '%s' for date.\n") ,
1191                         line_num, NULLORSTR(tok));
1192                     bad_profile = TRUE;
1193                     break;
1194                 }
1195
1196                 /* Test for special "null" date value */
1197                 if (strcmp (date_current->field_id, "null") == 0) {
1198                     date_pos_defined = TRUE;
1199                     null_date_specified = TRUE;
1200                     break;
1201                 }
1202
1203                 tok = my_strtok ('\0', del_string);
1204                 while (tok != NULL) {
1205                     date_current->next = (struct date_id *) malloc
1206                         (sizeof (struct date_id));
1207                     date_current = date_current->next;
1208                     date_current->next = NULL;
1209                     if (validate_id (tok))
1210                         strcpy (date_current->field_id, tok);
1211                     else {
1212                         /* Msg #111 used two places */
1213                         printf ( catgets(dtsearch_catd, MS_chandel, 111,
1214                             "Error line %d - bad identifier '%s' for date.\n"),
1215                             line_num, NULLORSTR(tok));
1216                         bad_profile = TRUE;
1217                         break;
1218                     }
1219                     tok = my_strtok ('\0', del_string);
1220                 }
1221                 date_pos_defined = TRUE;
1222                 break;          /* end case DATEFLD */
1223
1224             case KEY:
1225                 /*-- building the key --*/
1226                 if (warnings && key_pos_defined)
1227                     printf ( catgets(dtsearch_catd, MS_chandel, 40,
1228                         "Warning line %d - key field redefined.\n") ,
1229                         line_num);
1230                 key_table = (struct key_id *) malloc (sizeof (struct key_id));
1231                 key_current = key_table;
1232                 key_current->next = NULL;
1233                 tok = my_strtok ('\0', del_string);
1234                 if (validate_id (tok)) {
1235                     if (is_time (tok)) {
1236                         strcpy (key_current->field_id, "time");
1237                         key_pos_defined = TRUE;
1238                         break;
1239                     } else if (is_count (tok)) {
1240                         strcpy (key_current->field_id, "count");
1241                         key_pos_defined = TRUE;
1242                         break;
1243                     } else
1244                         strcpy (key_current->field_id, tok);
1245                 }
1246                 else {
1247                     printf ( catgets(dtsearch_catd, MS_chandel, 43,
1248                         "Error line %d - bad identifier '%s' for key.\n") ,
1249                         line_num, NULLORSTR(tok));
1250                     bad_profile = TRUE;
1251                     break;
1252                 }
1253                 tok = my_strtok ('\0', del_string);
1254                 while (tok != NULL) {
1255                     key_current->next = (struct key_id *) malloc (
1256                         sizeof (struct key_id));
1257                     key_current = key_current->next;
1258                     key_current->next = NULL;
1259                     if (validate_id (tok))
1260                         strcpy (key_current->field_id, tok);
1261                     else {
1262                         printf ( catgets(dtsearch_catd, MS_chandel, 43,
1263                             "Error line %d - bad identifier '%s' for key.\n") ,
1264                             line_num, tok);
1265                         bad_profile = TRUE;
1266                         break;
1267                     }
1268                     tok = my_strtok ('\0', del_string);
1269                 }
1270                 key_pos_defined = TRUE;
1271                 break;
1272
1273             case DISCARD:
1274                 tok = my_strtok ('\0', del_string);
1275                 if (tok == NULL)
1276                     goto BAD_DISCARD;
1277                 for (i = 0; i < strlen (tok); i++)
1278                     tok[i] = toupper (tok[i]);
1279                 if (!strcmp (tok, "TRUE"))
1280                     discard = TRUE;
1281                 else if (!strcmp (tok, "FALSE"))
1282                     discard = FALSE;
1283                 else {
1284 BAD_DISCARD:
1285                     printf ( catgets(dtsearch_catd, MS_chandel, 45,
1286                         "Error line %d: unknown option for 'discard': "
1287                         "'%s'.\n") , line_num, NULLORSTR(tok));
1288                     bad_profile = TRUE;
1289                 }
1290                 break;
1291
1292             case DELBLANKLINES:
1293                 tok = my_strtok ('\0', del_string);
1294                 if (tok == NULL)
1295                     goto BAD_DELBLANKLINES;
1296                 for (i = 0; i < strlen (tok); i++)
1297                     tok[i] = toupper (tok[i]);
1298                 if (!strcmp (tok, "TRUE"))
1299                     del_blanklines = TRUE;
1300                 else if (!strcmp (tok, "FALSE"))
1301                     del_blanklines = FALSE;
1302                 else {
1303 BAD_DELBLANKLINES:
1304                     printf ( catgets(dtsearch_catd, MS_chandel, 46,
1305                         "Error line %d: unknown option for "
1306                         "'delblanklines': '%s'.\n") ,
1307                         line_num, NULLORSTR(tok));
1308                     bad_profile = TRUE;
1309                 }
1310                 break;
1311
1312             case ABSTR:
1313                 tok = my_strtok ('\0', del_string);
1314                 abstract = token (tok);
1315                 switch (abstract) {
1316                     case GENERATE:
1317                         break;
1318                     case USER:
1319                         tok = my_strtok ('\0', del_string);
1320                         if (tok == NULL)
1321                             goto BAD_ABSTR;
1322                         strcpy (abstracter, tok);
1323                         break;
1324                     case FIELDS:
1325                         tok = my_strtok ('\0', del_string);
1326                         while (tok != NULL) {
1327                             if (abstract_table == NULL) {
1328                                 abstract_table = (struct key_id *) malloc
1329                                     (sizeof (struct key_id));
1330                                 abstract_current = abstract_table;
1331                             } else {
1332                                 abstract_current->next =
1333                                     (struct key_id *) malloc (
1334                                         sizeof (struct key_id));
1335                                 abstract_current = abstract_current->next;
1336                             }
1337                             strcpy (abstract_current->field_id, tok);
1338                             abstract_current->next = NULL;
1339                             tok = my_strtok ('\0', del_string);
1340                         }
1341                         break;
1342                     default:
1343 BAD_ABSTR:
1344                         printf ( catgets(dtsearch_catd, MS_chandel, 47,
1345                         "Error line %d: Unknown option for abstract :'%s'\n"),
1346                         line_num, NULLORSTR(tok));
1347                         bad_profile = TRUE;
1348                         break;
1349                 }               /* 'abstract' subswitch */
1350                 break;
1351
1352             default:
1353                 printf ( catgets(dtsearch_catd, MS_chandel, 48,
1354                         "Error line %d -unknown identifier type '%s'.\n") ,
1355                     line_num,  NULLORSTR(tok));
1356                 bad_profile = TRUE;
1357                 break;
1358         }                       /* main switch for each line in profile */
1359     } while (TRUE);             /* read-a-line do loop */
1360     if (!date_pos_defined)
1361         fprintf (aa_stderr,  catgets(dtsearch_catd, MS_chandel, 115,
1362             "%s Default object dates will be '%s'.\n") ,
1363             PROGNAME"1288", now_str);
1364     if (bad_profile)
1365         return;
1366
1367     /*---- Process tables, and check for identifiers referenced ----*/
1368     if (!top_defined && !bot_defined) {
1369         bad_profile = TRUE;
1370         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 49,
1371                 "Error - delimiter not defined.\n") );
1372     }
1373     if (!key_defined) {
1374         bad_profile = TRUE;
1375         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 50,
1376                 "Error - key-type character never defined.\n") );
1377     }
1378     if (!key_pos_defined) {
1379         bad_profile = TRUE;
1380         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 51,
1381                 "Error - key never defined.\n") );
1382     }
1383     if (bad_profile)
1384         return;
1385
1386     top_rec = NULL;
1387     line_current = line_table;
1388     while (line_current != NULL) {
1389         if (strcmp (line_current->name, top_rec_name) == 0)
1390             top_rec = line_current;
1391         line_current = line_current->next;
1392     }
1393     if (top_rec_name[0] != 0 && top_rec == NULL) {
1394         printf ( catgets(dtsearch_catd, MS_chandel, 52,
1395                 "Error - delimiter defined as '%s' was never found.\n") ,
1396             top_rec_name);
1397         bad_profile = TRUE;
1398     } else if (strcmp (top_rec->head->text, line_mode) == 0) {
1399         printf ( catgets(dtsearch_catd, MS_chandel, 53,
1400             "Error - delimiter defined as '%s' references a physical "
1401             "line in the record.\n   Since the delimiter defines the "
1402             "physical lines\n  it cannot be referenced as a physical line.\n"),
1403             top_rec_name);
1404         bad_profile = TRUE;
1405     }
1406     field_current = field_table;
1407     while (field_current != NULL) {
1408         found = FALSE;
1409         line_current = line_table;
1410         while (line_current != NULL) {
1411             if (!strcmp (field_current->line_id, line_current->name)) {
1412                 found = TRUE;
1413                 field_current->line = line_current;
1414             }
1415             line_current = line_current->next;
1416         }
1417         if (!found && !field_current->constant) {
1418             printf ( catgets(dtsearch_catd, MS_chandel, 54,
1419                 "Error - for field '%s', no line identifer matches '%s'.\n") ,
1420                 field_current->name, field_current->line_id);
1421             bad_profile = TRUE;
1422         }
1423         field_current = field_current->next;
1424     }
1425     finclude_current = finclude_tab;
1426     while (finclude_current != NULL) {
1427         /* find field, and set text_value */
1428         field_current = field_table;
1429         found = FALSE;
1430         while (field_current != NULL) {
1431             if (!strcmp (field_current->name, finclude_current->field_id)) {
1432                 field_current->text_action = finclude_current->value;
1433                 found = TRUE;
1434             }
1435             field_current = field_current->next;
1436         }
1437         if (!found) {
1438             printf ( catgets(dtsearch_catd, MS_chandel, 55,
1439                 "Error - field include/exclude list included\n"
1440                 "  the field '%s', which was never defined.\n") ,
1441                 finclude_current->field_id);
1442             bad_profile = TRUE;
1443         }
1444         finclude_current = finclude_current->next;
1445     }
1446     i_i_current = i_i_t;
1447     while (i_i_current != NULL) {
1448         /* find line, and set text_action */
1449         line_current = line_table;
1450         found = FALSE;
1451         while (line_current != NULL) {
1452             if (!strcmp (line_current->name, i_i_current->line_id)) {
1453                 line_current->image_action = i_i_current->value;
1454                 found = TRUE;
1455             }
1456             line_current = line_current->next;
1457         }
1458         if (!found) {
1459             printf ( catgets(dtsearch_catd, MS_chandel, 56,
1460                 "Error - image include/exclude list included\n"
1461                 "  the line '%s', which was never defined.\n") ,
1462                 include_current->line_id);
1463             bad_profile = TRUE;
1464         }
1465         i_i_current = i_i_current->next;
1466     }
1467     include_current = include_tab;
1468     while (include_current != NULL) {
1469         /* find line, and set text_action */
1470         line_current = line_table;
1471         found = FALSE;
1472         while (line_current != NULL) {
1473             if (!strcmp (line_current->name, include_current->line_id)) {
1474                 line_current->text_action = include_current->value;
1475                 found = TRUE;
1476             }
1477             line_current = line_current->next;
1478         }
1479         if (!found) {
1480             printf ( catgets(dtsearch_catd, MS_chandel, 57,
1481                 "Error - text include/exclude list included\n"
1482                 "  the line '%s', which was never defined.\n") ,
1483                 include_current->line_id);
1484             bad_profile = TRUE;
1485         }
1486         include_current = include_current->next;
1487     }
1488
1489     /* If "null" dates specified, no need to look for other date fields */
1490     if (null_date_specified) 
1491         goto END_DATE_TABLE;
1492
1493     /* loop thru date table and link each field id to its structure */
1494     for (date_current = date_table; date_current != NULL;
1495         date_current = date_current->next) {
1496         found = FALSE;
1497
1498         for (field_current = field_table; field_current != NULL;
1499             field_current = field_current->next) {
1500             if (strcmp (field_current->name, date_current->field_id) == 0) {
1501                 date_current->field = field_current;
1502                 found = TRUE;
1503                 break;
1504             }
1505         }
1506         if (!found) {
1507             printf ( catgets(dtsearch_catd, MS_chandel, 116,
1508                 "Error - date references undefined field '%s'.\n"),
1509                 date_current->field_id);
1510             bad_profile = TRUE;
1511         }
1512     }
1513 END_DATE_TABLE:
1514
1515     key_current = key_table;
1516     while (key_current != NULL) {
1517         field_current = field_table;
1518         found = FALSE;
1519         if (!strcmp ("time", key_current->field_id)) {
1520             found = TRUE;
1521             key_current->field = NULL;
1522         } else if (!strcmp ("count", key_current->field_id)) {
1523             found = TRUE;
1524             key_current->field = NULL;
1525         }
1526         while (field_current != NULL) {
1527             if (!strcmp (field_current->name, key_current->field_id)) {
1528                 found = TRUE;
1529                 key_current->field = field_current;
1530             } else if (!strcmp ("time", key_current->field_id)) {
1531                 found = TRUE;
1532                 key_current->field = NULL;
1533             } else if (!strcmp ("count", key_current->field_id)) {
1534                 found = TRUE;
1535                 key_current->field = NULL;
1536             }
1537             field_current = field_current->next;
1538         }
1539         if (!found) {
1540             printf ( catgets(dtsearch_catd, MS_chandel, 58,
1541                 "Error - key definition references field '%s'\n"
1542                 "  which was never defined.\n") ,
1543                 key_current->field_id);
1544             bad_profile = TRUE;
1545         }
1546         key_current = key_current->next;
1547     }
1548     abstract_current = abstract_table;
1549     while (abstract_current != NULL) {
1550         field_current = field_table;
1551         found = FALSE;
1552         while (field_current != NULL) {
1553             if (!strcmp (field_current->name, abstract_current->field_id)) {
1554                 found = TRUE;
1555                 abstract_current->field = field_current;
1556             }
1557             field_current = field_current->next;
1558         }
1559         if (!found) {
1560             printf ( catgets(dtsearch_catd, MS_chandel, 59,
1561                 "Error - abstract definition references field '%s'\n"
1562                 "  which was never defined.\n") ,
1563                 abstract_current->field_id);
1564             bad_profile = TRUE;
1565         }
1566         abstract_current = abstract_current->next;
1567     }
1568
1569 } /*--process_profile--*/
1570
1571 /**********************************************************************
1572    CLEANUP - frees memory used by record
1573 ***********************************************************************/
1574 void            cleanup ()
1575 {
1576     struct line_id *line_current;
1577     struct field_id *field_current;
1578     struct rec     *record;
1579
1580     /*-- Reset line_table --*/
1581     line_current = line_table;
1582     while (line_current != NULL) {
1583         line_current->line = UNDEFINED;
1584         line_current = line_current->next;
1585     }
1586
1587     /*-- Reset field table --*/
1588     field_current = field_table;
1589     while (field_current != NULL) {
1590         if (field_current->constant == FALSE)
1591             field_current->value[0] = 0;
1592         field_current = field_current->next;
1593     }
1594
1595     /*-- clean up record, free memory for reuse --*/
1596     record = record_head;
1597     while (record_head != NULL) {
1598         record_head = record->next;
1599         free (record);
1600         record = record_head;
1601     }
1602 }
1603
1604 /**************************************************************************
1605    WRITE_RECORD - writes the final form of the record - key, fzkey, abstract,
1606  and image.
1607 **************************************************************************/
1608 void            write_record ()
1609 {
1610     static int      dotcount = 0;
1611     char           *ptr;
1612     struct key_id  *abst;
1613     struct rec     *record;
1614     char            value[200];
1615     int             lvalue;
1616     int             i;
1617     int             good = FALSE;
1618     char            buffer[200];
1619
1620     /* Line #1 is fzkey */
1621     fprintf (outstream, " 0,2\n"); /* hardcoded null fzkey */
1622
1623     /* Line #2 is abstract */
1624     value[0] = 0;
1625     if (abstract == FIELDS) {
1626         abst = abstract_table;
1627         while (abst != NULL) {
1628             strcat (value, abst->field->value);
1629             abst = abst->next;
1630         }
1631         for (i = 0; i < strlen (value); i++)
1632             if (value[i] == '\n')
1633                 value[i] = ' ';
1634     }
1635     fprintf (outstream, "ABSTRACT: %s\n", value);
1636
1637     /* Line #3 is unique database key */
1638     if (key_value[strlen (key_value) - 1] == '\n')
1639         key_value[strlen (key_value) - 1] = 0;
1640     if (uppercase)
1641         strupr (key_value);
1642     fprintf (outstream, "%c%s\n", key_char, key_value);
1643
1644     /* Line #4 is object date in objdate string format.
1645      * Prior to version 2.0.8 this would be the first line of text.
1646      */
1647     if (null_date_specified)
1648         fputs (NULLDATESTR"\n", outstream);
1649     else
1650         fprintf (outstream, "%s\n",
1651             objdate2fzkstr (tm2objdate (objdate_tmptr)));
1652
1653     /* Lines #5 and thereafter (text) of .fzk rec */
1654     record = record_head;
1655     while (record != NULL) {
1656         /*
1657          * Strip out any control-l's, as we put our own later,
1658          * and any extras might freak out something that wants
1659          * a control-l as a delimeter.
1660          */
1661         for (i = 0; i < strlen (record->text); i++)
1662             if (record->text[i] == CNTRL_L)
1663                 record->text[i] = ' ';
1664
1665         lvalue = (record->line)? record->line->image_action : 0;
1666         switch (lvalue) {
1667             case CLEAR:
1668                 imageflag = INCLUDE;
1669                 break;
1670             case SET:
1671                 imageflag = EXCLUDE;
1672                 break;
1673             default:
1674                 break;
1675         }
1676         if ((imageflag == INCLUDE && lvalue != EXCLUDE)
1677                 || (lvalue == INCLUDE)) {
1678             /* trim to fit in screen */
1679             strcpy (buffer, record->text);
1680             if (strlen (buffer) > screen_width) {
1681                 buffer[screen_width] = '\n';
1682                 buffer[screen_width + 1] = 0;
1683             }
1684             fprintf (outstream, "%s", buffer);
1685         }
1686         record = record->next;
1687         if (lvalue == DEFAULT)
1688             imageflag = imagemode;
1689     }
1690
1691     /* Test final record write to check for full filesystem */
1692     if (fprintf (outstream, "%c\n", CNTRL_L) <= 0) {
1693         printf ( catgets(dtsearch_catd, MS_chandel, 124,
1694             "%s Unable to write to output file '%s':\n  %s\n") ,
1695             PROGNAME"1663", outfile, strerror(errno));
1696         DtSearchExit (2);
1697     }
1698     return;
1699 } /* write_record */
1700
1701
1702 /************************************************/
1703 /*                                              */
1704 /*                mmm_to_digits                 */
1705 /*                                              */
1706 /************************************************/
1707 /* Translates a field value which is a recognizable month
1708  * name string into a two-char digit string from "01" to "12".
1709  */
1710 static void     mmm_to_digits (struct field_id *fld)
1711 {
1712     static char valbuf[8];
1713     static char *months = NULL;
1714     int         i;
1715
1716     if (months == NULL)
1717         months = strdup (catgets(dtsearch_catd, MS_chandel, 125,
1718             "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"));
1719     for (i=0; i<3; i++)
1720         valbuf[i] = toupper (fld->value[i]);
1721     for (i=0; i<12; i++)
1722         if (strncmp (valbuf, months + (i*3), 3) == 0) {
1723             sprintf (fld->value, "%02d", ++i);
1724             break;
1725         }
1726 return;
1727 } /* mmm_to_digits() */
1728
1729
1730 /************************************************/
1731 /*                                              */
1732 /*                process_record                */
1733 /*                                              */
1734 /************************************************/
1735 /* PROCESS_RECORD - does all processing for the record currently stored
1736  * in the data structure pointed to by record_head.  If record_head points
1737  * to NULL, it can safely be assumed that no record is currently awaiting
1738  * processing.
1739  */
1740 void    process_record (void)
1741 {
1742     struct field_id
1743                 *field_current;
1744     struct key_id
1745                 *key_current;
1746     struct date_id
1747                 *date_current;
1748     struct rec  *record;
1749     char        *pos;
1750     char        value[200];
1751     int         lvalue;
1752     int         i;
1753     int         linelen;
1754     char        date_value[256];
1755     int         dummy;
1756     int         meaningless;
1757     static int  dotcount = 0;
1758
1759     if (record_head == NULL)
1760         return;
1761
1762     /* Print progress dots and messages */
1763     rec_count++;
1764     if (rec_count % RECS_PER_DOT == 0L) {
1765         putchar('.');
1766         if (++dotcount % 10 == 0)
1767             putchar(' ');
1768         if (dotcount % 50 == 0) {
1769             putchar('\n');
1770             dotcount = 0;
1771         }
1772         fflush(stdout);
1773     }
1774
1775     discard_record = FALSE;
1776     meaningless = FALSE;
1777
1778     /* Main loop on every line in record */
1779     record = record_head;
1780     while (record != NULL) {
1781         lvalue = (record->line)? record->line->text_action : 0;
1782         switch (lvalue) {
1783             case CLEAR:
1784                 textflag = INCLUDE;
1785                 break;
1786             case SET:
1787                 textflag = EXCLUDE;
1788                 break;
1789             default:
1790                 break;
1791         }                       /* switch */
1792
1793         field_current = field_table;
1794         while (field_current != NULL) {
1795             if (field_current->line == record->line) {
1796                 /* this field is defined within this line */
1797                 memset (value, 0, sizeof(value));
1798
1799                 /* If profile pattern str was empty ("") ...*/
1800                 if (field_current->text[0] == 0) {
1801                     if (field_current->defined_length == EOLN)
1802                         strncpy (value, record->text +
1803                             (field_current->offset - 1), sizeof(value)-1);
1804                     else if (field_current->defined_length == EOW)
1805                         /* copy until end of word only */
1806                         for (dummy = 0;
1807                              (!isspace ((record->text +
1808                                 (field_current->offset - 1))[dummy]))
1809                                 &&  dummy < sizeof(value);
1810                              dummy++
1811                              )
1812                                 value[dummy] = (record->text +
1813                                     (field_current->offset - 1))[dummy];
1814                     else {
1815                         i = (field_current->defined_length < sizeof(value))?
1816                             field_current->defined_length : sizeof(value)-1;
1817                         strncpy (value,
1818                             record->text + (field_current->offset - 1),
1819                             i);
1820                     }
1821                 }
1822
1823                 /* ...else if profile pattern str was not empty ("xxx") */
1824                 else {
1825                     pos = strstr (record->text, field_current->text);
1826                     if (pos != NULL) {  /* pattern found... */
1827                         if (field_current->defined_length == EOLN)
1828                             strncpy (value,
1829                                 pos + (field_current->offset - 1),
1830                                 sizeof(value) - 1);
1831                         else if (field_current->defined_length == EOW)
1832                             /* copy until end of word only */
1833                             for (dummy = 0;
1834                                  (!isspace ((pos +
1835                                     (field_current->offset - 1))[dummy]))
1836                                     &&  dummy < sizeof(value);
1837                                  dummy++
1838                                  )
1839                                     value[dummy] = (pos +
1840                                         (field_current->offset - 1))[dummy];
1841                         else {
1842                             i = (field_current->defined_length<sizeof(value))?
1843                                 field_current->defined_length : sizeof(value)-1;
1844                             strncpy (value,
1845                                 pos + (field_current->offset - 1),
1846                                 i);
1847                         }
1848                     }   /* end pattern found */
1849                 } /* end else where pattern str not empty */
1850
1851                 /* strip \n's out of value */
1852                 for (i = 0; i < strlen (value); i++)
1853                     if (value[i] == '\n')
1854                         value[i] = 0;
1855                 if (field_current->constant == FALSE) {
1856                     strncpy (field_current->value, value,
1857                         sizeof(field_current->value));
1858                     field_current->value [sizeof(field_current->value)-1] = 0;
1859                     field_current->length = strlen (field_current->value);
1860                     if (field_current->is_month)
1861                         mmm_to_digits (field_current);
1862                 }
1863             }
1864             field_current = field_current->next;
1865         } /* end while loop on each field within each line */
1866
1867         if (lvalue == DEFAULT)
1868             textflag = textmode;
1869         record = record->next;
1870     } /* end while loop on each record line */
1871
1872
1873     /* Build a handel date_value string from specified fields.
1874      * If 'date' was not specified, uses current date/time.
1875      * If 'date = null' was specified, uses special constant string.
1876      * If value error in specified date fields,
1877      * uses current date/time and prints err msg. 
1878      */
1879     objdate_tmptr = &nowtm;             /* default */
1880     if (date_pos_defined && !null_date_specified) {
1881         date_value[0] = 0;
1882         for (date_current = date_table; date_current != NULL;
1883             date_current = date_current->next) {
1884             if (date_current->field->value[0] != 0) {
1885                 strcat (date_value, date_current->field->value);
1886             }
1887             else {
1888                 date_value[0] = 0;      /* flags error msg */
1889                 break;
1890             }
1891         }
1892
1893         /*
1894          * Validate format for date_value of this record.
1895          * Date value format: YYYYMMDDhhmm (exactly 12 digits).
1896          * The area at date_value + 100 is just a little atoi buffer. 
1897          */
1898         if (date_value[0] == 0)
1899             goto BAD_DATE_VALUE;
1900         if (strlen (date_value) != 12)
1901             goto BAD_DATE_VALUE;
1902         for (i = 0; i < 12; i++)
1903             if (!isdigit (date_value[i]))
1904                 goto BAD_DATE_VALUE;
1905
1906         /* year = YYYY */
1907         strncpy (date_value + 100, date_value, 4);
1908         date_value[104] = 0;
1909         i = atoi (date_value + 100);
1910         if (i < 1900 || i > 5995)       /* valid OBJDATE years */
1911             goto BAD_DATE_VALUE;
1912         else
1913             rectm.tm_year = i - 1900;
1914
1915         /* month = MM */
1916         strncpy (date_value + 100, date_value + 4, 2);
1917         date_value[102] = 0;
1918         i = atoi (date_value + 100);
1919         if (i < 1 || i > 12)
1920             goto BAD_DATE_VALUE;
1921         else
1922             rectm.tm_mon = i - 1;       /* tm values = 0 - 11 */
1923
1924         /* day = DD */
1925         strncpy (date_value + 100, date_value + 6, 2);
1926         date_value[102] = 0;
1927         i = atoi (date_value + 100);
1928         if (i < 1 || i > 31)
1929             goto BAD_DATE_VALUE;
1930         else
1931             rectm.tm_mday = i;
1932
1933         /* hours = hh */
1934         strncpy (date_value + 100, date_value + 8, 2);
1935         date_value[102] = 0;
1936         i = atoi (date_value + 100);
1937         if (i < 0 || i > 23)
1938             goto BAD_DATE_VALUE;
1939         else
1940             rectm.tm_hour = i;
1941
1942         /* minutes = mm */
1943         strncpy (date_value + 100, date_value + 10, 2);
1944         date_value[102] = 0;
1945         i = atoi (date_value + 100);
1946         if (i < 0 || i > 59)
1947             goto BAD_DATE_VALUE;
1948         else
1949             rectm.tm_min = i;
1950
1951         objdate_tmptr = &rectm;
1952         goto GOOD_DATE_VALUE;
1953
1954     BAD_DATE_VALUE:
1955         objdate_tmptr = &nowtm;
1956         printf ( catgets(dtsearch_catd, MS_chandel, 133,
1957             "Warning - '%s' is invalid date specification.\n"
1958             "  Using '%s' date for record number %ld that began: %.30s\n") ,
1959             date_value, now_str, rec_count, record_head->text);
1960     GOOD_DATE_VALUE:
1961         ;
1962     }   /* end if (date_pos_defined) */
1963
1964     key_current = key_table;
1965     key_count++;
1966     for (dummy = 0; dummy < 80; dummy++)
1967         key_value[dummy] = 0;
1968     dummy = FALSE;
1969     while (key_current != NULL) {
1970         if (key_current->field == NULL) {
1971             if (strcmp (key_current->field_id, "time") == 0)
1972                 sprintf (key_value, "%ld%06ld", now, key_count);
1973             else        /* must be 'count' */
1974                 sprintf (key_value, "%09ld", key_count);
1975         } else if (key_current->field->value[0] != 0) {
1976             strcat (key_value, key_current->field->value);
1977         } else {
1978             dummy = TRUE;
1979         }
1980         key_current = key_current->next;
1981     }
1982     if (dummy && warnings) {
1983         printf ( catgets(dtsearch_catd, MS_chandel, 68,
1984                 "Warning - fields necessary for key not found.\n"
1985                 "  discarding record #%ld that began:\n  %s\n") ,
1986             rec_count, record_head->text);
1987     } else if (discard && meaningless && warnings) {
1988         printf ( catgets(dtsearch_catd, MS_chandel, 69,
1989                 "Warning - record #ld deemed meaningless, discarding...\n"
1990                 "  record began: %.60s\n") ,
1991             rec_count, record_head->text);
1992     } else {
1993         outcount++;
1994         write_record ();
1995     }
1996     cleanup ();
1997 } /*--process_record--*/
1998
1999
2000 /**************************************************************************
2001    NEW_REC - determines if the string sent represents a new record or
2002   not.
2003 **************************************************************************/
2004 int             new_rec (char *buffer)
2005 {
2006     int             cant_be = FALSE;
2007     top_rec->comp = top_rec->head;
2008     while (top_rec->comp != NULL) {
2009         if (strcmp (top_rec->comp->text, line_mode) != 0) {
2010             if (top_rec->comp->column_number == ANY) {
2011             if (strstr(buffer,top_rec->comp->text)==NULL) 
2012                     cant_be = TRUE;
2013             }
2014             /* if */
2015             else if (strncmp (buffer + (top_rec->comp->column_number - 1),
2016                         top_rec->comp->text,
2017                     strlen (top_rec->comp->text)) != 0)
2018                 cant_be = TRUE;
2019         }                       /* if */
2020         top_rec->comp = top_rec->comp->next;
2021     }                           /* while */
2022     if (cant_be == FALSE) {
2023         return TRUE;
2024     } else
2025         return FALSE;
2026 }                               /*--new_rec--*/
2027
2028 /**************************************************************************
2029    IS_WHITESPACE - returns true if the string passed contains only
2030  whitespace
2031 **************************************************************************/
2032 int             is_whitespace (char *s)
2033 {
2034     int             i;
2035     for (i = 0; i < strlen (s); i++)
2036         if (!isspace (s[i]) || s[i] == 12)
2037             return FALSE;
2038     return TRUE;
2039 }
2040
2041 /**************************************************************************
2042    PROCESS_INFILE - processes the input file, 1 record at a time.  For each
2043 record, the lines must first be compared against the line id's we have, to
2044 try and identify each line.  Then fields are processed against these lines,
2045 and finally fzk processing can begin on any lines that are indicated being
2046 important.
2047 ***************************************************************************/
2048 void            process_infile ()
2049 {
2050     int             line_num = 0;
2051     struct line_id *line_current;
2052     struct rec     *record;
2053     char            buffer[200];
2054     int             cant_be;
2055     time_t          startime = 0L;
2056     int             i;
2057     int             rc;
2058
2059     if (!strcmp (infile, "-"))
2060         instream = stdin;
2061     else {
2062         if ((instream = fopen (infile, "rt")) == NULL) {
2063             printf ( catgets(dtsearch_catd, MS_chandel, 70,
2064                 " Unable to open input file '%s'.\n") , infile);
2065             exit (FILE_ERROR);
2066         }
2067     }
2068
2069     record_head = NULL;
2070     time (&startime);
2071     while (fgets (buffer, sizeof (buffer) - 1, instream) != NULL) {
2072         /* clean any non ASCII characters out of buffer */
2073         delete_whitespace (buffer);
2074         if (feof (instream))
2075             continue;           /*-* end of file *-*/
2076         if (del_blanklines && is_whitespace (buffer))
2077             continue;
2078         if (new_rec (buffer)) {
2079             if (bot_defined) {
2080                 if (record_head == NULL) {
2081                     record_head = (struct rec *) malloc (sizeof (struct rec));
2082                     record = record_head;
2083                 } else {
2084                     record->next = (struct rec *) malloc (sizeof (struct rec));
2085                     record = record->next;
2086                 }
2087                 record->next = NULL;
2088                 line_num++;
2089                 record->line_num = line_num;
2090                 strcpy (record->text, buffer);
2091                 record->line = NULL;
2092                 /*-- search list of line_id's for a possible match --*/
2093                 line_current = line_table;
2094                 while (line_current != NULL) {
2095                     cant_be = FALSE;
2096                     line_current->comp = line_current->head;
2097                     while (line_current->comp != NULL) {
2098                         if (strcmp (line_current->comp->text, line_mode) != 0) {
2099                             if (line_current->comp->column_number == ANY) {
2100                                 if (strstr(buffer,line_current->comp->text)
2101                                         == NULL)
2102                                     cant_be = TRUE;
2103                             } else if (
2104                                     strncmp (buffer +
2105                                         (line_current->comp->column_number - 1),
2106                                         line_current->comp->text,
2107                                     strlen (line_current->comp->text)) != 0)
2108                                 cant_be = TRUE;
2109                         } else if (line_current->comp->column_number
2110                                 != line_num)
2111                             cant_be = TRUE;
2112                         line_current->comp = line_current->comp->next;
2113                     }
2114                     if (cant_be == FALSE) {
2115                         /* found a hit, set pointers */
2116                         line_current->line = record;
2117                         record->line = line_current;
2118                     }           /* if */
2119                     line_current = line_current->next;
2120                 }               /* while - line_current loop */
2121             }                   /* if bot_defined */
2122             process_record ();
2123             if (shutdown_now)
2124                 break;
2125             line_num = 0;
2126             started = TRUE;
2127             if (bot_defined)
2128                 continue;
2129         }
2130         if (record_head == NULL) {
2131             record_head = (struct rec *) malloc (sizeof (struct rec));
2132             record = record_head;
2133         } else {
2134             record->next = (struct rec *) malloc (sizeof (struct rec));
2135             record = record->next;
2136         }
2137         record->next = NULL;
2138         line_num++;
2139         record->line_num = line_num;
2140         strcpy (record->text, buffer);
2141         record->line = NULL;
2142         /*-- search list of line_id's for a possible match --*/
2143         line_current = line_table;
2144         while (line_current != NULL) {
2145             cant_be = FALSE;
2146             line_current->comp = line_current->head;
2147             while (line_current->comp != NULL) {
2148                 if (strcmp (line_current->comp->text, line_mode) != 0) {
2149                     if (line_current->comp->column_number == ANY) {
2150                   if (strstr(buffer,line_current->comp->text)==NULL){
2151                             cant_be = TRUE;
2152                         }
2153                     } else if (strncmp (buffer +
2154                                     (line_current->comp->column_number - 1),
2155                                 line_current->comp->text,
2156                             strlen (line_current->comp->text)) != 0) {
2157                         cant_be = TRUE;
2158                     }
2159                 } else if (line_current->comp->column_number != line_num) {
2160                     cant_be = TRUE;
2161                 }
2162                 line_current->comp = line_current->comp->next;
2163             }
2164             if (cant_be == FALSE) {
2165                 /* found a hit, set pointers */
2166                 line_current->line = record;
2167                 record->line = line_current;
2168             }                   /* if */
2169             line_current = line_current->next;
2170         }                       /* while - line_current loop */
2171         for (rc = 0; rc < 200; rc++)
2172             buffer[rc] = 0;
2173     }                           /* while - buffer read loop */
2174     /*- check for any leftover records -*/
2175     process_record ();
2176 }   /*-- process_infile --*/
2177
2178
2179 /************************************************/
2180 /*                                              */
2181 /*                  usage_msg                   */
2182 /*                                              */
2183 /************************************************/
2184 static void     usage_msg (void)
2185 {
2186     static char       *default_text =
2187       "\nUSAGE: %s [options] <profile> <infile> [<outfile>]\n"
2188       "  -m         Turn off all but error messages.\n"
2189       "  -wN        Change target screen width to <N>.\n"
2190       "  -oo        Preapprove overwrite of outfile.\n"
2191       "  -oa        Preapprove append to outfile.\n"
2192       "  <profile>  Input file containing profile of records\n"
2193       "             to be processed.\n"
2194       "  <infile>   Input file containing actual records.\n"
2195       "  <outfile>  Output file name, .fzk format (%s).\n\n";
2196
2197     if (!warnings)
2198         return;
2199     printf (catgets (dtsearch_catd, MS_chandel, 71, default_text),
2200       aa_argv0, EXT_FZKEY);
2201     return;
2202 } /* usage_msg() */
2203
2204
2205 /************************************************/
2206 /*                                              */
2207 /*              user_arg_processor              */
2208 /*                                              */
2209 /************************************************/
2210 /* Process any user arguments passed thru the command line parameters. */
2211 static void     user_arg_processor (int argc, char **argv)
2212 {
2213     char        *cptr, *argptr;
2214     char        *pos;
2215
2216     if (argc <= 1) {
2217         bad_parm = TRUE;
2218         return;
2219     }                           /* if */
2220     while (--argc > 0 && (*++argv)[0] == '-') {
2221         argptr = argv[0];
2222         argptr[1] = tolower (argptr[1]);
2223         switch (argptr[1]) {
2224
2225             case 'w':
2226                 if ((screen_width = atoi (argptr + 2)) == 0) {
2227                     printf ( "%s", catgets(dtsearch_catd, MS_chandel, 72,
2228                         "Invalid screen width specified.\n") );
2229                     bad_parm = TRUE;
2230                 }
2231                 break;
2232
2233             case 'm':
2234                 warnings = FALSE;
2235                 break;
2236
2237             case 'o':
2238                 argptr[2] = tolower (argptr[2]);
2239                 if (argptr[2] == 'o')
2240                     strcpy (outmode, "w");
2241                 else if (argptr[2] == 'a')
2242                     strcpy (outmode, "a");
2243                 else {
2244                     printf ( catgets(dtsearch_catd, MS_chandel, 75,
2245                         "'%s' is invalid output mode.\n") , argptr);
2246                     bad_parm = TRUE;
2247                 }               /* else */
2248                 outmode_specified = TRUE;
2249                 break;
2250
2251             default:
2252                 printf ( catgets(dtsearch_catd, MS_chandel, 76,
2253                         "Unknown command line argument '%s'.\n") , argptr);
2254                 bad_parm = TRUE;
2255         }                       /*--switch--*/
2256     }                           /*--while--*/
2257
2258     if (argc-- <= 0) {
2259         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 77,
2260                 "Missing required profile-file name.\n") );
2261         bad_parm = TRUE;
2262     }
2263     /* if */
2264     else {
2265 /******
2266     strcpy(profile,argv[0]);
2267     profile=argv[0];
2268 *******/
2269         profile = (char *) malloc (sizeof (char) * (strlen (argv[0])) +10);
2270         strcpy (profile, argv[0]);
2271         if (strchr (profile, '.') == NULL)
2272             strcat (profile, EXT_HANDEL);
2273     }
2274
2275     if (argc-- <= 0) {
2276         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 78,
2277                 "Missing required input-file name.\n") );
2278         bad_parm = TRUE;
2279     }
2280     /* if */
2281     else
2282 /********    strcpy(infile,argv[1]); ********/
2283         infile = argv[1];
2284
2285     if (argc-- <= 0) {
2286 /*****************
2287       strcpy(outfile,infile);
2288       if (strchr(outfile,'.')!=NULL)
2289          strcpy(strchr(outfile,'.'), EXT_FZKEY);
2290       else
2291          strcat(outfile,EXT_FZKEY);
2292 *****************/
2293         if (strcmp (infile, "-") == 0) {
2294             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 79, "Error - using "
2295                 "stdin as input, output filename is required!\n") );
2296             exit (FILE_ERROR);
2297         } else {
2298             outfile = (char *) malloc (sizeof (char) * (strlen (infile) + 10));
2299             strcpy (outfile, infile);
2300             pos = strrchr (outfile, (int) '.');
2301             if (pos == NULL)
2302                 strcat (outfile, EXT_FZKEY);
2303             else {
2304                 pos++;
2305                 pos[0] = 'f';
2306                 pos++;
2307                 pos[0] = 'z';
2308                 pos++;
2309                 pos[0] = 'k';
2310                 pos++;
2311                 pos[0] = 0;
2312             }
2313         }
2314     }
2315     /* if */
2316     else
2317 /*    strcpy(outfile,argv[2]); */
2318         outfile = argv[2];
2319
2320 /*-- Sanity checks --*/
2321     /*-- duplicates? --*/
2322     if (strcmp (infile, profile) == 0) {
2323         printf ( catgets(dtsearch_catd, MS_chandel, 80,
2324                 "Profile file and input file have same name:'%s'.\n") ,
2325             infile);
2326         bad_parm = TRUE;
2327     }                           /* if */
2328     if (strcmp (infile, outfile) == 0 && strcmp (infile, "-")) {
2329         printf ( catgets(dtsearch_catd, MS_chandel, 81,
2330                 "Input file and output file have same name:'%s'.\n") ,
2331             infile);
2332         bad_parm = TRUE;
2333     }                           /* if */
2334     if (strcmp (profile, outfile) == 0) {
2335         printf ( catgets(dtsearch_catd, MS_chandel, 82,
2336                 "Profile file and output file have same name:'%s'.\n") ,
2337             profile);
2338         bad_parm = TRUE;
2339     }                           /* if */
2340     if(warnings)
2341         {
2342         printf ( catgets(dtsearch_catd, MS_chandel, 83,
2343                 "        Profile file: %s\n") , profile);
2344         if (strcmp (infile, "-") == 0)
2345             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 84,
2346                 "          Input file: stdin\n") );
2347         else
2348             printf ( catgets(dtsearch_catd, MS_chandel, 85,
2349                 "          Input file: %s\n") , infile);
2350         if (strcmp (outfile, "-") == 0)
2351             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 86,
2352                 "         Output file: stdout\n") );
2353         else
2354             printf ( catgets(dtsearch_catd, MS_chandel, 87,
2355                 "         Output file: %s\n") , outfile);
2356         }
2357 }                               /*--user_args_processor--*/
2358
2359 /****************************************************************************
2360      FLAG_SHUTDOWN - signal handler - to allow for graceful exiting
2361 ****************************************************************************/
2362 static void     flag_shutdown (int sig)
2363 {
2364                     shutdown_now = TRUE;
2365 }
2366
2367 /****************************************************************************
2368      MAIN - Body of Handel.  Checks user parameters, processes the profile
2369  file, and then goes into the main loop, running each record from the input
2370  file against the profile and thru the text processor.  
2371 *****************************************************************************/
2372 int             main (int argc, char **argv)
2373 {
2374     int         oops;
2375
2376     /*-- Initialization --*/
2377     aa_argv0 = argv[0];
2378     setlocale (LC_ALL, "");
2379     dtsearch_catd = catopen (FNAME_DTSRCAT, 0);
2380     printf ( catgets(dtsearch_catd, MS_chandel, 88,
2381         "%s. %s %s Text Filter.\n") ,
2382         aa_argv0, PRODNAME, DtSrVERSION);
2383
2384     time (&now);
2385     memcpy (&nowtm, localtime(&now), sizeof(struct tm));
2386     strftime (now_str, sizeof(now_str), "%y/%m/%d~%H:%M", &nowtm);
2387     memset (&rectm, 0, sizeof(struct tm));
2388
2389     /* check user arguments */
2390     user_arg_processor (argc, argv);
2391     if (bad_parm) {
2392         usage_msg ();
2393         exit (USAGE);
2394     }
2395
2396     process_profile ();
2397     if (warnings && !bad_profile) {
2398         signal (SIGINT, flag_shutdown);
2399         signal (SIGTERM, flag_shutdown);
2400         open_outfile ();
2401         printf ( catgets(dtsearch_catd, MS_chandel, 89,
2402                 "\nInterrupt with CTRL-C to exit gracefully "
2403                 "at record boundary.\n  Each dot is %ld records...\n"),
2404             RECS_PER_DOT);
2405         process_infile ();      /* process the input file */
2406         oops = fclose (outstream);
2407         fclose (instream);
2408         if (oops < 0) {
2409             printf ( "%s", catgets(dtsearch_catd, MS_chandel, 90,
2410                 "\nError closing output file - disk full?\n") );
2411             exit (FILE_ERROR);
2412         }
2413     }
2414     else {
2415         printf ( "%s", catgets(dtsearch_catd, MS_chandel, 91,
2416                 "Quitting due to errors in profile file.\n") );
2417         exit (BAD_PROFILE);
2418     }
2419     printf ( catgets(dtsearch_catd, MS_chandel, 92,
2420         "\n%s: Normal completion.  %ld records processed.  Exit code = 0.\n"),
2421         aa_argv0, rec_count);
2422     return 0;
2423 }
2424 /*************** DTSRHAN.C ****************/