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