示例#1
0
/* Builds array of database name string ptrs with same
 * architecture as command line arguments argv and argc
 * from the shell.  Uses dblk.label if it exists,
 * otherwise uses dblk.name.
 * Called at initialization and reinitialization.
 */
static void     build_dbnames_array (void)
{
    char           *targ, *src;
    DBLK           *db;
    int             i;
    size_t          mallocsz = 0L;

    if (ausapi_dbnamesv)
	free (ausapi_dbnamesv);
    ausapi_dbnamesc = 0;
    for (db = usrblk.dblist; db != NULL; db = db->link) {
	ausapi_dbnamesc++;
	mallocsz += ((db->label) ? strlen (db->label) : sizeof (db->name)) + 2L;
    }
    ausapi_dbnamesv = austext_malloc (
	mallocsz + (sizeof (char *) * (2 + ausapi_dbnamesc)) + 4,
	PROGNAME "106", NULL);
    /* The first part of the malloc is the array of pointers.
     * The strings start just after the array.  Set 'targ' to
     * the beginning of the strings, while 'i' indexes the ptrs.
     */
    targ = (char *) ausapi_dbnamesv + (sizeof (char *) * (1 + ausapi_dbnamesc));
    for (i = 0, db = usrblk.dblist; db != NULL; i++, db = db->link) {
	ausapi_dbnamesv[i] = targ;
	src = (db->label) ? db->label : db->name;
	while (*src != 0)
	    *targ++ = *src++;
	*targ++ = 0;

	if (save_init_switches & DtSrInIDEBUG) {
	    fprintf (aa_stderr, PROGNAME "490 "
		"dbnames[%d] = '%s': dname='%s', dlabel='%s'\n",
		i, ausapi_dbnamesv[i], db->name, db->label);
	    fflush (aa_stderr);
	}

    }
    ausapi_dbnamesv[i] = NULL;	/* terminate the list this way too */
    return;
}  /* build_dbnames_array() */
示例#2
0
/* Mallocs and returns hitwords array for passed text string
 * using database and stems array from last search.
 * The stems ptr may be NULL, but if specified
 * the passed stems array MUST be defined:
 *      char   stems [DtSrMAX_STEMCOUNT] [DtSrMAXWIDTH_HWORD].
 */
int             DtSearchHighlight (
                    char *dbname,	/* database name */
                    char *cleartext,	/* text to be hilited */
                    DtSrHitword ** hitwords,
					/* where to put hitwords array */
                    long *hitwcount,	/* num items in hitwords array */
                    int search_type,	/* [opt] override save_search_type */
                    char *stems,	/* [opt] override last search stems */
                    int stemcount	/* num stems in stems array */
)
{
    int             i;
    char           *cptr;

    if (!valid_dbname (dbname))
	return DtSrREINIT;

    /* copy cleartext to usrblk if necessary */
    if (cleartext == NULL || cleartext[0] == 0) {
	sprintf (sprintbuf, catgets (dtsearch_catd, MS_ausapi, 40,
		"%1$s Null cleartext.  No highlighting performed."),
	    PROGNAME "349 ", dbname);
	DtSearchAddMessage (sprintbuf);
	return DtSrERROR;
    }
    if (cleartext != usrblk.cleartext) {
	if (usrblk.cleartext != NULL)
	    free (usrblk.cleartext);
	usrblk.clearlen = strlen (cleartext);
	usrblk.cleartext = austext_malloc (usrblk.clearlen + 16,
	    PROGNAME "267", NULL);
	strcpy (usrblk.cleartext, cleartext);
    }

    if (search_type)
	usrblk.search_type = search_type;
    else
	usrblk.search_type = save_search_type;

    if (stems) {
	if (stemcount > DtSrMAX_STEMCOUNT) {
	    sprintf (sprintbuf, catgets (dtsearch_catd, MS_ausapi, 1072,
		"%s Program Error: Stem count (%d) greater than maximum (%d)."),
		PROGNAME"1072", stemcount, DtSrMAX_STEMCOUNT);
	    DtSearchAddMessage (sprintbuf);
	    return DtSrERROR;
	}
	usrblk.stemcount = stemcount;
	cptr = stems;
	for (i = 0; i < stemcount; i++) {
	    strcpy (usrblk.stems[i], cptr);
	    cptr += DtSrMAXWIDTH_HWORD;
	}
    }

    usrblk.request = OE_HILITE_STEMS;
    Opera_Engine ();

    /* Set this func's retn value based on engine's retncode, and return. */
    switch (usrblk.retncode) {
	case OE_OK:
	    /*
	     * Note that the following assignment works even if the
	     * user's hitwords arg is in fact &usrblk.hitwords and
	     * hitwcount is in fact &usrblk.hitwcount. 
	     */
	    *hitwords = usrblk.hitwords;
	    *hitwcount = usrblk.hitwcount;
	    return DtSrOK;

	case OE_ABORT:
	    return DtSrABORT;

	case OE_REINIT:
	    return aa_reinit ();

	case OE_NOOP:
	case OE_NOTAVAIL:
	    return DtSrFAIL;

	default:
	    /*
	     * Includes OE_BAD_QUERY and all unexpected return
	     * codes. Probable program error.  Msgs may or may not
	     * say why. In case they don't, put OE's retncode on
	     * msglist. 
	     */
	    if (!ausapi_msglist) {
		sprintf (sprintbuf, catgets (dtsearch_catd, MS_ausapi, 1342,
		    "%s Search Engine Error %d for highlight request for "
		    "database '%s', hit word count=%ld, search type='%c', text='%.30s'"),
		    PROGNAME "1342",
		    usrblk.retncode, dbname, *hitwcount, search_type,
		    NULLORSTR (cleartext));
		DtSearchAddMessage (sprintbuf);
	    }
	    return DtSrERROR;
    }	/* end switch */
}  /* DtSearchHighlight() */
示例#3
0
/* Returns hitlist (dittolist) if search successful.
 * If dbname is NULL, assumes name from first dblk on dblist.
 * Will work correctly even if arg dittolist == &usrblk.dittolist.
 * Only return hits 'after' date1 and 'before' date2.
 * NULL in one date field means search not limited in that direction.
 * NULL in both date fields means search not restricted by dates.
 * NULL is also permitted in stems, but if stems is
 * not NULL, the passed stems array MUST be defined:
 *      char   stems [DtSrMAX_STEMCOUNT] [DtSrMAXWIDTH_HWORD].
 * If query is fzkeyi, it must point to
 * array of FZKEYSZ integers.
 * DtSearchQuery() was formerly named ausapi_search().
 */
int             DtSearchQuery (
		void	*qry,		/* query, fzkeyi, nav string */
		char	*dbname,	/* database name from dbnamesv */
		int	search_type,	/* 'P', 'W', 'S', 'T', 'Z', or 'N' */
		char	*date1,		/* "yyyy mm dd", 3 numeric tokens */
		char	*date2,		/* date1 earlier than date2 */
		DtSrResult
			**dittolist,	/* put hitlist here */
		long	*dittocount,	/* put num items on returned hitlist */
		char	*stems,		/* put stems array here */
		int	*stemcount)	/* put size of stems array */
{
    int             final_request;
    int             i;
    char           *ptr;
    DBLK           *db;
    LLIST          *llp;
    enum { TEXT, NAVSTRING, FZKEYI }
                    qryarg;
    char            date1str[24];

    if (!valid_dbname (dbname))
	return DtSrREINIT;

    /* Verify valid search_type and set flag
     * to tell us how to interpret 'qry' arg.
     */
    switch (search_type) {
	case 'P':	/* statistical search */
	    qryarg = TEXT;
	    final_request = OE_SRCH_STATISTICAL;
	    break;

	case 'W':	/* exact words search */
	    qryarg = TEXT;
	    final_request = OE_SRCH_WORDS;
	    break;

	case 'S':	/* exact stems search */
	    qryarg = TEXT;
	    final_request = OE_SRCH_STEMS;
	    break;

	default:
	    sprintf (sprintbuf, catgets (dtsearch_catd, MS_ausapi, 20,
		    "%1$s Invalid search_type '%2$c'."),
		PROGNAME "172 ", search_type);
	    DtSearchAddMessage (sprintbuf);
	    return DtSrERROR;

    }	/* end switch on search_type */

    /* Validate the 'qry' argument */
    if (qry == NULL) {
QUERY_ERROR:
	sprintf (sprintbuf, catgets (dtsearch_catd, MS_ausapi, 30,
		"%s Null query.  No search performed."),
	    PROGNAME"81");
	DtSearchAddMessage (sprintbuf);
	return DtSrFAIL;
    }

    /* If qry is a char string, it must be nonempty. */
    if (qryarg != FZKEYI && ((char *) qry)[0] == 0)
	goto QUERY_ERROR;

    /* If qry is text to be sent as is to engine,
     * copy it over now to userblk.
     */
    if (qryarg == TEXT && qry != usrblk.query) {
	if (usrblk.query != NULL)
	    free (usrblk.query);
	usrblk.query = austext_malloc (strlen (qry) + 16, PROGNAME "102", NULL);
	strcpy (usrblk.query, qry);
    }

    /* Validate the 'date' args and place them into usrblk. */
    if (!both_valid_dates (date1, date2))
	return DtSrFAIL;

    /* Finish setup usrblk for final search */
    usrblk.flags |= USR_NO_ITERATE;	/* must ALWAYS be ON in this api */
    usrblk.request = final_request;
    db = usrblk.dblk;
    db->maxhits = aa_maxhits;
    if (qryarg == TEXT)
	save_search_type = usrblk.search_type = search_type;

    if (usrblk.debug & USRDBG_SRCHCMPL) {
	ptr = sprintbuf;
	for (i = 0; i < db->ktcount; i++) {
	    if (db->keytypes[i].is_selected)
		*ptr++ = '*';
	    *ptr++ = db->keytypes[i].ktchar;
	    *ptr++ = ' ';
	}
	*(--ptr) = 0;
	strcpy (date1str, objdate2fzkstr (usrblk.objdate1));
	fprintf (aa_stderr,
	    PROGNAME "353 DtSearchQuery(): dbname='%s' srchtype='%c'\n"
	    "  maxhits=%d keytypes='%s'\n"
	    "  date1='%s' -> %s.  date2='%s' -> %s.\n"
	    "  query='%.60s'\n",
	    db->name, search_type, db->maxhits, sprintbuf,
	    NULLORSTR (date1), date1str,
	    NULLORSTR (date2), objdate2fzkstr (usrblk.objdate2),
	    NULLORSTR (usrblk.query));
	fflush (aa_stderr);
    }

    /* Final engine call, the search itself... */
    Opera_Engine ();

END_OF_SEARCH:
    if (usrblk.debug & USRDBG_SRCHCMPL) {
	/* count msgs */
	i = 0;
	for (llp = ausapi_msglist; llp != NULL; llp = llp->link)
	    i++;
	fprintf (aa_stderr, PROGNAME "380 Return from Search:  "
	    "retncode=%d  hitcount=%ld  srchmsgs=%d.\n",
	    usrblk.retncode, usrblk.dittocount, i);
	fflush (aa_stderr);
    }

    /* Set this func's retn value based on engine's retncode, and return. */
    switch (usrblk.retncode) {
	case OE_OK:
	    /*
	     * Transfer usrblk.dittolist to user's own dittolist
	     * pointer. Also he MUST use DtSearchFreeResults()
	     * between calls. Otherwise the code below will cause a
	     * memory leak. 
	     */
	    *dittolist = usrblk.dittolist;
	    *dittocount = usrblk.dittocount;
	    usrblk.dittolist = NULL;
	    usrblk.dittocount = 0;
	    if (stems) {
		*stemcount = usrblk.stemcount;
		for (i = 0; i < *stemcount; i++) {
		    strcpy (stems, usrblk.stems[i]);
		    stems += DtSrMAXWIDTH_HWORD;
		}
	    }
	    return DtSrOK;

	case OE_NOTAVAIL:
	    return DtSrNOTAVAIL;

	case OE_ABORT:
	    return DtSrABORT;

	case OE_REINIT:
	    return aa_reinit ();

	case OE_BAD_QUERY:
	    /* Query was invalid.  Tell the user why. */
	    if (ausapi_msglist == NULL) {
		sprintf (sprintbuf,
		    catgets (dtsearch_catd, MS_ausapi, 806,
			"%s Query insufficient or search options "
			"incompatible with database '%s' to commence search."),
		    PROGNAME "806", usrblk.dblk->name);
		DtSearchAddMessage (sprintbuf);
	    }
	    return DtSrFAIL;

	case OE_NOOP:
	    /* Search was unsuccessful. Msgs should say why. */
	    return DtSrFAIL;

	default:
	    /*
	     * Includes OE_SEARCHING, OE_USER_STOP, etc. Probable
	     * program error.  Msgs may or may not say why. 
	     */
	    return DtSrERROR;
    }	/* end switch */
}  /* DtSearchQuery() */
示例#4
0
/* Initializes ausapi and the AusText engine (performs OE_INIT).
 * Must be first ausapi call.  Must be called only once (reinit?).
 * See dtsearch.doc for specs.
 */
int             DtSearchInit (
                    char	*argv0,
                    char	*userid,
                    long	switches,
                    char	*config_file,
                    FILE	*err_file,
                    char	***dbnames,
                    int		*dbcount)
{
    if (aa_is_initialized) {
	sprintf (sprintbuf, catgets (dtsearch_catd, MS_ausapi, 621,
	    "%1$s %2%s has already been initialized."),
	    PROGNAME"621", PRODNAME);
	DtSearchAddMessage (sprintbuf);
	return DtSrFAIL;
    }

    aa_is_initialized = TRUE;
    save_init_switches = switches;
    if (argv0)
	aa_argv0 = argv0;
    if (err_file)
	aa_stderr = err_file;
    else
	aa_stderr = stderr;

    sprintbuf = austext_malloc (SPRINTBUFSZ, PROGNAME "135", NULL);

    /* Open msgs and help text catalogs. */
    if (switches & (DtSrInNOLOCALE == 0)) {
	setlocale (LC_ALL, "");
	dtsearch_catd = catopen (FNAME_DTSRCAT, 0);
    }

    /* Register AusText abort signal handlers.
     * This ensures that if caller is killed,
     * engine will shutdown gracefully.
     */
    if (switches & DtSrInSIGNAL) {
	if (!(switches & DtSrInENAB_NOHUP))
	    signal (SIGHUP, signal_abort);	/* trap hangups */
	signal (SIGINT, signal_abort);	/* interrupt, ctrl-c */
	signal (SIGQUIT, signal_abort);	/* quit, ctrl-d */
	signal (SIGKILL, signal_abort);	/* (kill -9, cannot be trapped) */
	signal (SIGTERM, signal_abort);	/* kill [-15], sfwr terminate */
#ifdef SIGPWR
	signal (SIGPWR, signal_abort);	/* power failure imminent */
#endif
#ifdef _AIX
	signal (SIGXCPU, signal_abort);	/* cpu time limit exceeded */
	signal (SIGDANGER, signal_abort);  /* imminent paging space crash */
#endif
    }

    /* If user name was not passed, get it from LOGNAME environment var */
    if (userid == NULL || *userid == 0)
	if ((userid = (char *) getenv ("LOGNAME")) == NULL) {
	    sprintf (sprintbuf, catgets (dtsearch_catd, MS_ausapi, 187,
		"%1$s Missing both userid and LOGNAME environment variable."),
		PROGNAME "187 ");
	    DtSearchAddMessage (sprintbuf);
	    return DtSrFAIL;
	}

    /* initialize usrblk fields */
    memset (&usrblk, 0, sizeof (USRBLK));
    strncpy (usrblk.userid, userid, 8);
    usrblk.userid[8] = 0;
    usrblk.flags |= USR_NO_INFOMSGS;	/* standard for ausapi */
    usrblk.flags |= USR_SORT_WHITL;	/* standard for ausapi */
    usrblk.flags |= USR_NO_ITERATE;	/* must ALWAYS be on in
					 * this api */

    if (switches & DtSrInIDEBUG)
	usrblk.debug |= USRDBG_RARE;
    if (switches & DtSrInSDEBUG)
	usrblk.debug |= USRDBG_SRCHCMPL;
    if (switches & DtSrInRDEBUG)
	usrblk.debug |= USRDBG_RETRVL;
    /* Secret unadvertised feature.  High order 2 bytes
     * are direct settings of lower 2 bytes of usrblk.debug.
     */
    usrblk.debug |= switches >> 16;

    /* Set vista's db_oflag from DtSrInRDWR switch.
     * Note the vista flag and the switch are inverses
     * of each other (RDWR vs. RDONLY).
     */
    if ((switches & DtSrInRDWR) == 0)
	db_oflag = O_RDONLY;

    /* Prespecify site config file to engine */
    if (config_file)
	OE_sitecnfg_fname = (char *) strdup (config_file);

    /* initialize AusText Engine */
    usrblk.request = OE_INITIALIZE;
    usrblk.query = AUSAPI_VERSION;
    Opera_Engine ();
    usrblk.query = NULL;  /* so we don't try to free it at query time */
    if (usrblk.retncode != OE_OK)
	return DtSrFAIL;

    build_dbnames_array ();
    if (dbnames) {
	*dbnames = ausapi_dbnamesv;
	if (!dbcount) {
	    sprintf (sprintbuf, catgets(dtsearch_catd, MS_ausapi, 7,
		"%s dbnames specified but not dbcount."),
		PROGNAME"304");
	    DtSearchAddMessage (sprintbuf);
	    return DtSrFAIL;
	}
	*dbcount = ausapi_dbnamesc;
    }

    return DtSrOK;
}  /* DtSearchInit() */
示例#5
0
/* Program 2: deletes records specified in input file.
 * Must be run offline when all online users have logged off.
 */
static void     deleter (char *infname)
{
    int             i;
    long            records_deleted;
    time_t          start_time, minutes, hours, seconds, elapsed;
    char            buf[128];

    if (!yesarg) {
	printf ( catgets(dtsearch_catd, MS_tomita, 25,
    "\nDO NOT CONTINUE under any of the following circumstances:\n"
    "-> If the input file which lists record ids to be deleted is not\n"
    "      named '%s'.\n"
    "-> If any users are still accessing the affected database(s).\n"
    "-> If any database files have not been backed up.\n\n"
    "If you are sure you are ready to start deleting, enter 'y' now... ") ,
	    infname, OE_prodname);

	fgets (buf, sizeof(buf)-1, stdin);
	if (tolower (*buf) != 'y')
	    return;
    }

    /* Make sure engine doesn't abort because of
     * recurring changes to d99 files.
     */
    OE_sitecnfg_mtime = 0L;

    /* Init table of db addrs */
    usrblk.dbatab = austext_malloc
	(sizeof (DB_ADDR) * (max_dbacount + 2), PROGNAME "531", NULL);
    usrblk.dbacount = 0;	/* number of recs currently in table */

    /* Init status msg stuff */
    records_read = 0L;
    records_deleted = 0L;
    time (&start_time);

    signal (SIGINT, kill_delete);
    signal (SIGQUIT, kill_delete);
    signal (SIGTRAP, kill_delete);
    signal (SIGTERM, kill_delete);
#ifdef SIGPWR
    signal (SIGPWR, kill_delete);
#endif
#ifdef _AIX
    signal (SIGXCPU, kill_delete);	/* cpu time limit exceeded */
    signal (SIGDANGER, kill_delete);	/* imminent paging space
					 * crash */
#endif

    /* MAIN LOOP */
    while (load_dbatab ()) {
	/*
	 * Stop now if we have exceeded user specified time limit
	 * or if user sent termination or interrupt signal. 
	 */
	if (shutdown_now)
	    break;
	elapsed = time (NULL) - start_time;
	if (maxtime > 0L && elapsed >= maxtime)
	    break;

	/* echo status for humans who might be watching */
	hours = elapsed / 3600L;
	seconds = elapsed - (3600L * hours);	/* remaining after hours */
	minutes = seconds / 60L;
	seconds = seconds - (60L * minutes);
	printf ( catgets(dtsearch_catd, MS_tomita, 26,
	    "%s %ld read, %ld deleted, %ldh %2ldm %2lds elapsed.\n"
	    "  Database '%s': Current record count = %ld, Batch size = %d.\n") ,
	    aa_argv0, records_read, records_deleted,
	    hours, minutes, seconds,
	    usrblk.dblk->name, usrblk.dblk->dbrec.or_reccount, usrblk.dbacount);
	/*****fflush (stdout);*****/

	/* call OE to delete batch of records */
	usrblk.request = OE_DELETE_BATCH;
	Opera_Engine ();
	if (DtSearchHasMessages ()) {
	    putchar ('\n');
	    PRINT_MESSAGES
	}
	if (usrblk.retncode != OE_OK)
	    retncode_abort (572);
	records_deleted += usrblk.dbacount;

    }	/* end main loop */


    /* Print final status messages */
    elapsed = time (NULL) - start_time;	/* total elapsed time */

    hours = elapsed / 3600L;
    seconds = elapsed - (3600L * hours);	/* remaining after hours */
    minutes = seconds / 60L;
    seconds = seconds - (60L * minutes);	/* remaining after hours
						 * & mins */
    printf ( catgets(dtsearch_catd, MS_tomita, 27,
	"%s %ld records read from input file.  %ld were deleted and\n"
	"  %ld were not found in %ld hours, %ld minutes, %ld seconds,\n") ,
	aa_argv0, records_read, records_deleted,
	records_read - records_deleted,
	hours, minutes, seconds);

    /* Figure average time for a deletion */
    elapsed = (records_deleted) ? elapsed / records_deleted : 0L;
    minutes = elapsed / 60L;
    seconds = elapsed - (60L * minutes);
    printf ( catgets(dtsearch_catd, MS_tomita, 28,
	"  or an average of %ld minutes, %ld seconds per record deleted.\n"),
	minutes, seconds);
    return;
}  /* deleter() */
示例#6
0
/* dblk.path may be NULL */
int             open_dblk (DBLK ** dblist, int numpages, int debugging)
{
    DBLK           *db, *bad_db, **lastlink;
    int             i;
    size_t          totlen = 0L;
    char           *allnames;
    int             vistano = 0;
    char           *srcptr, *targptr;
    char            temp_file_name[1024];
    char            sprintbuf[1024];
    struct stat     statbuf;
    char	open_mode [8];

    if (debugging)
	fprintf (aa_stderr, PROGNAME"76 "
	    "Entering open_dblks().  db_oflag==%d.\n",
	    db_oflag);
    if (dblist == NULL || numpages < 8) {
BAD_INPUT:
	sprintf (sprintbuf, catgets (dtsearch_catd, MS_oeinit, 99,
		"%s Programming Error: Invalid input to open_dblk()."),
	    PROGNAME "99");
	DtSearchAddMessage (sprintbuf);
	return FALSE;
    }
    if (*dblist == NULL)	/* empty list of dblks */
	goto BAD_INPUT;

    if (debugging) {
	fprintf (aa_stderr, PROGNAME "96 Current list of dblks:\n");
	for (db = *dblist; db != NULL; db = db->link) {
	    targptr = sprintbuf;
	    for (i = 0; i < db->ktcount; i++) {
		*targptr++ = db->keytypes[i].ktchar;
	    }
	    *targptr = 0;
	    fprintf (aa_stderr, "--> DBLK at %p link=%p name='%s' maxhits=%d\n"
		"    keytypes='%s', path='%s'\n",
		(void *) db, (void *) db->link, db->name, db->maxhits,
		sprintbuf, NULLORSTR (db->path));
	}
    }

    /* By doing setpages first, we can trap previously opened databases.
     * Overflow and transaction locking files are not required.
     */
    d_setpages (numpages, 0);
    if (db_status != S_OKAY) {
	DtSearchAddMessage (vista_msg (PROGNAME "389"));
	return FALSE;
    }

    /* ---- PASS #1 ------------------------------------------
     * Open nonvista (d99) files.  If error, unlink dblk from dblist.
     * Add up the total string length of surviving paths and database names.
     * This giant path/file string will be used in the single d_open()
     * below to find the .dbd files.
     * While we're at it, set vistano in each dblk.
     * The open mode depends on the current setting of db_oflag.
     */
    if (db_oflag == O_RDONLY)
	strcpy (open_mode, "rb");
    else
	strcpy (open_mode, "r+b");
    db = *dblist;
    lastlink = dblist;
    while (db != NULL) {
	if (db->path == NULL)
	    db->path = strdup ("");
	strcpy (temp_file_name, db->path);
	strcat (temp_file_name, db->name);
	strcat (temp_file_name, EXT_DTBS);
	if ((db->iifile = fopen (temp_file_name, open_mode)) == NULL) {
	    if (debugging)
		fprintf (aa_stderr, PROGNAME "129 UNLINK: cant open '%s'.\n",
		    temp_file_name);
	    sprintf (sprintbuf, catgets (dtsearch_catd, MS_oeinit, 317,
		    "%s Cannot open database file '%s'.\n"
		    "  Errno %d = %s\n"
		    "  %s is removing '%s' from list of available databases."),
		PROGNAME "317", temp_file_name, errno, strerror (errno),
		OE_prodname, db->name);
	    if (errno == ENOENT)
		strcat (sprintbuf, catgets (dtsearch_catd, MS_oeinit, 318,
		    "\n  This can usually be corrected by specifying a valid\n"
		    "  database PATH in the site configuration file."));
	    DtSearchAddMessage (sprintbuf);
	    goto DELETE_DB;
	}

	/*
	 * Find and save the timestamp for when the d99 file was
	 * last modified. An engine reinit is forced if it changes
	 * while the engine is running. 
	 */
	if (fstat (fileno (db->iifile), &statbuf) == -1) {
	    if (debugging)
		fprintf (aa_stderr,
		    PROGNAME "149 UNLINK: cant get status '%s'.\n",
		    temp_file_name);
	    sprintf (sprintbuf, catgets (dtsearch_catd, MS_oeinit, 1404,
		    "%s Removing database '%s' from list of "
		    "available databases because status is "
		    "unavailable for file %s: %s"),
		PROGNAME "1404", db->name, temp_file_name, strerror (errno));
	    DtSearchAddMessage (sprintbuf);
	    goto DELETE_DB;
	}
	db->iimtime = statbuf.st_mtime;

	/*
	 * This dblk is ok so far.  Increment pointers and
	 * continue. 
	 */
	if (debugging)
	    fprintf (aa_stderr, PROGNAME "163 opened '%s'.\n", temp_file_name);
	db->vistano = vistano++;
	totlen += strlen (db->path) + strlen (db->name) + 16;
	lastlink = &db->link;
	db = db->link;
	continue;

DELETE_DB:
	/*
	 * This dblk failed in one or more ways. Unlink it and
	 * don't increment pointers. If all dblks unlinked, *dblist
	 * will = NULL. 
	 */
	bad_db = db;	/* temp save */
	*lastlink = db->link;
	db = db->link;
	free (bad_db);
    }	/* end PASS #1 */

    /* quit if no dblks remain */
    if (vistano <= 0) {
	sprintf (sprintbuf, catgets (dtsearch_catd, MS_misc, 8,
		"%s No valid databases remain."), PROGNAME "265");
	DtSearchAddMessage (sprintbuf);
	return FALSE;
    }

    allnames = austext_malloc (totlen + 512, PROGNAME "66", NULL);

    /* ---- PASS #2 ------------------------------------------
     * Build string of accumulated path and database names.
     */
    targptr = allnames;
    for (db = *dblist; db != NULL; db = db->link) {
	srcptr = db->path;
	while (*srcptr != 0)
	    *targptr++ = *srcptr++;

	srcptr = db->name;
	while (*srcptr != 0)
	    *targptr++ = *srcptr++;
	*targptr++ = ';';
    }
    *(--targptr) = 0;	/* terminate string */

    if (debugging)
	fprintf (aa_stderr,
	    PROGNAME "150 vista opening databases '%s'\n", allnames);
    d_open (allnames, "o");	/* replaces OPEN() call from dmacros.h */

    if (db_status != S_OKAY) {
	targptr = austext_malloc (totlen + 128, PROGNAME"239", NULL);
	sprintf (targptr, catgets (dtsearch_catd, MS_vista, 378,
	    "%s Could not open following database name string:\n  '%s'"),
	    PROGNAME"378", allnames);
	DtSearchAddMessage (targptr);
	DtSearchAddMessage (vista_msg (PROGNAME"379"));
	free (allnames);
	free (targptr);
	return FALSE;
    }
    else if (debugging)
	fprintf (aa_stderr, " --> vista open successful!\n");

    /* From here on, emergency exits MUST close the databases */
    austext_exit_dbms = (void (*) (int)) d_close;

    free (allnames);
    return TRUE;
}  /* open_dblk() */