/* Returns pointer to dbnames array. * Used after database or config file changes to trigger * engine reinitialization and to reaccess the database names. */ int DtSearchReinit (char ***dbnames, int *dbcount) { aa_check_initialization(); usrblk.request = OE_PING; Opera_Engine(); switch (usrblk.retncode) { case OE_REINIT: if (save_init_switches & DtSrInANY_DEBUG) { fputs (PROGNAME"755 " "DtSearchReinit: Engine did return REINIT.\n", aa_stderr); fflush (aa_stderr); } aa_reinit(); /* fall thru to OK... */ case OE_OK: *dbnames = ausapi_dbnamesv; *dbcount = ausapi_dbnamesc; return DtSrOK; default: return DtSrERROR; } } /* DtSearchReinit() */
/* Mallocs and returns cleartext of a record given database address (dba). * fzkey integers start at bkt #2, just like categories. * WARNING! USER SHOULD NEITHER MALLOC NOR FREE HIS CLEARTEXT POINTER! */ int DtSearchRetrieve ( char *dbname, /* 1 - 8 char database name */ DB_ADDR dba, /* database address from dittolist */ char **cleartext, /* cleartext put here (freed first) */ long *clearlen, /* length of returned cleartext */ int *fzkeyi) /* ptr to array of FZKEYSZ integers */ { if (!valid_dbname (dbname)) return DtSrREINIT; usrblk.dba = dba; usrblk.request = OE_GETREC; Opera_Engine (); /* Set this func's retn value based on engine's retncode, and return. */ switch (usrblk.retncode) { case OE_OK: /* * WARNING! USER SHOULD NEITHER MALLOC NOR FREE HIS * CLEARTEXT POINTER. */ *cleartext = usrblk.cleartext; /* user MUST leave * cleartext alone */ *clearlen = usrblk.clearlen; return DtSrOK; case OE_NOTAVAIL: return DtSrNOTAVAIL; case OE_ABORT: return DtSrABORT; case OE_REINIT: return aa_reinit (); case OE_NOOP: return DtSrFAIL; default: /* * Includes all unexpected return codes. Probable * program error. Msgs may or may not say why. */ return DtSrERROR; } /* end switch */ } /* DtSearchRetrieve() */
/* 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() */
int main (int argc, char *argv[]) { char *arg; time_t mytime; char timebuf[80]; aa_argv0 = argv[0]; setlocale (LC_ALL, ""); dtsearch_catd = catopen (FNAME_DTSRCAT, 0); time (&mytime); strftime (timebuf, sizeof (timebuf), catgets(dtsearch_catd, MS_misc, 22, "%A, %b %d %Y, %I:%M %p"), localtime (&mytime)); printf (catgets(dtsearch_catd, MS_tomita, 29, "%s. Run %s.\n") , aa_argv0, timebuf); austext_exit_last = print_exit_code; signal (SIGINT, DtSearchExit); signal (SIGTERM, DtSearchExit); /****memset (&usrblk, 0, sizeof(USRBLK));****/ /* Validate program number argument */ if (argc < 2) { BAD_ARGS: fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 30, "\nUSAGE: %s [options]\n" " -i Input file name. If not specified, defaults to %s.\n" " -d[v] Print debug statements.\n" " -dv turns on verbose (record-by-record) debugging.\n" " -t<N> Max desired number of seconds of run time.\n" " Ctrl-C/Break will also stop deletion at next record.\n" " -n<N> Change number of records in a batch from %d to <N>.\n" " -y Automatically answers 'yes' to Delete mode confirm prompt.\n" " -d trace deletion operations.\n") , aa_argv0, FNAME_DISCARD_DATA, FNAME_CONFIRM_LIST, FNAME_CONFIRM_LIST, DBACOUNT); DtSearchExit (2); } prog = toupper (argv[1][0]); if (prog != 'B' && prog != 'D') goto BAD_ARGS; /* Initialize defaults depending on program mode */ if (prog == 'B') { infname = FNAME_DISCARD_DATA; outfname = FNAME_CONFIRM_LIST; } else { infname = FNAME_CONFIRM_LIST; outfname = PROGNAME "654"; } maxtime = 0L; /* Save rest of command line arguments */ for (argc -= 2, argv += 2; argc > 0; argc--, argv++) { arg = *argv; switch (tolower (arg[1])) { case 'i': infname = arg + 2; break; case 'o': outfname = arg + 2; break; case 'd': debug_mode = TRUE; usrblk.debug |= USRDBG_DELETE; if (arg[2] == 'v') usrblk.debug |= USRDBG_VERBOSE; break; case 'y': yesarg = TRUE; break; case 't': maxtime = atol (arg + 2); break; case 'n': max_dbacount = atol (arg + 2); break; default: fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 31, "\n%s Unknown argument '%s'.\n") , PROGNAME"689", arg); goto BAD_ARGS; } /* end switch */ } /* end arg parsing */ /* Open input file to test for its existence. * For the Browse program, file ptr 'inf' == NULL * means the file is not open. */ if ((inf = fopen (infname, "r")) == NULL) { if (prog == 'D') { fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 32, "%s Unable to open input file '%s'.\n") , PROGNAME"710", infname); goto BAD_ARGS; } } /* If browsing, get output file name and * open it to test for write permission. */ if (prog == 'B') { if ((outf = fopen (outfname, "a ")) == NULL) /* the blank in "a " works around old aix bug */ { fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 33, "\n%s Unable to open output file '%s'.\n") , PROGNAME"721", outfname); goto BAD_ARGS; } } /* Initialize the opera engine, i.e. open the database */ printf ( catgets(dtsearch_catd, MS_tomita, 34, "Initializing %s engine...\n"), OE_prodname); strcpy (usrblk.userid, "ToMiTa"); usrblk.request = OE_INITIALIZE; usrblk.query = AUSAPI_VERSION; Opera_Engine (); if (usrblk.retncode != OE_OK) retncode_abort (733); PRINT_MESSAGES if (prog == 'B') browser (); else deleter (infname); usrblk.request = OE_SHUTDOWN; Opera_Engine (); printf ( "%s", catgets(dtsearch_catd, MS_tomita, 36, "Normal engine shutdown.\n") ); DtSearchExit (0); } /* main() */
/* 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() */
/* Subroutine of deleter(). Reads discard file containing * record ids to be deleted, converts to database addresses, * loads usrblk.dbatab up to max batch size. * Returns number of dba's added to table. * Returns 0 when file is empty after last batch. */ static int load_dbatab (void) { static int read_next_rec = TRUE; static char last_dbname[24] = ""; static DBLK *last_dblk; DB_ADDR *next_dba; char buf[1024]; int first_err = TRUE; if (inf == NULL) return 0; usrblk.dbacount = 0; next_dba = usrblk.dbatab; KEEP_READING: /* MAIN LOOP - break it at EOF, max count, or dbname change */ while (usrblk.dbacount < max_dbacount) { /* * Skip the read of the first record if the reason we left * main loop the last time was because of a database name * change, and the data from the last read is still in * parsed_dbname, _dblk, and _recid. Update usrblk.dblk * because it's based on the last table's database. */ if (!read_next_rec) { read_next_rec = TRUE; usrblk.dblk = parsed_dblk; } else { *buf = '\0'; if (fgets (buf, sizeof (buf), inf) == NULL) { fclose (inf); inf = NULL; break; } records_read++; buf[sizeof (buf) - 1] = 0; /* guarantee termination */ if (strlen(buf) && buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; /* * Parse line into dbname and recid. Skip line if * error. */ if (!parse_infbuf (buf)) continue; /* on very first read, save the database name */ if (last_dbname[0] == 0) { strcpy (last_dbname, parsed_dbname); last_dblk = parsed_dblk; } } /* finished reading next rec in input file */ /* * Test for change of database name. Restore usrblk.dblk * to reflect all the records on the dba table so far. Then * save the new dblk for when we are again called. */ if (strcmp (last_dbname, parsed_dbname) != 0) { read_next_rec = FALSE; strcpy (last_dbname, parsed_dbname); usrblk.dblk = last_dblk; last_dblk = parsed_dblk; break; } /* * Call OE to get record's db address. Turn off debug * temporarily so won't flood output with messages. */ usrblk.query = parsed_recid; usrblk.debug &= ~USRDBG_DELETE; usrblk.request = OE_RECKEY2DBA; Opera_Engine (); if (debug_mode) /* restore */ usrblk.debug |= USRDBG_DELETE; if (DtSearchHasMessages ()) { putchar ('\n'); PRINT_MESSAGES } if (usrblk.retncode == OE_WRAPPED) { if (first_err) { first_err = FALSE; fputc ('\n', aa_stderr); } fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 24, "%s Database %s, '%s' not found.\n") , PROGNAME"482", parsed_dbname, parsed_recid); continue; } else if (usrblk.retncode != OE_OK) retncode_abort (486); /* add db address to growing table */ *next_dba = usrblk.dba; next_dba++; usrblk.dbacount++; } /* end of main record read loop */ /* It is possible to exit the main loop, because database changed * or whatever, but no records were added to usrblk.dbatab. * If there are still records to be read from the input file, * go back and try another pass. */ if (inf != NULL && usrblk.dbacount == 0) goto KEEP_READING; return usrblk.dbacount; } /* load_dbatab() */
/* Program 1: displays records in input file, * or user selected records, and if confirmed, * writes their record ids to output file. */ static int browser (void) { int done = FALSE; int pausing = FALSE; int redisplay_rec = FALSE; int pause_counter; time_t stamp; LLIST *llptr; char *ptr; char datestr[32]; /* "1946/04/17 13:03" */ char userbuf[1024]; char infbuf[1024]; /* All writes to output file will have same date string in comment */ time (&stamp); strftime (datestr, sizeof (datestr), "%Y/%m/%d %H:%M", localtime (&stamp)); /* Main menu loop */ while (!done) { if (DtSearchHasMessages ()) { putchar ('\n'); PRINT_MESSAGES } /* Write main menu prompt */ printf ( catgets(dtsearch_catd, MS_tomita, 10, "\n---------- SHOW NEXT RECORD ----------- Database = '%s'\n" "q QUIT. Current Record Count = %ld\n" "p Toggle PAUSE from %s.\n" "n NEXT INPUT file record.\n" "+ NEXT SEQUENTIAL database record.\n" "- PRIOR SEQUENTIAL database record.\n" "r REDISPLAY current record '%s'.\n" "x CONFIRM DELETION of current record.\n" "dxxx Change DATABASE to xxx.\n" "\"xxx GET record id xxx (embedded blanks are ok).\n" "> ") , usrblk.dblk->name, usrblk.dblk->dbrec.or_reccount, (pausing) ? "on to OFF" : "off to ON", usrblk.objrec.or_objkey ); /* Read user's response. Remove user's \n. */ *userbuf = '\0'; if ((fgets (userbuf, sizeof (userbuf), stdin)) == NULL) break; if (strlen(userbuf) && userbuf[strlen(userbuf)-1] == '\n') userbuf[strlen(userbuf)-1] = '\0'; putchar ('\n'); /* depending on response, get database address into usrblk */ redisplay_rec = FALSE; switch (tolower (*userbuf)) { case 'q': done = TRUE; break; case 'd': change_database (userbuf + 1); continue; break; case 'p': pausing = !pausing; continue; break; case 'r': if (usrblk.objrec.or_objkey[0] == 0) { fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 11, "%s Record buffer empty.\n"), PROGNAME"267"); continue; } redisplay_rec = FALSE; break; case '+': case '-': usrblk.request = (*userbuf == '+') ? OE_NEXT_DBA : OE_PREV_DBA; Opera_Engine (); break; case 'n': if (inf == NULL) { fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 12, "%s Input file unavailable.\n"), PROGNAME"282"); continue; } *infbuf = '\0'; if ((fgets (infbuf, sizeof (infbuf), inf)) == NULL) { fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 13, "%s No more records in input file.\n"), PROGNAME"288"); fclose (inf); inf = NULL; continue; } if (strlen(infbuf) && infbuf[strlen(infbuf)-1] == '\n') infbuf[strlen(infbuf)-1] = '\0'; if (!parse_infbuf (infbuf)) continue; usrblk.request = OE_RECKEY2DBA; usrblk.query = parsed_recid; Opera_Engine (); break; case '\"': ptr = strtok (userbuf, "\""); if (ptr == NULL || *ptr == 0) { fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 14, "%s Invalid Record ID.\n"), PROGNAME"303"); continue; } usrblk.request = OE_RECKEY2DBA; usrblk.query = ptr; Opera_Engine (); break; case 'x': /* * Write record id to output file. Format: * dbasename "recid" userid comments(date)... */ fprintf (outf, DISCARD_FORMAT, usrblk.dblk->name, usrblk.objrec.or_objkey, usrblk.userid, datestr); printf ( catgets(dtsearch_catd, MS_tomita, 15, "%s '%s' appended to file of confirmed deletions.\n") , PROGNAME"317", usrblk.objrec.or_objkey); continue; default: printf ("%s", catgets(dtsearch_catd, MS_tomita, 16, "...what?\n")); continue; } /* end switch */ if (done) break; /* if user requested redisplay, skip the following OE code */ if (redisplay_rec) goto DISPLAY_RECORD; /* * check return code from attempt to get opera database * address */ if (usrblk.retncode == OE_WRAPPED) fprintf (aa_stderr, catgets(dtsearch_catd, MS_tomita, 17, "%s %s Engine wrapped to next record.\n") , PROGNAME"333", OE_prodname); else if (usrblk.retncode != OE_OK) retncode_abort (334); /* retrieve the record and uncompress it */ usrblk.request = OE_GETREC; Opera_Engine (); if (usrblk.retncode != OE_OK) retncode_abort (339); DISPLAY_RECORD: /* display the record's cleartext, character by character */ printf ( catgets(dtsearch_catd, MS_tomita, 18, "\n\n" "Record: '%s'\n" "Abstract: '%s'\n" "--------------------------------------\n") , usrblk.objrec.or_objkey, (usrblk.abstrbufsz > 0) ? usrblk.abstrbuf : catgets (dtsearch_catd, MS_misc, 1, "<null>")); pause_counter = 0; for (ptr = usrblk.cleartext; *ptr != 0; ptr++) { putchar (*ptr); /* * pause every so many lines so user can browse the * output */ if (pausing && *ptr == '\n') { if (++pause_counter >= PAUSE_ROWS) { /* Msg 21 is used in two places */ printf ( "%s", catgets(dtsearch_catd, MS_tomita, 21, "\n...push ENTER to continue... ") ); *userbuf = '\0'; fgets (userbuf, sizeof (userbuf), stdin); if (strlen(userbuf) && userbuf[strlen(userbuf)-1] == '\n') userbuf[strlen(userbuf)-1] = '\0'; putchar ('\n'); pause_counter = 0; } } } /* end of cleartext printing */ /* display the user notes if any, character by character */ if (usrblk.notes != NULL) { printf ( catgets(dtsearch_catd, MS_tomita, 20, "--------------------------------------\n" "End of Text Blob for '%s':\n\n" "User Notes:\n" "--------------------------------------\n") , usrblk.objrec.or_objkey); pause_counter += 5; for (llptr = usrblk.notes; llptr != NULL; llptr = llptr->link) { for (ptr = llptr->data; *ptr != '\0'; ptr++) { putchar (*ptr); if (pausing && *ptr == '\n') if (++pause_counter >= PAUSE_ROWS) { /* Msg 21 is used in two places */ printf ( "%s", catgets(dtsearch_catd, MS_tomita, 21, "\n...push ENTER to continue... ") ); *userbuf = '\0'; fgets (userbuf, sizeof (userbuf), stdin); if (strlen(userbuf) && userbuf[strlen(userbuf)-1] == '\n') userbuf[strlen(userbuf)-1] = '\0'; putchar ('\n'); pause_counter = 0; } } } } /* end of user notes printing */ printf ("--------------------------------------\n" "End of Record '%s'.\n", usrblk.objrec.or_objkey); } /* end of main menu loop */ return 0; } /* browser() */