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