Link with C++ linker
[oweals/cde.git] / cde / programs / dtsr / dtsrcreate.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: change_max_wordsize
27  *              change_min_wordsize
28  *              confirm_ok_to_overwrite
29  *              create_new_dbd
30  *              main
31  *              print_usage
32  *              remove_d9x_file
33  *              user_args_processor
34  *
35  *   ORIGINS: 27
36  *
37  *
38  *   (C) COPYRIGHT International Business Machines Corp. 1993,1996
39  *   All Rights Reserved
40  *   Licensed Materials - Property of IBM
41  *   US Government Users Restricted Rights - Use, duplication or
42  *   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
43  */
44 /************************* DTSRCREATE.C **************************
45  * $XConsortium: dtsrcreate.c /main/9 1996/09/23 21:02:04 cde-ibm $
46  * October 1993.
47  * Program formerly named initausd, in module initausd.c.
48  * Essentially performs the same function as vista's initdb,
49  * but uses only the dtsearch.dbd and renames the files during creation.
50  * Also creates and initializes the first slot, the 'dbrec'.
51  *
52  * $Log$
53  * Revision 2.8  1996/03/25  18:53:33  miker
54  * Changed FILENAME_MAX to _POSIX_PATH_MAX.
55  *
56  * Revision 2.7  1996/02/01  18:16:16  miker
57  * Changed some arg defaults depending on DTSEARCH definition.
58  * Deleted BETA definition.
59  *
60  * Revision 2.6  1995/12/27  16:10:03  miker
61  * Permit -wx before -wn on command line.
62  *
63  * Revision 2.5  1995/12/07  23:27:51  miker
64  * Fixed bug: minwordsz was > max when max inited to -1.
65  * Changed 'Engine Type' to 'Flavor' for AusBuild.
66  *
67  * Revision 2.4  1995/10/25  21:09:42  miker
68  * Added prolog.
69  *
70  * Revision 2.3  1995/10/20  21:28:25  miker
71  * Intelligently look for dtsearch.dbd in 3 places.
72  *
73  * Revision 2.2  1995/10/19  21:16:17  miker
74  * Internally rename database files so it doesn't have to be
75  * done at open time.  Ask permission to overwrite preexisting
76  * files.  Always create databases from current model dtsearch.dbd
77  * (elminate SECOND CASE).  Coincides with libDtvis enhancements.
78  *
79  * Revision 2.1  1995/09/22  19:32:18  miker
80  * Freeze DtSearch 0.1, AusText 2.1.8
81  *
82  * Revision 1.2  1995/09/19  21:56:53  miker
83  * Enabled Japanese language DtSrJPN.
84  * If DtSearch, use DtSrVERSION instead of AUSAPI_VERSION in banner.
85  *
86  * Revision 1.1  1995/08/31  20:50:28  miker
87  * Initial revision
88  */
89 #include "SearchP.h"
90 #include <limits.h>
91 #include <errno.h>
92 #include <ctype.h>
93 #include <sys/types.h>
94 #include <sys/stat.h>
95 #include <locale.h>
96 #include "vista.h"
97
98 #define PROGNAME                "DTSRCREATE"
99 #define DEFAULT_MINWORD         (MINWIDTH_TOKEN + 1)
100 #define STANDARD_MAXWORD        (DtSrMAXWIDTH_HWORD - 1)
101 #define MS_misc                 1
102 #define MS_initausd             12
103 #define FNAME_MODEL             "dtsearch.dbd"
104
105 /* The following MUST MATCH vista's dbtype.h! */
106 #define SIZEOF_FILE_ENTRY       252     /* sizeof(FILE_ENTRY) */
107 #define DBD_COMPAT_LEN          6
108 #define START_OF_FT             (DBD_COMPAT_LEN + (8 * sizeof(INT)))
109
110 /* Values for 'flavor' global variable */
111 #define AUSTEXT_FLAVOR  'a'
112 #define DTSEARCH_FLAVOR 'd'
113
114 /*------------------ GLOBALS -------------------*/
115 static int      abstrsz =       -1;
116 static char     dbname [12] =   "<dbname>";
117 struct or_dbrec dbrec;
118 static int      debug_mode =    FALSE;
119 static char     default_cant_open_msg[] =
120                                 "%s: %s: %s.\n";
121 static int      fzkeysz =       0;
122 static int      flavor =        DTSEARCH_FLAVOR;
123 static int      language =      DtSrLaENG;
124 static int      minwordsz =     DEFAULT_MINWORD;
125 static int      maxwordsz =     INT_MAX;
126 static int      max_ormisc_size;
127 static int      maxwidth_lword;
128 static int      maxwidth_sword;
129 static char     modelpath [_POSIX_PATH_MAX];
130                                 /* path/name of model dbd file */
131 static char     newpath [_POSIX_PATH_MAX];
132                                 /* path/name for each renamed file */
133 static char     *newextp;       /* loc where extension suffixes placed */
134 static int      ok_to_overwrite = FALSE;
135 static long     path_offset =   0;
136 static int      quiet_mode =    FALSE;
137
138 static char     *exttab[] = {
139         /* Must be in same order as model .dbd file tables */
140         ".d00", ".d01", ".d21", ".d22", ".d23",
141         ".k00", ".k01", ".k21", ".k22", ".k23",
142         NULL };
143
144 /* Same as MS_initausd, 213... */
145 static char     default_unable_to_open_msg[] =
146         "%1$s Unable to open '%2$s':\n  %3$s.\a\n";
147
148
149 /************************************************/
150 /*                                              */
151 /*          confirm_ok_to_overwrite             */
152 /*                                              */
153 /************************************************/
154 /* Called whenever we are about to write a new file.
155  * Checks to see if file preexists.  If it does,
156  * and user has never said it's ok to overwrite,
157  * prompts for permission to overlay all preexisting files.
158  * If 'yes', never asks again.  If 'no', exits.
159  * Returns if ok to overwrite, else exits.
160  */
161 static void     confirm_ok_to_overwrite (char *fname)
162 {
163     FILE        *fptr;
164     int         i;
165
166     if (ok_to_overwrite)
167         return;
168     if ((fptr = fopen (newpath, "r")) == NULL)
169         return;
170     fclose (fptr);
171
172     printf ( catgets(dtsearch_catd, MS_initausd, 12,
173         "\nFile '%s' already exists.\n"
174         "Is it ok to overwrite it and other database files? [y,n] ") ,
175         newpath);
176     i = tolower (getchar());
177     if (i == 'y')
178         ok_to_overwrite = TRUE;
179     else
180         DtSearchExit (2);
181     return;
182 } /* confirm_ok_to_overwrite() */
183
184
185 /************************************************/
186 /*                                              */
187 /*              change_max_wordsize             */
188 /*                                              */
189 /************************************************/
190 /* Subroutine of user_args_processor().
191  * Adjusts maxwordsz per user request and allowed sizes of schema.
192  */
193 static int      change_max_wordsize (char *new_size)
194 {
195     int         users_newsize;
196
197     maxwordsz = users_newsize = atoi (new_size);
198
199     /* error if min and max specifications incompatible */
200     if (minwordsz > maxwordsz) {
201         printf (catgets (dtsearch_catd, MS_initausd, 5,
202             PROGNAME" Minimum word size %d greater "
203             "than maximum word size %d.\n"),
204             minwordsz, maxwordsz);
205         return FALSE;
206     }
207
208     /* If necessary, adjust to nearest logical maxwordsz */
209     if (maxwordsz != maxwidth_sword &&
210         maxwordsz != maxwidth_lword &&
211         maxwordsz != DtSrMAXWIDTH_HWORD - 1) {
212         if (maxwordsz < maxwidth_sword)
213             maxwordsz = maxwidth_sword;
214         else if (maxwordsz < maxwidth_lword)
215             maxwordsz = maxwidth_lword;
216         else
217             maxwordsz = DtSrMAXWIDTH_HWORD - 1;
218     }
219
220     if (maxwordsz != users_newsize)
221         printf (catgets (dtsearch_catd, MS_initausd, 8,
222             PROGNAME " Adjusted maximum word size to %d.\n"),
223             maxwordsz);
224
225     /* Give user a final warning about large word sizes */
226     if (maxwordsz > STANDARD_MAXWORD && language != DtSrLaDEU && !quiet_mode)
227         printf (catgets (dtsearch_catd, MS_initausd, 10,
228                 PROGNAME" Specifying large maximum word sizes may "
229                 "significantly\n  increase storage requirements.\n"));
230     return TRUE;
231 }  /* change_max_wordsize() */
232
233
234 /************************************************/
235 /*                                              */
236 /*               change_min_wordsize            */
237 /*                                              */
238 /************************************************/
239 /* Subroutine of user_args_processor().
240  * Adjusts minwordsz per user request.
241  */
242 static int      change_min_wordsize (char *new_size)
243 {
244     int         old_minwordsz = minwordsz;
245     if ((minwordsz = atoi (new_size)) < 0)
246         return FALSE;
247
248     /* error if min and max specifications incompatible */
249     if (minwordsz > maxwordsz) {
250         printf (catgets (dtsearch_catd, MS_initausd, 5,
251             PROGNAME " Minimum word size %d greater than "
252             "maximum word size %d.\n"),
253             minwordsz, maxwordsz);
254         return FALSE;
255     }
256
257     if (!quiet_mode) {
258         if (minwordsz != old_minwordsz)
259             printf (catgets (dtsearch_catd, MS_initausd, 6,
260                 PROGNAME " Adjusted minimum word size to %d.\n"),
261                 minwordsz);
262
263         /* give user a warning about short word sizes */
264         if (minwordsz < DEFAULT_MINWORD)
265             printf (catgets (dtsearch_catd, MS_initausd, 9,
266                     PROGNAME " Specifying small minimum word sizes"
267                     " may require extensive\n"
268                     "  editing of stopword file to prevent significantly\n"
269                     "  increased index storage requirements.\n"));
270     }
271     return TRUE;
272 }  /* change_min_wordsize() */
273
274
275 /************************************************/
276 /*                                              */
277 /*                 print_usage                  */
278 /*                                              */
279 /************************************************/
280 static void     print_usage (void)
281 {
282     int         i;
283
284     printf (catgets (dtsearch_catd, MS_initausd,
285             3,
286   "\nUSAGE: %s [-options] dbname\n"
287   "       Creates and initializes DtSearch/AusText database files.\n"
288   "  -q       Do not print information messages.\n"
289   "  -o       Ok to overwrite preexisting database.\n"
290   "  -a<n>    Set maximum abstract size to <N> (default per flavor).\n"
291   "  -d<dir>  Dir containing "FNAME_MODEL" file if not in dbname dir.\n"
292   "  -wn<n>   Change minimum word size to <N>.  Default is %d.\n"
293   "  -wx<n>   Change maximum word size to <N>.  Default per language.\n"
294   "  ---------- Database Flavor ----------\n"
295   "  -fd      DtSearch flavor.  No documents, only document references\n"
296   "           in abstracts (default).\n"
297   "  -fa      AusText flavor.  Documents stored in central server repository.\n"
298   "  ------------ Supported Languages ------------\n"
299   "  -l<n>    Set language number to <N>.  Default is 0.  Supported values:\n"
300   "           0 English-ASCII\n"
301   "           1 English-Latin1\n"
302   "           2 Spanish\n"
303   "           3 French\n"
304   "           4 Italian\n"
305   "           5 German\n"
306   "           6 Japanese-autoknj\n"
307   "           7 Japanese-knjlist\n"
308   "  <dbname> Optional path prefix, then 1 - 8 character\n"
309   "           database name. Do not specify 'austext' or 'dtsearch'.\n"),
310             aa_argv0, DEFAULT_MINWORD);
311
312     return;
313 }  /* print_usage() */
314
315
316 /************************************************/
317 /*                                              */
318 /*              user_args_processor             */
319 /*                                              */
320 /************************************************/
321 /* Handles command line arguments for main().
322  * Initializes global variables.
323  */
324 static void     user_args_processor (int argc, char **argv)
325 {
326     int         i;
327     int         remaining_slot_space;
328     char        *ptr;
329
330     /* Initialize variables prior to parsing command line */
331     newpath[0] = 0;
332     modelpath[0] = 0;
333
334     if (argc < 2) {
335         print_usage();
336         DtSearchExit (2);
337     }
338
339     /* Each pass grabs new parm of "-xxx" format */
340     for (;;) {
341         argc--;
342         argv++;
343         if (argc <= 0)
344             break;
345         ptr = argv[0];
346         if (ptr[0] != '-')
347             break;
348
349         switch (ptr[1]) {
350             case 'r':   /* unadvertised debug mode */
351                 if (strcmp (ptr, "-russell") == 0) {
352                     debug_mode = TRUE;
353                     puts ("001*** debug mode.");
354                 }
355                 else {
356 BAD_ARG:
357                     print_usage();
358                     printf (catgets (dtsearch_catd, MS_misc, 9,
359                             "%sInvalid command line argument '%s'.\a\n"),
360                         "\n"PROGNAME" ", ptr);
361                     DtSearchExit (2);
362                 }
363                 break;
364
365             case 'a':
366                 /* zero length abstract may be explicity specified */
367                 abstrsz = atoi (ptr + 2);
368                 if (abstrsz < 0 || (abstrsz == 0 && ptr[2] != '0'))
369                     goto BAD_ARG;
370                 break;
371
372             case 'q':
373                 quiet_mode = TRUE;
374                 break;
375
376             case 'o':
377                 ok_to_overwrite = TRUE;
378                 break;
379
380             case 'f':
381                 switch (ptr[2]) {
382                     case AUSTEXT_FLAVOR:
383                     case DTSEARCH_FLAVOR:
384                         flavor = ptr[2];
385                         break;
386                     default:
387                         goto BAD_ARG;
388                 }
389                 break;
390
391             case 'w':   /* change min (-wn..) or max (-wx..) word size */
392                 switch (ptr[2]) {
393                     case 'x':
394                         if (!change_max_wordsize (ptr + 3))
395                             goto BAD_ARG;
396                         break;
397                     case 'n':
398                         if (!change_min_wordsize (ptr + 3))
399                             goto BAD_ARG;
400                         break;
401                     default:
402                         goto BAD_ARG;
403                 }
404                 break;
405
406             case 'd':   /* special path name for model .dbd */
407                 strncpy (modelpath, ptr + 2, sizeof(modelpath));
408                 modelpath [sizeof(modelpath) - sizeof(FNAME_MODEL) - 4] = 0;
409                 ensure_end_slash (modelpath);
410                 strcat (modelpath, FNAME_MODEL);
411                 break;
412
413             case 'l':
414                 /* Note that custom, unsupported languages
415                  * greater than DtSrLaLAST are permitted.
416                  */
417                 language = atoi (ptr + 2);
418                 if (language < 0)
419                     goto BAD_ARG;
420                 if (!quiet_mode  &&  language > DtSrLaLAST)
421                     printf ( catgets(dtsearch_catd, MS_initausd, 13,
422                         "%s Warning! you have specified "
423                         "an unsupported, custom language.\n"
424                         "  You will have to provide your own "
425                         "language loaders at run time\n"
426                         "  in user function 'load_custom_language' "
427                         "to access this database.\a\n"),
428                         PROGNAME"444");
429                 break;
430
431             default:
432                 printf (catgets (dtsearch_catd, MS_misc, 10,
433                         "%sIgnored unknown command line argument '%s'.\n"),
434                     PROGNAME " ", ptr);
435                 break;
436         }       /* end switch */
437     }   /* end parse of cmd line options beginning with '-' */
438
439     /* Only required arg is new database name,
440      * including optional path prefix.
441      * Load newpath and newextp, leaving room
442      * for long dbnames and .xxx extensions.
443      */
444     if (argc <= 0) {
445         print_usage();
446         printf (catgets (dtsearch_catd, MS_misc, 18,
447                 "%sDatabase name not specified.\n\a"), "\n"PROGNAME" ");
448         DtSearchExit(2);
449     }
450     strncpy (newpath, argv[0], sizeof (newpath));
451     newpath [sizeof(newpath) - 12] = 0;
452     newextp = newpath + strlen (newpath);
453
454     /* Get just the 1 - 8 char database name by moving ptr
455      * backwards until first non-alphanumeric character
456      * (such as a ":" in the dos drive id or a slash between directories),
457      * or to the beginning of string.
458      * Then test database name for validity.
459      */
460     for (ptr = newpath + strlen(newpath) - 1;  ptr >= newpath;  ptr--)
461         if (!isalnum (*ptr)) {
462             ptr++;
463             break;
464         }
465     if (ptr < newpath)
466         ptr = newpath;
467     i = strlen (ptr);
468     if (i < 1 || i > 8) {
469 BAD_DBNAME:
470         print_usage();
471         printf (catgets (dtsearch_catd, MS_misc, 11,
472                 "%sInvalid database name '%s'.\a\n"),
473             "\n"PROGNAME"346 ", ptr);
474         DtSearchExit(2);
475     }
476     path_offset = ptr - newpath;
477     strcpy (dbname, ptr);       /* save it */
478     if (strcmp (dbname, "austext") == 0 || strcmp (dbname, "dtsearch") == 0) {
479         goto BAD_DBNAME;
480     }
481
482     /* Ensure semantic processing specified only for english language */
483     if (fzkeysz != 0  && language != DtSrLaENG  &&  language != DtSrLaENG2) {
484         print_usage();
485         printf ( catgets(dtsearch_catd, MS_initausd, 14,
486             "\n%s semantic processing is only available "
487             "for English language databases.\n\a") ,
488             PROGNAME"340");
489         DtSearchExit(2);
490     }
491
492     /* Unless overridden by user args,
493      * initialize abstract based on flavor.
494      * The abstract size defaults to the remaining 
495      * space in the final misc slot after the fzkey.
496      * However if the user specified a specific
497      * abstract size, it may be adjusted later
498      * to fill up the last slot.
499      */
500     if (abstrsz == -1)
501         abstrsz = max_ormisc_size - (fzkeysz % max_ormisc_size);
502
503     /* Default maxword size is 'short', except for German */
504     if (maxwordsz == INT_MAX)
505         maxwordsz = STANDARD_MAXWORD;
506
507     if (debug_mode)
508         printf ("002*** userargs: modelpath='%s' newpath='%s'\n"
509             "  fzkeysz=%d abstrsz=%d\n",
510             modelpath, newpath, fzkeysz, abstrsz);
511     return;
512 }  /* user_args_processor() */
513
514
515 /************************************************/
516 /*                                              */
517 /*               remove_d9x_file                */
518 /*                                              */
519 /************************************************/
520 static void     remove_d9x_file (char *extension)
521 {
522                     strcpy (newextp, extension);
523     if (debug_mode)
524         printf ("094*** delete '%s'.\n", newpath);
525     if (remove (newpath) != 0) {
526         /* 'file not found' is not an error */
527         if (errno != ENOENT) {
528             printf (catgets (dtsearch_catd, MS_initausd, 244,
529                     PROGNAME "244 Unable to remove '%s': %s\n"),
530                 newpath, strerror (errno));
531             DtSearchExit (5);
532         }
533     }
534     return;
535 }  /* remove_d9x_file() */
536
537
538 /************************************************/
539 /*                                              */
540 /*               create_new_dbd                 */
541 /*                                              */
542 /************************************************/
543 /* Copies and moves binary contents in passed, preopened
544  * model .dbd file (f) to new dbd file in target directory.
545  * Rename the internal .d00, etc filenames to match dbname.
546  */
547 static void     create_new_dbd (FILE *f)
548 {
549     FILE        *g;     /* target dbd file */
550     int         i;
551     static char *nocopy_msg =
552                 "%s Unable to copy '%s' to '%s':\n  %s\a\n";
553                 /* (Same as dtsearch.msg: MS_initausd, 214) */
554     static char zeros[] =
555                 "\0\0\0\0\0\0\0\0\0\0\0\0";
556
557     strcpy (newextp, ".dbd");
558     if (debug_mode)
559         printf (PROGNAME"507 create_new_dbd '%s'\n", newpath);
560
561     /* If new .dbd file preexists, make sure it is writable */
562     confirm_ok_to_overwrite (newpath);
563     if (chmod (newpath, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) {
564         if (errno != ENOENT) {
565             printf (catgets (dtsearch_catd, MS_initausd, 214, nocopy_msg),
566                 PROGNAME"515", modelpath, newpath, strerror(errno));
567             DtSearchExit (15);
568         }
569     }
570
571     if ((g = fopen (newpath, "w+b")) == NULL) {
572         printf (catgets (dtsearch_catd, MS_initausd, 214, nocopy_msg),
573             PROGNAME"509", modelpath, newpath, strerror(errno));
574         DtSearchExit (4);
575     }
576     errno = 0;
577     while ((i = fgetc (f)) != EOF)
578         fputc (i, g);
579     if (errno) {
580         printf (catgets (dtsearch_catd, MS_initausd, 214, nocopy_msg),
581             PROGNAME"531", modelpath, newpath, strerror(errno));
582         DtSearchExit (13);
583     }
584
585     /* Now reposition the write head in the new dbd file
586      * to rename the filenames.  Rename each internal file
587      * name to '<newdbname>.xxx'.
588      */
589     for (i = 0;  exttab[i] != NULL;  i++) {
590         fseek (g, START_OF_FT + (i * SIZEOF_FILE_ENTRY), SEEK_SET);     
591         fprintf (g, "%s%s", dbname, exttab[i]);
592         fwrite (zeros, sizeof(char), sizeof(zeros), g);
593     }
594
595     /* The new dbd file only has to be readable */
596     fclose (g);
597     chmod (newpath, S_IRUSR | S_IRGRP | S_IROTH);
598     return;
599 }  /* create_new_dbd() */
600
601
602 /************************************************/
603 /*                                              */
604 /*                    main                      */
605 /*                                              */
606 /************************************************/
607 /* 1. CREATE or find database dictionary (.dbd file).
608  * 2. CREATE empty 'dtsearch' database files.
609  * 3. OPEN 'dtsearch' database.
610  * 4. INITIALIZE the database.
611  * 5. WRITE dbrec after initializing it.
612  * 6. RENAME each database file.
613  * 7. UNLINK (delete) d9x files.
614  */
615 int             main (int argc, char *argv[])
616 {
617     int         i;
618     char        *ptr;
619     FILE        *f;
620     struct or_miscrec   miscrec;
621     struct or_swordrec  swordrec;
622     struct or_lwordrec  lwordrec;
623
624     setlocale (LC_ALL, "");
625     dtsearch_catd = catopen (FNAME_DTSRCAT, 0);
626
627     aa_argv0 = argv[0];
628     max_ormisc_size = sizeof (miscrec.or_misc);
629     maxwidth_sword = sizeof (swordrec.or_swordkey) - 1;
630     maxwidth_lword = sizeof (lwordrec.or_lwordkey) - 1;
631
632     printf (catgets (dtsearch_catd, MS_misc, 4,
633             "%s Version %s.\n"),
634         aa_argv0,
635         DtSrVERSION
636         );
637
638     /* Handle cmd line args.  Init global variables. */
639     user_args_processor (argc, argv);
640
641     /* ------- copy model .dbd to new .dbd ------- */
642
643     /* CASE 1: If user specified -d special alternative
644      * directory for model .dbd, it should be there.
645      */
646     if (modelpath[0] != 0) {
647         if (debug_mode)
648             printf (PROGNAME"628 Try opening '%s' (-d dir).\n", modelpath);
649         if ((f = fopen (modelpath, "rb")) != NULL) {
650             if (debug_mode)
651                 puts (PROGNAME"638 Found it!");
652             create_new_dbd (f);
653             fclose (f);
654             goto DBD_OKAY;
655         }
656         else {
657             print_usage();
658             printf (catgets (dtsearch_catd, MS_initausd, 213,
659                     default_unable_to_open_msg),
660                 "\n"PROGNAME"302", modelpath, strerror(errno));
661             DtSearchExit (4);
662         }
663     } /* end CASE 1 */
664
665     /* CASE 2: If model .dbd is in current directory, use it.
666      * If error is anything other than 'cant find file', quit now.
667      */
668     if (debug_mode)
669         printf (PROGNAME"649 Try opening '%s' (curr dir).\n", FNAME_MODEL);
670     if ((f = fopen (FNAME_MODEL, "rb")) != NULL) {
671         if (debug_mode)
672             puts (PROGNAME"660 Found it!");
673         create_new_dbd (f);
674         fclose (f);
675         goto DBD_OKAY;
676     }
677     else if (errno != ENOENT) {
678         print_usage();
679         printf (catgets (dtsearch_catd, MS_initausd, 213,
680                 default_unable_to_open_msg),
681             "\n"PROGNAME"655", FNAME_MODEL, strerror(errno));
682         DtSearchExit (4);
683     } /* end else CASE 2 */
684
685     /* CASE 3: Last chance.  Look for model .dbd in target directory.
686      * At this point have to quit on any error.
687      */
688     strcpy (modelpath, newpath);
689     strcpy (modelpath + path_offset, FNAME_MODEL);
690     if (debug_mode)
691         printf (PROGNAME"672 Try opening '%s' (new dir).\n", modelpath);
692     if ((f = fopen (modelpath, "rb")) != NULL) {
693         if (debug_mode)
694             puts (PROGNAME"675 Found it!");
695         create_new_dbd (f);
696         fclose (f);
697         goto DBD_OKAY;
698     }
699
700     if (debug_mode)
701         puts (PROGNAME"682 Never found it!");
702     print_usage();
703     printf (catgets (dtsearch_catd, MS_initausd, 213,
704             default_unable_to_open_msg),
705         "\n"PROGNAME"686", FNAME_MODEL,
706         "Not found in either current or target directories.  Use -d option\a");
707     DtSearchExit (4);
708
709
710 DBD_OKAY:
711
712     /* Open a new database */
713     *newextp = 0;       /* use no extension when opening database */
714     if (debug_mode)
715         printf ("040*** d_open newpath = '%s'.\n", newpath);
716     d_open (newpath, "o");
717     if (db_status != S_OKAY) {
718         printf (catgets (dtsearch_catd, MS_initausd, 230,
719                 PROGNAME "230 Could not open database '%s'.\n"), newpath);
720         puts (vista_msg (PROGNAME "231"));
721         DtSearchExit (3);
722     }
723     austext_exit_dbms = (void (*) (int)) d_close;       /* emerg exit func */
724
725     /* initialize the 'dtsearch' database */
726     if (debug_mode)
727         printf ("042*** d_initialize.\n");
728     d_initialize (0);
729     if (db_status != S_OKAY) {
730         printf (catgets (dtsearch_catd, MS_initausd, 239,
731                 PROGNAME "239 Could not initialize database '%s'.\n"), newpath);
732         puts (vista_msg (PROGNAME "240"));
733         DtSearchExit (3);
734     }
735
736
737     /* Create and initialize dbrec database header record in first slot.
738      * First fill entire record with binary zeros.
739      * Then set specific values as specified by flavor on command line.
740      * For now most values are hard-coded.
741      */
742     if (debug_mode)
743         printf ("050*** create dbrec.\n");
744     memset (&dbrec, 0, sizeof (dbrec));
745
746     /* Init fields that are completely independent */
747     dbrec.or_language =         (DtSrINT16) language;
748     dbrec.or_maxwordsz =        (DtSrINT16) maxwordsz;
749     dbrec.or_minwordsz =        (DtSrINT16) minwordsz;
750     dbrec.or_fzkeysz =          (DtSrINT16) fzkeysz;
751     dbrec.or_abstrsz =          (DtSrINT16) abstrsz;
752     dbrec.or_dbflags =          ORD_NONOTES | ORD_NOMARKDEL | ORD_XWORDS;
753     strncpy (dbrec.or_version, SCHEMA_VERSION, sizeof(dbrec.or_version));
754     dbrec.or_version [sizeof(dbrec.or_version) - 1] = 0;
755
756     /* Load dbrec's recslots fields based on correct number
757      * of misc recs required to hold user's abstract.
758      * Round abstrsz upward if there is any space left on last misc rec.
759      */
760     dbrec.or_recslots = 1;      /* start with obj rec itself */
761     for (i = dbrec.or_fzkeysz + dbrec.or_abstrsz; i > 0; i -= max_ormisc_size)
762         dbrec.or_recslots++;
763     if (i < 0) {
764         /* Add in difference to INCREASE abstrsz */
765         dbrec.or_abstrsz -= i;
766         printf (catgets (dtsearch_catd, MS_misc, 433,
767                 "%1$sAdjusted maximum abstract size upward to %2$hd.\n"),
768             PROGNAME "433 ", dbrec.or_abstrsz);
769     }
770
771     /* Init fields that are dependent on language */
772     switch (language) {
773         case DtSrLaENG:
774         case DtSrLaENG2:
775             dbrec.or_dbflags |= ORD_XSTEMS;
776             break;
777         default:
778             break;
779     }
780
781     /* Init fields that are dependent on flavor */
782     if (flavor == AUSTEXT_FLAVOR) {
783         dbrec.or_dbaccess = ORA_BLOB;
784         dbrec.or_compflags = ORC_COMPBLOB;
785         dbrec.or_hufid = -1L;   /* -1 = use huffman compression, but
786                                  * hufid not yet known. */
787         dbrec.or_dbotype = DtSrObjTEXT;
788     }
789     else {      /* default flavor == DTSEARCH_FLAVOR */
790         dbrec.or_dbaccess = ORA_NOTAVAIL;
791     }
792
793     if (!quiet_mode) {
794         /******putchar ('\n');******/
795         print_dbrec (newpath, &dbrec);
796         fflush (stdout);
797     }
798     swab_dbrec (&dbrec, HTON);
799     if (debug_mode)
800         printf ("060*** fillnew dbrec.\n");
801     d_fillnew (OR_DBREC, &dbrec, 0);
802     if (db_status != S_OKAY) {
803         printf (catgets (dtsearch_catd, MS_initausd, 509,
804                 PROGNAME "509 Could not initialize database header record.\n"));
805         puts (vista_msg (PROGNAME "510"));
806         DtSearchExit (3);
807     }
808
809     /* Close the database */
810     d_close ();
811     austext_exit_dbms = NULL;   /* emerg exit no longer required */
812
813     /* Delete all nonvista (inverted index) database files (.d9x) */
814     remove_d9x_file (".d97");
815     remove_d9x_file (".d98");
816     remove_d9x_file (".d99");
817
818     *newextp = 0;       /* no extension suffixes for next msgs */
819     printf (catgets (dtsearch_catd, MS_initausd, 24,
820             PROGNAME " Successfully initialized database '%s'.\n"), newpath);
821
822     return 0;
823 }  /* main() */
824
825 /************************* DTSRCREATE.C **************************/