1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/lib/DtSearch/dtsrve.c
Lev Kujawski 7010b2c11b Centralize catgets() calls through MsgCat
CDE has relied upon catgets() implementations following a relaxed
interpretation of the XPG internationalization standard that ignored
-1, the standard error value returned by catopen, as the catalog
argument. However, this same behavior causes segmentation faults with
the musl C library.

This patch:

- Centralizes (with the exception of ToolTalk) all calls to catopen(),
  catgets(), and catclose() through MsgCat within the DtSvc library.
- Prevents calls to catgets() and catclose() that rely upon
  undefined behavior.
- Eliminates a number of bespoke catgets() wrappers, including multiple
  redundant caching implementations designed to work around a design
  peculiarity in HP/UX.
- Eases building CDE without XPG internationalization support by providing
  the appropriate macros.
2021-01-31 16:17:13 -07:00

1057 lines
33 KiB
C

/*
* 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 <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include "vista.h"
#define XOS_USE_NO_LOCKING
#define X_INCLUDE_TIME_H
#include <X11/Xos_r.h>
#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 <User Note Appended by '%s' on %s>\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 ******************************/