"Fossies" - the Fresh Open Source Software Archive

Member "lynx2.9.0dev.1/WWW/Library/Implementation/HTVMS_WaisUI.c" (27 Dec 2018, 60991 Bytes) of package /linux/www/lynx2.9.0dev.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "HTVMS_WaisUI.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8.9_vs_2.9.0dev.1.

    1 /*
    2  * $LynxId: HTVMS_WaisUI.c,v 1.20 2018/12/27 10:28:12 tom Exp $
    3  *                              HTVMS_WAISUI.c
    4  *
    5  *  Adaptation for Lynx by F.Macrides (macrides@sci.wfeb.edu)
    6  *
    7  *  30-May-1994 FM  Initial version.
    8  *
    9  *----------------------------------------------------------------------*/
   10 
   11 /*
   12  *  Routines originally from UI.c -- FM
   13  *
   14  *----------------------------------------------------------------------*/
   15 /* WIDE AREA INFORMATION SERVER SOFTWARE:
   16  * No guarantees or restrictions.  See the readme file for the full standard
   17  * disclaimer.
   18  *
   19  * Brewster@think.com
   20  */
   21 
   22 /*
   23  * this is a simple ui toolkit for building other ui's on top.
   24  * -brewster
   25  *
   26  * top level functions:
   27  *   generate_search_apdu
   28  *   generate_retrieval_apdu
   29  *   interpret_message
   30  *
   31  */
   32 
   33 /* to do:
   34  *   generate multiple queries for long documents.
   35  *     this will crash if the file being retrieved is larger than 100k.
   36  *   do log_write()
   37  *
   38  */
   39 
   40 #include <HTUtils.h>
   41 
   42 #ifdef VMS
   43 #include <HTVMS_WaisUI.h>
   44 #include <HTVMS_WaisProt.h>
   45 #include <HTTCP.h>
   46 
   47 #undef MAXINT           /* we don't need it here, and www_tcp.h may conflict */
   48 #include <math.h>
   49 
   50 #include <LYexit.h>
   51 #include <LYLeaks.h>
   52 
   53 void log_write(char *s GCC_UNUSED)
   54 {
   55     return;
   56 }
   57 
   58 /*----------------------------------------------------------------------*/
   59 
   60 /* returns a pointer in the buffer of the first free byte.
   61    if it overflows, then NULL is returned
   62  */
   63 char *generate_search_apdu(char *buff,  /* buffer to hold the apdu */
   64                long *buff_len,  /* length of the buffer changed to reflect new data written */
   65                char *seed_words,    /* string of the seed words */
   66                char *database_name,
   67                DocObj **docobjs,
   68                long maxDocsRetrieved)
   69 {
   70     /* local variables */
   71 
   72     SearchAPDU *search3;
   73     char *end_ptr;
   74     static char *database_names[2] =
   75     {"", 0};
   76     any refID;
   77     WAISSearch *query;
   78 
   79     refID.size = 1;
   80     refID.bytes = "3";
   81 
   82     database_names[0] = database_name;
   83     query = makeWAISSearch(seed_words,
   84                docobjs, /* DocObjsPtr */
   85                0,
   86                1,   /* DateFactor */
   87                0,   /* BeginDateRange */
   88                0,   /* EndDateRange */
   89                maxDocsRetrieved
   90     );
   91 
   92     search3 = makeSearchAPDU(30,
   93                  5000,  /* should be large */
   94                  30,
   95                  1, /* replace indicator */
   96                  "",    /* result set name */
   97                  database_names,    /* database name */
   98                  QT_RelevanceFeedbackQuery,     /* query_type */
   99                  0, /* element name */
  100                  NULL,  /* reference ID */
  101                  query);
  102 
  103     end_ptr = writeSearchAPDU(search3, buff, buff_len);
  104 
  105     CSTFreeWAISSearch(query);
  106     freeSearchAPDU(search3);
  107     return (end_ptr);
  108 }
  109 
  110 /*----------------------------------------------------------------------*/
  111 
  112 /* returns a pointer into the buffer of the next free byte.
  113    if it overflowed, then NULL is returned
  114  */
  115 
  116 char *generate_retrieval_apdu(char *buff,
  117                   long *buff_len,   /* length of the buffer changed to reflect new data written */
  118                   any *docID,
  119                   long chunk_type,
  120                   long start,
  121                   long end,
  122                   char *type,
  123                   char *database_name)
  124 {
  125     SearchAPDU *search;
  126     char *end_ptr;
  127 
  128     static char *database_names[2];
  129     static char *element_names[3];
  130     any refID;
  131 
  132     DocObj *DocObjs[2];
  133     any *query;         /* changed from char* by brewster */
  134 
  135     if (NULL == type)
  136     type = s_strdup("TEXT");
  137 
  138     database_names[0] = database_name;
  139     database_names[1] = NULL;
  140 
  141     element_names[0] = " ";
  142     element_names[1] = ES_DocumentText;
  143     element_names[2] = NULL;
  144 
  145     refID.size = 1;
  146     refID.bytes = "3";
  147 
  148     switch (chunk_type) {
  149     case CT_line:
  150     DocObjs[0] = makeDocObjUsingLines(docID, type, start, end);
  151     break;
  152     case CT_byte:
  153     DocObjs[0] = makeDocObjUsingBytes(docID, type, start, end);
  154     break;
  155     }
  156     DocObjs[1] = NULL;
  157 
  158     query = makeWAISTextQuery(DocObjs);
  159     search = makeSearchAPDU(10, 16, 15,
  160                 1,  /* replace indicator */
  161                 "FOO",  /* result set name */
  162                 database_names, /* database name */
  163                 QT_TextRetrievalQuery,  /* query_type */
  164                 element_names,  /* element name */
  165                 &refID, /* reference ID */
  166                 query);
  167     end_ptr = writeSearchAPDU(search, buff, buff_len);
  168     CSTFreeWAISTextQuery(query);
  169     freeSearchAPDU(search);
  170     return (end_ptr);
  171 }
  172 
  173 /*----------------------------------------------------------------------*/
  174 
  175 /* this is a safe version of unix 'read' it does all the checking
  176  * and looping necessary
  177  * to those trying to modify the transport code to use non-UNIX streams:
  178  *  This is the function to modify!
  179  */
  180 static long read_from_stream(int d, char *buf, long nbytes)
  181 {
  182     long didRead;
  183     long toRead = nbytes;
  184     long totalRead = 0;     /* paranoia */
  185 
  186     while (toRead > 0) {
  187     didRead = NETREAD(d, buf, (int) toRead);
  188     if (didRead == HT_INTERRUPTED)
  189         return (HT_INTERRUPTED);
  190     if (didRead == -1)  /* error */
  191         return (-1);
  192     if (didRead == 0)   /* eof */
  193         return (-2);    /* maybe this should return 0? */
  194     toRead -= didRead;
  195     buf += didRead;
  196     totalRead += didRead;
  197     }
  198     if (totalRead != nbytes)    /* we overread for some reason */
  199     return (-totalRead);    /* bad news */
  200     return (totalRead);
  201 }
  202 
  203 /*----------------------------------------------------------------------*/
  204 
  205 /* returns the length of the response, 0 if an error */
  206 
  207 static long transport_message(long connection,
  208                   char *request_message,
  209                   long request_length,
  210                   char *response_message,
  211                   long response_buffer_length)
  212 {
  213     WAISMessage header;
  214     long response_length;
  215     int rv;
  216 
  217     /* Write out message.  Read back header.  Figure out response length. */
  218 
  219     if (request_length + HEADER_LENGTH !=
  220     NETWRITE(connection, request_message,
  221          (int) (request_length + HEADER_LENGTH)))
  222     return 0;
  223 
  224     /* read for the first '0' */
  225 
  226     while (1) {
  227     rv = read_from_stream(connection, response_message, 1);
  228     if (rv == HT_INTERRUPTED)
  229         return HT_INTERRUPTED;
  230     if (rv < 0)
  231         return 0;
  232     if ('0' == response_message[0])
  233         break;
  234     }
  235 
  236     rv = read_from_stream(connection, response_message + 1, HEADER_LENGTH - 1);
  237     if (rv == HT_INTERRUPTED)
  238     return HT_INTERRUPTED;
  239     if (rv < 0)
  240     return 0;
  241 
  242     readWAISPacketHeader(response_message, &header);
  243     {
  244     char length_array[11];
  245 
  246     LYStrNCpy(length_array, header.msg_len, 10);
  247     response_length = atol(length_array);
  248     /*
  249        if(verbose){
  250        printf("WAIS header: '%s' length_array: '%s'\n",
  251        response_message, length_array);
  252        }
  253      */
  254     if (response_length > response_buffer_length) {
  255         /* we got a message that is too long, therefore empty the message out,
  256            and return 0 */
  257         long i;
  258 
  259         for (i = 0; i < response_length; i++) {
  260         rv = read_from_stream(connection,
  261                       response_message + HEADER_LENGTH,
  262                       1);
  263         if (rv == HT_INTERRUPTED)
  264             return HT_INTERRUPTED;
  265         if (rv < 0)
  266             return 0;
  267         }
  268         return (0);
  269     }
  270     }
  271     rv = read_from_stream(connection,
  272               response_message + HEADER_LENGTH,
  273               response_length);
  274     if (rv == HT_INTERRUPTED)
  275     return HT_INTERRUPTED;
  276     if (rv < 0)
  277     return 0;
  278     return (response_length);
  279 }
  280 
  281 /*----------------------------------------------------------------------*/
  282 
  283 /* returns the number of bytes written.  0 if an error */
  284 long interpret_message(char *request_message,
  285                long request_length, /* length of the buffer */
  286                char *response_message,
  287                long response_buffer_length,
  288                long connection,
  289                boolean verbose GCC_UNUSED)
  290 {
  291     long response_length;
  292 
  293     /* ?
  294        if(verbose){
  295        printf ("sending");
  296        if(hostname_internal && strlen(hostname_internal) > 0)
  297        printf(" to host %s", hostname_internal);
  298        if(service_name && strlen(service_name) > 0)
  299        printf(" for service %s", service_name);
  300        printf("\n");
  301        twais_dsply_rsp_apdu(request_message + HEADER_LENGTH,
  302        request_length);
  303        }
  304 
  305      */
  306 
  307     writeWAISPacketHeader(request_message,
  308               request_length,
  309               (long) 'z',   /* Z39.50 */
  310               "wais      ",     /* server name */
  311               (long) NO_COMPRESSION,    /* no compression */
  312               (long) NO_ENCODING, (long) HEADER_VERSION);
  313     if (connection != 0) {
  314     response_length = transport_message(connection, request_message,
  315                         request_length,
  316                         response_message,
  317                         response_buffer_length);
  318     if (response_length == HT_INTERRUPTED)
  319         return (HT_INTERRUPTED);
  320     } else
  321     return (0);
  322 
  323     return (response_length);
  324 }
  325 
  326 /*----------------------------------------------------------------------*/
  327 
  328 /* modifies the string to exclude all seeker codes. sets length to
  329    the new length. */
  330 static char *delete_seeker_codes(char *string, long *length)
  331 {
  332     long original_count;    /* index into the original string */
  333     long new_count = 0;     /* index into the collapsed string */
  334 
  335     for (original_count = 0; original_count < *length; original_count++) {
  336     if (27 == string[original_count]) {
  337         /* then we have an escape code */
  338         /* if the next letter is '(' or ')', then ignore two letters */
  339         if ('(' == string[original_count + 1] ||
  340         ')' == string[original_count + 1])
  341         original_count += 1;    /* it is a term marker */
  342         else
  343         original_count += 4;    /* it is a paragraph marker */
  344     } else
  345         string[new_count++] = string[original_count];
  346     }
  347     *length = new_count;
  348     return (string);
  349 }
  350 
  351 /*----------------------------------------------------------------------*/
  352 
  353 #if defined(VMS) && defined(__GNUC__)   /* 10-AUG-1995 [pr] */
  354 /*
  355   Workaround for an obscure bug in gcc's 2.6.[123] and 2.7.0 vax/vms port;
  356   sometimes global variables will end up not being defined properly,
  357   causing first gas to assume they're routines, then the linker to complain
  358   about unresolved symbols, and finally the program to reference the wrong
  359   objects (provoking ACCVIO).  It's triggered by the specific ordering of
  360   variable usage in the source code, hence rarely appears.  This bug is
  361   fixed in gcc 2.7.1, and was not present in 2.6.0 and earlier.
  362 
  363    Make a reference to VAXCRTL's _ctype_[], and also one to this dummy
  364    variable itself to prevent any "defined but not used" warning.
  365  */
  366 static __const void *__const ctype_dummy[] =
  367 {&_ctype_, &ctype_dummy};
  368 #endif /* VMS && __GNUC__ */
  369 
  370 /* returns a pointer to a string with good stuff */
  371 char *trim_junk(char *headline)
  372 {
  373     long length = strlen(headline) + 1;     /* include the trailing null */
  374     size_t i;
  375 
  376     headline = delete_seeker_codes(headline, &length);
  377     /* delete leading spaces */
  378     for (i = 0; i < strlen(headline); i++) {
  379     if (isprint(headline[i])) {
  380         break;
  381     }
  382     }
  383     headline = headline + i;
  384     /* delete trailing stuff */
  385     for (i = strlen(headline) - 1; i > 0; i--) {
  386     if (isprint(headline[i])) {
  387         break;
  388     }
  389     headline[i] = '\0';
  390     }
  391     return (headline);
  392 }
  393 
  394 /*----------------------------------------------------------------------*/
  395 
  396 /*
  397  *  Routines originally from ZProt.c -- FM
  398  *
  399  *----------------------------------------------------------------------*/
  400 /* WIDE AREA INFORMATION SERVER SOFTWARE:`
  401  * No guarantees or restrictions.  See the readme file for the full standard
  402  * disclaimer.
  403  *
  404  * 3.26.90  Harry Morris, morris@think.com
  405  * 3.30.90  Harry Morris - Changed any->bits to any->bytes
  406  * 4.11.90  HWM - generalized conditional includes (see c-dialect.h)
  407  */
  408 
  409 #define RESERVE_SPACE_FOR_HEADER(spaceLeft)     \
  410     *spaceLeft -= HEADER_LEN;
  411 
  412 #define RELEASE_HEADER_SPACE(spaceLeft)         \
  413     if (*spaceLeft > 0)             \
  414       *spaceLeft += HEADER_LEN;
  415 
  416 /*----------------------------------------------------------------------*/
  417 
  418 InitResponseAPDU *makeInitResponseAPDU(boolean result,
  419                        boolean search,
  420                        boolean present,
  421                        boolean deleteIt,
  422                        boolean accessControl,
  423                        boolean resourceControl,
  424                        long prefSize,
  425                        long maxMsgSize,
  426                        char *auth,
  427                        char *id,
  428                        char *name,
  429                        char *version,
  430                        any *refID,
  431                        void *userInfo)
  432 /* build an initResponse APDU with user specified information */
  433 {
  434     InitResponseAPDU *init = (InitResponseAPDU *) s_malloc((size_t) sizeof(InitResponseAPDU));
  435 
  436     init->PDUType = initResponseAPDU;
  437     init->Result = result;
  438     init->willSearch = search;
  439     init->willPresent = present;
  440     init->willDelete = deleteIt;
  441     init->supportAccessControl = accessControl;
  442     init->supportResourceControl = resourceControl;
  443     init->PreferredMessageSize = prefSize;
  444     init->MaximumRecordSize = maxMsgSize;
  445     init->IDAuthentication = s_strdup(auth);
  446     init->ImplementationID = s_strdup(id);
  447     init->ImplementationName = s_strdup(name);
  448     init->ImplementationVersion = s_strdup(version);
  449     init->ReferenceID = duplicateAny(refID);
  450     init->UserInformationField = userInfo;  /* not copied! */
  451 
  452     return (init);
  453 }
  454 
  455 /*----------------------------------------------------------------------*/
  456 
  457 void freeInitResponseAPDU(InitResponseAPDU *init)
  458 /* free an initAPDU */
  459 {
  460     s_free(init->IDAuthentication);
  461     s_free(init->ImplementationID);
  462     s_free(init->ImplementationName);
  463     s_free(init->ImplementationVersion);
  464     freeAny(init->ReferenceID);
  465     s_free(init);
  466 }
  467 
  468 /*----------------------------------------------------------------------*/
  469 
  470 char *writeInitResponseAPDU(InitResponseAPDU *init, char *buffer, long *len)
  471 /* write the initResponse to a buffer, adding system information */
  472 {
  473     char *buf = buffer + HEADER_LEN;    /* leave room for the header-length-indicator */
  474     long size;
  475     bit_map *optionsBM = NULL;
  476 
  477     RESERVE_SPACE_FOR_HEADER(len);
  478 
  479     buf = writePDUType(init->PDUType, buf, len);
  480     buf = writeBoolean(init->Result, buf, len);
  481     buf = writeProtocolVersion(buf, len);
  482 
  483     optionsBM = makeBitMap((unsigned long) 5, init->willSearch, init->willPresent,
  484                init->willDelete, init->supportAccessControl,
  485                init->supportResourceControl);
  486     buf = writeBitMap(optionsBM, DT_Options, buf, len);
  487     freeBitMap(optionsBM);
  488 
  489     buf = writeNum(init->PreferredMessageSize,
  490            DT_PreferredMessageSize,
  491            buf,
  492            len);
  493     buf = writeNum(init->MaximumRecordSize,
  494            DT_MaximumRecordSize,
  495            buf,
  496            len);
  497     buf = writeString(init->IDAuthentication,
  498               DT_IDAuthentication,
  499               buf,
  500               len);
  501     buf = writeString(init->ImplementationID,
  502               DT_ImplementationID,
  503               buf,
  504               len);
  505     buf = writeString(init->ImplementationName,
  506               DT_ImplementationName,
  507               buf,
  508               len);
  509     buf = writeString(init->ImplementationVersion,
  510               DT_ImplementationVersion,
  511               buf,
  512               len);
  513     buf = writeAny(init->ReferenceID,
  514            DT_ReferenceID,
  515            buf,
  516            len);
  517 
  518     /* go back and write the header-length-indicator */
  519     RELEASE_HEADER_SPACE(len);
  520     size = buf - buffer - HEADER_LEN;
  521     writeBinaryInteger(size, HEADER_LEN, buffer, len);
  522 
  523     if (init->UserInformationField != NULL)
  524     buf = writeInitResponseInfo(init, buf, len);
  525 
  526     return (buf);
  527 }
  528 
  529 /*----------------------------------------------------------------------*/
  530 
  531 char *readInitResponseAPDU(InitResponseAPDU **init, char *buffer)
  532 {
  533     char *buf = buffer;
  534     boolean search, present, delete, accessControl, resourceControl;
  535     long prefSize, maxMsgSize;
  536     char *auth, *id, *name, *version;
  537     long size;
  538     pdu_type pduType;
  539     bit_map *versionBM = NULL;
  540     bit_map *optionsBM = NULL;
  541     boolean result;
  542     any *refID = NULL;
  543     void *userInfo = NULL;
  544 
  545     auth = id = name = version = NULL;
  546     refID = NULL;
  547 
  548     /* read required part */
  549     buf = readBinaryInteger(&size, HEADER_LEN, buf);
  550     buf = readPDUType(&pduType, buf);
  551     buf = readBoolean(&result, buf);
  552     buf = readBitMap(&versionBM, buf);
  553     buf = readBitMap(&optionsBM, buf);
  554     buf = readNum(&prefSize, buf);
  555     buf = readNum(&maxMsgSize, buf);
  556 
  557     /* decode optionsBM */
  558     search = bitAtPos(0, optionsBM);
  559     present = bitAtPos(1, optionsBM);
  560     delete = bitAtPos(2, optionsBM);
  561     accessControl = bitAtPos(3, optionsBM);
  562     resourceControl = bitAtPos(4, optionsBM);
  563 
  564     /* read optional part */
  565     while (buf < (buffer + size + HEADER_LEN)) {
  566     data_tag tag = peekTag(buf);
  567 
  568     switch (tag) {
  569     case DT_IDAuthentication:
  570         buf = readString(&auth, buf);
  571         break;
  572     case DT_ImplementationID:
  573         buf = readString(&id, buf);
  574         break;
  575     case DT_ImplementationName:
  576         buf = readString(&name, buf);
  577         break;
  578     case DT_ImplementationVersion:
  579         buf = readString(&version, buf);
  580         break;
  581     case DT_ReferenceID:
  582         buf = readAny(&refID, buf);
  583         break;
  584     default:
  585         freeBitMap(versionBM);
  586         freeBitMap(optionsBM);
  587         s_free(auth);
  588         s_free(id);
  589         s_free(name);
  590         s_free(version);
  591         freeAny(refID);
  592         REPORT_READ_ERROR(buf);
  593         break;
  594     }
  595     }
  596 
  597     buf = readInitResponseInfo(&userInfo, buf);
  598     if (buf == NULL) {
  599     freeBitMap(versionBM);
  600     freeBitMap(optionsBM);
  601     s_free(auth);
  602     s_free(id);
  603     s_free(name);
  604     s_free(version);
  605     freeAny(refID);
  606     }
  607     RETURN_ON_NULL(buf);
  608 
  609     /* construct the basic init object */
  610     *init = makeInitResponseAPDU(result,
  611                  search,
  612                  present,
  613                  delete,
  614                  accessControl,
  615                  resourceControl,
  616                  prefSize,
  617                  maxMsgSize,
  618                  auth,
  619                  id,
  620                  name,
  621                  version,
  622                  refID,
  623                  userInfo);
  624 
  625     freeBitMap(versionBM);
  626     freeBitMap(optionsBM);
  627     s_free(auth);
  628     s_free(id);
  629     s_free(name);
  630     s_free(version);
  631     freeAny(refID);
  632 
  633     return (buf);
  634 }
  635 
  636 /*----------------------------------------------------------------------*/
  637 
  638 InitResponseAPDU *replyToInitAPDU(InitAPDU * init, boolean result, void *userInfo)
  639 /* respond to an init message in the default way - echoing back
  640    the init info
  641  */
  642 {
  643     InitResponseAPDU *initResp;
  644 
  645     initResp = makeInitResponseAPDU(result,
  646                     init->willSearch,
  647                     init->willPresent,
  648                     init->willDelete,
  649                     init->supportAccessControl,
  650                     init->supportResourceControl,
  651                     init->PreferredMessageSize,
  652                     init->MaximumRecordSize,
  653                     init->IDAuthentication,
  654                     defaultImplementationID(),
  655                     defaultImplementationName(),
  656                     defaultImplementationVersion(),
  657                     init->ReferenceID,
  658                     userInfo);
  659     return (initResp);
  660 }
  661 
  662 /*----------------------------------------------------------------------*/
  663 
  664 SearchAPDU *makeSearchAPDU(long small,
  665                long large,
  666                long medium,
  667                boolean replace,
  668                char *name,
  669                char **databases,
  670                char *type,
  671                char **elements,
  672                any *refID,
  673                void *queryInfo)
  674 {
  675     char *ptr = NULL;
  676     long i;
  677     SearchAPDU *query = (SearchAPDU *) s_malloc((size_t) sizeof(SearchAPDU));
  678 
  679     query->PDUType = searchAPDU;
  680     query->SmallSetUpperBound = small;
  681     query->LargeSetLowerBound = large;
  682     query->MediumSetPresentNumber = medium;
  683     query->ReplaceIndicator = replace;
  684     query->ResultSetName = s_strdup(name);
  685     query->DatabaseNames = NULL;
  686     if (databases != NULL) {
  687     for (i = 0, ptr = databases[i]; ptr != NULL; ptr = databases[++i]) {
  688         if (query->DatabaseNames == NULL)
  689         query->DatabaseNames = (char **) s_malloc((size_t) (sizeof(char
  690                                        *)
  691                                     * 2));
  692 
  693         else
  694         query->DatabaseNames = (char **) s_realloc((char *) query->DatabaseNames,
  695                                (size_t) (sizeof(char
  696                                         *) *
  697                                      (i + 2)));
  698 
  699         query->DatabaseNames[i] = s_strdup(ptr);
  700         query->DatabaseNames[i + 1] = NULL;
  701     }
  702     }
  703     query->QueryType = s_strdup(type);
  704     query->ElementSetNames = NULL;
  705     if (elements != NULL) {
  706     for (i = 0, ptr = elements[i]; ptr != NULL; ptr = elements[++i]) {
  707         if (query->ElementSetNames == NULL)
  708         query->ElementSetNames =
  709             (char **) s_malloc((size_t) (sizeof(char *) * 2));
  710 
  711         else
  712         query->ElementSetNames = (char **) s_realloc((char *) query->ElementSetNames,
  713                                  (size_t) (sizeof(char
  714                                           *) *
  715                                        (i + 2)));
  716 
  717         query->ElementSetNames[i] = s_strdup(ptr);
  718         query->ElementSetNames[i + 1] = NULL;
  719     }
  720     }
  721     query->ReferenceID = duplicateAny(refID);
  722     query->Query = queryInfo;   /* not copied! */
  723     return (query);
  724 }
  725 
  726 /*----------------------------------------------------------------------*/
  727 
  728 void freeSearchAPDU(SearchAPDU *query)
  729 {
  730     s_free(query->ResultSetName);
  731     s_free(query->QueryType);
  732     doList((void **) query->DatabaseNames, fs_free);    /* can't use the macro here ! */
  733     s_free(query->DatabaseNames);
  734     doList((void **) query->ElementSetNames, fs_free);  /* can't use the macro here ! */
  735     s_free(query->ElementSetNames);
  736     freeAny(query->ReferenceID);
  737     s_free(query);
  738 }
  739 
  740 /*----------------------------------------------------------------------*/
  741 
  742 #define DB_DELIMITER    "\037"  /* hex 1F occurs between each database name */
  743 #define ES_DELIMITER_1  "\037"  /* separates database name from element name */
  744 #define ES_DELIMITER_2  "\036"  /* hex 1E separates <db,es> groups from one another */
  745 
  746 char *writeSearchAPDU(SearchAPDU *query, char *buffer, long *len)
  747 {
  748     char *buf = buffer + HEADER_LEN;    /* leave room for the header-length-indicator */
  749     long size, i;
  750     char *ptr = NULL;
  751     char *scratch = NULL;
  752 
  753     RESERVE_SPACE_FOR_HEADER(len);
  754 
  755     buf = writePDUType(query->PDUType, buf, len);
  756     buf = writeBinaryInteger(query->SmallSetUpperBound, (size_t) 3, buf, len);
  757     buf = writeBinaryInteger(query->LargeSetLowerBound, (size_t) 3, buf, len);
  758     buf = writeBinaryInteger(query->MediumSetPresentNumber, (size_t) 3, buf, len);
  759     buf = writeBoolean(query->ReplaceIndicator, buf, len);
  760     buf = writeString(query->ResultSetName, DT_ResultSetName, buf, len);
  761     /* write database names */
  762     if (query->DatabaseNames != NULL) {
  763     for (i = 0, scratch = NULL, ptr = query->DatabaseNames[i]; ptr != NULL;
  764          ptr = query->DatabaseNames[++i]) {
  765         if (scratch == NULL)
  766         scratch = s_strdup(ptr);
  767         else {
  768         size_t newScratchSize = (size_t) (strlen(scratch) +
  769                           strlen(ptr) + 2);
  770 
  771         scratch = (char *) s_realloc(scratch, newScratchSize);
  772         s_strncat(scratch, DB_DELIMITER, 2, newScratchSize);
  773         s_strncat(scratch, ptr, strlen(ptr) + 1, newScratchSize);
  774         }
  775     }
  776     buf = writeString(scratch, DT_DatabaseNames, buf, len);
  777     s_free(scratch);
  778     }
  779     buf = writeString(query->QueryType, DT_QueryType, buf, len);
  780     /* write element set names */
  781     if (query->ElementSetNames != NULL) {
  782     for (i = 0, scratch = NULL, ptr = query->ElementSetNames[i];
  783          ptr != NULL;
  784          ptr = query->ElementSetNames[++i]) {
  785         if (scratch == NULL) {
  786         if (query->ElementSetNames[i + 1] == NULL)  /* there is a single element set name */
  787         {
  788             scratch = (char *) s_malloc((size_t) strlen(ptr) + 2);
  789             StrNCpy(scratch, ES_DELIMITER_1, 2);
  790             s_strncat(scratch, ptr, strlen(ptr) + 1, strlen(ptr) + 2);
  791         } else {    /* this is the first of a series of element set names */
  792             size_t newScratchSize = (size_t) (strlen(ptr) +
  793                               strlen(query->ElementSetNames[i
  794                                             + 1])
  795                               + 2);
  796 
  797             scratch = s_strdup(ptr);    /* the database name */
  798             ptr = query->ElementSetNames[++i];  /* the element set name */
  799             scratch = (char *) s_realloc(scratch, newScratchSize);
  800             s_strncat(scratch, ES_DELIMITER_1, 2, newScratchSize);
  801             s_strncat(scratch, ptr, strlen(ptr) + 1, newScratchSize);
  802         }
  803         } else {
  804         char *esPtr = query->ElementSetNames[++i];  /* the element set name */
  805         size_t newScratchSize = (size_t) (strlen(scratch) +
  806                           strlen(ptr) +
  807                           strlen(esPtr) +
  808                           3);
  809 
  810         scratch = (char *) s_realloc(scratch, newScratchSize);
  811         s_strncat(scratch, ES_DELIMITER_2, 2, newScratchSize);
  812         s_strncat(scratch, ptr, strlen(ptr) + 1, newScratchSize);
  813         s_strncat(scratch, ES_DELIMITER_1, 2, newScratchSize);
  814         s_strncat(scratch, esPtr, strlen(esPtr) + 1, newScratchSize);
  815         }
  816     }
  817     buf = writeString(scratch, DT_ElementSetNames, buf, len);
  818     s_free(scratch);
  819     }
  820     buf = writeAny(query->ReferenceID, DT_ReferenceID, buf, len);
  821 
  822     /* go back and write the header-length-indicator */
  823     RELEASE_HEADER_SPACE(len);
  824     size = buf - buffer - HEADER_LEN;
  825     writeBinaryInteger(size, HEADER_LEN, buffer, len);
  826 
  827     if (query->Query != NULL)
  828     buf = writeSearchInfo(query, buf, len);
  829 
  830     return (buf);
  831 }
  832 
  833 /*----------------------------------------------------------------------*/
  834 
  835 SearchResponseAPDU *makeSearchResponseAPDU(long result,
  836                        long count,
  837                        long recordsReturned,
  838                        long nextPos,
  839                        long resultStatus,
  840                        long presentStatus,
  841                        any *refID,
  842                        void *records)
  843 {
  844     SearchResponseAPDU *query =
  845     (SearchResponseAPDU *) s_malloc((size_t) sizeof(SearchResponseAPDU));
  846 
  847     query->PDUType = searchResponseAPDU;
  848     query->SearchStatus = result;
  849     query->ResultCount = count;
  850     query->NumberOfRecordsReturned = recordsReturned;
  851     query->NextResultSetPosition = nextPos;
  852     query->ResultSetStatus = resultStatus;
  853     query->PresentStatus = presentStatus;
  854     query->ReferenceID = duplicateAny(refID);
  855     query->DatabaseDiagnosticRecords = records;
  856     return (query);
  857 }
  858 
  859 /*----------------------------------------------------------------------*/
  860 
  861 void freeSearchResponseAPDU(SearchResponseAPDU *queryResponse)
  862 {
  863     freeAny(queryResponse->ReferenceID);
  864     s_free(queryResponse);
  865 }
  866 
  867 /*----------------------------------------------------------------------*/
  868 
  869 char *writeSearchResponseAPDU(SearchResponseAPDU *queryResponse, char *buffer,
  870                   long *len)
  871 {
  872     char *buf = buffer + HEADER_LEN;    /* leave room for the header-length-indicator */
  873     long size;
  874 
  875     RESERVE_SPACE_FOR_HEADER(len);
  876 
  877     buf = writePDUType(queryResponse->PDUType,
  878                buf,
  879                len);
  880     buf = writeBinaryInteger(queryResponse->SearchStatus,
  881                  (size_t) 1,
  882                  buf,
  883                  len);
  884     buf = writeBinaryInteger(queryResponse->ResultCount,
  885                  (size_t) 3,
  886                  buf,
  887                  len);
  888     buf = writeBinaryInteger(queryResponse->NumberOfRecordsReturned,
  889                  (size_t) 3,
  890                  buf,
  891                  len);
  892     buf = writeBinaryInteger(queryResponse->NextResultSetPosition,
  893                  (size_t) 3,
  894                  buf,
  895                  len);
  896     buf = writeNum(queryResponse->ResultSetStatus,
  897            DT_ResultSetStatus,
  898            buf,
  899            len);
  900     buf = writeNum(queryResponse->PresentStatus,
  901            DT_PresentStatus,
  902            buf,
  903            len);
  904     buf = writeAny(queryResponse->ReferenceID,
  905            DT_ReferenceID,
  906            buf,
  907            len);
  908 
  909     /* go back and write the header-length-indicator */
  910     RELEASE_HEADER_SPACE(len);
  911     size = buf - buffer - HEADER_LEN;
  912     writeBinaryInteger(size, HEADER_LEN, buffer, len);
  913 
  914     if (queryResponse->DatabaseDiagnosticRecords != NULL)
  915     buf = writeSearchResponseInfo(queryResponse, buf, len);
  916 
  917     return (buf);
  918 }
  919 
  920 /*----------------------------------------------------------------------*/
  921 
  922 char *readSearchResponseAPDU(SearchResponseAPDU **queryResponse, char *buffer)
  923 {
  924     char *buf = buffer;
  925     long size;
  926     pdu_type pduType;
  927     long result, count, recordsReturned, nextPos;
  928     long resultStatus, presentStatus;
  929     any *refID = NULL;
  930     void *userInfo = NULL;
  931 
  932     /* read required part */
  933     buf = readBinaryInteger(&size, HEADER_LEN, buf);
  934     buf = readPDUType(&pduType, buf);
  935     buf = readBinaryInteger(&result, (size_t) 1, buf);
  936     buf = readBinaryInteger(&count, (size_t) 3, buf);
  937     buf = readBinaryInteger(&recordsReturned, (size_t) 3, buf);
  938     buf = readBinaryInteger(&nextPos, (size_t) 3, buf);
  939 
  940     resultStatus = presentStatus = UNUSED;
  941     refID = NULL;
  942 
  943     /* read optional part */
  944     while (buf < (buffer + size + HEADER_LEN)) {
  945     data_tag tag = peekTag(buf);
  946 
  947     switch (tag) {
  948     case DT_ResultSetStatus:
  949         buf = readNum(&resultStatus, buf);
  950         break;
  951     case DT_PresentStatus:
  952         buf = readNum(&presentStatus, buf);
  953         break;
  954     case DT_ReferenceID:
  955         buf = readAny(&refID, buf);
  956         break;
  957     default:
  958         freeAny(refID);
  959         REPORT_READ_ERROR(buf);
  960         break;
  961     }
  962     }
  963 
  964     buf = readSearchResponseInfo(&userInfo, buf);
  965     if (buf == NULL)
  966     freeAny(refID);
  967     RETURN_ON_NULL(buf);
  968 
  969     /* construct the search object */
  970     *queryResponse = makeSearchResponseAPDU(result,
  971                         count,
  972                         recordsReturned,
  973                         nextPos,
  974                         (long) resultStatus,
  975                         (long) presentStatus,
  976                         refID,
  977                         userInfo);
  978 
  979     freeAny(refID);
  980 
  981     return (buf);
  982 }
  983 
  984 /*
  985  *  Routines originally from ZUtil.c -- FM
  986  *
  987  *----------------------------------------------------------------------*/
  988 /* WIDE AREA INFORMATION SERVER SOFTWARE:
  989  * No guarantees or restrictions.  See the readme file for the full standard
  990  * disclaimer.
  991  *
  992  * 3.26.90  Harry Morris, morris@think.com
  993  * 3.30.90  Harry Morris - Changed any->bits to any->bytes
  994  * 4.11.90  HWM - fixed include file names, changed
  995  *      - writeCompressedIntegerWithPadding() to
  996  *        writeCompressedIntWithPadding()
  997  *      - generalized conditional includes (see c-dialect.h)
  998  * 3.7.91   Jonny Goldman.  Replaced "short" in makeBitMap with "int" line 632.
  999  */
 1000 
 1001 char *readErrorPosition = NULL; /* pos where buf stoped making sense */
 1002 
 1003 /*----------------------------------------------------------------------*/
 1004 /* A note on error handling
 1005    read - these are low level routines, they do not check the type tags
 1006    which (sometimes) preceed the data (this is done by the higher
 1007    level functions which call these functions).  There is no
 1008    attempt made to check that the reading does not exceed the read
 1009    buffer.  Such cases should be very rare and usually will be
 1010    caught by the calling functions. (note - it is unlikely that
 1011    a series of low level reads will go far off the edge without
 1012    triggering a type error.  However, it is possible for a single
 1013    bad read in an array function (eg. readAny) to attempt to read a
 1014    large ammount, possibly causing a segmentation violation or out
 1015    of memory condition.
 1016  */
 1017 /*----------------------------------------------------------------------*/
 1018 
 1019 diagnosticRecord *makeDiag(boolean surrogate, char *code, char *addInfo)
 1020 {
 1021     diagnosticRecord *diag =
 1022     (diagnosticRecord *) s_malloc((size_t) sizeof(diagnosticRecord));
 1023 
 1024     diag->SURROGATE = surrogate;
 1025     MemCpy(diag->DIAG, code, DIAGNOSTIC_CODE_SIZE);
 1026     diag->ADDINFO = s_strdup(addInfo);
 1027 
 1028     return (diag);
 1029 }
 1030 
 1031 /*----------------------------------------------------------------------*/
 1032 
 1033 void freeDiag(diagnosticRecord * diag)
 1034 {
 1035     if (diag != NULL) {
 1036     if (diag->ADDINFO != NULL)
 1037         s_free(diag->ADDINFO);
 1038     s_free(diag);
 1039     }
 1040 }
 1041 
 1042 /*----------------------------------------------------------------------*/
 1043 
 1044 #define END_OF_RECORD   0x1D
 1045 
 1046 char *writeDiag(diagnosticRecord * diag, char *buffer, long *len)
 1047 /* diagnostics (as per Appendix D) have a very weird format - this changes
 1048    in SR-1
 1049  */
 1050 {
 1051     char *buf = buffer;
 1052     long length;
 1053 
 1054     if (diag == NULL)       /* handle unspecified optional args */
 1055     return (buf);
 1056 
 1057     buf = writeTag(DT_DatabaseDiagnosticRecords, buf, len);
 1058     CHECK_FOR_SPACE_LEFT(0, len);
 1059 
 1060     length = 3;
 1061     if (diag->ADDINFO != NULL)
 1062     length += strlen(diag->ADDINFO);
 1063 
 1064     if (length >= 0xFFFF)   /* make sure the length is reasonable */
 1065     {
 1066     length = 0xFFFF - 1;
 1067     diag->ADDINFO[0xFFFF - 3 - 1] = '\0';
 1068     }
 1069 
 1070     buf = writeBinaryInteger(length, 2, buf, len);
 1071 
 1072     CHECK_FOR_SPACE_LEFT(1, len);
 1073     buf[0] = diag->DIAG[0];
 1074     buf++;
 1075 
 1076     CHECK_FOR_SPACE_LEFT(1, len);
 1077     buf[0] = diag->DIAG[1];
 1078     buf++;
 1079 
 1080     if (length > 3) {
 1081     CHECK_FOR_SPACE_LEFT(3, len);
 1082     MemCpy(buf, diag->ADDINFO, length - 3);
 1083     buf += length - 3;
 1084     }
 1085 
 1086     CHECK_FOR_SPACE_LEFT(1, len);
 1087     buf[0] = diag->SURROGATE;
 1088     buf++;
 1089 
 1090     CHECK_FOR_SPACE_LEFT(1, len);
 1091     buf[0] = END_OF_RECORD;
 1092     buf++;
 1093 
 1094     return (buf);
 1095 }
 1096 
 1097 /*----------------------------------------------------------------------*/
 1098 
 1099 char *readDiag(diagnosticRecord ** diag, char *buffer)
 1100 {
 1101     char *buf = buffer;
 1102     diagnosticRecord *d = (diagnosticRecord *) s_malloc((size_t) sizeof(diagnosticRecord));
 1103     data_tag tag;
 1104     long len;
 1105 
 1106     buf = readTag(&tag, buf);
 1107 
 1108     buf = readBinaryInteger(&len, 2, buf);
 1109 
 1110     d->DIAG[0] = buf[0];
 1111     d->DIAG[1] = buf[1];
 1112     d->DIAG[2] = '\0';
 1113 
 1114     if (len > 3) {
 1115     d->ADDINFO = (char *) s_malloc((size_t) (len - 3 + 1));
 1116     MemCpy(d->ADDINFO, (char *) (buf + 2), len - 3);
 1117     d->ADDINFO[len - 3] = '\0';
 1118     } else
 1119     d->ADDINFO = NULL;
 1120 
 1121     d->SURROGATE = buf[len - 1];
 1122 
 1123     *diag = d;
 1124 
 1125     return (buf + len + 1);
 1126 }
 1127 
 1128 /*----------------------------------------------------------------------*/
 1129 
 1130 #define continueBit 0x80
 1131 #define dataMask    0x7F
 1132 #define dataBits    7
 1133 
 1134 char *writeCompressedInteger(unsigned long num, char *buf, long *len)
 1135 /* write a binary integer in the format described on p. 40.
 1136    this might be sped up
 1137 */
 1138 {
 1139     char byte;
 1140     unsigned long i;
 1141     unsigned long size;
 1142 
 1143     size = writtenCompressedIntSize(num);
 1144     CHECK_FOR_SPACE_LEFT(size, len);
 1145 
 1146     for (i = size - 1; i != 0; i--) {
 1147     byte = num & dataMask;
 1148     if (i != (size - 1))    /* turn on continue bit */
 1149         byte = (char) (byte | continueBit);
 1150     buf[i] = byte;
 1151     num = num >> dataBits;  /* don't and here */
 1152     }
 1153 
 1154     return (buf + size);
 1155 }
 1156 
 1157 /*----------------------------------------------------------------------*/
 1158 
 1159 char *readCompressedInteger(unsigned long *num, char *buf)
 1160 /* read a binary integer in the format described on p. 40.
 1161    this might be sped up
 1162 */
 1163 {
 1164     long i = 0;
 1165     unsigned char byte;
 1166 
 1167     *num = 0;
 1168 
 1169     do {
 1170     byte = buf[i++];
 1171     *num = *num << dataBits;
 1172     *num += (byte & dataMask);
 1173     }
 1174     while (byte & continueBit);
 1175 
 1176     return (buf + i);
 1177 }
 1178 
 1179 /*----------------------------------------------------------------------*/
 1180 
 1181 #define pad 128     /* high bit is set */
 1182 
 1183 char *writeCompressedIntWithPadding(unsigned long num,
 1184                     unsigned long size,
 1185                     char *buffer,
 1186                     long *len)
 1187 /* Like writeCompressedInteger, except writes padding (128) to make
 1188    sure that size bytes are used.  This can be read correctly by
 1189    readCompressedInteger()
 1190 */
 1191 {
 1192     char *buf = buffer;
 1193     unsigned long needed, padding;
 1194     long i;
 1195 
 1196     CHECK_FOR_SPACE_LEFT(size, len);
 1197 
 1198     needed = writtenCompressedIntSize(num);
 1199     padding = size - needed;
 1200     i = padding - 1;
 1201 
 1202     for (i = padding - 1; i >= 0; i--) {
 1203     buf[i] = pad;
 1204     }
 1205 
 1206     buf = writeCompressedInteger(num, buf + padding, len);
 1207 
 1208     return (buf);
 1209 }
 1210 
 1211 /*----------------------------------------------------------------------*/
 1212 
 1213 unsigned long writtenCompressedIntSize(unsigned long num)
 1214 /* return the number of bytes needed to represnet the value num in
 1215    compressed format.  curently limited to 4 bytes
 1216  */
 1217 {
 1218     if (num < CompressedInt1Byte)
 1219     return (1);
 1220     else if (num < CompressedInt2Byte)
 1221     return (2);
 1222     else if (num < CompressedInt3Byte)
 1223     return (3);
 1224     else
 1225     return (4);
 1226 }
 1227 
 1228 /*----------------------------------------------------------------------*/
 1229 
 1230 char *writeTag(data_tag tag, char *buf, long *len)
 1231 /* write out a data tag */
 1232 {
 1233     return (writeCompressedInteger(tag, buf, len));
 1234 }
 1235 
 1236 /*----------------------------------------------------------------------*/
 1237 
 1238 char *readTag(data_tag *tag, char *buf)
 1239 /* read a data tag */
 1240 {
 1241     return (readCompressedInteger(tag, buf));
 1242 }
 1243 
 1244 /*----------------------------------------------------------------------*/
 1245 
 1246 unsigned long writtenTagSize(data_tag tag)
 1247 {
 1248     return (writtenCompressedIntSize(tag));
 1249 }
 1250 
 1251 /*----------------------------------------------------------------------*/
 1252 
 1253 data_tag peekTag(char *buf)
 1254 /* read a data tag without advancing the buffer */
 1255 {
 1256     data_tag tag;
 1257 
 1258     readTag(&tag, buf);
 1259     return (tag);
 1260 }
 1261 
 1262 /*----------------------------------------------------------------------*/
 1263 
 1264 any *makeAny(unsigned long size, char *data)
 1265 {
 1266     any *a = (any *) s_malloc((size_t) sizeof(any));
 1267 
 1268     a->size = size;
 1269     a->bytes = data;
 1270     return (a);
 1271 }
 1272 
 1273 /*----------------------------------------------------------------------*/
 1274 
 1275 void freeAny(any *a)
 1276 /* destroy an any and its associated data.  Assumes a->bytes was
 1277    allocated using the s_malloc family of libraries
 1278  */
 1279 {
 1280     if (a != NULL) {
 1281     if (a->bytes != NULL)
 1282         s_free(a->bytes);
 1283     s_free(a);
 1284     }
 1285 }
 1286 
 1287 /*----------------------------------------------------------------------*/
 1288 
 1289 any *duplicateAny(any *a)
 1290 {
 1291     any *copy = NULL;
 1292 
 1293     if (a == NULL)
 1294     return (NULL);
 1295 
 1296     copy = (any *) s_malloc((size_t) sizeof(any));
 1297 
 1298     copy->size = a->size;
 1299     if (a->bytes == NULL)
 1300     copy->bytes = NULL;
 1301     else {
 1302     copy->bytes = (char *) s_malloc((size_t) copy->size);
 1303     MemCpy(copy->bytes, a->bytes, copy->size);
 1304     }
 1305     return (copy);
 1306 }
 1307 
 1308 /*----------------------------------------------------------------------*/
 1309 
 1310 char *writeAny(any *a, data_tag tag, char *buffer, long *len)
 1311 /* write an any + tag and size info */
 1312 {
 1313     char *buf = buffer;
 1314 
 1315     if (a == NULL)      /* handle unspecified optional args */
 1316     return (buf);
 1317 
 1318     /* write the tags */
 1319     buf = writeTag(tag, buf, len);
 1320     buf = writeCompressedInteger(a->size, buf, len);
 1321 
 1322     /* write the bytes */
 1323     CHECK_FOR_SPACE_LEFT(a->size, len);
 1324     MemCpy(buf, a->bytes, a->size);
 1325 
 1326     return (buf + a->size);
 1327 }
 1328 
 1329 /*----------------------------------------------------------------------*/
 1330 
 1331 char *readAny(any **anAny, char *buffer)
 1332 /* read an any + tag and size info */
 1333 {
 1334     char *buf;
 1335     any *a;
 1336     data_tag tag;
 1337 
 1338     a = (any *) s_malloc((size_t) sizeof(any));
 1339 
 1340     buf = buffer;
 1341 
 1342     buf = readTag(&tag, buf);
 1343 
 1344     buf = readCompressedInteger(&a->size, buf);
 1345 
 1346     /* now simply copy the bytes */
 1347     a->bytes = (char *) s_malloc((size_t) a->size);
 1348     MemCpy(a->bytes, buf, a->size);
 1349     *anAny = a;
 1350 
 1351     return (buf + a->size);
 1352 }
 1353 
 1354 /*----------------------------------------------------------------------*/
 1355 
 1356 unsigned long writtenAnySize(data_tag tag, any *a)
 1357 {
 1358     unsigned long size;
 1359 
 1360     if (a == NULL)
 1361     return (0);
 1362 
 1363     size = writtenTagSize(tag);
 1364     size += writtenCompressedIntSize(a->size);
 1365     size += a->size;
 1366     return (size);
 1367 }
 1368 
 1369 /*----------------------------------------------------------------------*/
 1370 
 1371 any *stringToAny(char *s)
 1372 {
 1373     any *a = NULL;
 1374 
 1375     if (s == NULL)
 1376     return (NULL);
 1377 
 1378     a = (any *) s_malloc((size_t) sizeof(any));
 1379 
 1380     a->size = strlen(s);
 1381     a->bytes = (char *) s_malloc((size_t) a->size);
 1382     MemCpy(a->bytes, s, a->size);
 1383     return (a);
 1384 }
 1385 
 1386 /*----------------------------------------------------------------------*/
 1387 
 1388 char *anyToString(any *a)
 1389 {
 1390     char *s = NULL;
 1391 
 1392     if (a == NULL)
 1393     return (NULL);
 1394 
 1395     s = s_malloc((size_t) (a->size + 1));
 1396     MemCpy(s, a->bytes, a->size);
 1397     s[a->size] = '\0';
 1398     return (s);
 1399 }
 1400 
 1401 /*----------------------------------------------------------------------*/
 1402 
 1403 char *writeString(char *s, data_tag tag, char *buffer, long *len)
 1404 /* Write a C style string.  The terminating null is not written.
 1405    This function is not part of the Z39.50 spec.  It is provided
 1406    for the convienience of those wishing to pass C strings in
 1407    the place of an any.
 1408  */
 1409 {
 1410     char *buf = buffer;
 1411     any *data = NULL;
 1412 
 1413     if (s == NULL)
 1414     return (buffer);    /* handle unused optional item before making an any */
 1415     data = (any *) s_malloc((size_t) sizeof(any));
 1416 
 1417     data->size = strlen(s);
 1418     data->bytes = s;        /* save a copy here by not using stringToAny() */
 1419     buf = writeAny(data, tag, buf, len);
 1420     s_free(data);       /* don't use freeAny() since it will free s too */
 1421     return (buf);
 1422 }
 1423 
 1424 /*----------------------------------------------------------------------*/
 1425 
 1426 char *readString(char **s, char *buffer)
 1427 /* Read an any and convert it into a C style string.
 1428    This function is not part of the Z39.50 spec.  It is provided
 1429    for the convienience of those wishing to pass C strings in
 1430    the place of an any.
 1431  */
 1432 {
 1433     any *data = NULL;
 1434     char *buf = readAny(&data, buffer);
 1435 
 1436     *s = anyToString(data);
 1437     freeAny(data);
 1438     return (buf);
 1439 }
 1440 
 1441 /*----------------------------------------------------------------------*/
 1442 
 1443 unsigned long writtenStringSize(data_tag tag, char *s)
 1444 {
 1445     unsigned long size;
 1446 
 1447     if (s == NULL)
 1448     return (0);
 1449 
 1450     size = writtenTagSize(tag);
 1451     size += writtenCompressedIntSize(size);
 1452     size += strlen(s);
 1453     return (size);
 1454 }
 1455 
 1456 /*----------------------------------------------------------------------*/
 1457 
 1458 any *longToAny(long num)
 1459 /* a convienience function */
 1460 {
 1461     char s[40];
 1462 
 1463     sprintf(s, "%ld", num);
 1464 
 1465     return (stringToAny(s));
 1466 }
 1467 
 1468 /*----------------------------------------------------------------------*/
 1469 
 1470 long anyToLong(any *a)
 1471 /* a convienience function */
 1472 {
 1473     long num;
 1474     char *str = NULL;
 1475 
 1476     str = anyToString(a);
 1477     sscanf(str, "%ld", &num);   /* could check the result and return
 1478                    an error */
 1479     s_free(str);
 1480     return (num);
 1481 }
 1482 
 1483 /*----------------------------------------------------------------------*/
 1484 
 1485 #define bitsPerByte 8
 1486 
 1487 bit_map *makeBitMap(unsigned long numBits, ...)
 1488 /* construct and return a bitmap with numBits elements */
 1489 {
 1490     va_list ap;
 1491     unsigned long i, j;
 1492     bit_map *bm = NULL;
 1493 
 1494     LYva_start(ap, numBits);
 1495 
 1496     bm = (bit_map *) s_malloc((size_t) sizeof(bit_map));
 1497 
 1498     bm->size = (unsigned long) (ceil((double) numBits / bitsPerByte));
 1499     bm->bytes = (char *) s_malloc((size_t) bm->size);
 1500 
 1501     /* fill up the bits */
 1502     for (i = 0; i < bm->size; i++)  /* iterate over bytes */
 1503     {
 1504     char byte = 0;
 1505 
 1506     for (j = 0; j < bitsPerByte; j++)   /* iterate over bits */
 1507     {
 1508         if ((i * bitsPerByte + j) < numBits) {
 1509         boolean bit = false;
 1510 
 1511         bit = (boolean) va_arg(ap, boolean);
 1512 
 1513         if (bit) {
 1514             byte = byte | (1 << (bitsPerByte - j - 1));
 1515         }
 1516         }
 1517     }
 1518     bm->bytes[i] = byte;
 1519     }
 1520 
 1521     va_end(ap);
 1522     return (bm);
 1523 }
 1524 
 1525 /*----------------------------------------------------------------------*/
 1526 
 1527 void freeBitMap(bit_map *bm)
 1528 /* destroy a bit map created by makeBitMap() */
 1529 {
 1530     s_free(bm->bytes);
 1531     s_free(bm);
 1532 }
 1533 
 1534 /*----------------------------------------------------------------------*/
 1535 
 1536 /* use this routine to interpret a bit map.  pos specifies the bit
 1537    number.  bit 0 is the Leftmost bit of the first byte.
 1538    Could do bounds checking.
 1539  */
 1540 
 1541 boolean bitAtPos(unsigned long pos, bit_map *bm)
 1542 {
 1543     if (pos > bm->size * bitsPerByte)
 1544     return false;
 1545     else
 1546     return ((bm->bytes[(pos / bitsPerByte)] &
 1547          (0x80 >> (pos % bitsPerByte))) ?
 1548         true : false);
 1549 }
 1550 
 1551 /*----------------------------------------------------------------------*/
 1552 
 1553 char *writeBitMap(bit_map *bm, data_tag tag, char *buffer, long *len)
 1554 /* write a bitmap + type and size info */
 1555 {
 1556     return (writeAny((any *) bm, tag, buffer, len));
 1557 }
 1558 
 1559 /*----------------------------------------------------------------------*/
 1560 
 1561 char *readBitMap(bit_map **bm, char *buffer)
 1562 /* read a bitmap + type and size info */
 1563 {
 1564     char *c;
 1565 
 1566     c = readAny((any **) bm, buffer);
 1567     return (c);
 1568 }
 1569 
 1570 /*----------------------------------------------------------------------*/
 1571 
 1572 char *writeByte(unsigned long byte, char *buf, long *len)
 1573 {
 1574     CHECK_FOR_SPACE_LEFT(1, len);
 1575     buf[0] = byte & 0xFF;   /* we really only want the first byte */
 1576     return (buf + 1);
 1577 }
 1578 
 1579 /*----------------------------------------------------------------------*/
 1580 
 1581 char *readByte(unsigned char *byte, char *buf)
 1582 {
 1583     *byte = buf[0];
 1584     return (buf + 1);
 1585 }
 1586 
 1587 /*----------------------------------------------------------------------*/
 1588 
 1589 char *writeBoolean(boolean flag, char *buf, long *len)
 1590 {
 1591     return (writeByte(flag, buf, len));
 1592 }
 1593 
 1594 /*----------------------------------------------------------------------*/
 1595 
 1596 char *readBoolean(boolean *flag, char *buffer)
 1597 {
 1598     unsigned char byte;
 1599     char *buf = readByte(&byte, buffer);
 1600 
 1601     *flag = (byte == true) ? true : false;
 1602     return (buf);
 1603 }
 1604 
 1605 /*----------------------------------------------------------------------*/
 1606 
 1607 char *writePDUType(pdu_type pduType, char *buf, long *len)
 1608 /* PDUType is a single byte */
 1609 {
 1610     return (writeBinaryInteger((long) pduType, (unsigned long) 1, buf, len));
 1611 }
 1612 
 1613 /*----------------------------------------------------------------------*/
 1614 
 1615 char *readPDUType(pdu_type *pduType, char *buf)
 1616 /* PDUType is a single byte */
 1617 {
 1618     return (readBinaryInteger((long *) pduType, (unsigned long) 1, buf));
 1619 }
 1620 
 1621 /*----------------------------------------------------------------------*/
 1622 
 1623 pdu_type peekPDUType(char *buf)
 1624 /* read the next pdu without advancing the buffer, Note that this
 1625    function is to be used on a buffer that is known to contain an
 1626    APDU.  The pdu_type is written HEADER_LEN bytes into the buffer
 1627  */
 1628 {
 1629     pdu_type pdu;
 1630 
 1631     readPDUType(&pdu, buf + HEADER_LEN);
 1632     return (pdu);
 1633 }
 1634 
 1635 /*----------------------------------------------------------------------*/
 1636 
 1637 #define BINARY_INTEGER_BYTES    sizeof(long)    /* the number of bytes used by
 1638                            a "binary integer" */
 1639 char *writeBinaryInteger(long num, unsigned long size, char *buf, long *len)
 1640 /* write out first size bytes of num - no type info
 1641   XXX should this take unsigned longs instead ???  */
 1642 {
 1643     long i;
 1644     char byte;
 1645 
 1646     if (size < 1 || size > BINARY_INTEGER_BYTES)
 1647     return (NULL);      /* error */
 1648 
 1649     CHECK_FOR_SPACE_LEFT(size, len);
 1650 
 1651     for (i = size - 1; i >= 0; i--) {
 1652     byte = (char) (num & 255);
 1653     buf[i] = byte;
 1654     num = num >> bitsPerByte;   /* don't and here */
 1655     }
 1656 
 1657     return (buf + size);
 1658 }
 1659 
 1660 /*----------------------------------------------------------------------*/
 1661 
 1662 char *readBinaryInteger(long *num, unsigned long size, char *buf)
 1663 /* read in first size bytes of num - no type info
 1664   XXX this should take unsigned longs instead !!! */
 1665 {
 1666     unsigned long i;
 1667     unsigned char byte;
 1668 
 1669     if (size < 1 || size > BINARY_INTEGER_BYTES)
 1670     return (buf);       /* error */
 1671     *num = 0;
 1672 
 1673     for (i = 0; i < size; i++) {
 1674     byte = buf[i];
 1675     *num = *num << bitsPerByte;
 1676     *num += byte;
 1677     }
 1678 
 1679     return (buf + size);
 1680 }
 1681 
 1682 /*----------------------------------------------------------------------*/
 1683 
 1684 unsigned long writtenCompressedBinIntSize(long num)
 1685 /* return the number of bytes needed to represent the value num.
 1686    currently limited to max of 4 bytes
 1687    Only compresses for positive nums - negatives get whole 4 bytes
 1688  */
 1689 {
 1690     if (num < 0L)
 1691     return (4);
 1692     else if (num < 256L)    /* 2**8 */
 1693     return (1);
 1694     else if (num < 65536L)  /* 2**16 */
 1695     return (2);
 1696     else if (num < 16777216L)   /* 2**24 */
 1697     return (3);
 1698     else
 1699     return (4);
 1700 }
 1701 
 1702 /*----------------------------------------------------------------------*/
 1703 
 1704 char *writeNum(long num, data_tag tag, char *buffer, long *len)
 1705 /* write a binary integer + size and tag info */
 1706 {
 1707     char *buf = buffer;
 1708     long size = writtenCompressedBinIntSize(num);
 1709 
 1710     if (num == UNUSED)
 1711     return (buffer);
 1712 
 1713     buf = writeTag(tag, buf, len);
 1714     buf = writeCompressedInteger(size, buf, len);
 1715     buf = writeBinaryInteger(num, (unsigned long) size, buf, len);
 1716     return (buf);
 1717 }
 1718 
 1719 /*----------------------------------------------------------------------*/
 1720 
 1721 char *readNum(long *num, char *buffer)
 1722 /* read a binary integer + size and tag info */
 1723 {
 1724     char *buf = buffer;
 1725     data_tag tag;
 1726     unsigned long size;
 1727     unsigned long val;
 1728 
 1729     buf = readTag(&tag, buf);
 1730     buf = readCompressedInteger(&val, buf);
 1731     size = (unsigned long) val;
 1732     buf = readBinaryInteger(num, size, buf);
 1733     return (buf);
 1734 }
 1735 
 1736 /*----------------------------------------------------------------------*/
 1737 
 1738 unsigned long writtenNumSize(data_tag tag, long num)
 1739 {
 1740     long dataSize = writtenCompressedBinIntSize(num);
 1741     long size;
 1742 
 1743     size = writtenTagSize(tag); /* space for the tag */
 1744     size += writtenCompressedIntSize(dataSize);     /* space for the size */
 1745     size += dataSize;       /* space for the data */
 1746 
 1747     return (size);
 1748 }
 1749 
 1750 /*----------------------------------------------------------------------*/
 1751 
 1752 typedef void (voidfunc) (void *);
 1753 
 1754 void doList(void **list, voidfunc * func)
 1755 /* call func on each element of the NULL terminated list of pointers */
 1756 {
 1757     register long i;
 1758     register void *ptr = NULL;
 1759 
 1760     if (list == NULL)
 1761     return;
 1762     for (i = 0, ptr = list[i]; ptr != NULL; ptr = list[++i])
 1763     (*func) (ptr);
 1764 }
 1765 
 1766 /*----------------------------------------------------------------------*/
 1767 
 1768 char *writeProtocolVersion(char *buf, long *len)
 1769 /* write a bitmap describing the protocols available */
 1770 {
 1771     static bit_map *version = NULL;
 1772 
 1773     if (version == NULL) {
 1774     version = makeBitMap((unsigned long) 1, true);  /* version 1! */
 1775     }
 1776 
 1777     return (writeBitMap(version, DT_ProtocolVersion, buf, len));
 1778 }
 1779 
 1780 /*----------------------------------------------------------------------*/
 1781 
 1782 char *defaultImplementationID(void)
 1783 {
 1784     static char ImplementationID[] = "TMC";
 1785 
 1786     return (ImplementationID);
 1787 }
 1788 
 1789 /*----------------------------------------------------------------------*/
 1790 
 1791 char *defaultImplementationName(void)
 1792 {
 1793     static char ImplementationName[] = "Thinking Machines Corporation Z39.50";
 1794 
 1795     return (ImplementationName);
 1796 }
 1797 
 1798 /*----------------------------------------------------------------------*/
 1799 
 1800 char *defaultImplementationVersion(void)
 1801 {
 1802     static char ImplementationVersion[] = "2.0A";
 1803 
 1804     return (ImplementationVersion);
 1805 }
 1806 
 1807 /*----------------------------------------------------------------------*/
 1808 
 1809 /*
 1810  *  Routines originally from ZType1.c -- FM
 1811  *
 1812  *----------------------------------------------------------------------*/
 1813 /* WIDE AREA INFORMATION SERVER SOFTWARE:
 1814  * No guarantees or restrictions.  See the readme file for the full standard
 1815  * disclaimer.
 1816  *
 1817  * 3.26.90  Harry Morris, morris@think.com
 1818  * 4.11.90  HWM - generalized conditional includes (see c-dialect.h)
 1819  */
 1820 /*----------------------------------------------------------------------*/
 1821 
 1822 query_term *makeAttributeTerm(char *use,
 1823                   char *relation,
 1824                   char *position,
 1825                   char *structure,
 1826                   char *truncation,
 1827                   char *completeness,
 1828                   any *term)
 1829 {
 1830     query_term *qt = (query_term *) s_malloc((size_t) sizeof(query_term));
 1831 
 1832     qt->TermType = TT_Attribute;
 1833 
 1834     /* copy in the attributes */
 1835     LYStrNCpy(qt->Use, use, ATTRIBUTE_SIZE);
 1836     LYStrNCpy(qt->Relation, relation, ATTRIBUTE_SIZE);
 1837     LYStrNCpy(qt->Position, position, ATTRIBUTE_SIZE);
 1838     LYStrNCpy(qt->Structure, structure, ATTRIBUTE_SIZE);
 1839     LYStrNCpy(qt->Truncation, truncation, ATTRIBUTE_SIZE);
 1840     LYStrNCpy(qt->Completeness, completeness, ATTRIBUTE_SIZE);
 1841 
 1842     qt->Term = duplicateAny(term);
 1843 
 1844     qt->ResultSetID = NULL;
 1845 
 1846     return (qt);
 1847 }
 1848 
 1849 /*----------------------------------------------------------------------*/
 1850 
 1851 query_term *makeResultSetTerm(any *resultSet)
 1852 {
 1853     query_term *qt = (query_term *) s_malloc((size_t) sizeof(query_term));
 1854 
 1855     qt->TermType = TT_ResultSetID;
 1856 
 1857     qt->ResultSetID = duplicateAny(resultSet);
 1858 
 1859     qt->Term = NULL;
 1860 
 1861     return (qt);
 1862 }
 1863 
 1864 /*----------------------------------------------------------------------*/
 1865 
 1866 query_term *makeOperatorTerm(char *operatorCode)
 1867 {
 1868     query_term *qt = (query_term *) s_malloc((size_t) sizeof(query_term));
 1869 
 1870     qt->TermType = TT_Operator;
 1871 
 1872     LYStrNCpy(qt->Operator, operatorCode, OPERATOR_SIZE);
 1873 
 1874     qt->Term = NULL;
 1875     qt->ResultSetID = NULL;
 1876 
 1877     return (qt);
 1878 }
 1879 
 1880 /*----------------------------------------------------------------------*/
 1881 
 1882 void freeTerm(void *param)
 1883 {
 1884     query_term *qt = (query_term *) param;
 1885 
 1886     switch (qt->TermType) {
 1887     case TT_Attribute:
 1888     freeAny(qt->Term);
 1889     break;
 1890     case TT_ResultSetID:
 1891     freeAny(qt->ResultSetID);
 1892     break;
 1893     case TT_Operator:
 1894     /* do nothing */
 1895     break;
 1896     default:
 1897     panic("Implementation error: Unknown term type %ld",
 1898           qt->TermType);
 1899     break;
 1900     }
 1901     s_free(qt);
 1902 }
 1903 
 1904 /*----------------------------------------------------------------------*/
 1905 
 1906 #define ATTRIBUTE_LIST_SIZE ATTRIBUTE_SIZE * 6
 1907 #define AT_DELIMITER    " "
 1908 
 1909 char *writeQueryTerm(query_term *qt, char *buffer, long *len)
 1910 {
 1911     char *buf = buffer;
 1912     char attributes[ATTRIBUTE_LIST_SIZE];
 1913 
 1914     switch (qt->TermType) {
 1915     case TT_Attribute:
 1916     LYStrNCpy(attributes, qt->Use, ATTRIBUTE_LIST_SIZE);
 1917     s_strncat(attributes, AT_DELIMITER, sizeof(AT_DELIMITER) + 1, ATTRIBUTE_LIST_SIZE);
 1918     s_strncat(attributes, qt->Relation, ATTRIBUTE_SIZE, ATTRIBUTE_LIST_SIZE);
 1919     s_strncat(attributes, AT_DELIMITER, sizeof(AT_DELIMITER) + 1, ATTRIBUTE_LIST_SIZE);
 1920     s_strncat(attributes, qt->Position, ATTRIBUTE_SIZE, ATTRIBUTE_LIST_SIZE);
 1921     s_strncat(attributes, AT_DELIMITER, sizeof(AT_DELIMITER) + 1, ATTRIBUTE_LIST_SIZE);
 1922     s_strncat(attributes, qt->Structure, ATTRIBUTE_SIZE, ATTRIBUTE_LIST_SIZE);
 1923     s_strncat(attributes, AT_DELIMITER, sizeof(AT_DELIMITER) + 1, ATTRIBUTE_LIST_SIZE);
 1924     s_strncat(attributes, qt->Truncation, ATTRIBUTE_SIZE, ATTRIBUTE_LIST_SIZE);
 1925     s_strncat(attributes, AT_DELIMITER, sizeof(AT_DELIMITER) + 1, ATTRIBUTE_LIST_SIZE);
 1926     s_strncat(attributes, qt->Completeness, ATTRIBUTE_SIZE, ATTRIBUTE_LIST_SIZE);
 1927     buf = writeString(attributes, DT_AttributeList, buf, len);
 1928     buf = writeAny(qt->Term, DT_Term, buf, len);
 1929     break;
 1930     case TT_ResultSetID:
 1931     buf = writeAny(qt->ResultSetID, DT_ResultSetID, buf, len);
 1932     break;
 1933     case TT_Operator:
 1934     buf = writeString(qt->Operator, DT_Operator, buf, len);
 1935     break;
 1936     default:
 1937     panic("Implementation error: Unknown term type %ld",
 1938           qt->TermType);
 1939     break;
 1940     }
 1941 
 1942     return (buf);
 1943 }
 1944 
 1945 /*----------------------------------------------------------------------*/
 1946 
 1947 char *readQueryTerm(query_term **qt, char *buffer)
 1948 {
 1949     char *buf = buffer;
 1950     char *attributeList = NULL;
 1951     char *operator = NULL;
 1952     any *term;
 1953     char *use = NULL;
 1954     char *relation = NULL;
 1955     char *position = NULL;
 1956     char *structure = NULL;
 1957     char *truncation = NULL;
 1958     char *completeness;
 1959     any *resultSetID = NULL;
 1960     data_tag tag;
 1961 
 1962     tag = peekTag(buffer);
 1963 
 1964     switch (tag) {
 1965     case DT_AttributeList:
 1966     buf = readString(&attributeList, buf);
 1967     buf = readAny(&term, buf);
 1968     use = strtok(attributeList, AT_DELIMITER);
 1969     relation = strtok(NULL, AT_DELIMITER);
 1970     position = strtok(NULL, AT_DELIMITER);
 1971     structure = strtok(NULL, AT_DELIMITER);
 1972     truncation = strtok(NULL, AT_DELIMITER);
 1973     completeness = strtok(NULL, AT_DELIMITER);
 1974     *qt = makeAttributeTerm(use, relation, position, structure,
 1975                 truncation, completeness, term);
 1976     s_free(attributeList);
 1977     freeAny(term);
 1978     break;
 1979     case DT_ResultSetID:
 1980     buf = readAny(&resultSetID, buf);
 1981     *qt = makeResultSetTerm(resultSetID);
 1982     freeAny(resultSetID);
 1983     break;
 1984     case DT_Operator:
 1985     buf = readString(&operator, buf);
 1986     *qt = makeOperatorTerm(operator);
 1987     s_free(operator);
 1988     break;
 1989     default:
 1990     REPORT_READ_ERROR(buf);
 1991     break;
 1992     }
 1993 
 1994     return (buf);
 1995 }
 1996 
 1997 /*----------------------------------------------------------------------*/
 1998 
 1999 static unsigned long getQueryTermSize(query_term *qt);
 2000 
 2001 static unsigned long getQueryTermSize(query_term *qt)
 2002 /* figure out how many bytes it will take to write this query */
 2003 {
 2004     unsigned long size = 0;
 2005     static char attributes[] = "11 22 33 44 55 66"; /* we just need this to
 2006 
 2007                                calculate its written
 2008                                size */
 2009 
 2010     switch (qt->TermType) {
 2011     case TT_Attribute:
 2012     size = writtenStringSize(DT_AttributeList, attributes);
 2013     size += writtenAnySize(DT_Term, qt->Term);
 2014     break;
 2015     case TT_ResultSetID:
 2016     size = writtenAnySize(DT_ResultSetID, qt->ResultSetID);
 2017     break;
 2018     case TT_Operator:
 2019     size = writtenStringSize(DT_Operator, qt->Operator);
 2020     break;
 2021     default:
 2022     panic("Implementation error: Unknown term type %ld",
 2023           qt->TermType);
 2024     break;
 2025     }
 2026 
 2027     return (size);
 2028 }
 2029 
 2030 /*----------------------------------------------------------------------*/
 2031 
 2032 /* A query is simply a null terminated list of query terms.  For
 2033    transmission, a query is written into an any which is sent as
 2034    the user information field. */
 2035 
 2036 any *writeQuery(query_term **terms)
 2037 {
 2038     any *info = NULL;
 2039     char *writePos = NULL;
 2040     char *data = NULL;
 2041     unsigned long size = 0;
 2042     long remaining = 0;
 2043     long i;
 2044     query_term *qt = NULL;
 2045 
 2046     if (terms == NULL)
 2047     return (NULL);
 2048 
 2049     /* calculate the size of write buffer */
 2050     for (i = 0, qt = terms[i]; qt != NULL; qt = terms[++i])
 2051     size += getQueryTermSize(qt);
 2052 
 2053     data = (char *) s_malloc((size_t) size);
 2054 
 2055     /* write the terms */
 2056     writePos = data;
 2057     remaining = size;
 2058     for (i = 0, qt = terms[i]; qt != NULL; qt = terms[++i])
 2059     writePos = writeQueryTerm(qt, writePos, &remaining);
 2060 
 2061     info = makeAny(size, data);
 2062 
 2063     return (info);
 2064 }
 2065 
 2066 /*----------------------------------------------------------------------*/
 2067 
 2068 query_term **readQuery(any *info)
 2069 {
 2070     char *readPos = info->bytes;
 2071     query_term **terms = NULL;
 2072     query_term *qt = NULL;
 2073     long numTerms = 0L;
 2074     char tmp[100];
 2075 
 2076     sprintf(tmp, "readquery: bytes: %ld", info->size);
 2077     log_write(tmp);
 2078 
 2079     while (readPos < info->bytes + info->size) {
 2080     readPos = readQueryTerm(&qt, readPos);
 2081 
 2082     if (terms == NULL) {
 2083         terms = (query_term **) s_malloc((size_t) (sizeof(query_term *) * 2));
 2084     } else {
 2085         terms =
 2086         (query_term **) s_realloc((char *) terms,
 2087                       (size_t) (sizeof(query_term *) *
 2088                               (numTerms + 2)));
 2089     }
 2090     if (qt == NULL)
 2091         log_write("qt = null");
 2092     terms[numTerms++] = qt;
 2093     terms[numTerms] = NULL;
 2094     }
 2095 
 2096     return (terms);
 2097 }
 2098 
 2099 /*----------------------------------------------------------------------*/
 2100 
 2101 /*
 2102  *  Routines originally from panic.c -- FM
 2103  *
 2104  *----------------------------------------------------------------------*/
 2105 /* WIDE AREA INFORMATION SERVER SOFTWARE:
 2106  * No guarantees or restrictions.  See the readme file for the full standard
 2107  * disclaimer.
 2108  *
 2109  * Morris@think.com
 2110  */
 2111 
 2112 /* panic is an error system interface.  On the Mac, it will pop
 2113  * up a little window to explain the problem.
 2114  * On a unix box, it will print out the error and call perror()
 2115  */
 2116 
 2117 /*----------------------------------------------------------------------*/
 2118 
 2119 static void exitAction(long error);
 2120 
 2121 static void exitAction(long error GCC_UNUSED)
 2122 {
 2123     exit_immediately(EXIT_SUCCESS);
 2124 }
 2125 
 2126 /*----------------------------------------------------------------------*/
 2127 
 2128 #define PANIC_HEADER "Fatal Error:  "
 2129 
 2130 void panic(char *format, ...)
 2131 {
 2132     va_list ap;         /* the variable arguments */
 2133 
 2134     fprintf(stderr, PANIC_HEADER);
 2135     LYva_start(ap, format); /* init ap */
 2136     vfprintf(stderr, format, ap);   /* print the contents */
 2137     va_end(ap);         /* free ap */
 2138     fflush(stderr);
 2139 
 2140     exitAction(0);
 2141 }
 2142 
 2143 /*----------------------------------------------------------------------*/
 2144 
 2145 /*
 2146  *  Routines originally from cutil.c -- FM
 2147  *
 2148  *----------------------------------------------------------------------*/
 2149 /* Wide AREA INFORMATION SERVER SOFTWARE
 2150  * No guarantees or restrictions.  See the readme file for the full standard
 2151  * disclaimer.
 2152  *
 2153  * 3.26.90  Harry Morris, morris@think.com
 2154  * 4.11.90  HWM - generalized conditional includes (see c-dialect.h)
 2155  */
 2156 
 2157 /*----------------------------------------------------------------------*/
 2158 
 2159 void fs_checkPtr(void *ptr)
 2160 /* If the ptr is NULL, give an error */
 2161 {
 2162     if (ptr == NULL)
 2163     panic("checkPtr found a NULL pointer");
 2164 }
 2165 
 2166 /*----------------------------------------------------------------------*/
 2167 
 2168 void *fs_malloc(size_t size)
 2169 /* does safety checks and optional accounting */
 2170 {
 2171     register void *ptr = NULL;
 2172 
 2173     ptr = (void *) calloc((size_t) size, (size_t) 1);
 2174     s_checkPtr(ptr);
 2175 
 2176     return (ptr);
 2177 }
 2178 
 2179 /*----------------------------------------------------------------------*/
 2180 
 2181 void *fs_realloc(void *ptr, size_t size)
 2182 /* does safety checks and optional accounting
 2183    note - we don't know how big ptr's memory is, so we can't ensure
 2184    that any new memory allocated is NULLed!
 2185  */
 2186 {
 2187     register void *nptr = NULL;
 2188 
 2189     if (ptr == NULL)        /* this is really a malloc */
 2190     return (s_malloc(size));
 2191 
 2192     nptr = (void *) realloc(ptr, size);
 2193     s_checkPtr(ptr);
 2194 
 2195     return (nptr);
 2196 }
 2197 
 2198 /*----------------------------------------------------------------------*/
 2199 
 2200 void fs_free(void *ptr)
 2201 /* does safety checks and optional accounting */
 2202 {
 2203     if (ptr != NULL)        /* some non-ansi compilers/os's cant handle freeing null */
 2204     {               /* if we knew the size of this block of memory, we could clear it - oh well */
 2205     free(ptr);
 2206     ptr = NULL;
 2207     }
 2208 }
 2209 
 2210 /*----------------------------------------------------------------------*/
 2211 
 2212 char *s_strdup(char *s)
 2213 
 2214 /* return a copy of s.  This is identical to the standard library routine
 2215    strdup(), except that it is safe.  If s == NULL or malloc fails,
 2216    appropriate action is taken.
 2217  */
 2218 {
 2219     unsigned long len;
 2220     char *copy = NULL;
 2221 
 2222     if (s == NULL)      /* saftey check to postpone stupid errors */
 2223     return (NULL);
 2224 
 2225     len = strlen(s);        /* length of string - terminator */
 2226     copy = (char *) s_malloc((size_t) (sizeof(char) * (len + 1)));
 2227 
 2228     StrNCpy(copy, s, len + 1);
 2229     return (copy);
 2230 }
 2231 
 2232 /*----------------------------------------------------------------------*/
 2233 
 2234 char *fs_strncat(char *dst, char *src, size_t maxToAdd, size_t maxTotal)
 2235 
 2236 /* like strncat, except the fourth argument limits the maximum total
 2237    length of the resulting string
 2238  */
 2239 {
 2240     size_t dstSize = strlen(dst);
 2241     size_t srcSize = strlen(src);
 2242 
 2243     if (dstSize + srcSize < maxTotal)   /* use regular old strncat */
 2244     return (StrNCat(dst, src, maxToAdd));
 2245     else {
 2246     size_t truncateTo = maxTotal - dstSize - 1;
 2247     char saveChar = src[truncateTo];
 2248     char *result = NULL;
 2249 
 2250     src[truncateTo] = '\0';
 2251     result = StrNCat(dst, src, maxToAdd);
 2252     src[truncateTo] = saveChar;
 2253     return (result);
 2254     }
 2255 }
 2256 
 2257 /*----------------------------------------------------------------------*/
 2258 
 2259 char char_downcase(unsigned long long_ch)
 2260 {
 2261     unsigned char ch = long_ch & 0xFF;  /* just want one byte */
 2262 
 2263     /* when ansi is the way of the world, this can be tolower */
 2264     return (((ch >= 'A') && (ch <= 'Z')) ? (ch + 'a' - 'A') : ch);
 2265 }
 2266 
 2267 char *string_downcase(char *word)
 2268 {
 2269     long i = 0;
 2270 
 2271     while (word[i] != '\0') {
 2272     word[i] = char_downcase((unsigned long) word[i]);
 2273     i++;
 2274     }
 2275     return (word);
 2276 }
 2277 
 2278 /*----------------------------------------------------------------------*/
 2279 #endif /* VMS */