2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
24 * COMPONENT_NAME: austext
26 * FUNCTIONS: append_blob
40 * (C) COPYRIGHT International Business Machines Corp. 1991,1995
42 * Licensed Materials - Property of IBM
43 * US Government Users Restricted Rights - Use, duplication or
44 * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
46 /**************************** DTSRVE.C ******************************
47 * $XConsortium: dtsrve.c /main/8 1996/11/21 19:49:59 drk $
49 * The 'vista engine' of opera.
50 * Contains all modules that actually access the database.
51 * Theoretically, if opera replaced vista with some other DBMS
52 * this is the only module that would have to be modified.
55 * Revision 2.4 1996/02/01 18:48:49 miker
56 * Enhanced blob retrieval debug msgs.
58 * Revision 2.3 1995/10/25 18:08:27 miker
59 * Renamed from ve.c. Added prolog.
62 * Revision 2.2 1995/10/19 21:02:35 miker
63 * Open mode of non-vista d9x files now tracks db_oflag.
65 * Revision 2.1 1995/09/22 22:26:36 miker
66 * Freeze DtSearch 0.1, AusText 2.1.8
68 * Revision 1.12 1995/09/05 19:18:56 miker
69 * Made usrblk global. Name, msgs, etc changes for DtSearch.
70 * Made ausapi_msglist global. Deleted obsolete socblk refs.
71 * Added DTSEARCH define.
73 * Revision 1.11 1995/07/18 22:29:18 miker
74 * Delete msglist arg from vista_abort() function calls.
83 #define XOS_USE_NO_LOCKING
84 #define X_INCLUDE_TIME_H
85 #include <X11/Xos_r.h>
87 #define PROGNAME "DTSRVE"
88 #define NOTES_SEM_DELAY 3
93 extern time_t hctree_id; /**** hardcoded only temporarily ******/
94 static int max_abstrbufsz = 0;
95 static int max_ormisc_size;
99 /************************************************/
103 /************************************************/
104 /* Loaded by any workproc when it has successfully completed.
105 * Should never be called because GUI should turn off workproc
106 * calls after real workproc completes with OE_OK.
108 void dummy_workproc (void)
110 fputs (catgets (dtsearch_catd, MS_ve, 26,
111 PROGNAME "26 Called dummy_workproc().\n"),
114 } /* dummy_workproc() */
117 /************************************************/
121 /************************************************/
122 /* Mallocs space for new compressed vista text record (blob)
123 * appends copy of passed blob to passed link address.
124 * Subroutine of ve_getrec_dba() and ve_getblobs() below.
125 * Similar to append_msglist() function except that data string
126 * is not presumed to be terminated with \0. Instead the entire
127 * vista member record is copied, as binary bytes,
128 * irrespective of their contents.
129 * This function allocates memory for the blobs but DOES NOT FREE IT.
130 * free_llist() must be called before building a new bloblist.
132 static LLIST *append_blob (LLIST ** bloblink,
133 struct or_blobrec * blobrec)
137 new = austext_malloc (sizeof (struct or_blobrec) + sizeof (LLIST) + 4,
138 PROGNAME "36", NULL);
139 new->data = new + 1; /* hop over exactly 1 LLIST
143 memcpy (new->data, blobrec, sizeof (struct or_blobrec));
145 } /* append_blob() */
148 /************************************************/
152 /************************************************/
153 /* Opens databases in usrblk (calls open_dblk()), and reads dbrecs.
154 * Returns TRUE if 1 or more dblks survived the opening ordeal.
155 * Returns FALSE if no dblks survived.
157 int ve_initialize (void)
159 DBLK*db, *bad_db, **lastlink;
160 int debugging = (usrblk.debug & USRDBG_RARE); /* boolean */
162 char d9x_fname[1024];
166 static char default_cant_open_msg[] =
167 "%s Cannot open database file '%s', errno %d = %s. "
168 "%s is removing '%s' from list of available databases.";
170 /* ---- PASS #1 and #2 ------------------------------------------
171 * Open the d99 and vista database files.
173 if (!open_dblk (&usrblk.dblist, 64, debugging))
176 /* ---- PASS #3 ------------------------------------------
177 * (1) Read dbrec database-wide globals for each database.
178 * (2) Determine max abstract size from largest abstrsz.
179 * (3) Open other nonvista (d9x) files.
180 * Open mode is determined by value of db_oflag.
181 * Disconnect any dblks with invalid dbrecs or d9x files.
183 if (db_oflag == O_RDONLY)
184 strcpy (open_mode, "rb");
186 strcpy (open_mode, "r+b");
188 fprintf (aa_stderr, PROGNAME "76 "
189 "Begin dblks Pass #3 in ve_initialize(). Open mode '%s'.\n",
193 lastlink = &usrblk.dblist;
195 /*-------------- READ DBREC ----------------*/
198 "--> reading dbrec for database '%s':\n",
201 RECFRST (PROGNAME "285", OR_DBREC, db->vistano); /* seqtl retrieval */
202 if (db_status != S_OKAY) {
204 sprintf (msgbuf, catgets (dtsearch_catd, MS_misc, 13,
205 "%s No DB record in database '%s'."),
206 PROGNAME "853 ", db->name);
207 DtSearchAddMessage (msgbuf);
210 RECREAD (PROGNAME "302", &db->dbrec, db->vistano);
211 if (db_status != S_OKAY)
213 swab_dbrec (&db->dbrec, NTOH);
215 if (db->dbrec.or_abstrsz > usrblk.abstrbufsz) {
218 "\t(changing usrblk.abstrbufsz from %d to %d).\n",
219 usrblk.abstrbufsz, db->dbrec.or_abstrsz);
220 usrblk.abstrbufsz = db->dbrec.or_abstrsz;
223 /*-------------- DBREC SANITY CHECKS ----------------*/
224 if (db->dbrec.or_reccount <= 0) {
225 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 167,
226 "%s No data in database '%s'."),
227 PROGNAME"167 ", db->name);
228 DtSearchAddMessage (msgbuf);
231 if (!is_compatible_version (db->dbrec.or_version, SCHEMA_VERSION)) {
232 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 178,
233 "%s Database '%s' version '%s' incompatible"
234 " with Engine version '%s'."),
236 db->name, db->dbrec.or_version, AUSAPI_VERSION);
237 DtSearchAddMessage (msgbuf);
240 if (db->dbrec.or_reccount > db->dbrec.or_maxdba) {
241 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 251,
242 "%s Database '%s' corrupted: "
243 "Incompatible record counts and database addresses.\n"),
244 PROGNAME" 251", db->name);
245 DtSearchAddMessage (msgbuf);
248 if (db->dbrec.or_maxwordsz < MAXWIDTH_SWORD - 1) {
249 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 185,
250 "%s Database '%s' maximum word size %d is too short."),
251 PROGNAME" 185", db->name, db->dbrec.or_maxwordsz);
252 DtSearchAddMessage (msgbuf);
255 if (db->dbrec.or_hufid != 0L && db->dbrec.or_hufid != hctree_id) {
257 * for now, huffman decompress table hardcoded and
260 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 156,
261 "%s Incompatible data compression table used for database '%s'.\n"
262 " Database compressed with %ld, "
263 "engine decompressor is %ld.\n"),
264 PROGNAME" 156", db->name, db->dbrec.or_hufid, hctree_id);
265 DtSearchAddMessage (msgbuf);
268 /* dbrec ok: print debug msg */
271 "\tvers='%s' reccount=%ld maxdba=%ld fzkeysz=%d\n"
272 "\tdbflags=x%lx maxwordsz=%d hufid=%ld abstrsz=%d\n",
273 db->dbrec.or_version, (long) db->dbrec.or_reccount,
274 (long) db->dbrec.or_maxdba, db->dbrec.or_fzkeysz,
275 (unsigned long) db->dbrec.or_dbflags, db->dbrec.or_maxwordsz,
276 (long) db->dbrec.or_hufid, db->dbrec.or_abstrsz);
279 /*-------------- OPEN D97 and D98 FILES ----------------
280 * If semantic (symptom) search is enabled,
281 * open the d97 (offsets table) and d98 (index) files.
283 if (db->dbrec.or_fzkeysz > 0) {
284 /* build complete path-file name */
285 snprintf(d9x_fname, sizeof(d9x_fname), "%s%s", db->path, db->name);
286 d9x_fext = d9x_fname + strlen (d9x_fname);
287 strcpy (d9x_fext, ".d97");
289 fprintf (aa_stderr, "--> opening '%s'\n", d9x_fname);
291 if ((db->syofile = fopen (d9x_fname, open_mode)) == NULL) {
292 sprintf (msgbuf, catgets (dtsearch_catd, MS_oeinit, 317,
293 default_cant_open_msg), PROGNAME "286",
294 d9x_fname, errno, strerror (errno), OE_prodname, db->name);
295 DtSearchAddMessage (msgbuf);
299 strcpy (d9x_fext, ".d98");
301 fprintf (aa_stderr, "--> opening '%s'\n", d9x_fname);
303 if ((db->syifile = fopen (d9x_fname, open_mode)) == NULL) {
304 sprintf (msgbuf, catgets (dtsearch_catd, MS_oeinit, 317,
305 default_cant_open_msg), PROGNAME "298",
306 d9x_fname, errno, strerror (errno), OE_prodname, db->name);
307 DtSearchAddMessage (msgbuf);
310 } /* endif to open d97 and d98 files */
313 /*---------------------- DB OK -------------------------
314 * This dblk passed all dbrec validations and all other
315 * d9x files were available. Increment pointers and continue.
318 fprintf (aa_stderr, "------> dblk '%s' ok in veinitialize()\n",
321 lastlink = &db->link;
325 /*---------------------- DELETE DB -------------------------
326 * This dblk failed one or more dbrec validity checks.
327 * Unlink it and don't increment pointers.
331 fprintf (aa_stderr, "------> ERROR UNLINK '%s'.\n", db->name);
332 bad_db = db; /* temp save */
333 *lastlink = db->link;
338 /* Quit if no dblks remain */
339 if (good_dblk_count <= 0) {
340 sprintf (msgbuf, catgets (dtsearch_catd, MS_misc, 8,
341 "%s No valid databases remain."), PROGNAME "246");
342 DtSearchAddMessage (msgbuf);
346 /* Allocate an abstract buffer for the usrblk
347 * if any abstracts are used in any database.
348 * The size is saved in case the client doesn't
349 * return the buffer in subsequent calls.
351 if (usrblk.abstrbufsz) {
352 max_abstrbufsz = usrblk.abstrbufsz; /* save */
353 usrblk.abstrbuf = austext_malloc (usrblk.abstrbufsz + 4,
354 PROGNAME "274", NULL);
357 PROGNAME "282 Allocating %d bytes for usrblk.abstrbuf.\n",
358 usrblk.abstrbufsz + 4);
361 fprintf (aa_stderr, PROGNAME "284 usrblk.abstrbuf NOT allocated.\n");
364 } /* ve_initialize() */
367 /************************************************/
371 /************************************************/
372 /* closes databases */
373 void ve_shutdown (void)
376 austext_exit_dbms = NULL;
380 /************************************************/
382 /* ve_append_notes */
384 /************************************************/
385 /* Appends user notes in usrblk.query to
386 * opera record specified by usrblk.dba.
387 * usrblk.dba is presumed valid opera record.
388 * Saves all appends in separate backup flat file
389 * for restoring database after a crash or initdb.
391 * The technique to prevent 2 users from updating
392 * at the same time does not require vista locking.
393 * This function considers itself a 'critical region' and
394 * uses a value in a special file as a semaphore to prevent multiple
395 * users from threading through it at the same time.
397 * Does NOT change status of current record in usrblk--it only uses dba.
398 * Returns OE_DISABLED if function disabled in or_dbflags or global var.
399 * Returns OE_OK after successful append.
400 * Returns OE_TIMEOUT if a user cannot acquire the semaphore
401 * after a reasonable length of time.
402 * Returns OE_ABORT on fatal error.
404 int ve_append_notes (void)
407 FILE *backup_file, *semaphore_file;
413 char *entirebufptr, *appendbufptr;
415 static char formfeed_line[] = "\f\n";
420 /* Test if function is disabled */
421 if (!OE_enable_usernotes || usrblk.dblk->dbrec.or_dbflags & ORD_NONOTES) {
422 sprintf (mybuf, catgets (dtsearch_catd, MS_ve, 309,
423 "%s User notes disabled "), PROGNAME" 309");
424 ptr = mybuf + strlen (mybuf);
425 if (!OE_enable_usernotes)
426 strcpy (ptr, catgets (dtsearch_catd, MS_ve, 310,
427 "for entire Engine."));
429 sprintf (ptr, catgets (dtsearch_catd, MS_ve, 311,
430 "for database '%s'."),
432 DtSearchAddMessage (mybuf);
436 /* Test for invalid dba */
437 if (usrblk.dba == NULL_DBA) {
438 DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 157,
439 PROGNAME "157 Client Program Error: "
440 "Null database address in usrblk.dba."));
441 OE_flags |= OE_PERMERR;
445 /* Acquire the semaphore: Open the semaphore file.
446 * If first char = '1', somebody is already in the critical region.
447 * If '1' remains in file after several tries, quit with FALSE retncode.
448 * If first char = '0', critical region is available for this task.
449 * Write a '1' and enter the region.
451 i = 0; /* loop counter */
453 if ((semaphore_file = fopen (OEF_notessem, "r+")) == NULL) {
455 catgets (dtsearch_catd, MS_ve, 183,
456 "%s Could not open user notes semaphore file '%s': %s.\n"),
457 PROGNAME "183 ", OEF_notessem, strerror (errno));
458 DtSearchAddMessage (mybuf);
461 fread (mybuf, 1, 1, semaphore_file);
464 * If semaphore is available, grab it and enter critical
468 rewind (semaphore_file);
469 fwrite ("1", 1, 1, semaphore_file);
470 fflush (semaphore_file);
475 * Otherwise check that we havent looped too often, and try
478 fclose (semaphore_file);
479 if (++i > NOTES_SEM_DELAY) {
481 catgets (dtsearch_catd, MS_ve, 199,
482 "%s Could not acquire user notes semaphore '%s' "
483 "within %d tries.\n"),
484 PROGNAME " 199", OEF_notessem, NOTES_SEM_DELAY);
485 DtSearchAddMessage (mybuf);
488 sleep (1); /* wait a second */
489 } /* end of semaphore loop */
491 /* We have acquired the semaphore, beginning of critical region... */
493 /* Enlarge the buffer so we can prefix users text with the record key
494 * (for the backup file), and a header line.
496 entirebufptr = austext_malloc
497 (DtSrMAX_DB_KEYSIZE + sizeof (mybuf) + strlen (usrblk.query),
498 PROGNAME "170", NULL);
499 sprintf (entirebufptr, "%s\n%s",
500 usrblk.dblk->name, usrblk.objrec.or_objkey);
502 /* Now add a timstamped, user identified 'header' line */
503 appendbufptr = entirebufptr + strlen (entirebufptr);
505 time_ptr = _XLocaltime(&mystamp, localtime_buf);
506 strftime (mybuf, sizeof (mybuf), catgets (dtsearch_catd, MS_ve, 332,
507 "%Y/%m/%d at %H:%M %Z"), time_ptr);
508 sprintf (appendbufptr, catgets (dtsearch_catd, MS_ve, 333,
509 "\n <User Note Appended by '%s' on %s>\n"),
510 usrblk.userid, mybuf);
511 strcat (appendbufptr, usrblk.query); /* now add user's text */
513 /* Make sure users note ends in \n */
514 ptr = appendbufptr + strlen (appendbufptr);
515 if (*(ptr - 1) != '\n') {
520 /* Append text to current list of notes */
521 vistano = usrblk.dblk->vistano;
522 CSOSET (PROGNAME "153", OR_OBJ_MISCS, &usrblk.dba, vistano);
526 i = strlen (ptr); /* i = remaining amount of text */
527 if (i < sizeof (miscrec.or_misc)) {
528 strcpy ((char *) miscrec.or_misc, ptr);
532 i = sizeof (miscrec.or_misc) - 1; /* now i = amt of curr
534 strncpy ((char *) miscrec.or_misc, ptr, i);
535 miscrec.or_misc[0][i] = 0;
538 miscrec.or_misctype = ORM_OLDNOTES;
539 HTONS (miscrec.or_misctype);
540 FILLNEW (PROGNAME "169", OR_MISCREC, &miscrec, vistano);
541 CONNECT (PROGNAME "170", OR_OBJ_MISCS, vistano);
542 } /* end of vista append loop */
544 /* Also append the note to the backup flat file */
545 if ((backup_file = fopen (OEF_notesnot, "at ")) == NULL) {
547 catgets (dtsearch_catd, MS_ve, 230,
548 "%s Could not open user notes backup file '%s': %s."),
549 PROGNAME " 230", OEF_notesnot, strerror (errno));
550 DtSearchAddMessage (mybuf);
553 mylen = strlen (entirebufptr);
554 strcpy (entirebufptr + mylen, formfeed_line);
555 mylen += sizeof (formfeed_line);
556 fwrite (entirebufptr, --mylen, 1, backup_file);
557 fclose (backup_file);
562 /* End of critical region....
563 * release the semaphore so somebody else can append.
565 rewind (semaphore_file);
566 fwrite ("0", 1, 1, semaphore_file);
567 fclose (semaphore_file);
570 } /* ve_append_notes() */
573 /************************************************/
575 /* store_next_misc */
577 /************************************************/
578 /* Subroutine of ve_getrec_dba(). Repeatedly called
579 * for each read of a miscrec of type ORM_FZKABS
580 * to load usrblk fields objfzkey and objabstr.
581 * First call for a given object is signaled by passed arg.
582 * Thereafter static pointers keep track of where we are
583 * in usrblk buffers to correctly store data from next
584 * miscrec. Works as a state machine: initial state
585 * is store-fzkey, then store-abstract,
586 * but only if either or both of those exist.
587 * Code similar to load_next_... function in cravel.c.
588 * WARNING! maximum size of fzkey is still hardcoded FZKEYSZ!
590 static void store_next_misc (
592 char *misc /* miscrec.or_misc */
595 static enum { STORE_DONE, STORE_FZKEY, STORE_ABSTR }
596 store_state = STORE_DONE;
597 static char *targ = NULL;
598 static int targlen = 0;
599 static int abstrsz = 0;
602 /* Initialize static variables at first call. */
604 abstrsz = usrblk.dblk->dbrec.or_abstrsz;
607 * if client didn't send back his astrbuf malloc a new
610 if (usrblk.abstrbuf == NULL) {
611 usrblk.abstrbuf = austext_malloc (max_abstrbufsz + 4,
612 PROGNAME "546", NULL);
614 targ = usrblk.abstrbuf;
615 targlen = abstrsz - 1; /* leave room for final \0 */
616 store_state = STORE_ABSTR;
619 /* If no miscs needed return immediately. */
621 store_state = STORE_DONE;
626 /* If NOT first call, but there's nothing left to do because
627 * fzkey and abstract already stored, return immediately.
629 else if (store_state == STORE_DONE)
632 /*********************
633 if (usrblk.debug & USRDBG_RETRVL)
634 fprintf (aa_stderr, PROGNAME"562 store_next_misc():"
635 " frst?=%d state=%d, fbuf=%p fsz=%d,\n"
636 " abuf=%p (bufsz=%d) asz=%d, targ=%p targlen=%d\n",
637 is_first_misc, store_state, usrblk.objfzkey, fzkeysz,
638 usrblk.abstrbuf, usrblk.abstrbufsz, abstrsz,
640 ************************/
642 /* Main loop is on each byte of the or_misc field of miscrec.
643 * Depending on the state, the byte will be a fzkey byte
644 * or an abstract byte.
646 for (i = 0; i < max_ormisc_size; i++) {
647 switch (store_state) {
649 if (*misc == 0 || --targlen <= 0) { /* end of abstract? */
651 store_state = STORE_DONE;
658 fprintf (aa_stderr, "%s\n", DtSearchGetMessages ());
659 fputs (PROGNAME "549 Abort due to programming error.\n",
666 /* If storing abstracts, put a \0 at the current targ location to
667 * terminate the abstract string in case there are no more misc recs.
668 * (but should not occur).
670 if ((store_state = STORE_ABSTR))
673 } /* store_next_misc() */
676 /************************************************/
680 /************************************************/
681 /* Given a valid vista database address, returns the opera record
682 * itself, its linked list of compressed text lines (blobs)
683 * or NULL if there are none, its abstract and fzkey if any,
684 * and user notes, exactly as stored in vista.
685 * The objrec, fzkey, abstract, and notes are returned in usrblk.
686 * The blob list is returned in the passed ptr arg,
687 * or it is set to NULL if there are no blobs.
688 * Saves size of uncompressed data (or_objsize) in OE_objsize.
689 * CALLER MUST FREE the blob list when done.
690 * Returns OE_OK if all goes well, else returns other appropriate retncode.
691 * Simpler version that only gets text blobs is ve_getblobs() below.
693 int ve_getrec_dba (LLIST ** bloblist)
701 int debugging = (usrblk.debug & USRDBG_RETRVL);
702 LLIST *new, *lastnode, **lastlink;
703 int vistano = usrblk.dblk->vistano;
704 int is_first_misc = TRUE;
705 DB_ADDR dba = usrblk.dba;
710 PROGNAME"644 retrieve db='%s' dba=%ld (x%x:%lx)\n",
712 (long)dba, (int)dba >> 24, (long)dba & 0xffffffL);
714 /* Test for invalid dba */
715 if (dba == NULL_DBA) {
716 DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 157,
717 PROGNAME "245 Client Program Error: "
718 "Null database address in usrblk.dba."));
719 OE_flags |= OE_PERMERR;
723 max_ormisc_size = sizeof (mymiscrec.or_misc);
725 /* Retrieve the opera header record. Don't use
726 * CRSET macro here so we can trap invalid dba errs.
728 d_crset (&dba, vistano);
729 if (db_status == S_INVADDR) {
730 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 142,
731 "%s Client Error: Requested record with invalid\n"
732 " database addr %ld (%d:%ld, x'%08.8lx') for database '%s'."),
733 PROGNAME "142 ", dba, dba >> 24, dba & 0xffffff, dba, usrblk.dblk->label);
734 fprintf (aa_stderr, "%s: %s\n", aa_argv0, msgbuf);
735 DtSearchAddMessage (msgbuf);
736 OE_flags |= OE_PERMERR;
739 RECREAD (PROGNAME "143", &myobjbuf, vistano);
740 if (db_status != S_OKAY)
742 swab_objrec (&myobjbuf, NTOH);
743 OE_objsize = myobjbuf.or_objsize; /* save tot num bytes
747 fprintf (aa_stderr, " --> got '%s': flags=x%lx sz=%ld dt=%s\n",
748 myobjbuf.or_objkey, (long)myobjbuf.or_objflags,
749 (long)myobjbuf.or_objsize,
750 objdate2fzkstr (myobjbuf.or_objdate));
752 clear_usrblk_record ();
753 memcpy (&usrblk.objrec, &myobjbuf, sizeof (struct or_objrec));
755 /* Setup currency table: curr record is owner of all object's sets */
756 SETOR (PROGNAME "145", OR_OBJ_BLOBS, vistano);
757 SETOR (PROGNAME "146", OR_OBJ_MISCS, vistano);
759 /* Retrieve text blobs or set bloblist to NULL if no blobs */
761 fputs (PROGNAME "678 Retrieving blobs: ", aa_stderr);
764 FINDFM (PROGNAME "148", OR_OBJ_BLOBS, vistano);
765 while (db_status == S_OKAY) {
766 /* Read next text blob record and append to end of list.
767 * Each debug 'b' = 1 blobrec.
770 fputc ('b', aa_stderr);
771 RECREAD (PROGNAME "151", &myblobuf, vistano);
772 if (db_status != S_OKAY)
773 vista_abort (PROGNAME "152");
774 NTOHS (myblobuf.or_bloblen);
775 lastnode = append_blob (lastlink, &myblobuf);
776 lastlink = &lastnode->link;
777 FINDNM (PROGNAME "155", OR_OBJ_BLOBS, vistano);
780 if (*bloblist == NULL)
781 fputs ("--> there are no blobs!\n", aa_stderr);
783 fputc ('\n', aa_stderr);
787 /* Retrieve abstract, fzkey, and user notes, if any */
789 fputs (PROGNAME "698 Retrieving misc recs: ", aa_stderr);
790 lastlink = &usrblk.notes;
791 FINDFM (PROGNAME "164", OR_OBJ_MISCS, vistano);
792 is_first_misc = TRUE;
793 while (db_status == S_OKAY) {
795 * Read next misc record. If notes, append to end of notes list.
796 * If abstract or fzkey, move to appropriate usrblk field.
797 * Each debug char ids the type of miscrec.
799 RECREAD (PROGNAME "168", &mymiscrec, vistano);
800 if (db_status != S_OKAY)
801 vista_abort (PROGNAME "169");
802 NTOHS (mymiscrec.or_misctype);
804 switch (mymiscrec.or_misctype) {
807 fputc ('n', aa_stderr);
808 new = austext_malloc (sizeof (mymiscrec.or_misc)
809 + sizeof (LLIST) + 4,
810 PROGNAME "543", NULL);
812 /* hop over exactly 1 LLIST structure */
814 memcpy (new->data, mymiscrec.or_misc,
815 sizeof (mymiscrec.or_misc));
817 lastlink = &new->link;
821 /* Concatenated fzkey + abstract rec */
823 fputc ('a', aa_stderr);
824 store_next_misc (is_first_misc, (char *) mymiscrec.or_misc);
825 is_first_misc = FALSE;
830 fputc ('?', aa_stderr);
831 break; /* ignore it */
834 FINDNM (PROGNAME "172", OR_OBJ_MISCS, vistano);
835 } /* end loop on miscrecs */
837 /* Currently no provision for retrieving hyperlink records */
841 fputs ("--> there are no misc recs!\n", aa_stderr);
843 fputc ('\n', aa_stderr);
844 print_usrblk_record (PROGNAME"600");
847 } /* ve_getrec_dba() */
850 /************************************************/
854 /************************************************/
855 /* Given a valid vista database address for an operarec,
856 * returns its linked list of compressed text lines (blobs),
857 * exactly as stored in vista, and returns the or_objsize
858 * field in the global OE_objsize (for later unblobing).
859 * Returns NULL if invalid database addr or no text blobs.
860 * CALLER MUST FREE the blob list himself when done.
861 * This is a simpler version of ve_getrec_dba() and will
862 * get blobs from any database, not just the one in usrblk.dblk.
864 LLIST *ve_getblobs (DtSrINT32 dba, int vistano)
866 LLIST *bloblist, *lastnode, **lastlink;
867 struct or_blobrec myblobuf;
868 struct or_objrec myobjbuf;
869 int debugging = (usrblk.debug & USRDBG_RETRVL);
871 /* Retrieve the opera header record */
874 CRSET (PROGNAME "401", &dba, vistano);
875 RECREAD (PROGNAME "402", &myobjbuf, vistano);
876 if (db_status != S_OKAY)
878 swab_objrec (&myobjbuf, NTOH);
879 OE_objsize = myobjbuf.or_objsize;
881 fprintf (aa_stderr, PROGNAME "792 ve_getblobs: "
882 "db='%s'[v#%d] dba=%ld:%ld v#=%d sz=%ld: '%s'\n",
883 usrblk.dblk->name, usrblk.dblk->vistano,
884 (long) (dba >> 24), (long) (dba % 0xffffff), vistano,
885 (long) myobjbuf.or_objsize, myobjbuf.or_objkey);
888 /* Retrieve blobs and append to end of growing list.
889 * If no blobs, return NULL.
892 lastlink = &bloblist;
893 SETOR (PROGNAME "406", OR_OBJ_BLOBS, vistano);
894 FINDFM (PROGNAME "407", OR_OBJ_BLOBS, vistano);
895 while (db_status == S_OKAY) {
896 RECREAD (PROGNAME "413", &myblobuf, vistano);
897 if (db_status != S_OKAY)
898 vista_abort (PROGNAME "414");
899 NTOHS (myblobuf.or_bloblen);
900 lastnode = append_blob (lastlink, &myblobuf);
901 lastlink = &lastnode->link;
902 FINDNM (PROGNAME "417", OR_OBJ_BLOBS, vistano);
905 } /* ve_getblobs() */
908 /************************************************/
912 /************************************************/
913 /* Given a vista database record key (in usrblk.query),
914 * returns the vista database address of the record.
915 * If a record cant be found for the exact key,
916 * or if the requested record is a 'reserved' record,
917 * wrap to the NEXT available nonreserved record address.
918 * By convention, reserved records have an ascii control char
919 * (< 32, 0x20) for the keytype char (first char of record key).
920 * Also sets usrblk.retncode to OE_OK or OE_WRAPPED.
922 DtSrINT32 ve_reckey2dba (void)
924 static char debugkey[] =
925 {0x73, 0x31, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x33, 0x00};
926 static char debugmsg[] = {
927 0x54, 0x68, 0x69, 0x73, 0x20, 0x49, 0x6E, 0x66,
928 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E,
929 0x20, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76,
930 0x61, 0x6C, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
931 0x6D, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65,
932 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20, 0x61,
933 0x6E, 0x64, 0x20, 0x69, 0x6D, 0x70, 0x6C, 0x65,
934 0x6D, 0x65, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x62,
935 0x79, 0x0A, 0x4D, 0x69, 0x6B, 0x65, 0x20,
936 0x52, 0x75, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x20,
937 0x61, 0x6E, 0x64, 0x20, 0x45, 0x66, 0x69, 0x6D,
938 0x20, 0x47, 0x65, 0x6E, 0x64, 0x6C, 0x65, 0x72,
939 0x0A, 0x6F, 0x66, 0x20, 0x41, 0x75, 0x73,
940 0x74, 0x69, 0x6E, 0x2C, 0x20, 0x54, 0x65, 0x78,
941 0x61, 0x73, 0x2C, 0x20, 0x55, 0x53, 0x41, 0x2E,
944 int null_query = FALSE;
945 int vistano = usrblk.dblk->vistano;
946 char mykeybuf[DtSrMAX_DB_KEYSIZE + 2];
948 usrblk.retncode = OE_OK;
950 /* If UI sent a null query ptr, reset it to empty string */
951 if (usrblk.query == NULL) {
954 DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 398,
955 PROGNAME "398 NULL query string."));
957 if (strncmp (usrblk.query, debugkey, strlen (debugkey)) == 0) {
959 DtSearchAddMessage (debugmsg);
962 /* If case insensitive keys is the site standard,
963 * force key to uppercase.
965 if (OE_uppercase_keys)
966 strupr (usrblk.query);
968 /* Find the record. If exact record key isnt found,
969 * keep reading until we get one, including wrapping.
972 KEYFIND (PROGNAME "191", OR_OBJKEY, usrblk.query, vistano);
974 while (db_status == S_NOTFOUND) {
975 usrblk.retncode = OE_WRAPPED;
976 KEYNEXT (PROGNAME "196", OR_OBJKEY, vistano);
979 /* If the retrieved record is a 'reserved' record, wrap some more */
980 KEYREAD (PROGNAME "208", mykeybuf);
981 if (db_status != S_OKAY)
982 vista_abort (PROGNAME "209");
983 if (mykeybuf[0] < 32) {
984 KEYNEXT (PROGNAME "210", OR_OBJKEY, vistano);
988 CRGET (PROGNAME "211", &dba, vistano);
990 usrblk.query = NULL; /* restore */
992 } /* ve_reckey2dba() */
995 /************************************************/
999 /************************************************/
1000 /* Increments/decrements dba address field.
1001 * If original dba is null, returns first dba in database.
1002 * Otherwise UI must ensure that original dba is valid for current database.
1003 * Does not alter other record oriented usrblk fields.
1005 void ve_browse_dba (int direction)
1007 int vistano = usrblk.dblk->vistano;
1008 char mykeybuf[DtSrMAX_DB_KEYSIZE + 2];
1010 usrblk.retncode = OE_OK;
1013 if (usrblk.dba == NULL_DBA) {
1014 KEYFRST (PROGNAME "224", OR_OBJKEY, vistano);
1015 if (db_status != S_OKAY)
1016 vista_abort (PROGNAME "226");
1019 /* at this point, dba must be valid for current database */
1020 CRSET (PROGNAME "230", &usrblk.dba, vistano);
1021 CRREAD (PROGNAME "232", OR_OBJKEY, mykeybuf, vistano);
1022 if (db_status != S_OKAY)
1023 vista_abort (PROGNAME "234");
1025 /* descend b-tree to current location */
1026 KEYFIND (PROGNAME "236", OR_OBJKEY, mykeybuf, vistano);
1027 if (direction < 0) { /* get prev rec */
1028 KEYPREV (PROGNAME "238", OR_OBJKEY, vistano);
1029 if (db_status == S_NOTFOUND) { /* at begin of file,
1031 usrblk.retncode = OE_WRAPPED;
1032 KEYPREV (PROGNAME "240", OR_OBJKEY, vistano);
1035 else { /* get next rec */
1036 KEYNEXT (PROGNAME "242", OR_OBJKEY, vistano);
1037 if (db_status == S_NOTFOUND) { /* at eof, wrap */
1038 usrblk.retncode = OE_WRAPPED;
1039 KEYNEXT (PROGNAME "244", OR_OBJKEY, vistano);
1042 } /* end else where orig rec is not null */
1044 CRGET (PROGNAME "246", &usrblk.dba, vistano);
1046 /* If retrieved rec is a reserved record,
1047 * ignore it and retry the browse from here.
1049 KEYREAD (PROGNAME "561", mykeybuf);
1050 if (db_status != S_OKAY)
1051 vista_abort (PROGNAME "562");
1052 if (mykeybuf[0] < 32)
1055 } /* ve_browse_dba() */
1057 /**************************** DTSRVE.C ******************************/