1 /*
2  * $LynxId: HTVMS_WaisUI.c,v 1.21 2020/01/21 22:00:50 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 
log_write(char * s GCC_UNUSED)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  */
generate_search_apdu(char * buff,long * buff_len,char * seed_words,char * database_name,DocObj ** docobjs,long maxDocsRetrieved)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 
generate_retrieval_apdu(char * buff,long * buff_len,any * docID,long chunk_type,long start,long end,char * type,char * database_name)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  */
read_from_stream(int d,char * buf,long nbytes)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 
transport_message(long connection,char * request_message,long request_length,char * response_message,long response_buffer_length)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 */
interpret_message(char * request_message,long request_length,char * response_message,long response_buffer_length,long connection,boolean verbose GCC_UNUSED)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. */
delete_seeker_codes(char * string,long * 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 */
trim_junk(char * headline)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 
makeInitResponseAPDU(boolean result,boolean search,boolean present,boolean deleteIt,boolean accessControl,boolean resourceControl,long prefSize,long maxMsgSize,char * auth,char * id,char * name,char * version,any * refID,void * userInfo)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 
freeInitResponseAPDU(InitResponseAPDU * init)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 
writeInitResponseAPDU(InitResponseAPDU * init,char * buffer,long * len)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 
readInitResponseAPDU(InitResponseAPDU ** init,char * buffer)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 
replyToInitAPDU(InitAPDU * init,boolean result,void * userInfo)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 
makeSearchAPDU(long small,long large,long medium,boolean replace,char * name,char ** databases,char * type,char ** elements,any * refID,void * queryInfo)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 
freeSearchAPDU(SearchAPDU * query)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 
writeSearchAPDU(SearchAPDU * query,char * buffer,long * len)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 
makeSearchResponseAPDU(long result,long count,long recordsReturned,long nextPos,long resultStatus,long presentStatus,any * refID,void * records)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 
freeSearchResponseAPDU(SearchResponseAPDU * queryResponse)861 void freeSearchResponseAPDU(SearchResponseAPDU *queryResponse)
862 {
863     freeAny(queryResponse->ReferenceID);
864     s_free(queryResponse);
865 }
866 
867 /*----------------------------------------------------------------------*/
868 
writeSearchResponseAPDU(SearchResponseAPDU * queryResponse,char * buffer,long * len)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 
readSearchResponseAPDU(SearchResponseAPDU ** queryResponse,char * buffer)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 stopped 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) precede 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 amount, possibly causing a segmentation violation or out
1015    of memory condition.
1016  */
1017 /*----------------------------------------------------------------------*/
1018 
makeDiag(boolean surrogate,char * code,char * addInfo)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 
freeDiag(diagnosticRecord * diag)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 
writeDiag(diagnosticRecord * diag,char * buffer,long * len)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 
readDiag(diagnosticRecord ** diag,char * buffer)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 
writeCompressedInteger(unsigned long num,char * buf,long * len)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 
readCompressedInteger(unsigned long * num,char * buf)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 
writeCompressedIntWithPadding(unsigned long num,unsigned long size,char * buffer,long * len)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 
writtenCompressedIntSize(unsigned long num)1213 unsigned long writtenCompressedIntSize(unsigned long num)
1214 /* return the number of bytes needed to represent the value num in
1215    compressed format.  currently 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 
writeTag(data_tag tag,char * buf,long * len)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 
readTag(data_tag * tag,char * buf)1238 char *readTag(data_tag *tag, char *buf)
1239 /* read a data tag */
1240 {
1241     return (readCompressedInteger(tag, buf));
1242 }
1243 
1244 /*----------------------------------------------------------------------*/
1245 
writtenTagSize(data_tag tag)1246 unsigned long writtenTagSize(data_tag tag)
1247 {
1248     return (writtenCompressedIntSize(tag));
1249 }
1250 
1251 /*----------------------------------------------------------------------*/
1252 
peekTag(char * buf)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 
makeAny(unsigned long size,char * data)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 
freeAny(any * a)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 
duplicateAny(any * a)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 
writeAny(any * a,data_tag tag,char * buffer,long * len)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 
readAny(any ** anAny,char * buffer)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 
writtenAnySize(data_tag tag,any * a)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 
stringToAny(char * s)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 
anyToString(any * a)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 
writeString(char * s,data_tag tag,char * buffer,long * len)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 convenience 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 
readString(char ** s,char * buffer)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 convenience 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 
writtenStringSize(data_tag tag,char * s)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 
longToAny(long num)1458 any *longToAny(long num)
1459 /* a convenience function */
1460 {
1461     char s[40];
1462 
1463     sprintf(s, "%ld", num);
1464 
1465     return (stringToAny(s));
1466 }
1467 
1468 /*----------------------------------------------------------------------*/
1469 
anyToLong(any * a)1470 long anyToLong(any *a)
1471 /* a convenience 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 
makeBitMap(unsigned long numBits,...)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 
freeBitMap(bit_map * bm)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 
bitAtPos(unsigned long pos,bit_map * bm)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 
writeBitMap(bit_map * bm,data_tag tag,char * buffer,long * len)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 
readBitMap(bit_map ** bm,char * buffer)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 
writeByte(unsigned long byte,char * buf,long * len)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 
readByte(unsigned char * byte,char * buf)1581 char *readByte(unsigned char *byte, char *buf)
1582 {
1583     *byte = buf[0];
1584     return (buf + 1);
1585 }
1586 
1587 /*----------------------------------------------------------------------*/
1588 
writeBoolean(boolean flag,char * buf,long * len)1589 char *writeBoolean(boolean flag, char *buf, long *len)
1590 {
1591     return (writeByte(flag, buf, len));
1592 }
1593 
1594 /*----------------------------------------------------------------------*/
1595 
readBoolean(boolean * flag,char * buffer)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 
writePDUType(pdu_type pduType,char * buf,long * len)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 
readPDUType(pdu_type * pduType,char * buf)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 
peekPDUType(char * buf)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" */
writeBinaryInteger(long num,unsigned long size,char * buf,long * len)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 
readBinaryInteger(long * num,unsigned long size,char * buf)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 
writtenCompressedBinIntSize(long num)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 
writeNum(long num,data_tag tag,char * buffer,long * len)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 
readNum(long * num,char * buffer)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 
writtenNumSize(data_tag tag,long num)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 
doList(void ** list,voidfunc * func)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 
writeProtocolVersion(char * buf,long * len)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 
defaultImplementationID(void)1782 char *defaultImplementationID(void)
1783 {
1784     static char ImplementationID[] = "TMC";
1785 
1786     return (ImplementationID);
1787 }
1788 
1789 /*----------------------------------------------------------------------*/
1790 
defaultImplementationName(void)1791 char *defaultImplementationName(void)
1792 {
1793     static char ImplementationName[] = "Thinking Machines Corporation Z39.50";
1794 
1795     return (ImplementationName);
1796 }
1797 
1798 /*----------------------------------------------------------------------*/
1799 
defaultImplementationVersion(void)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 
makeAttributeTerm(char * use,char * relation,char * position,char * structure,char * truncation,char * completeness,any * term)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 
makeResultSetTerm(any * resultSet)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 
makeOperatorTerm(char * operatorCode)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 
freeTerm(void * param)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 
writeQueryTerm(query_term * qt,char * buffer,long * len)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 
readQueryTerm(query_term ** qt,char * buffer)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 
getQueryTermSize(query_term * qt)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 
writeQuery(query_term ** terms)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 
readQuery(any * info)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 
exitAction(long error GCC_UNUSED)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 
panic(char * format,...)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 
fs_checkPtr(void * ptr)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 
fs_malloc(size_t size)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 
fs_realloc(void * ptr,size_t size)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 
fs_free(void * ptr)2200 void fs_free(void *ptr)
2201 /* does safety checks and optional accounting */
2202 {
2203     if (ptr != NULL)		/* some non-ansi compilers/os's can't 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 
s_strdup(char * s)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)		/* safety 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 
fs_strncat(char * dst,char * src,size_t maxToAdd,size_t maxTotal)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 
char_downcase(unsigned long long_ch)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 
string_downcase(char * word)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 */
2280