tomita.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  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 libraries 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: browser
  27. * change_database
  28. * deleter
  29. * kill_delete
  30. * load_dbatab
  31. * main
  32. * parse_infbuf
  33. * print_exit_code
  34. * retncode_abort
  35. *
  36. * ORIGINS: 27
  37. *
  38. * (C) COPYRIGHT International Business Machines Corp. 1992,1995
  39. * All Rights Reserved
  40. * US Government Users Restricted Rights - Use, duplication or
  41. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  42. */
  43. /******************* TOMITA.C *******************
  44. * $TOG: tomita.c /main/9 1998/04/17 11:23:38 mgreess $
  45. * May 1992.
  46. * Replaces original tomita but removes curses dependencies
  47. * and uses Opera Engine for deletes rather than hard
  48. * coding vista calls.
  49. *
  50. * In effect, tomita is two programs.
  51. * Program #1 browses an input list of opera record ids and
  52. * prompts user to confirm that they should be deleted from opera.
  53. * The confirmed list is written to an output file that is identical in format.
  54. * Program 1 can be run anytime because it only reads the database.
  55. *
  56. * Program #2 deletes record from an input list, presumably
  57. * the output of program #1. Program #2 writes to vista and changes it.
  58. * It MUST be run offline when no users are logged into opera,
  59. * in order to prevent database corruption.
  60. * Currently password is passed on command line.
  61. * The password is maintained in an encrypted flat file.
  62. * It can be changed from an undocumented Opera Engine function
  63. * available in tuiopera.
  64. *
  65. * RECORD ID FILE FORMAT (shdscrd.lst format):
  66. * One record to be deleted per line.
  67. * 3 words per line separated by whitespace, everything thereafter is comments.
  68. * (These programs only use the first 2 words).
  69. * All words may be optionally enclosed in double quotes
  70. * to capture embedded blanks ("xxx xxx").
  71. * ...
  72. * databasename recordid userid comments...\n
  73. * ...
  74. *
  75. * $Log$
  76. * Revision 2.2 1995/10/25 15:21:36 miker
  77. * Added prolog.
  78. *
  79. * Revision 2.1 1995/09/22 22:17:11 miker
  80. * Freeze DtSearch 0.1, AusText 2.1.8
  81. *
  82. * Revision 1.11 1995/09/05 19:14:39 miker
  83. * Removed password requirement. DtSearch header file and function
  84. * name changes. Made usrblk universal global.
  85. */
  86. #include "SearchE.h"
  87. #include <string.h>
  88. #include <ctype.h>
  89. #include <signal.h>
  90. #include <sys/stat.h>
  91. #include <locale.h>
  92. #include <stdlib.h>
  93. #define PRINT_MESSAGES \
  94. { puts (DtSearchGetMessages()); DtSearchFreeMessages(); }
  95. #define TOKEN_DELIM " \t\n"
  96. #define PAUSE_ROWS 15
  97. #define DBACOUNT 2000
  98. #define PROGNAME "TOMITA"
  99. #define MS_tomita 29
  100. #define MS_misc 1
  101. /*------------------ GLOBALS ------------------*/
  102. static int debug_mode = FALSE;
  103. static int prog = 'B'; /* 'D' = deleting, 'B' = browsing */
  104. static int shutdown_now = FALSE;
  105. static int yesarg = FALSE;
  106. static int retncode = 0;
  107. static int max_dbacount = DBACOUNT;
  108. static FILE *inf, *outf;
  109. static char *infname;
  110. static char *outfname;
  111. static long maxtime;
  112. static long records_read;
  113. static char parsed_dbname [24];
  114. static DBLK *parsed_dblk;
  115. char parsed_recid [2048];
  116. /************************************************/
  117. /* */
  118. /* print_exit_code */
  119. /* */
  120. /************************************************/
  121. /* Called from inside DtSearchExit() at austext_exit_last */
  122. static void print_exit_code (int exit_code)
  123. {
  124. printf ( CATGETS(dtsearch_catd, MS_tomita, 3,
  125. "%s: Exit Code = %d.\n") ,
  126. aa_argv0, exit_code);
  127. return;
  128. } /* print_exit_code() */
  129. /************************************************/
  130. /* */
  131. /* kill_delete */
  132. /* */
  133. /************************************************/
  134. /* Interrupt handler for all termination signals
  135. * in Delete mode. Just sets global flag so we
  136. * can come down gracefully between deletions.
  137. */
  138. static void kill_delete (int sig)
  139. {
  140. shutdown_now = TRUE;
  141. printf ( CATGETS(dtsearch_catd, MS_tomita, 1,
  142. "\n%s Received interrupt %d.\n"
  143. " Program will stop after current batch of deletions.\n") ,
  144. PROGNAME"069", sig);
  145. return;
  146. } /* kill_delete() */
  147. /************************************************/
  148. /* */
  149. /* retncode_abort */
  150. /* */
  151. /************************************************/
  152. static void retncode_abort (int location)
  153. {
  154. fputc ('\n', aa_stderr);
  155. if (DtSearchHasMessages ())
  156. fprintf (aa_stderr, "%s\n", DtSearchGetMessages ());
  157. fprintf (aa_stderr,
  158. PROGNAME "%d Program abort. usrblk.retncode = %d. Exit code = 3.\n",
  159. location, usrblk.retncode);
  160. DtSearchExit (3);
  161. } /* retncode_abort() */
  162. /****************************************/
  163. /* */
  164. /* change_database */
  165. /* */
  166. /****************************************/
  167. /* Changes usrblk.dblk to point to passed database name.
  168. * Returns TRUE if successful.
  169. */
  170. static int change_database (char *newname)
  171. {
  172. DBLK *db;
  173. for (db = usrblk.dblist; db != NULL; db = db->link)
  174. if (strcmp (db->name, newname) == 0) {
  175. usrblk.dblk = db;
  176. return TRUE;
  177. }
  178. /* Invalid newname. If deleting, just say which database is invalid. */
  179. retncode = 1;
  180. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 4,
  181. "%s Database '%s' not found.\n") ,
  182. PROGNAME"114", newname);
  183. if (prog == 'D')
  184. return FALSE;
  185. /* If browsing, tell user his options */
  186. fprintf (aa_stderr, "%s", CATGETS(dtsearch_catd, MS_tomita, 5,
  187. "Available choices are:") );
  188. for (db = usrblk.dblist; db != NULL; db = db->link)
  189. fprintf (aa_stderr, " '%s'", db->name);
  190. fputc ('\n', aa_stderr);
  191. return FALSE;
  192. } /* change_database() */
  193. /****************************************/
  194. /* */
  195. /* parse_infbuf */
  196. /* */
  197. /****************************************/
  198. /* Parses a line from a standard formatted discard file.
  199. * If first word indicates different database from usrblk.dblk,
  200. * changes it. First token loaded into parsed_dbname
  201. * (and parsed_dblk will be made to track it), and
  202. * second token is loaded into parsed_recid.
  203. * Tokens are separated by blanks and/or tabs,
  204. * except 2nd token may have embedded spaces if it is
  205. * surrounded by double quotes. Returns TRUE unless
  206. * database couldn't change or other error, then returns FALSE.
  207. */
  208. static int parse_infbuf (char *infbuf)
  209. {
  210. char *ptr;
  211. char mybuf[1024];
  212. /* Do all parsing in my own buf so infbuf not peppered with \0's */
  213. strncpy (mybuf, infbuf, sizeof (mybuf));
  214. mybuf[sizeof (mybuf) - 1] = 0;
  215. /* Parse first token (database name) */
  216. if ((ptr = strtok (mybuf, " \t")) == NULL) {
  217. /* Msg #8 is used in two places */
  218. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 8,
  219. "%s Invalid input format: %.30s...\n") ,
  220. PROGNAME"152", infbuf);
  221. retncode = 1;
  222. return FALSE;
  223. }
  224. /* Change database if necessary */
  225. if (strcmp (ptr, usrblk.dblk->name) != 0)
  226. if (!change_database (ptr)) {
  227. retncode = 1;
  228. return FALSE;
  229. }
  230. snprintf(parsed_dbname, sizeof(parsed_dbname), "%s", ptr);
  231. parsed_dblk = usrblk.dblk;
  232. /* Hop over to beginning of 2nd token */
  233. for (ptr += strlen (ptr) + 1; *ptr == ' ' || *ptr == '\t'; ptr++);
  234. /* Get 2nd token (record id). Token delimiters depend
  235. * on whether token begins with a double quote.
  236. */
  237. ptr = strtok (ptr, (*ptr == '\"') ? "\"" : " \t");
  238. if (ptr == NULL) {
  239. /* Msg #8 is used in two places */
  240. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 8,
  241. "%s Invalid input format: %.30s...\n") ,
  242. PROGNAME"176", infbuf);
  243. retncode = 1;
  244. return FALSE;
  245. }
  246. strncpy (parsed_recid, ptr, sizeof (parsed_recid));
  247. parsed_recid[sizeof (parsed_recid) - 1] = 0;
  248. return TRUE;
  249. } /* parse_infbuf() */
  250. /****************************************/
  251. /* */
  252. /* browser */
  253. /* */
  254. /****************************************/
  255. /* Program 1: displays records in input file,
  256. * or user selected records, and if confirmed,
  257. * writes their record ids to output file.
  258. */
  259. static int browser (void)
  260. {
  261. int done = FALSE;
  262. int pausing = FALSE;
  263. int redisplay_rec = FALSE;
  264. int pause_counter;
  265. time_t stamp;
  266. LLIST *llptr;
  267. char *ptr;
  268. char datestr[32]; /* "1946/04/17 13:03" */
  269. char userbuf[1024];
  270. char infbuf[1024];
  271. /* All writes to output file will have same date string in comment */
  272. time (&stamp);
  273. strftime (datestr, sizeof (datestr), "%Y/%m/%d %H:%M", localtime (&stamp));
  274. /* Main menu loop */
  275. while (!done) {
  276. if (DtSearchHasMessages ()) {
  277. putchar ('\n');
  278. PRINT_MESSAGES
  279. }
  280. /* Write main menu prompt */
  281. printf ( CATGETS(dtsearch_catd, MS_tomita, 10,
  282. "\n---------- SHOW NEXT RECORD ----------- Database = '%s'\n"
  283. "q QUIT. Current Record Count = %ld\n"
  284. "p Toggle PAUSE from %s.\n"
  285. "n NEXT INPUT file record.\n"
  286. "+ NEXT SEQUENTIAL database record.\n"
  287. "- PRIOR SEQUENTIAL database record.\n"
  288. "r REDISPLAY current record '%s'.\n"
  289. "x CONFIRM DELETION of current record.\n"
  290. "dxxx Change DATABASE to xxx.\n"
  291. "\"xxx GET record id xxx (embedded blanks are ok).\n"
  292. "> ") ,
  293. usrblk.dblk->name,
  294. usrblk.dblk->dbrec.or_reccount,
  295. (pausing) ? "on to OFF" : "off to ON",
  296. usrblk.objrec.or_objkey
  297. );
  298. /* Read user's response. Remove user's \n. */
  299. *userbuf = '\0';
  300. if ((fgets (userbuf, sizeof (userbuf), stdin)) == NULL) break;
  301. if (strlen(userbuf) && userbuf[strlen(userbuf)-1] == '\n')
  302. userbuf[strlen(userbuf)-1] = '\0';
  303. putchar ('\n');
  304. /* depending on response, get database address into usrblk */
  305. redisplay_rec = FALSE;
  306. switch (tolower (*userbuf)) {
  307. case 'q':
  308. done = TRUE;
  309. break;
  310. case 'd':
  311. change_database (userbuf + 1);
  312. continue;
  313. break;
  314. case 'p':
  315. pausing = !pausing;
  316. continue;
  317. break;
  318. case 'r':
  319. if (usrblk.objrec.or_objkey[0] == 0) {
  320. fprintf (aa_stderr,
  321. CATGETS(dtsearch_catd, MS_tomita, 11,
  322. "%s Record buffer empty.\n"),
  323. PROGNAME"267");
  324. continue;
  325. }
  326. redisplay_rec = FALSE;
  327. break;
  328. case '+':
  329. case '-':
  330. usrblk.request = (*userbuf == '+') ? OE_NEXT_DBA : OE_PREV_DBA;
  331. Opera_Engine ();
  332. break;
  333. case 'n':
  334. if (inf == NULL) {
  335. fprintf (aa_stderr,
  336. CATGETS(dtsearch_catd, MS_tomita, 12,
  337. "%s Input file unavailable.\n"),
  338. PROGNAME"282");
  339. continue;
  340. }
  341. *infbuf = '\0';
  342. if ((fgets (infbuf, sizeof (infbuf), inf)) == NULL)
  343. {
  344. fprintf (aa_stderr,
  345. CATGETS(dtsearch_catd, MS_tomita, 13,
  346. "%s No more records in input file.\n"),
  347. PROGNAME"288");
  348. fclose (inf);
  349. inf = NULL;
  350. continue;
  351. }
  352. if (strlen(infbuf) && infbuf[strlen(infbuf)-1] == '\n')
  353. infbuf[strlen(infbuf)-1] = '\0';
  354. if (!parse_infbuf (infbuf))
  355. continue;
  356. usrblk.request = OE_RECKEY2DBA;
  357. usrblk.query = parsed_recid;
  358. Opera_Engine ();
  359. break;
  360. case '\"':
  361. ptr = strtok (userbuf, "\"");
  362. if (ptr == NULL || *ptr == 0) {
  363. fprintf (aa_stderr,
  364. CATGETS(dtsearch_catd, MS_tomita, 14,
  365. "%s Invalid Record ID.\n"),
  366. PROGNAME"303");
  367. continue;
  368. }
  369. usrblk.request = OE_RECKEY2DBA;
  370. usrblk.query = ptr;
  371. Opera_Engine ();
  372. break;
  373. case 'x':
  374. /*
  375. * Write record id to output file. Format:
  376. * dbasename "recid" userid comments(date)...
  377. */
  378. fprintf (outf, DISCARD_FORMAT, usrblk.dblk->name,
  379. usrblk.objrec.or_objkey, usrblk.userid, datestr);
  380. printf ( CATGETS(dtsearch_catd, MS_tomita, 15,
  381. "%s '%s' appended to file of confirmed deletions.\n") ,
  382. PROGNAME"317", usrblk.objrec.or_objkey);
  383. continue;
  384. default:
  385. printf ("%s", CATGETS(dtsearch_catd, MS_tomita, 16, "...what?\n"));
  386. continue;
  387. } /* end switch */
  388. if (done)
  389. break;
  390. /* if user requested redisplay, skip the following OE code */
  391. if (redisplay_rec)
  392. goto DISPLAY_RECORD;
  393. /*
  394. * check return code from attempt to get opera database
  395. * address
  396. */
  397. if (usrblk.retncode == OE_WRAPPED)
  398. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 17,
  399. "%s %s Engine wrapped to next record.\n") ,
  400. PROGNAME"333", OE_prodname);
  401. else if (usrblk.retncode != OE_OK)
  402. retncode_abort (334);
  403. /* retrieve the record and uncompress it */
  404. usrblk.request = OE_GETREC;
  405. Opera_Engine ();
  406. if (usrblk.retncode != OE_OK)
  407. retncode_abort (339);
  408. DISPLAY_RECORD:
  409. /* display the record's cleartext, character by character */
  410. printf ( CATGETS(dtsearch_catd, MS_tomita, 18,
  411. "\n\n"
  412. "Record: '%s'\n"
  413. "Abstract: '%s'\n"
  414. "--------------------------------------\n") ,
  415. usrblk.objrec.or_objkey,
  416. (usrblk.abstrbufsz > 0) ? usrblk.abstrbuf :
  417. CATGETS(dtsearch_catd, MS_misc, 1, "<null>"));
  418. pause_counter = 0;
  419. for (ptr = usrblk.cleartext; *ptr != 0; ptr++) {
  420. putchar (*ptr);
  421. /*
  422. * pause every so many lines so user can browse the
  423. * output
  424. */
  425. if (pausing && *ptr == '\n') {
  426. if (++pause_counter >= PAUSE_ROWS) {
  427. /* Msg 21 is used in two places */
  428. printf ( "%s", CATGETS(dtsearch_catd, MS_tomita, 21,
  429. "\n...push ENTER to continue... ") );
  430. *userbuf = '\0';
  431. if(NULL == fgets (userbuf, sizeof (userbuf), stdin)) {
  432. fprintf(stderr, "Failed to read from stdin\n");
  433. exit(EXIT_FAILURE);
  434. }
  435. if (strlen(userbuf) && userbuf[strlen(userbuf)-1] == '\n')
  436. userbuf[strlen(userbuf)-1] = '\0';
  437. putchar ('\n');
  438. pause_counter = 0;
  439. }
  440. }
  441. } /* end of cleartext printing */
  442. /* display the user notes if any, character by character */
  443. if (usrblk.notes != NULL) {
  444. printf ( CATGETS(dtsearch_catd, MS_tomita, 20,
  445. "--------------------------------------\n"
  446. "End of Text Blob for '%s':\n\n"
  447. "User Notes:\n"
  448. "--------------------------------------\n") ,
  449. usrblk.objrec.or_objkey);
  450. pause_counter += 5;
  451. for (llptr = usrblk.notes; llptr != NULL; llptr = llptr->link) {
  452. for (ptr = llptr->data; *ptr != '\0'; ptr++) {
  453. putchar (*ptr);
  454. if (pausing && *ptr == '\n')
  455. if (++pause_counter >= PAUSE_ROWS) {
  456. /* Msg 21 is used in two places */
  457. printf ( "%s", CATGETS(dtsearch_catd, MS_tomita, 21,
  458. "\n...push ENTER to continue... ") );
  459. *userbuf = '\0';
  460. if(NULL == fgets (userbuf, sizeof (userbuf), stdin)) {
  461. fprintf(stderr, "Failed to read from stdin 2\n");
  462. exit(EXIT_FAILURE);
  463. }
  464. if (strlen(userbuf) &&
  465. userbuf[strlen(userbuf)-1] == '\n')
  466. userbuf[strlen(userbuf)-1] = '\0';
  467. putchar ('\n');
  468. pause_counter = 0;
  469. }
  470. }
  471. }
  472. } /* end of user notes printing */
  473. printf ("--------------------------------------\n"
  474. "End of Record '%s'.\n", usrblk.objrec.or_objkey);
  475. } /* end of main menu loop */
  476. return 0;
  477. } /* browser() */
  478. /****************************************/
  479. /* */
  480. /* load_dbatab */
  481. /* */
  482. /****************************************/
  483. /* Subroutine of deleter(). Reads discard file containing
  484. * record ids to be deleted, converts to database addresses,
  485. * loads usrblk.dbatab up to max batch size.
  486. * Returns number of dba's added to table.
  487. * Returns 0 when file is empty after last batch.
  488. */
  489. static int load_dbatab (void)
  490. {
  491. static int read_next_rec = TRUE;
  492. static char last_dbname[24] = "";
  493. static DBLK *last_dblk;
  494. DB_ADDR *next_dba;
  495. char buf[1024];
  496. int first_err = TRUE;
  497. if (inf == NULL)
  498. return 0;
  499. usrblk.dbacount = 0;
  500. next_dba = usrblk.dbatab;
  501. KEEP_READING:
  502. /* MAIN LOOP - break it at EOF, max count, or dbname change */
  503. while (usrblk.dbacount < max_dbacount) {
  504. /*
  505. * Skip the read of the first record if the reason we left
  506. * main loop the last time was because of a database name
  507. * change, and the data from the last read is still in
  508. * parsed_dbname, _dblk, and _recid. Update usrblk.dblk
  509. * because it's based on the last table's database.
  510. */
  511. if (!read_next_rec) {
  512. read_next_rec = TRUE;
  513. usrblk.dblk = parsed_dblk;
  514. }
  515. else {
  516. *buf = '\0';
  517. if (fgets (buf, sizeof (buf), inf) == NULL)
  518. {
  519. fclose (inf);
  520. inf = NULL;
  521. break;
  522. }
  523. records_read++;
  524. buf[sizeof (buf) - 1] = 0; /* guarantee termination */
  525. if (strlen(buf) && buf[strlen(buf)-1] == '\n')
  526. buf[strlen(buf)-1] = '\0';
  527. /*
  528. * Parse line into dbname and recid. Skip line if
  529. * error.
  530. */
  531. if (!parse_infbuf (buf))
  532. continue;
  533. /* on very first read, save the database name */
  534. if (last_dbname[0] == 0) {
  535. strcpy (last_dbname, parsed_dbname);
  536. last_dblk = parsed_dblk;
  537. }
  538. } /* finished reading next rec in input file */
  539. /*
  540. * Test for change of database name. Restore usrblk.dblk
  541. * to reflect all the records on the dba table so far. Then
  542. * save the new dblk for when we are again called.
  543. */
  544. if (strcmp (last_dbname, parsed_dbname) != 0) {
  545. read_next_rec = FALSE;
  546. strcpy (last_dbname, parsed_dbname);
  547. usrblk.dblk = last_dblk;
  548. last_dblk = parsed_dblk;
  549. break;
  550. }
  551. /*
  552. * Call OE to get record's db address. Turn off debug
  553. * temporarily so won't flood output with messages.
  554. */
  555. usrblk.query = parsed_recid;
  556. usrblk.debug &= ~USRDBG_DELETE;
  557. usrblk.request = OE_RECKEY2DBA;
  558. Opera_Engine ();
  559. if (debug_mode) /* restore */
  560. usrblk.debug |= USRDBG_DELETE;
  561. if (DtSearchHasMessages ()) {
  562. putchar ('\n');
  563. PRINT_MESSAGES
  564. }
  565. if (usrblk.retncode == OE_WRAPPED) {
  566. if (first_err) {
  567. first_err = FALSE;
  568. fputc ('\n', aa_stderr);
  569. }
  570. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 24,
  571. "%s Database %s, '%s' not found.\n") ,
  572. PROGNAME"482", parsed_dbname, parsed_recid);
  573. continue;
  574. }
  575. else if (usrblk.retncode != OE_OK)
  576. retncode_abort (486);
  577. /* add db address to growing table */
  578. *next_dba = usrblk.dba;
  579. next_dba++;
  580. usrblk.dbacount++;
  581. } /* end of main record read loop */
  582. /* It is possible to exit the main loop, because database changed
  583. * or whatever, but no records were added to usrblk.dbatab.
  584. * If there are still records to be read from the input file,
  585. * go back and try another pass.
  586. */
  587. if (inf != NULL && usrblk.dbacount == 0)
  588. goto KEEP_READING;
  589. return usrblk.dbacount;
  590. } /* load_dbatab() */
  591. /****************************************/
  592. /* */
  593. /* deleter */
  594. /* */
  595. /****************************************/
  596. /* Program 2: deletes records specified in input file.
  597. * Must be run offline when all online users have logged off.
  598. */
  599. static void deleter (char *infname)
  600. {
  601. int i;
  602. long records_deleted;
  603. time_t start_time, minutes, hours, seconds, elapsed;
  604. char buf[128];
  605. if (!yesarg) {
  606. printf ( CATGETS(dtsearch_catd, MS_tomita, 25,
  607. "\nDO NOT CONTINUE under any of the following circumstances:\n"
  608. "-> If the input file which lists record ids to be deleted is not\n"
  609. " named '%s'.\n"
  610. "-> If any users are still accessing the affected database(s).\n"
  611. "-> If any database files have not been backed up.\n\n"
  612. "If you are sure you are ready to start deleting, enter 'y' now... ") ,
  613. infname, OE_prodname);
  614. if(NULL == fgets (buf, sizeof(buf)-1, stdin)) {
  615. fprintf(stderr, "no input\n");
  616. return;
  617. }
  618. if (tolower (*buf) != 'y')
  619. return;
  620. }
  621. /* Make sure engine doesn't abort because of
  622. * recurring changes to d99 files.
  623. */
  624. OE_sitecnfg_mtime = 0L;
  625. /* Init table of db addrs */
  626. usrblk.dbatab = austext_malloc
  627. (sizeof (DB_ADDR) * (max_dbacount + 2), PROGNAME "531", NULL);
  628. usrblk.dbacount = 0; /* number of recs currently in table */
  629. /* Init status msg stuff */
  630. records_read = 0L;
  631. records_deleted = 0L;
  632. time (&start_time);
  633. signal (SIGINT, kill_delete);
  634. signal (SIGQUIT, kill_delete);
  635. signal (SIGTRAP, kill_delete);
  636. signal (SIGTERM, kill_delete);
  637. #ifdef SIGPWR
  638. signal (SIGPWR, kill_delete);
  639. #endif
  640. #ifdef _AIX
  641. signal (SIGXCPU, kill_delete); /* cpu time limit exceeded */
  642. signal (SIGDANGER, kill_delete); /* imminent paging space
  643. * crash */
  644. #endif
  645. /* MAIN LOOP */
  646. while (load_dbatab ()) {
  647. /*
  648. * Stop now if we have exceeded user specified time limit
  649. * or if user sent termination or interrupt signal.
  650. */
  651. if (shutdown_now)
  652. break;
  653. elapsed = time (NULL) - start_time;
  654. if (maxtime > 0L && elapsed >= maxtime)
  655. break;
  656. /* echo status for humans who might be watching */
  657. hours = elapsed / 3600L;
  658. seconds = elapsed - (3600L * hours); /* remaining after hours */
  659. minutes = seconds / 60L;
  660. seconds = seconds - (60L * minutes);
  661. printf ( CATGETS(dtsearch_catd, MS_tomita, 26,
  662. "%s %ld read, %ld deleted, %ldh %2ldm %2lds elapsed.\n"
  663. " Database '%s': Current record count = %ld, Batch size = %d.\n") ,
  664. aa_argv0, records_read, records_deleted,
  665. hours, minutes, seconds,
  666. usrblk.dblk->name, usrblk.dblk->dbrec.or_reccount, usrblk.dbacount);
  667. /*****fflush (stdout);*****/
  668. /* call OE to delete batch of records */
  669. usrblk.request = OE_DELETE_BATCH;
  670. Opera_Engine ();
  671. if (DtSearchHasMessages ()) {
  672. putchar ('\n');
  673. PRINT_MESSAGES
  674. }
  675. if (usrblk.retncode != OE_OK)
  676. retncode_abort (572);
  677. records_deleted += usrblk.dbacount;
  678. } /* end main loop */
  679. /* Print final status messages */
  680. elapsed = time (NULL) - start_time; /* total elapsed time */
  681. hours = elapsed / 3600L;
  682. seconds = elapsed - (3600L * hours); /* remaining after hours */
  683. minutes = seconds / 60L;
  684. seconds = seconds - (60L * minutes); /* remaining after hours
  685. * & mins */
  686. printf ( CATGETS(dtsearch_catd, MS_tomita, 27,
  687. "%s %ld records read from input file. %ld were deleted and\n"
  688. " %ld were not found in %ld hours, %ld minutes, %ld seconds,\n") ,
  689. aa_argv0, records_read, records_deleted,
  690. records_read - records_deleted,
  691. hours, minutes, seconds);
  692. /* Figure average time for a deletion */
  693. elapsed = (records_deleted) ? elapsed / records_deleted : 0L;
  694. minutes = elapsed / 60L;
  695. seconds = elapsed - (60L * minutes);
  696. printf ( CATGETS(dtsearch_catd, MS_tomita, 28,
  697. " or an average of %ld minutes, %ld seconds per record deleted.\n"),
  698. minutes, seconds);
  699. return;
  700. } /* deleter() */
  701. /****************************************/
  702. /* */
  703. /* main */
  704. /* */
  705. /****************************************/
  706. int main (int argc, char *argv[])
  707. {
  708. char *arg;
  709. time_t mytime;
  710. char timebuf[80];
  711. aa_argv0 = argv[0];
  712. setlocale (LC_ALL, "");
  713. dtsearch_catd = CATOPEN(FNAME_DTSRCAT, 0);
  714. time (&mytime);
  715. strftime (timebuf, sizeof (timebuf),
  716. CATGETS(dtsearch_catd, MS_misc, 22, "%A, %b %d %Y, %I:%M %p"),
  717. localtime (&mytime));
  718. printf (CATGETS(dtsearch_catd, MS_tomita, 29,
  719. "%s. Run %s.\n") ,
  720. aa_argv0, timebuf);
  721. austext_exit_last = print_exit_code;
  722. signal (SIGINT, DtSearchExit);
  723. signal (SIGTERM, DtSearchExit);
  724. /****memset (&usrblk, 0, sizeof(USRBLK));****/
  725. /* Validate program number argument */
  726. if (argc < 2) {
  727. BAD_ARGS:
  728. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 30,
  729. "\nUSAGE: %s [options]\n"
  730. " -i Input file name. If not specified, defaults to %s.\n"
  731. " -d[v] Print debug statements.\n"
  732. " -dv turns on verbose (record-by-record) debugging.\n"
  733. " -t<N> Max desired number of seconds of run time.\n"
  734. " Ctrl-C/Break will also stop deletion at next record.\n"
  735. " -n<N> Change number of records in a batch from %d to <N>.\n"
  736. " -y Automatically answers 'yes' to Delete mode confirm prompt.\n"
  737. " -d trace deletion operations.\n") ,
  738. aa_argv0, FNAME_DISCARD_DATA,
  739. FNAME_CONFIRM_LIST, FNAME_CONFIRM_LIST, DBACOUNT);
  740. DtSearchExit (2);
  741. }
  742. prog = toupper (argv[1][0]);
  743. if (prog != 'B' && prog != 'D')
  744. goto BAD_ARGS;
  745. /* Initialize defaults depending on program mode */
  746. if (prog == 'B') {
  747. infname = FNAME_DISCARD_DATA;
  748. outfname = FNAME_CONFIRM_LIST;
  749. }
  750. else {
  751. infname = FNAME_CONFIRM_LIST;
  752. outfname = PROGNAME "654";
  753. }
  754. maxtime = 0L;
  755. /* Save rest of command line arguments */
  756. for (argc -= 2, argv += 2; argc > 0; argc--, argv++) {
  757. arg = *argv;
  758. switch (tolower (arg[1])) {
  759. case 'i':
  760. infname = arg + 2;
  761. break;
  762. case 'o':
  763. outfname = arg + 2;
  764. break;
  765. case 'd':
  766. debug_mode = TRUE;
  767. usrblk.debug |= USRDBG_DELETE;
  768. if (arg[2] == 'v')
  769. usrblk.debug |= USRDBG_VERBOSE;
  770. break;
  771. case 'y':
  772. yesarg = TRUE;
  773. break;
  774. case 't':
  775. maxtime = atol (arg + 2);
  776. break;
  777. case 'n':
  778. max_dbacount = atol (arg + 2);
  779. break;
  780. default:
  781. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 31,
  782. "\n%s Unknown argument '%s'.\n") ,
  783. PROGNAME"689", arg);
  784. goto BAD_ARGS;
  785. } /* end switch */
  786. } /* end arg parsing */
  787. /* Open input file to test for its existence.
  788. * For the Browse program, file ptr 'inf' == NULL
  789. * means the file is not open.
  790. */
  791. if ((inf = fopen (infname, "r")) == NULL) {
  792. if (prog == 'D') {
  793. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 32,
  794. "%s Unable to open input file '%s'.\n") ,
  795. PROGNAME"710", infname);
  796. goto BAD_ARGS;
  797. }
  798. }
  799. /* If browsing, get output file name and
  800. * open it to test for write permission.
  801. */
  802. if (prog == 'B') {
  803. if ((outf = fopen (outfname, "a ")) == NULL)
  804. /* the blank in "a " works around old aix bug */
  805. {
  806. fprintf (aa_stderr, CATGETS(dtsearch_catd, MS_tomita, 33,
  807. "\n%s Unable to open output file '%s'.\n") ,
  808. PROGNAME"721", outfname);
  809. goto BAD_ARGS;
  810. }
  811. }
  812. /* Initialize the opera engine, i.e. open the database */
  813. printf ( CATGETS(dtsearch_catd, MS_tomita, 34,
  814. "Initializing %s engine...\n"),
  815. OE_prodname);
  816. strcpy (usrblk.userid, "ToMiTa");
  817. usrblk.request = OE_INITIALIZE;
  818. usrblk.query = AUSAPI_VERSION;
  819. Opera_Engine ();
  820. if (usrblk.retncode != OE_OK)
  821. retncode_abort (733);
  822. PRINT_MESSAGES
  823. if (prog == 'B')
  824. browser ();
  825. else
  826. deleter (infname);
  827. usrblk.request = OE_SHUTDOWN;
  828. Opera_Engine ();
  829. printf ( "%s", CATGETS(dtsearch_catd, MS_tomita, 36,
  830. "Normal engine shutdown.\n") );
  831. DtSearchExit (0);
  832. } /* main() */
  833. /******************* TOMITA.C *******************/