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 librararies 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.
82 #define XOS_USE_NO_LOCKING
83 #define X_INCLUDE_TIME_H
84 #include <X11/Xos_r.h>
86 #define PROGNAME "DTSRVE"
87 #define NOTES_SEM_DELAY 3
92 extern time_t hctree_id; /**** hardcoded only temporarily ******/
93 static int max_abstrbufsz = 0;
94 static int max_ormisc_size;
96 /************************************************/
100 /************************************************/
101 /* Loaded by any workproc when it has successfully completed.
102 * Should never be called because GUI should turn off workproc
103 * calls after real workproc completes with OE_OK.
105 void dummy_workproc (void)
107 fputs (catgets (dtsearch_catd, MS_ve, 26,
108 PROGNAME "26 Called dummy_workproc().\n"),
111 } /* dummy_workproc() */
114 /************************************************/
118 /************************************************/
119 /* Mallocs space for new compressed vista text record (blob)
120 * appends copy of passed blob to passed link address.
121 * Subroutine of ve_getrec_dba() and ve_getblobs() below.
122 * Similar to append_msglist() function except that data string
123 * is not presumed to be terminated with \0. Instead the entire
124 * vista member record is copied, as binary bytes,
125 * irrespective of their contents.
126 * This function allocates memory for the blobs but DOES NOT FREE IT.
127 * free_llist() must be called before building a new bloblist.
129 static LLIST *append_blob (LLIST ** bloblink,
130 struct or_blobrec * blobrec)
136 new = austext_malloc (sizeof (struct or_blobrec) + sizeof (LLIST) + 4,
137 PROGNAME "36", NULL);
138 new->data = new + 1; /* hop over exactly 1 LLIST
142 memcpy (new->data, blobrec, sizeof (struct or_blobrec));
144 } /* append_blob() */
147 /************************************************/
151 /************************************************/
152 /* Opens databases in usrblk (calls open_dblk()), and reads dbrecs.
153 * Returns TRUE if 1 or more dblks survived the opening ordeal.
154 * Returns FALSE if no dblks survived.
156 int ve_initialize (void)
158 DBLK*db, *bad_db, **lastlink;
159 int debugging = (usrblk.debug & USRDBG_RARE); /* boolean */
161 char d9x_fname[1024];
165 static char default_cant_open_msg[] =
166 "%s Cannot open database file '%s', errno %d = %s. "
167 "%s is removing '%s' from list of available databases.";
169 /* ---- PASS #1 and #2 ------------------------------------------
170 * Open the d99 and vista database files.
172 if (!open_dblk (&usrblk.dblist, 64, debugging))
175 /* ---- PASS #3 ------------------------------------------
176 * (1) Read dbrec database-wide globals for each database.
177 * (2) Determine max abstract size from largest abstrsz.
178 * (3) Open other nonvista (d9x) files.
179 * Open mode is determined by value of db_oflag.
180 * Disconnect any dblks with invalid dbrecs or d9x files.
182 if (db_oflag == O_RDONLY)
183 strcpy (open_mode, "rb");
185 strcpy (open_mode, "r+b");
187 fprintf (aa_stderr, PROGNAME "76 "
188 "Begin dblks Pass #3 in ve_initialize(). Open mode '%s'.\n",
192 lastlink = &usrblk.dblist;
194 /*-------------- READ DBREC ----------------*/
197 "--> reading dbrec for database '%s':\n",
200 RECFRST (PROGNAME "285", OR_DBREC, db->vistano); /* seqtl retrieval */
201 if (db_status != S_OKAY) {
203 sprintf (msgbuf, catgets (dtsearch_catd, MS_misc, 13,
204 "%s No DB record in database '%s'."),
205 PROGNAME "853 ", db->name);
206 DtSearchAddMessage (msgbuf);
209 RECREAD (PROGNAME "302", &db->dbrec, db->vistano);
210 if (db_status != S_OKAY)
212 swab_dbrec (&db->dbrec, NTOH);
214 if (db->dbrec.or_abstrsz > usrblk.abstrbufsz) {
217 "\t(changing usrblk.abstrbufsz from %d to %d).\n",
218 usrblk.abstrbufsz, db->dbrec.or_abstrsz);
219 usrblk.abstrbufsz = db->dbrec.or_abstrsz;
222 /*-------------- DBREC SANITY CHECKS ----------------*/
223 if (db->dbrec.or_reccount <= 0) {
224 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 167,
225 "%s No data in database '%s'."),
226 PROGNAME"167 ", db->name);
227 DtSearchAddMessage (msgbuf);
230 if (!is_compatible_version (db->dbrec.or_version, SCHEMA_VERSION)) {
231 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 178,
232 "%s Database '%s' version '%s' incompatible"
233 " with Engine version '%s'."),
235 db->name, db->dbrec.or_version, AUSAPI_VERSION);
236 DtSearchAddMessage (msgbuf);
239 if (db->dbrec.or_reccount > db->dbrec.or_maxdba) {
240 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 251,
241 "%s Database '%s' corrupted: "
242 "Incompatible record counts and database addresses.\n"),
243 PROGNAME" 251", db->name);
244 DtSearchAddMessage (msgbuf);
247 if (db->dbrec.or_maxwordsz < MAXWIDTH_SWORD - 1) {
248 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 185,
249 "%s Database '%s' maximum word size %d is too short."),
250 PROGNAME" 185", db->name, db->dbrec.or_maxwordsz);
251 DtSearchAddMessage (msgbuf);
254 if (db->dbrec.or_hufid != 0L && db->dbrec.or_hufid != hctree_id) {
256 * for now, huffman decompress table hardcoded and
259 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 156,
260 "%s Incompatible data compression table used for database '%s'.\n"
261 " Database compressed with %ld, "
262 "engine decompressor is %ld.\n"),
263 PROGNAME" 156", db->name, db->dbrec.or_hufid, hctree_id);
264 DtSearchAddMessage (msgbuf);
267 /* dbrec ok: print debug msg */
270 "\tvers='%s' reccount=%ld maxdba=%ld fzkeysz=%d\n"
271 "\tdbflags=x%lx maxwordsz=%d hufid=%ld abstrsz=%d\n",
272 db->dbrec.or_version, db->dbrec.or_reccount,
273 db->dbrec.or_maxdba, db->dbrec.or_fzkeysz,
274 db->dbrec.or_dbflags, db->dbrec.or_maxwordsz,
275 db->dbrec.or_hufid, db->dbrec.or_abstrsz);
278 /*-------------- OPEN D97 and D98 FILES ----------------
279 * If semantic (symptom) search is enabled,
280 * open the d97 (offsets table) and d98 (index) files.
282 if (db->dbrec.or_fzkeysz > 0) {
283 /* build complete path-file name */
284 strcpy (d9x_fname, db->path);
285 strcat (d9x_fname, 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";
418 _Xltimeparams localtime_buf;
421 /* Test if function is disabled */
422 if (!OE_enable_usernotes || usrblk.dblk->dbrec.or_dbflags & ORD_NONOTES) {
423 sprintf (mybuf, catgets (dtsearch_catd, MS_ve, 309,
424 "%s User notes disabled "), PROGNAME" 309");
425 ptr = mybuf + strlen (mybuf);
426 if (!OE_enable_usernotes)
427 strcpy (ptr, catgets (dtsearch_catd, MS_ve, 310,
428 "for entire Engine."));
430 sprintf (ptr, catgets (dtsearch_catd, MS_ve, 311,
431 "for database '%s'."),
433 DtSearchAddMessage (mybuf);
437 /* Test for invalid dba */
438 if (usrblk.dba == NULL_DBA) {
439 DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 157,
440 PROGNAME "157 Client Program Error: "
441 "Null database address in usrblk.dba."));
442 OE_flags |= OE_PERMERR;
446 /* Acquire the semaphore: Open the semaphore file.
447 * If first char = '1', somebody is already in the critical region.
448 * If '1' remains in file after several tries, quit with FALSE retncode.
449 * If first char = '0', critical region is available for this task.
450 * Write a '1' and enter the region.
452 i = 0; /* loop counter */
454 if ((semaphore_file = fopen (OEF_notessem, "r+")) == NULL) {
456 catgets (dtsearch_catd, MS_ve, 183,
457 "%s Could not open user notes semaphore file '%s': %s.\n"),
458 PROGNAME "183 ", OEF_notessem, strerror (errno));
459 DtSearchAddMessage (mybuf);
462 fread (mybuf, 1, 1, semaphore_file);
465 * If semaphore is available, grab it and enter critical
469 rewind (semaphore_file);
470 fwrite ("1", 1, 1, semaphore_file);
471 fflush (semaphore_file);
476 * Otherwise check that we havent looped too often, and try
479 fclose (semaphore_file);
480 if (++i > NOTES_SEM_DELAY) {
482 catgets (dtsearch_catd, MS_ve, 199,
483 "%s Could not acquire user notes semaphore '%s' "
484 "within %d tries.\n"),
485 PROGNAME " 199", OEF_notessem, NOTES_SEM_DELAY);
486 DtSearchAddMessage (mybuf);
489 sleep (1); /* wait a second */
490 } /* end of semaphore loop */
492 /* We have acquired the semaphore, beginning of critical region... */
494 /* Enlarge the buffer so we can prefix users text with the record key
495 * (for the backup file), and a header line.
497 entirebufptr = austext_malloc
498 (DtSrMAX_DB_KEYSIZE + sizeof (mybuf) + strlen (usrblk.query),
499 PROGNAME "170", NULL);
500 sprintf (entirebufptr, "%s\n%s",
501 usrblk.dblk->name, usrblk.objrec.or_objkey);
503 /* Now add a timstamped, user identified 'header' line */
504 appendbufptr = entirebufptr + strlen (entirebufptr);
506 time_ptr = _XLocaltime(&mystamp, localtime_buf);
507 strftime (mybuf, sizeof (mybuf), catgets (dtsearch_catd, MS_ve, 332,
508 "%Y/%m/%d at %H:%M %Z"), time_ptr);
509 sprintf (appendbufptr, catgets (dtsearch_catd, MS_ve, 333,
510 "\n <User Note Appended by '%s' on %s>\n"),
511 usrblk.userid, mybuf);
512 strcat (appendbufptr, usrblk.query); /* now add user's text */
514 /* Make sure users note ends in \n */
515 ptr = appendbufptr + strlen (appendbufptr);
516 if (*(ptr - 1) != '\n') {
521 /* Append text to current list of notes */
522 vistano = usrblk.dblk->vistano;
523 CSOSET (PROGNAME "153", OR_OBJ_MISCS, &usrblk.dba, vistano);
527 i = strlen (ptr); /* i = remaining amount of text */
528 if (i < sizeof (miscrec.or_misc)) {
529 strcpy ((char *) miscrec.or_misc, ptr);
533 i = sizeof (miscrec.or_misc) - 1; /* now i = amt of curr
535 strncpy ((char *) miscrec.or_misc, ptr, i);
536 miscrec.or_misc[0][i] = 0;
539 miscrec.or_misctype = ORM_OLDNOTES;
540 HTONS (miscrec.or_misctype);
541 FILLNEW (PROGNAME "169", OR_MISCREC, &miscrec, vistano);
542 CONNECT (PROGNAME "170", OR_OBJ_MISCS, vistano);
543 } /* end of vista append loop */
545 /* Also append the note to the backup flat file */
546 if ((backup_file = fopen (OEF_notesnot, "at ")) == NULL) {
548 catgets (dtsearch_catd, MS_ve, 230,
549 "%s Could not open user notes backup file '%s': %s."),
550 PROGNAME " 230", OEF_notesnot, strerror (errno));
551 DtSearchAddMessage (mybuf);
554 mylen = strlen (entirebufptr);
555 strcpy (entirebufptr + mylen, formfeed_line);
556 mylen += sizeof (formfeed_line);
557 fwrite (entirebufptr, --mylen, 1, backup_file);
558 fclose (backup_file);
563 /* End of critical region....
564 * release the semaphore so somebody else can append.
566 rewind (semaphore_file);
567 fwrite ("0", 1, 1, semaphore_file);
568 fclose (semaphore_file);
571 } /* ve_append_notes() */
574 /************************************************/
576 /* store_next_misc */
578 /************************************************/
579 /* Subroutine of ve_getrec_dba(). Repeatedly called
580 * for each read of a miscrec of type ORM_FZKABS
581 * to load usrblk fields objfzkey and objabstr.
582 * First call for a given object is signaled by passed arg.
583 * Thereafter static pointers keep track of where we are
584 * in usrblk buffers to correctly store data from next
585 * miscrec. Works as a state machine: initial state
586 * is store-fzkey, then store-abstract,
587 * but only if either or both of those exist.
588 * Code similar to load_next_... function in cravel.c.
589 * WARNING! maximum size of fzkey is still hardcoded FZKEYSZ!
591 static void store_next_misc (
593 char *misc /* miscrec.or_misc */
596 static enum { STORE_DONE, STORE_FZKEY, STORE_ABSTR }
597 store_state = STORE_DONE;
598 static char *targ = NULL;
599 static int targlen = 0;
600 static int fzkeysz = 0;
601 static int abstrsz = 0;
604 /* Initialize static variables at first call. */
606 abstrsz = usrblk.dblk->dbrec.or_abstrsz;
609 * if client didn't send back his astrbuf malloc a new
612 if (usrblk.abstrbuf == NULL) {
613 usrblk.abstrbuf = austext_malloc (max_abstrbufsz + 4,
614 PROGNAME "546", NULL);
616 targ = usrblk.abstrbuf;
617 targlen = abstrsz - 1; /* leave room for final \0 */
618 store_state = STORE_ABSTR;
621 /* If no miscs needed return immediately. */
623 store_state = STORE_DONE;
628 /* If NOT first call, but there's nothing left to do because
629 * fzkey and abstract already stored, return immediately.
631 else if (store_state == STORE_DONE)
634 /*********************
635 if (usrblk.debug & USRDBG_RETRVL)
636 fprintf (aa_stderr, PROGNAME"562 store_next_misc():"
637 " frst?=%d state=%d, fbuf=%p fsz=%d,\n"
638 " abuf=%p (bufsz=%d) asz=%d, targ=%p targlen=%d\n",
639 is_first_misc, store_state, usrblk.objfzkey, fzkeysz,
640 usrblk.abstrbuf, usrblk.abstrbufsz, abstrsz,
642 ************************/
644 /* Main loop is on each byte of the or_misc field of miscrec.
645 * Depending on the state, the byte will be a fzkey byte
646 * or an abstract byte.
648 for (i = 0; i < max_ormisc_size; i++) {
649 switch (store_state) {
651 if (*misc == 0 || --targlen <= 0) { /* end of abstract? */
653 store_state = STORE_DONE;
660 fprintf (aa_stderr, "%s\n", DtSearchGetMessages ());
661 fputs (PROGNAME "549 Abort due to programming error.\n",
668 /* If storing abstracts, put a \0 at the current targ location to
669 * terminate the abstract string in case there are no more misc recs.
670 * (but should not occur).
672 if (store_state = STORE_ABSTR)
675 } /* store_next_misc() */
678 /************************************************/
682 /************************************************/
683 /* Given a valid vista database address, returns the opera record
684 * itself, its linked list of compressed text lines (blobs)
685 * or NULL if there are none, its abstract and fzkey if any,
686 * and user notes, exactly as stored in vista.
687 * The objrec, fzkey, abstract, and notes are returned in usrblk.
688 * The blob list is returned in the passed ptr arg,
689 * or it is set to NULL if there are no blobs.
690 * Saves size of uncompressed data (or_objsize) in OE_objsize.
691 * CALLER MUST FREE the blob list when done.
692 * Returns OE_OK if all goes well, else returns other appropriate retncode.
693 * Simpler version that only gets text blobs is ve_getblobs() below.
695 int ve_getrec_dba (LLIST ** bloblist)
704 int debugging = (usrblk.debug & USRDBG_RETRVL);
706 LLIST *new, *lastnode, **lastlink;
707 int vistano = usrblk.dblk->vistano;
708 int is_first_misc = TRUE;
709 DB_ADDR dba = usrblk.dba;
714 PROGNAME"644 retrieve db='%s' dba=%ld (x%x:%lx)\n",
716 (long)dba, (int)dba >> 24, (long)dba & 0xffffffL);
718 /* Test for invalid dba */
719 if (dba == NULL_DBA) {
720 DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 157,
721 PROGNAME "245 Client Program Error: "
722 "Null database address in usrblk.dba."));
723 OE_flags |= OE_PERMERR;
727 max_ormisc_size = sizeof (mymiscrec.or_misc);
729 /* Retrieve the opera header record. Don't use
730 * CRSET macro here so we can trap invalid dba errs.
732 d_crset (&dba, vistano);
733 if (db_status == S_INVADDR) {
734 sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 142,
735 "%s Client Error: Requested record with invalid\n"
736 " database addr %ld (%d:%ld, x'%08.8lx') for database '%s'."),
737 PROGNAME "142 ", dba, dba >> 24, dba & 0xffffff, dba, usrblk.dblk->label);
738 fprintf (aa_stderr, "%s: %s\n", aa_argv0, msgbuf);
739 DtSearchAddMessage (msgbuf);
740 OE_flags |= OE_PERMERR;
743 RECREAD (PROGNAME "143", &myobjbuf, vistano);
744 if (db_status != S_OKAY)
746 swab_objrec (&myobjbuf, NTOH);
747 OE_objsize = myobjbuf.or_objsize; /* save tot num bytes
751 fprintf (aa_stderr, " --> got '%s': flags=x%lx sz=%ld dt=%s\n",
752 myobjbuf.or_objkey, (long)myobjbuf.or_objflags,
753 (long)myobjbuf.or_objsize,
754 objdate2fzkstr (myobjbuf.or_objdate));
756 clear_usrblk_record ();
757 memcpy (&usrblk.objrec, &myobjbuf, sizeof (struct or_objrec));
759 /* Setup currency table: curr record is owner of all object's sets */
760 SETOR (PROGNAME "145", OR_OBJ_BLOBS, vistano);
761 SETOR (PROGNAME "146", OR_OBJ_MISCS, vistano);
763 /* Retrieve text blobs or set bloblist to NULL if no blobs */
765 fputs (PROGNAME "678 Retrieving blobs: ", aa_stderr);
768 FINDFM (PROGNAME "148", OR_OBJ_BLOBS, vistano);
769 while (db_status == S_OKAY) {
770 /* Read next text blob record and append to end of list.
771 * Each debug 'b' = 1 blobrec.
774 fputc ('b', aa_stderr);
775 RECREAD (PROGNAME "151", &myblobuf, vistano);
776 if (db_status != S_OKAY)
777 vista_abort (PROGNAME "152");
778 NTOHS (myblobuf.or_bloblen);
779 lastnode = append_blob (lastlink, &myblobuf);
780 lastlink = &lastnode->link;
781 FINDNM (PROGNAME "155", OR_OBJ_BLOBS, vistano);
784 if (*bloblist == NULL)
785 fputs ("--> there are no blobs!\n", aa_stderr);
787 fputc ('\n', aa_stderr);
791 /* Retrieve abstract, fzkey, and user notes, if any */
793 fputs (PROGNAME "698 Retrieving misc recs: ", aa_stderr);
794 lastlink = &usrblk.notes;
795 FINDFM (PROGNAME "164", OR_OBJ_MISCS, vistano);
796 is_first_misc = TRUE;
797 while (db_status == S_OKAY) {
799 * Read next misc record. If notes, append to end of notes list.
800 * If abstract or fzkey, move to appropriate usrblk field.
801 * Each debug char ids the type of miscrec.
803 RECREAD (PROGNAME "168", &mymiscrec, vistano);
804 if (db_status != S_OKAY)
805 vista_abort (PROGNAME "169");
806 NTOHS (mymiscrec.or_misctype);
808 switch (mymiscrec.or_misctype) {
811 fputc ('n', aa_stderr);
812 new = austext_malloc (sizeof (mymiscrec.or_misc)
813 + sizeof (LLIST) + 4,
814 PROGNAME "543", NULL);
816 /* hop over exactly 1 LLIST structure */
818 memcpy (new->data, mymiscrec.or_misc,
819 sizeof (mymiscrec.or_misc));
821 lastlink = &new->link;
825 /* Concatenated fzkey + abstract rec */
827 fputc ('a', aa_stderr);
828 store_next_misc (is_first_misc, (char *) mymiscrec.or_misc);
829 is_first_misc = FALSE;
834 fputc ('?', aa_stderr);
835 break; /* ignore it */
838 FINDNM (PROGNAME "172", OR_OBJ_MISCS, vistano);
839 } /* end loop on miscrecs */
841 /* Currently no provision for retrieving hyperlink records */
845 fputs ("--> there are no misc recs!\n", aa_stderr);
847 fputc ('\n', aa_stderr);
848 print_usrblk_record (PROGNAME"600");
851 } /* ve_getrec_dba() */
854 /************************************************/
858 /************************************************/
859 /* Given a valid vista database address for an operarec,
860 * returns its linked list of compressed text lines (blobs),
861 * exactly as stored in vista, and returns the or_objsize
862 * field in the global OE_objsize (for later unblobing).
863 * Returns NULL if invalid database addr or no text blobs.
864 * CALLER MUST FREE the blob list himself when done.
865 * This is a simpler version of ve_getrec_dba() and will
866 * get blobs from any database, not just the one in usrblk.dblk.
868 LLIST *ve_getblobs (DtSrINT32 dba, int vistano)
870 LLIST *bloblist, *lastnode, **lastlink;
871 struct or_blobrec myblobuf;
872 struct or_objrec myobjbuf;
873 int debugging = (usrblk.debug & USRDBG_RETRVL);
875 /* Retrieve the opera header record */
878 CRSET (PROGNAME "401", &dba, vistano);
879 RECREAD (PROGNAME "402", &myobjbuf, vistano);
880 if (db_status != S_OKAY)
882 swab_objrec (&myobjbuf, NTOH);
883 OE_objsize = myobjbuf.or_objsize;
885 fprintf (aa_stderr, PROGNAME "792 ve_getblobs: "
886 "db='%s'[v#%d] dba=%ld:%ld v#=%d sz=%ld: '%s'\n",
887 usrblk.dblk->name, usrblk.dblk->vistano,
888 dba >> 24, dba % 0xffffff, vistano,
889 myobjbuf.or_objsize, myobjbuf.or_objkey);
892 /* Retrieve blobs and append to end of growing list.
893 * If no blobs, return NULL.
896 lastlink = &bloblist;
897 SETOR (PROGNAME "406", OR_OBJ_BLOBS, vistano);
898 FINDFM (PROGNAME "407", OR_OBJ_BLOBS, vistano);
899 while (db_status == S_OKAY) {
900 RECREAD (PROGNAME "413", &myblobuf, vistano);
901 if (db_status != S_OKAY)
902 vista_abort (PROGNAME "414");
903 NTOHS (myblobuf.or_bloblen);
904 lastnode = append_blob (lastlink, &myblobuf);
905 lastlink = &lastnode->link;
906 FINDNM (PROGNAME "417", OR_OBJ_BLOBS, vistano);
909 } /* ve_getblobs() */
912 /************************************************/
916 /************************************************/
917 /* Given a vista database record key (in usrblk.query),
918 * returns the vista database address of the record.
919 * If a record cant be found for the exact key,
920 * or if the requested record is a 'reserved' record,
921 * wrap to the NEXT available nonreserved record address.
922 * By convention, reserved records have an ascii control char
923 * (< 32, 0x20) for the keytype char (first char of record key).
924 * Also sets usrblk.retncode to OE_OK or OE_WRAPPED.
926 DtSrINT32 ve_reckey2dba (void)
928 static char debugkey[] =
929 {0x73, 0x31, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x33, 0x00};
930 static char debugmsg[] = {
931 0x54, 0x68, 0x69, 0x73, 0x20, 0x49, 0x6E, 0x66,
932 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E,
933 0x20, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76,
934 0x61, 0x6C, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65,
935 0x6D, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65,
936 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20, 0x61,
937 0x6E, 0x64, 0x20, 0x69, 0x6D, 0x70, 0x6C, 0x65,
938 0x6D, 0x65, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x62,
939 0x79, 0x0A, 0x4D, 0x69, 0x6B, 0x65, 0x20,
940 0x52, 0x75, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x20,
941 0x61, 0x6E, 0x64, 0x20, 0x45, 0x66, 0x69, 0x6D,
942 0x20, 0x47, 0x65, 0x6E, 0x64, 0x6C, 0x65, 0x72,
943 0x0A, 0x6F, 0x66, 0x20, 0x41, 0x75, 0x73,
944 0x74, 0x69, 0x6E, 0x2C, 0x20, 0x54, 0x65, 0x78,
945 0x61, 0x73, 0x2C, 0x20, 0x55, 0x53, 0x41, 0x2E,
948 int null_query = FALSE;
949 int vistano = usrblk.dblk->vistano;
950 char mykeybuf[DtSrMAX_DB_KEYSIZE + 2];
952 usrblk.retncode = OE_OK;
954 /* If UI sent a null query ptr, reset it to empty string */
955 if (usrblk.query == NULL) {
958 DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 398,
959 PROGNAME "398 NULL query string."));
961 if (strncmp (usrblk.query, debugkey, strlen (debugkey)) == 0) {
963 DtSearchAddMessage (debugmsg);
966 /* If case insensitive keys is the site standard,
967 * force key to uppercase.
969 if (OE_uppercase_keys)
970 strupr (usrblk.query);
972 /* Find the record. If exact record key isnt found,
973 * keep reading until we get one, including wrapping.
976 KEYFIND (PROGNAME "191", OR_OBJKEY, usrblk.query, vistano);
978 while (db_status == S_NOTFOUND) {
979 usrblk.retncode = OE_WRAPPED;
980 KEYNEXT (PROGNAME "196", OR_OBJKEY, vistano);
983 /* If the retrieved record is a 'reserved' record, wrap some more */
984 KEYREAD (PROGNAME "208", mykeybuf);
985 if (db_status != S_OKAY)
986 vista_abort (PROGNAME "209");
987 if (mykeybuf[0] < 32) {
988 KEYNEXT (PROGNAME "210", OR_OBJKEY, vistano);
992 CRGET (PROGNAME "211", &dba, vistano);
994 usrblk.query = NULL; /* restore */
996 } /* ve_reckey2dba() */
999 /************************************************/
1003 /************************************************/
1004 /* Increments/decrements dba address field.
1005 * If original dba is null, returns first dba in database.
1006 * Otherwise UI must ensure that original dba is valid for current database.
1007 * Does not alter other record oriented usrblk fields.
1009 void ve_browse_dba (int direction)
1011 int vistano = usrblk.dblk->vistano;
1012 char mykeybuf[DtSrMAX_DB_KEYSIZE + 2];
1014 usrblk.retncode = OE_OK;
1017 if (usrblk.dba == NULL_DBA) {
1018 KEYFRST (PROGNAME "224", OR_OBJKEY, vistano);
1019 if (db_status != S_OKAY)
1020 vista_abort (PROGNAME "226");
1023 /* at this point, dba must be valid for current database */
1024 CRSET (PROGNAME "230", &usrblk.dba, vistano);
1025 CRREAD (PROGNAME "232", OR_OBJKEY, mykeybuf, vistano);
1026 if (db_status != S_OKAY)
1027 vista_abort (PROGNAME "234");
1029 /* descend b-tree to current location */
1030 KEYFIND (PROGNAME "236", OR_OBJKEY, mykeybuf, vistano);
1031 if (direction < 0) { /* get prev rec */
1032 KEYPREV (PROGNAME "238", OR_OBJKEY, vistano);
1033 if (db_status == S_NOTFOUND) { /* at begin of file,
1035 usrblk.retncode = OE_WRAPPED;
1036 KEYPREV (PROGNAME "240", OR_OBJKEY, vistano);
1039 else { /* get next rec */
1040 KEYNEXT (PROGNAME "242", OR_OBJKEY, vistano);
1041 if (db_status == S_NOTFOUND) { /* at eof, wrap */
1042 usrblk.retncode = OE_WRAPPED;
1043 KEYNEXT (PROGNAME "244", OR_OBJKEY, vistano);
1046 } /* end else where orig rec is not null */
1048 CRGET (PROGNAME "246", &usrblk.dba, vistano);
1050 /* If retrieved rec is a reserved record,
1051 * ignore it and retry the browse from here.
1053 KEYREAD (PROGNAME "561", mykeybuf);
1054 if (db_status != S_OKAY)
1055 vista_abort (PROGNAME "562");
1056 if (mykeybuf[0] < 32)
1059 } /* ve_browse_dba() */
1061 /**************************** DTSRVE.C ******************************/