/* 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() */
/* 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() */
/* 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() */
/* 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() */
/* 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() */
/* 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() */