cdesktopenv/cde/lib/DtSearch/dtsrjoint.c

614 lines
18 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: DtSearchFormatObjdate
* DtSearchFreeResults
* DtSearchGetMaxResults
* DtSearchMergeResults
* DtSearchSetMaxResults
* DtSearchSortResults
* DtSearchValidDateString
* aa_check_initialization
* aa_envars
* aa_get_passwd
* ditto_pop
* ditto_sort
* ditto_split
* merge_by_date
* merge_by_prox
*
* ORIGINS: 27
*
*
* (C) COPYRIGHT International Business Machines Corp. 1995, 1996
* 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.
*/
/**************************** DTSRJOINT.C *************************
* $XConsortium: dtsrjoint.c /main/5 1996/06/23 16:47:42 cde-ibm $
* February 1995.
* Split off of ausapi.c when I converted to client/server model.
* Ausclt.c is virtual copy of ausapi functions in RPC client stub.
* This module contains ausapi utilities that are common to both
* sides (ie do not result in RPC call to server or require
* access to real usrblk). My original version of this program
* was called "aacom" for "ausapi common" but I renamed it to avoid
* conflict with aacomm, the rpc/sockets communications module.
*
* $Log$
* Revision 2.5 1996/04/10 19:52:16 miker
* Added locale independent ISDIGIT macro. Changed function name
* from aa_merge_dittolists to DtSearchMergeResults.
*
* Revision 2.4 1995/12/27 16:11:54 miker
* Remove save_init_dbxxx globals for DtSearchReinit().
*
* Revision 2.3 1995/10/25 22:16:09 miker
* Renamed from aajoint.c. Added prolog.
*
* Log: aajoint.c,v
* Revision 2.2 1995/10/02 20:14:39 miker
* DtSearch function name changes.
* Added const to strdup() prototype for greater portability.
* Changed to more uniform output format in DtSearchFormatObjdate().
*
* Revision 2.1 1995/09/22 15:18:08 miker
* Freeze DtSearch 0.1, AusText 2.1.8
*
* Revision 1.3 1995/08/31 21:31:48 miker
* Renames and minor changes for DtSearch.
*
* Revision 1.2 1995/06/22 18:01:09 miker
* 2.1.6: RPC version no longer user specifiable. Removed aa_versnum etc.
* Added aa_sort_dittolist, date sorting of hitlists by any client.
*/
#include "SearchE.h"
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#ifndef strdup
extern char *strdup (const char *s);
#endif
#define PROGNAME "DTSRJOINT"
#define ISDIGIT(c) ((ascii_charmap [(unsigned int) (c)] & NUMERAL) != 0)
/*------------- GLOBALS VISIBLE TO CALLER -------------------*/
/* see also globals.c */
char **ausapi_dbnamesv = NULL; /* array of database names */
int ausapi_dbnamesc = 0; /* size of dbnames array */
int aa_maxhits = DtSrMAXHITS; /* num hits retnd after
* srch */
/*------------------- PRIVATE GLOBALS ---------------------*/
int aa_is_initialized = FALSE;
int aa_getnews_flag = 1;
long save_init_switches = 0L;
int ditsort_type = 0;
/************************************************/
/* */
/* aa_check_initialization */
/* */
/************************************************/
/* Confirms ausapi_init() was first function called. */
void aa_check_initialization (void)
{
if (aa_is_initialized)
return;
fprintf (aa_stderr,
catgets (dtsearch_catd, 2, 37,
"%s First API function call must be DtSearchInit().\n"),
PROGNAME"37");
DtSearchExit (37);
} /* aa_check_initialization() */
/************************************************/
/* */
/* DtSearchValidDateString */
/* */
/************************************************/
/* Subroutine of aa_both_valid_dates(), called once for each date string,
* or can be called from user interface to validate a date string.
* Converts passed date string into valid AusText DtSrObjdate.
* Date string format: "[yy]yy [mm [dd]]",
* 1, 2, or 3 numeric tokens separated by one
* or more nonnumeric chars (whitespace, slashes, etc).
* The first token is a complete year number integer yyyy
* in the range 1900 <= yyyy <= 5995. If the first token contains
* less than 4 digits it is presumed to be the number of years
* since 1900. The month number is the second token mm,
* in the range 1 - 12, and the third token dd is the day, 1 - 31.
* If only two tokens are in the string they are presumed to
* be year and month; the day is presumed to be to 1.
* If only one token is in the string it is presumed to
* be the year; the month is presumed to be 1 and the day
* is presumed to be 1. NULL and empty strings are always
* valid. They mean no date exclusion in the search
* and this function returns objdate 0 for them.
* Returns objdate on successful parse and conversion.
* Returns -1 and err msg if date string is invalid.
*/
DtSrObjdate DtSearchValidDateString (char *datestr)
{
DtSrObjdate objdate = 0L;
char parsebuf[64];
char *startp, *endp;
int yy, mm, dd;
int stop_parse = FALSE;
char msgbuf[256];
aa_check_initialization();
if (datestr == NULL) /* null string is valid */
return 0L;
if (datestr[0] == 0) /* empty string is valid */
return 0L;
strncpy (parsebuf, datestr, sizeof (parsebuf));
parsebuf[sizeof (parsebuf) - 1] = 0;
/* yyyy */
for (startp = parsebuf; *startp != 0 && !ISDIGIT(*startp); startp++);
if (*startp == 0) { /* no numeric digits in string */
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"269 No numeric digits in string\n");
#endif
INVALID_DATESTR:
sprintf (msgbuf,
catgets (dtsearch_catd, 2, 115,
"%s '%s' is invalid or incomplete date string.\n"
"The correct format is '[yy]yy [mm [dd]]'."),
PROGNAME"115", datestr);
DtSearchAddMessage (msgbuf);
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"278 Returning objdate -1\n");
fflush (aa_stderr);
#endif
return -1L;
}
for (endp = startp; ISDIGIT(*endp); endp++);
if (*endp == 0) { /* mm and dd both missing */
mm = 1;
dd = 1;
stop_parse = TRUE;
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"286 mm and dd both missing\n");
#endif
}
*endp = 0;
yy = atoi (startp);
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"293 yystr='%s' yy=%d\n", startp, yy);
#endif
if (strlen (startp) < 4)
yy += 1900;
if (yy < 1900 || yy > 5995)
goto INVALID_DATESTR;
if (stop_parse)
goto DATESTR_OK;
/* mm */
for (startp = ++endp; *startp != 0 && !ISDIGIT(*startp); startp++);
if (*startp == 0) { /* no mm in string */
mm = 1;
dd = 1;
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"309 No mm in string\n");
#endif
goto DATESTR_OK;
}
for (endp = startp; ISDIGIT(*endp); endp++);
if (*endp == 0) { /* no dd in string */
dd = 1;
stop_parse = TRUE;
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"318 No dd in string\n");
#endif
}
*endp = 0;
mm = atoi (startp);
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"293 mmstr='%s' mm=%d\n", startp, mm);
#endif
if (mm < 1 || mm > 12)
goto INVALID_DATESTR;
if (stop_parse)
goto DATESTR_OK;
/* dd */
for (startp = ++endp; *startp != 0 && !ISDIGIT(*startp); startp++);
if (*startp == 0) { /* no dd in string */
dd = 1;
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"336 No dd in string\n");
#endif
goto DATESTR_OK;
}
for (endp = startp; ISDIGIT(*endp); endp++);
*endp = 0;
dd = atoi (startp);
#ifdef DEBUG_VALDATE
fprintf (aa_stderr, PROGNAME"344 ddstr='%s' dd=%d\n", startp, dd);
#endif
if (dd < 1 || dd > 31)
goto INVALID_DATESTR;
DATESTR_OK:
objdate = (yy - 1900) << 20 | (mm-1) << 16 | dd << 11;
#ifdef DEBUG_VALDATE
fprintf (aa_stderr,
PROGNAME"352 Returning objdate %08lx, %d/%d/%d, %s\n",
objdate, yy, mm, dd, objdate2fzkstr(objdate));
fflush (aa_stderr);
#endif
return objdate;
} /* DtSearchValidDateString() */
/************************************************/
/* */
/* DtSearchFormatObjdate */
/* */
/************************************************/
/* Converts objdate in hitlist to displayable string */
char *DtSearchFormatObjdate (DtSrObjdate objdate)
{
static char datestr_buf[24];
if (objdate == 0L)
return "(undated)";
strftime (datestr_buf, sizeof(datestr_buf), "%Y.%m.%d",
objdate2tm (objdate));
return datestr_buf;
} /* DtSearchFormatObjdate() */
/************************************************/
/* */
/* DtSearchGetMaxResults */
/* DtSearchSetMaxResults */
/* */
/************************************************/
int DtSearchGetMaxResults (void)
{ return aa_maxhits; }
void DtSearchSetMaxResults (int newmax)
{ aa_maxhits = newmax; }
/************************************************/
/* */
/* DtSearchFreeResults */
/* */
/************************************************/
/* Frees storage allocated for the dittolist created
* by DtSearchQuery(), and sets dittolist pointer to NULL.
* Always returns DtSrOK.
*/
int DtSearchFreeResults (DtSrResult ** dittolist)
{
free_llist ((LLIST **) dittolist);
return DtSrOK;
} /* DtSearchFreeResults() */
/************************************************/
/* */
/* DtSearchMergeResults */
/* */
/************************************************/
/* Merges one dittolist into another using proximity
* for sort order. Sets 'src' dittolist pointer to NULL.
* Does not change dittocount of either list, user must do that.
* Returns DtSrOK on successful merge,
* else returns DtSrERROR for programming error.
* Formerly named aa_merge_dittolists.
*/
int DtSearchMergeResults (DtSrResult **targ_list, DtSrResult **src_list)
{
DtSrResult *targ, *src, *nextsrc, **prevtargl;
if (src_list == NULL || targ_list == NULL)
return DtSrERROR;
/* If there's no 'src' list, return with no changes.
* In other words, merge was successful before we started.
*/
if (*src_list == NULL)
return DtSrOK;
/* At this point we know there is a src_list.
* If there's no targ_list, just swap the pointers.
*/
if (*targ_list == NULL) {
*targ_list = *src_list;
*src_list = NULL;
return DtSrOK;
}
/* We have two nonempty lists. Now do a real merge.
* Insert src node into targ list only if it's
* proximity is smaller. Otherwise just
* advance to the next targ node.
*/
src = *src_list; /* curr src_list node to compare */
nextsrc = src->link; /* next src_list node to compare */
targ = *targ_list; /* curr targ_list node to compare */
prevtargl = targ_list; /* prev targ_list node link pointer */
while (src != NULL && targ != NULL) {
if (src->proximity < targ->proximity) {
/* Insert src node into targ list */
*prevtargl = src;
src->link = targ;
prevtargl = &src->link;
src = nextsrc;
if (src)
nextsrc = src->link;
}
else {
/* just advance to next targ node */
prevtargl = &targ->link;
targ = targ->link;
}
}
/* If there's any src_list left,
* just tack it onto the end of the targ_list.
*/
if (src) {
/* advance to end of targ_list */
while (targ) {
prevtargl = &targ->link;
targ = targ->link;
}
*prevtargl = src;
}
*src_list = NULL;
return DtSrOK;
} /* DtSearchMergeResults() */
/************************************************************
* Aa_sort_dittolist(): basically a copy of ditto_sort() from engine,
* but will sort on several different ditto fields
* (currently only date fields implemented),
* and is only used as convenience function on client/gui side.
* The proximity field is always the minor sort key.
* All functions with similar names to engine functions are static
* in this module so they won't collide with same function in engine.
* Performs a recursive split-merge sort on ditto lists.
************************************************************/
/************************************************/
/* */
/* ditto_pop */
/* */
/************************************************/
/* Subroutine of DtSearchSortResults().
* Detaches first node in a list and returns it...
* If *lst is empty return NULL, else set *lst to the link
* cell of the first DtSrResult node on *lst and return a pointer to
* the first DtSrResult node on *lst.
*/
static DtSrResult *ditto_pop (DtSrResult ** lst)
{
DtSrResult *first_node;
first_node = *lst;
if (first_node != NULL)
*lst = first_node->link;
return first_node;
} /* ditto_pop() */
/************************************************/
/* */
/* ditto_split */
/* */
/************************************************/
/* Subroutine of DtSearchSortResults().
* Find the middle node in lst. Set its 'next' pointer to NULL.
* Return the remainder of lst, i.e. a pointer to the
* next node after the middle node.
*/
static DtSrResult *ditto_split (DtSrResult * lst)
{
DtSrResult *tail = lst->link;
if (lst == NULL || tail == NULL)
return lst;
/*
* Advance 'tail' to end of list, and advance 'lst' only half
* as often
*/
while ((tail != NULL) && ((tail = tail->link) != NULL)) {
lst = lst->link;
tail = tail->link;
}
tail = lst->link;
lst->link = NULL;
return tail;
} /* ditto_split() */
/************************************************/
/* */
/* merge_by_prox */
/* */
/************************************************/
/* Subroutine of DtSearchSortResults().
* Merges two sorted DtSrResult lists together in proximity order.
*/
static DtSrResult *merge_by_prox (DtSrResult * l1, DtSrResult * l2)
{
DtSrResult *myqueue = NULL;
DtSrResult *myend = NULL;
DtSrResult *mynext;
while ((l1 != NULL) && (l2 != NULL)) {
/*
* Perform ENQUEUE function. Next item popped off a list is
* the next one in sorted order. It is added to END of
* myqueue to maintain order. THIS IS WHERE THE ACTUAL SORT
* COMPARE FUNCTION IS PERFORMED.
*/
mynext = (l1->proximity < l2->proximity) ?
ditto_pop (&l1) : ditto_pop (&l2);
mynext->link = NULL;
if (myqueue == NULL)
myqueue = mynext;
else
myend->link = mynext;
myend = mynext;
}
/*
* Perform JOIN QUEUE function. Append entire list to end of
* queue.
*/
if (l1 != NULL)
myend->link = l1;
if (l2 != NULL)
myend->link = l2;
return myqueue;
} /* merge_by_prox() */
/************************************************/
/* */
/* merge_by_date */
/* */
/************************************************/
/* Subroutine of DtSearchSortResults().
* Merges two sorted DtSrResult lists together in objdate order.
*/
static DtSrResult *merge_by_date (DtSrResult * l1, DtSrResult * l2)
{
DtSrResult *myqueue = NULL;
DtSrResult *myend = NULL;
DtSrResult *mynext;
while ((l1 != NULL) && (l2 != NULL)) {
/*
* Perform ENQUEUE function. Next item popped off a list is
* the next one in sorted order. It is added to END of
* myqueue to maintain order. THIS IS WHERE THE ACTUAL SORT
* COMPARE FUNCTION IS PERFORMED.
*/
if (l1->objdate == l2->objdate)
mynext = (l1->proximity < l2->proximity) ?
ditto_pop (&l1) : ditto_pop (&l2);
else
mynext = (l1->objdate > l2->objdate) ?
ditto_pop (&l1) : ditto_pop (&l2);
mynext->link = NULL;
if (myqueue == NULL)
myqueue = mynext;
else
myend->link = mynext;
myend = mynext;
}
/*
* Perform JOIN QUEUE function. Append entire list to end of
* queue.
*/
if (l1 != NULL)
myend->link = l1;
if (l2 != NULL)
myend->link = l2;
return myqueue;
} /* merge_by_date() */
/************************************************/
/* */
/* ditto_sort */
/* */
/************************************************/
/* Subroutine of DtSearchSortResults().
* Sorts a list of DtSrResult structures and returns ptr to sorted list.
* The basic idea is to sort by recursively splitting a list
* into two equal halves and sorting each of those. The recursion
* ends when there are only two small lists which are either
* already sorted or are swapped. This sort rarely runs out
* of stack space because each recursion cuts the list length in
* half so there are at most 1 + log-N-to-the-base-2 items on the stack.
* (e.g. 64,000 nodes = max stack depth of 16: 2**16 = 64K).
*/
static DtSrResult *ditto_sort (DtSrResult * lst)
{
DtSrResult *lst2;
if ((lst == NULL) || (lst->link == NULL))
return lst;
lst2 = ditto_split (lst);
switch (ditsort_type) {
case DtSrSORT_PROX:
return merge_by_prox (ditto_sort (lst), ditto_sort (lst2));
case DtSrSORT_DATE:
return merge_by_date (ditto_sort (lst), ditto_sort (lst2));
default:
fprintf (aa_stderr, PROGNAME "525 Invalid Sort Type %d.\n",
ditsort_type);
DtSearchExit (32);
}
} /* ditto_sort() */
/************************************************/
/* */
/* DtSearchSortResults */
/* */
/************************************************/
/* Only publicly visible sort function.
* DtSearchSortResults() was formerly named aa_sort_dittolist.
*/
int DtSearchSortResults (DtSrResult ** dittolist, int sort_type)
{
switch (sort_type) {
case DtSrSORT_PROX:
case DtSrSORT_DATE:
ditsort_type = sort_type;
*dittolist = ditto_sort (*dittolist); /* recursive call */
return DtSrOK;
default:
DtSearchAddMessage (PROGNAME "140 "
"Program Error: Invalid sort type.");
return DtSrERROR;
}
} /* DtSearchSortResults() */
/**************************** DTSRJOINT.C *************************/