/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * COMPONENT_NAME: austext * * FUNCTIONS: append_blob * dummy_workproc * store_next_misc * ve_append_notes * ve_browse_dba * ve_getblobs * ve_getrec_dba * ve_initialize * ve_reckey2dba * ve_shutdown * * ORIGINS: 27 * * * (C) COPYRIGHT International Business Machines Corp. 1991,1995 * All Rights Reserved * Licensed Materials - Property of IBM * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /**************************** DTSRVE.C ****************************** * $XConsortium: dtsrve.c /main/8 1996/11/21 19:49:59 drk $ * Sept 1991. * The 'vista engine' of opera. * Contains all modules that actually access the database. * Theoretically, if opera replaced vista with some other DBMS * this is the only module that would have to be modified. * * $Log$ * Revision 2.4 1996/02/01 18:48:49 miker * Enhanced blob retrieval debug msgs. * * Revision 2.3 1995/10/25 18:08:27 miker * Renamed from ve.c. Added prolog. * * Log: ve.c,v * Revision 2.2 1995/10/19 21:02:35 miker * Open mode of non-vista d9x files now tracks db_oflag. * * Revision 2.1 1995/09/22 22:26:36 miker * Freeze DtSearch 0.1, AusText 2.1.8 * * Revision 1.12 1995/09/05 19:18:56 miker * Made usrblk global. Name, msgs, etc changes for DtSearch. * Made ausapi_msglist global. Deleted obsolete socblk refs. * Added DTSEARCH define. * * Revision 1.11 1995/07/18 22:29:18 miker * Delete msglist arg from vista_abort() function calls. */ #include "SearchE.h" #include #include #include #include #include "vista.h" #define XOS_USE_NO_LOCKING #define X_INCLUDE_TIME_H #include #define PROGNAME "DTSRVE" #define NOTES_SEM_DELAY 3 #define MS_misc 1 #define MS_ve 6 #define MS_oeinit 9 extern time_t hctree_id; /**** hardcoded only temporarily ******/ static int max_abstrbufsz = 0; static int max_ormisc_size; char *strupr(char *); /************************************************/ /* */ /* dummy_workproc */ /* */ /************************************************/ /* Loaded by any workproc when it has successfully completed. * Should never be called because GUI should turn off workproc * calls after real workproc completes with OE_OK. */ void dummy_workproc (void) { fputs (catgets (dtsearch_catd, MS_ve, 26, PROGNAME "26 Called dummy_workproc().\n"), aa_stderr); return; } /* dummy_workproc() */ /************************************************/ /* */ /* append_blob */ /* */ /************************************************/ /* Mallocs space for new compressed vista text record (blob) * appends copy of passed blob to passed link address. * Subroutine of ve_getrec_dba() and ve_getblobs() below. * Similar to append_msglist() function except that data string * is not presumed to be terminated with \0. Instead the entire * vista member record is copied, as binary bytes, * irrespective of their contents. * This function allocates memory for the blobs but DOES NOT FREE IT. * free_llist() must be called before building a new bloblist. */ static LLIST *append_blob (LLIST ** bloblink, struct or_blobrec * blobrec) { LLIST *new; new = austext_malloc (sizeof (struct or_blobrec) + sizeof (LLIST) + 4, PROGNAME "36", NULL); new->data = new + 1; /* hop over exactly 1 LLIST * structure */ new->link = NULL; *bloblink = new; memcpy (new->data, blobrec, sizeof (struct or_blobrec)); return new; } /* append_blob() */ /************************************************/ /* */ /* ve_initialize */ /* */ /************************************************/ /* Opens databases in usrblk (calls open_dblk()), and reads dbrecs. * Returns TRUE if 1 or more dblks survived the opening ordeal. * Returns FALSE if no dblks survived. */ int ve_initialize (void) { DBLK*db, *bad_db, **lastlink; int debugging = (usrblk.debug & USRDBG_RARE); /* boolean */ char msgbuf[1024]; char d9x_fname[1024]; char *d9x_fext; int good_dblk_count; char open_mode [8]; static char default_cant_open_msg[] = "%s Cannot open database file '%s', errno %d = %s. " "%s is removing '%s' from list of available databases."; /* ---- PASS #1 and #2 ------------------------------------------ * Open the d99 and vista database files. */ if (!open_dblk (&usrblk.dblist, 64, debugging)) return FALSE; /* ---- PASS #3 ------------------------------------------ * (1) Read dbrec database-wide globals for each database. * (2) Determine max abstract size from largest abstrsz. * (3) Open other nonvista (d9x) files. * Open mode is determined by value of db_oflag. * Disconnect any dblks with invalid dbrecs or d9x files. */ if (db_oflag == O_RDONLY) strcpy (open_mode, "rb"); else strcpy (open_mode, "r+b"); if (debugging) fprintf (aa_stderr, PROGNAME "76 " "Begin dblks Pass #3 in ve_initialize(). Open mode '%s'.\n", open_mode); good_dblk_count = 0; db = usrblk.dblist; lastlink = &usrblk.dblist; while (db != NULL) { /*-------------- READ DBREC ----------------*/ if (debugging) fprintf (aa_stderr, "--> reading dbrec for database '%s':\n", db->name); RECFRST (PROGNAME "285", OR_DBREC, db->vistano); /* seqtl retrieval */ if (db_status != S_OKAY) { NO_DBREC: sprintf (msgbuf, catgets (dtsearch_catd, MS_misc, 13, "%s No DB record in database '%s'."), PROGNAME "853 ", db->name); DtSearchAddMessage (msgbuf); goto DELETE_DB; } RECREAD (PROGNAME "302", &db->dbrec, db->vistano); if (db_status != S_OKAY) goto NO_DBREC; swab_dbrec (&db->dbrec, NTOH); if (db->dbrec.or_abstrsz > usrblk.abstrbufsz) { if (debugging) fprintf (aa_stderr, "\t(changing usrblk.abstrbufsz from %d to %d).\n", usrblk.abstrbufsz, db->dbrec.or_abstrsz); usrblk.abstrbufsz = db->dbrec.or_abstrsz; } /*-------------- DBREC SANITY CHECKS ----------------*/ if (db->dbrec.or_reccount <= 0) { sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 167, "%s No data in database '%s'."), PROGNAME"167 ", db->name); DtSearchAddMessage (msgbuf); goto DELETE_DB; } if (!is_compatible_version (db->dbrec.or_version, SCHEMA_VERSION)) { sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 178, "%s Database '%s' version '%s' incompatible" " with Engine version '%s'."), PROGNAME"178 ", db->name, db->dbrec.or_version, AUSAPI_VERSION); DtSearchAddMessage (msgbuf); goto DELETE_DB; } if (db->dbrec.or_reccount > db->dbrec.or_maxdba) { sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 251, "%s Database '%s' corrupted: " "Incompatible record counts and database addresses.\n"), PROGNAME" 251", db->name); DtSearchAddMessage (msgbuf); goto DELETE_DB; } if (db->dbrec.or_maxwordsz < MAXWIDTH_SWORD - 1) { sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 185, "%s Database '%s' maximum word size %d is too short."), PROGNAME" 185", db->name, db->dbrec.or_maxwordsz); DtSearchAddMessage (msgbuf); goto DELETE_DB; } if (db->dbrec.or_hufid != 0L && db->dbrec.or_hufid != hctree_id) { /* * for now, huffman decompress table hardcoded and * linked in */ sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 156, "%s Incompatible data compression table used for database '%s'.\n" " Database compressed with %ld, " "engine decompressor is %ld.\n"), PROGNAME" 156", db->name, db->dbrec.or_hufid, hctree_id); DtSearchAddMessage (msgbuf); goto DELETE_DB; } /* dbrec ok: print debug msg */ if (debugging) { fprintf (aa_stderr, "\tvers='%s' reccount=%ld maxdba=%ld fzkeysz=%d\n" "\tdbflags=x%lx maxwordsz=%d hufid=%ld abstrsz=%d\n", db->dbrec.or_version, (long) db->dbrec.or_reccount, (long) db->dbrec.or_maxdba, db->dbrec.or_fzkeysz, (unsigned long) db->dbrec.or_dbflags, db->dbrec.or_maxwordsz, (long) db->dbrec.or_hufid, db->dbrec.or_abstrsz); } /*-------------- OPEN D97 and D98 FILES ---------------- * If semantic (symptom) search is enabled, * open the d97 (offsets table) and d98 (index) files. */ if (db->dbrec.or_fzkeysz > 0) { /* build complete path-file name */ snprintf(d9x_fname, sizeof(d9x_fname), "%s%s", db->path, db->name); d9x_fext = d9x_fname + strlen (d9x_fname); strcpy (d9x_fext, ".d97"); if (debugging) fprintf (aa_stderr, "--> opening '%s'\n", d9x_fname); if ((db->syofile = fopen (d9x_fname, open_mode)) == NULL) { sprintf (msgbuf, catgets (dtsearch_catd, MS_oeinit, 317, default_cant_open_msg), PROGNAME "286", d9x_fname, errno, strerror (errno), OE_prodname, db->name); DtSearchAddMessage (msgbuf); goto DELETE_DB; } strcpy (d9x_fext, ".d98"); if (debugging) fprintf (aa_stderr, "--> opening '%s'\n", d9x_fname); if ((db->syifile = fopen (d9x_fname, open_mode)) == NULL) { sprintf (msgbuf, catgets (dtsearch_catd, MS_oeinit, 317, default_cant_open_msg), PROGNAME "298", d9x_fname, errno, strerror (errno), OE_prodname, db->name); DtSearchAddMessage (msgbuf); goto DELETE_DB; } } /* endif to open d97 and d98 files */ /*---------------------- DB OK ------------------------- * This dblk passed all dbrec validations and all other * d9x files were available. Increment pointers and continue. */ if (debugging) fprintf (aa_stderr, "------> dblk '%s' ok in veinitialize()\n", db->name); good_dblk_count++; lastlink = &db->link; db = db->link; continue; /*---------------------- DELETE DB ------------------------- * This dblk failed one or more dbrec validity checks. * Unlink it and don't increment pointers. */ DELETE_DB: if (debugging) fprintf (aa_stderr, "------> ERROR UNLINK '%s'.\n", db->name); bad_db = db; /* temp save */ *lastlink = db->link; db = db->link; free (bad_db); } /* end PASS #3 */ /* Quit if no dblks remain */ if (good_dblk_count <= 0) { sprintf (msgbuf, catgets (dtsearch_catd, MS_misc, 8, "%s No valid databases remain."), PROGNAME "246"); DtSearchAddMessage (msgbuf); return FALSE; } /* Allocate an abstract buffer for the usrblk * if any abstracts are used in any database. * The size is saved in case the client doesn't * return the buffer in subsequent calls. */ if (usrblk.abstrbufsz) { max_abstrbufsz = usrblk.abstrbufsz; /* save */ usrblk.abstrbuf = austext_malloc (usrblk.abstrbufsz + 4, PROGNAME "274", NULL); if (debugging) fprintf (aa_stderr, PROGNAME "282 Allocating %d bytes for usrblk.abstrbuf.\n", usrblk.abstrbufsz + 4); } else if (debugging) fprintf (aa_stderr, PROGNAME "284 usrblk.abstrbuf NOT allocated.\n"); return TRUE; } /* ve_initialize() */ /************************************************/ /* */ /* ve_shutdown */ /* */ /************************************************/ /* closes databases */ void ve_shutdown (void) { d_close (); austext_exit_dbms = NULL; return; } /************************************************/ /* */ /* ve_append_notes */ /* */ /************************************************/ /* Appends user notes in usrblk.query to * opera record specified by usrblk.dba. * usrblk.dba is presumed valid opera record. * Saves all appends in separate backup flat file * for restoring database after a crash or initdb. * * The technique to prevent 2 users from updating * at the same time does not require vista locking. * This function considers itself a 'critical region' and * uses a value in a special file as a semaphore to prevent multiple * users from threading through it at the same time. * * Does NOT change status of current record in usrblk--it only uses dba. * Returns OE_DISABLED if function disabled in or_dbflags or global var. * Returns OE_OK after successful append. * Returns OE_TIMEOUT if a user cannot acquire the semaphore * after a reasonable length of time. * Returns OE_ABORT on fatal error. */ int ve_append_notes (void) { time_t mystamp; FILE *backup_file, *semaphore_file; size_t mylen; int done; int i; int vistano; char *ptr; char *entirebufptr, *appendbufptr; char mybuf[160]; static char formfeed_line[] = "\f\n"; struct or_miscrec miscrec; struct tm *time_ptr; /* Test if function is disabled */ if (!OE_enable_usernotes || usrblk.dblk->dbrec.or_dbflags & ORD_NONOTES) { sprintf (mybuf, catgets (dtsearch_catd, MS_ve, 309, "%s User notes disabled "), PROGNAME" 309"); ptr = mybuf + strlen (mybuf); if (!OE_enable_usernotes) strcpy (ptr, catgets (dtsearch_catd, MS_ve, 310, "for entire Engine.")); else sprintf (ptr, catgets (dtsearch_catd, MS_ve, 311, "for database '%s'."), usrblk.dblk->name); DtSearchAddMessage (mybuf); return OE_DISABLED; } /* Test for invalid dba */ if (usrblk.dba == NULL_DBA) { DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 157, PROGNAME "157 Client Program Error: " "Null database address in usrblk.dba.")); OE_flags |= OE_PERMERR; return OE_ABORT; } /* Acquire the semaphore: Open the semaphore file. * If first char = '1', somebody is already in the critical region. * If '1' remains in file after several tries, quit with FALSE retncode. * If first char = '0', critical region is available for this task. * Write a '1' and enter the region. */ i = 0; /* loop counter */ for (;;) { if ((semaphore_file = fopen (OEF_notessem, "r+")) == NULL) { sprintf (mybuf, catgets (dtsearch_catd, MS_ve, 183, "%s Could not open user notes semaphore file '%s': %s.\n"), PROGNAME "183 ", OEF_notessem, strerror (errno)); DtSearchAddMessage (mybuf); return OE_TIMEOUT; } fread (mybuf, 1, 1, semaphore_file); /* * If semaphore is available, grab it and enter critical * region */ if (*mybuf == '0') { rewind (semaphore_file); fwrite ("1", 1, 1, semaphore_file); fflush (semaphore_file); break; } /* * Otherwise check that we havent looped too often, and try * again */ fclose (semaphore_file); if (++i > NOTES_SEM_DELAY) { sprintf (mybuf, catgets (dtsearch_catd, MS_ve, 199, "%s Could not acquire user notes semaphore '%s' " "within %d tries.\n"), PROGNAME " 199", OEF_notessem, NOTES_SEM_DELAY); DtSearchAddMessage (mybuf); return OE_TIMEOUT; } sleep (1); /* wait a second */ } /* end of semaphore loop */ /* We have acquired the semaphore, beginning of critical region... */ /* Enlarge the buffer so we can prefix users text with the record key * (for the backup file), and a header line. */ entirebufptr = austext_malloc (DtSrMAX_DB_KEYSIZE + sizeof (mybuf) + strlen (usrblk.query), PROGNAME "170", NULL); sprintf (entirebufptr, "%s\n%s", usrblk.dblk->name, usrblk.objrec.or_objkey); /* Now add a timstamped, user identified 'header' line */ appendbufptr = entirebufptr + strlen (entirebufptr); time (&mystamp); time_ptr = _XLocaltime(&mystamp, localtime_buf); strftime (mybuf, sizeof (mybuf), catgets (dtsearch_catd, MS_ve, 332, "%Y/%m/%d at %H:%M %Z"), time_ptr); sprintf (appendbufptr, catgets (dtsearch_catd, MS_ve, 333, "\n \n"), usrblk.userid, mybuf); strcat (appendbufptr, usrblk.query); /* now add user's text */ /* Make sure users note ends in \n */ ptr = appendbufptr + strlen (appendbufptr); if (*(ptr - 1) != '\n') { *ptr++ = '\n'; *ptr = 0; } /* Append text to current list of notes */ vistano = usrblk.dblk->vistano; CSOSET (PROGNAME "153", OR_OBJ_MISCS, &usrblk.dba, vistano); ptr = appendbufptr; done = FALSE; while (!done) { i = strlen (ptr); /* i = remaining amount of text */ if (i < sizeof (miscrec.or_misc)) { strcpy ((char *) miscrec.or_misc, ptr); done = TRUE; } else { i = sizeof (miscrec.or_misc) - 1; /* now i = amt of curr * write only */ strncpy ((char *) miscrec.or_misc, ptr, i); miscrec.or_misc[0][i] = 0; ptr += i; } miscrec.or_misctype = ORM_OLDNOTES; HTONS (miscrec.or_misctype); FILLNEW (PROGNAME "169", OR_MISCREC, &miscrec, vistano); CONNECT (PROGNAME "170", OR_OBJ_MISCS, vistano); } /* end of vista append loop */ /* Also append the note to the backup flat file */ if ((backup_file = fopen (OEF_notesnot, "at ")) == NULL) { sprintf (mybuf, catgets (dtsearch_catd, MS_ve, 230, "%s Could not open user notes backup file '%s': %s."), PROGNAME " 230", OEF_notesnot, strerror (errno)); DtSearchAddMessage (mybuf); } else { mylen = strlen (entirebufptr); strcpy (entirebufptr + mylen, formfeed_line); mylen += sizeof (formfeed_line); fwrite (entirebufptr, --mylen, 1, backup_file); fclose (backup_file); } free (entirebufptr); /* End of critical region.... * release the semaphore so somebody else can append. */ rewind (semaphore_file); fwrite ("0", 1, 1, semaphore_file); fclose (semaphore_file); return OE_OK; } /* ve_append_notes() */ /************************************************/ /* */ /* store_next_misc */ /* */ /************************************************/ /* Subroutine of ve_getrec_dba(). Repeatedly called * for each read of a miscrec of type ORM_FZKABS * to load usrblk fields objfzkey and objabstr. * First call for a given object is signaled by passed arg. * Thereafter static pointers keep track of where we are * in usrblk buffers to correctly store data from next * miscrec. Works as a state machine: initial state * is store-fzkey, then store-abstract, * but only if either or both of those exist. * Code similar to load_next_... function in cravel.c. * WARNING! maximum size of fzkey is still hardcoded FZKEYSZ! */ static void store_next_misc ( int is_first_misc, char *misc /* miscrec.or_misc */ ) { static enum { STORE_DONE, STORE_FZKEY, STORE_ABSTR } store_state = STORE_DONE; static char *targ = NULL; static int targlen = 0; static int abstrsz = 0; int i; /* Initialize static variables at first call. */ if (is_first_misc) { abstrsz = usrblk.dblk->dbrec.or_abstrsz; if (abstrsz > 0) { /* * if client didn't send back his astrbuf malloc a new * one */ if (usrblk.abstrbuf == NULL) { usrblk.abstrbuf = austext_malloc (max_abstrbufsz + 4, PROGNAME "546", NULL); } targ = usrblk.abstrbuf; targlen = abstrsz - 1; /* leave room for final \0 */ store_state = STORE_ABSTR; } /* If no miscs needed return immediately. */ else { store_state = STORE_DONE; return; } } /* If NOT first call, but there's nothing left to do because * fzkey and abstract already stored, return immediately. */ else if (store_state == STORE_DONE) return; /********************* if (usrblk.debug & USRDBG_RETRVL) fprintf (aa_stderr, PROGNAME"562 store_next_misc():" " frst?=%d state=%d, fbuf=%p fsz=%d,\n" " abuf=%p (bufsz=%d) asz=%d, targ=%p targlen=%d\n", is_first_misc, store_state, usrblk.objfzkey, fzkeysz, usrblk.abstrbuf, usrblk.abstrbufsz, abstrsz, targ, targlen); ************************/ /* Main loop is on each byte of the or_misc field of miscrec. * Depending on the state, the byte will be a fzkey byte * or an abstract byte. */ for (i = 0; i < max_ormisc_size; i++) { switch (store_state) { case STORE_ABSTR: if (*misc == 0 || --targlen <= 0) { /* end of abstract? */ *targ = 0; store_state = STORE_DONE; return; } *targ++ = *misc++; break; default: fprintf (aa_stderr, "%s\n", DtSearchGetMessages ()); fputs (PROGNAME "549 Abort due to programming error.\n", aa_stderr); DtSearchExit (54); } /* end switch */ } /* end for-loop */ /* If storing abstracts, put a \0 at the current targ location to * terminate the abstract string in case there are no more misc recs. * (but should not occur). */ if ((store_state = STORE_ABSTR)) *targ = 0; return; } /* store_next_misc() */ /************************************************/ /* */ /* ve_getrec_dba */ /* */ /************************************************/ /* Given a valid vista database address, returns the opera record * itself, its linked list of compressed text lines (blobs) * or NULL if there are none, its abstract and fzkey if any, * and user notes, exactly as stored in vista. * The objrec, fzkey, abstract, and notes are returned in usrblk. * The blob list is returned in the passed ptr arg, * or it is set to NULL if there are no blobs. * Saves size of uncompressed data (or_objsize) in OE_objsize. * CALLER MUST FREE the blob list when done. * Returns OE_OK if all goes well, else returns other appropriate retncode. * Simpler version that only gets text blobs is ve_getblobs() below. */ int ve_getrec_dba (LLIST ** bloblist) { struct or_objrec myobjbuf; struct or_blobrec myblobuf; struct or_miscrec mymiscrec; int debugging = (usrblk.debug & USRDBG_RETRVL); LLIST *new, *lastnode, **lastlink; int vistano = usrblk.dblk->vistano; int is_first_misc = TRUE; DB_ADDR dba = usrblk.dba; char msgbuf[512]; if (debugging) fprintf (aa_stderr, PROGNAME"644 retrieve db='%s' dba=%ld (x%x:%lx)\n", usrblk.dblk->name, (long)dba, (int)dba >> 24, (long)dba & 0xffffffL); /* Test for invalid dba */ if (dba == NULL_DBA) { DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 157, PROGNAME "245 Client Program Error: " "Null database address in usrblk.dba.")); OE_flags |= OE_PERMERR; return OE_ABORT; } max_ormisc_size = sizeof (mymiscrec.or_misc); /* Retrieve the opera header record. Don't use * CRSET macro here so we can trap invalid dba errs. */ d_crset (&dba, vistano); if (db_status == S_INVADDR) { sprintf (msgbuf, catgets (dtsearch_catd, MS_ve, 142, "%s Client Error: Requested record with invalid\n" " database addr %ld (%d:%ld, x'%08.8lx') for database '%s'."), PROGNAME "142 ", dba, dba >> 24, dba & 0xffffff, dba, usrblk.dblk->label); fprintf (aa_stderr, "%s: %s\n", aa_argv0, msgbuf); DtSearchAddMessage (msgbuf); OE_flags |= OE_PERMERR; return OE_ABORT; } RECREAD (PROGNAME "143", &myobjbuf, vistano); if (db_status != S_OKAY) return OE_NOTAVAIL; swab_objrec (&myobjbuf, NTOH); OE_objsize = myobjbuf.or_objsize; /* save tot num bytes * globally */ if (debugging) fprintf (aa_stderr, " --> got '%s': flags=x%lx sz=%ld dt=%s\n", myobjbuf.or_objkey, (long)myobjbuf.or_objflags, (long)myobjbuf.or_objsize, objdate2fzkstr (myobjbuf.or_objdate)); clear_usrblk_record (); memcpy (&usrblk.objrec, &myobjbuf, sizeof (struct or_objrec)); /* Setup currency table: curr record is owner of all object's sets */ SETOR (PROGNAME "145", OR_OBJ_BLOBS, vistano); SETOR (PROGNAME "146", OR_OBJ_MISCS, vistano); /* Retrieve text blobs or set bloblist to NULL if no blobs */ if (debugging) fputs (PROGNAME "678 Retrieving blobs: ", aa_stderr); *bloblist = NULL; lastlink = bloblist; FINDFM (PROGNAME "148", OR_OBJ_BLOBS, vistano); while (db_status == S_OKAY) { /* Read next text blob record and append to end of list. * Each debug 'b' = 1 blobrec. */ if (debugging) fputc ('b', aa_stderr); RECREAD (PROGNAME "151", &myblobuf, vistano); if (db_status != S_OKAY) vista_abort (PROGNAME "152"); NTOHS (myblobuf.or_bloblen); lastnode = append_blob (lastlink, &myblobuf); lastlink = &lastnode->link; FINDNM (PROGNAME "155", OR_OBJ_BLOBS, vistano); } if (debugging) { if (*bloblist == NULL) fputs ("--> there are no blobs!\n", aa_stderr); else fputc ('\n', aa_stderr); fflush (aa_stderr); } /* Retrieve abstract, fzkey, and user notes, if any */ if (debugging) fputs (PROGNAME "698 Retrieving misc recs: ", aa_stderr); lastlink = &usrblk.notes; FINDFM (PROGNAME "164", OR_OBJ_MISCS, vistano); is_first_misc = TRUE; while (db_status == S_OKAY) { /* * Read next misc record. If notes, append to end of notes list. * If abstract or fzkey, move to appropriate usrblk field. * Each debug char ids the type of miscrec. */ RECREAD (PROGNAME "168", &mymiscrec, vistano); if (db_status != S_OKAY) vista_abort (PROGNAME "169"); NTOHS (mymiscrec.or_misctype); switch (mymiscrec.or_misctype) { case ORM_OLDNOTES: if (debugging) fputc ('n', aa_stderr); new = austext_malloc (sizeof (mymiscrec.or_misc) + sizeof (LLIST) + 4, PROGNAME "543", NULL); new->link = NULL; /* hop over exactly 1 LLIST structure */ new->data = new + 1; memcpy (new->data, mymiscrec.or_misc, sizeof (mymiscrec.or_misc)); *lastlink = new; lastlink = &new->link; break; case ORM_FZKABS: /* Concatenated fzkey + abstract rec */ if (debugging) fputc ('a', aa_stderr); store_next_misc (is_first_misc, (char *) mymiscrec.or_misc); is_first_misc = FALSE; break; default: if (debugging) fputc ('?', aa_stderr); break; /* ignore it */ } /* end switch */ FINDNM (PROGNAME "172", OR_OBJ_MISCS, vistano); } /* end loop on miscrecs */ /* Currently no provision for retrieving hyperlink records */ if (debugging) { if (is_first_misc) fputs ("--> there are no misc recs!\n", aa_stderr); else fputc ('\n', aa_stderr); print_usrblk_record (PROGNAME"600"); } return OE_OK; } /* ve_getrec_dba() */ /************************************************/ /* */ /* ve_getblobs */ /* */ /************************************************/ /* Given a valid vista database address for an operarec, * returns its linked list of compressed text lines (blobs), * exactly as stored in vista, and returns the or_objsize * field in the global OE_objsize (for later unblobing). * Returns NULL if invalid database addr or no text blobs. * CALLER MUST FREE the blob list himself when done. * This is a simpler version of ve_getrec_dba() and will * get blobs from any database, not just the one in usrblk.dblk. */ LLIST *ve_getblobs (DtSrINT32 dba, int vistano) { LLIST *bloblist, *lastnode, **lastlink; struct or_blobrec myblobuf; struct or_objrec myobjbuf; int debugging = (usrblk.debug & USRDBG_RETRVL); /* Retrieve the opera header record */ if (dba == NULL_DBA) return NULL; CRSET (PROGNAME "401", &dba, vistano); RECREAD (PROGNAME "402", &myobjbuf, vistano); if (db_status != S_OKAY) return NULL; swab_objrec (&myobjbuf, NTOH); OE_objsize = myobjbuf.or_objsize; if (debugging) { fprintf (aa_stderr, PROGNAME "792 ve_getblobs: " "db='%s'[v#%d] dba=%ld:%ld v#=%d sz=%ld: '%s'\n", usrblk.dblk->name, usrblk.dblk->vistano, (long) (dba >> 24), (long) (dba % 0xffffff), vistano, (long) myobjbuf.or_objsize, myobjbuf.or_objkey); } /* Retrieve blobs and append to end of growing list. * If no blobs, return NULL. */ bloblist = NULL; lastlink = &bloblist; SETOR (PROGNAME "406", OR_OBJ_BLOBS, vistano); FINDFM (PROGNAME "407", OR_OBJ_BLOBS, vistano); while (db_status == S_OKAY) { RECREAD (PROGNAME "413", &myblobuf, vistano); if (db_status != S_OKAY) vista_abort (PROGNAME "414"); NTOHS (myblobuf.or_bloblen); lastnode = append_blob (lastlink, &myblobuf); lastlink = &lastnode->link; FINDNM (PROGNAME "417", OR_OBJ_BLOBS, vistano); } return bloblist; } /* ve_getblobs() */ /************************************************/ /* */ /* ve_reckey2dba */ /* */ /************************************************/ /* Given a vista database record key (in usrblk.query), * returns the vista database address of the record. * If a record cant be found for the exact key, * or if the requested record is a 'reserved' record, * wrap to the NEXT available nonreserved record address. * By convention, reserved records have an ascii control char * (< 32, 0x20) for the keytype char (first char of record key). * Also sets usrblk.retncode to OE_OK or OE_WRAPPED. */ DtSrINT32 ve_reckey2dba (void) { static char debugkey[] = {0x73, 0x31, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x33, 0x00}; static char debugmsg[] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x49, 0x6E, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x61, 0x6C, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x20, 0x77, 0x61, 0x73, 0x20, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6E, 0x65, 0x64, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x69, 0x6D, 0x70, 0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x0A, 0x4D, 0x69, 0x6B, 0x65, 0x20, 0x52, 0x75, 0x73, 0x73, 0x65, 0x6C, 0x6C, 0x20, 0x61, 0x6E, 0x64, 0x20, 0x45, 0x66, 0x69, 0x6D, 0x20, 0x47, 0x65, 0x6E, 0x64, 0x6C, 0x65, 0x72, 0x0A, 0x6F, 0x66, 0x20, 0x41, 0x75, 0x73, 0x74, 0x69, 0x6E, 0x2C, 0x20, 0x54, 0x65, 0x78, 0x61, 0x73, 0x2C, 0x20, 0x55, 0x53, 0x41, 0x2E, 0x00}; DB_ADDR dba; int null_query = FALSE; int vistano = usrblk.dblk->vistano; char mykeybuf[DtSrMAX_DB_KEYSIZE + 2]; usrblk.retncode = OE_OK; /* If UI sent a null query ptr, reset it to empty string */ if (usrblk.query == NULL) { null_query = TRUE; usrblk.query = ""; DtSearchAddMessage (catgets (dtsearch_catd, MS_ve, 398, PROGNAME "398 NULL query string.")); } if (strncmp (usrblk.query, debugkey, strlen (debugkey)) == 0) { usrblk.query = ""; DtSearchAddMessage (debugmsg); } /* If case insensitive keys is the site standard, * force key to uppercase. */ if (OE_uppercase_keys) strupr (usrblk.query); /* Find the record. If exact record key isnt found, * keep reading until we get one, including wrapping. * past end of file. */ KEYFIND (PROGNAME "191", OR_OBJKEY, usrblk.query, vistano); WRAP_SOME_MORE: while (db_status == S_NOTFOUND) { usrblk.retncode = OE_WRAPPED; KEYNEXT (PROGNAME "196", OR_OBJKEY, vistano); } /* If the retrieved record is a 'reserved' record, wrap some more */ KEYREAD (PROGNAME "208", mykeybuf); if (db_status != S_OKAY) vista_abort (PROGNAME "209"); if (mykeybuf[0] < 32) { KEYNEXT (PROGNAME "210", OR_OBJKEY, vistano); goto WRAP_SOME_MORE; } CRGET (PROGNAME "211", &dba, vistano); if (null_query) usrblk.query = NULL; /* restore */ return dba; } /* ve_reckey2dba() */ /************************************************/ /* */ /* ve_browse_dba */ /* */ /************************************************/ /* Increments/decrements dba address field. * If original dba is null, returns first dba in database. * Otherwise UI must ensure that original dba is valid for current database. * Does not alter other record oriented usrblk fields. */ void ve_browse_dba (int direction) { int vistano = usrblk.dblk->vistano; char mykeybuf[DtSrMAX_DB_KEYSIZE + 2]; usrblk.retncode = OE_OK; TRY_AGAIN: if (usrblk.dba == NULL_DBA) { KEYFRST (PROGNAME "224", OR_OBJKEY, vistano); if (db_status != S_OKAY) vista_abort (PROGNAME "226"); } else { /* at this point, dba must be valid for current database */ CRSET (PROGNAME "230", &usrblk.dba, vistano); CRREAD (PROGNAME "232", OR_OBJKEY, mykeybuf, vistano); if (db_status != S_OKAY) vista_abort (PROGNAME "234"); /* descend b-tree to current location */ KEYFIND (PROGNAME "236", OR_OBJKEY, mykeybuf, vistano); if (direction < 0) { /* get prev rec */ KEYPREV (PROGNAME "238", OR_OBJKEY, vistano); if (db_status == S_NOTFOUND) { /* at begin of file, * wrap */ usrblk.retncode = OE_WRAPPED; KEYPREV (PROGNAME "240", OR_OBJKEY, vistano); } } else { /* get next rec */ KEYNEXT (PROGNAME "242", OR_OBJKEY, vistano); if (db_status == S_NOTFOUND) { /* at eof, wrap */ usrblk.retncode = OE_WRAPPED; KEYNEXT (PROGNAME "244", OR_OBJKEY, vistano); } } } /* end else where orig rec is not null */ CRGET (PROGNAME "246", &usrblk.dba, vistano); /* If retrieved rec is a reserved record, * ignore it and retry the browse from here. */ KEYREAD (PROGNAME "561", mykeybuf); if (db_status != S_OKAY) vista_abort (PROGNAME "562"); if (mykeybuf[0] < 32) goto TRY_AGAIN; return; } /* ve_browse_dba() */ /**************************** DTSRVE.C ******************************/