archie/prospero/lib/psrv/wais_gw/zutil.c
2024-05-27 16:13:40 +02:00

892 lines
16 KiB
C

/* WIDE AREA INFORMATION SERVER SOFTWARE:
Developed by Thinking Machines Corporation and put into the public
domain with no guarantees or restrictions.
*/
/*----------------------------------------------------------------------*/
#define _C_utils_Z39_50_
#include <math.h>
#include "zutil.h"
#include <string.h>
#include <pfs_threads.h>
EXTERN_CHARP_DEF(readErrorPosition);
/* Lets hope these get initialized to NULL or that noone cares*/
#define readErrorPosition p_th_arreadErrorPosition[p__th_self_num()]
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
diagnosticRecord*
makeDiag(surrogate,code,addInfo)
boolean surrogate;
char* code;
char* addInfo;
{
diagnosticRecord* diag =
(diagnosticRecord*)s_malloc((size_t)sizeof(diagnosticRecord));
diag->SURROGATE = surrogate;
memcpy(diag->DIAG,code,DIAGNOSTIC_CODE_SIZE);
diag->ADDINFO = s_strdup(addInfo);
return(diag);
}
/*----------------------------------------------------------------------*/
void
freeDiag(diag)
diagnosticRecord* diag;
{
if (diag != NULL)
{ if (diag->ADDINFO != NULL)
s_free(diag->ADDINFO);
s_free(diag);
}
}
/*----------------------------------------------------------------------*/
#define END_OF_RECORD 0x1D
char*
writeDiag(diag,buffer,len)
diagnosticRecord* diag;
char* buffer;
long* len;
{
char* buf = buffer;
long length;
if (diag == NULL)
return(buf);
buf = writeTag(DT_DatabaseDiagnosticRecords,buf,len);
CHECK_FOR_SPACE_LEFT(0L,len);
length = 3;
if (diag->ADDINFO != NULL)
length += strlen(diag->ADDINFO);
if (length >= 0xFFFF )
{ length = 0xFFFF - 1;
diag->ADDINFO[0xFFFF - 3 - 1] = '\0';
}
buf = writeBinaryInteger(length,2L,buf,len);
CHECK_FOR_SPACE_LEFT(1L,len);
buf[0] = diag->DIAG[0];
buf++;
CHECK_FOR_SPACE_LEFT(1L,len);
buf[0] = diag->DIAG[1];
buf++;
if (length > 3)
{ CHECK_FOR_SPACE_LEFT(3L,len);
memcpy(buf,diag->ADDINFO,(size_t)length - 3);
buf += length - 3;
}
CHECK_FOR_SPACE_LEFT(1L,len);
buf[0] = diag->SURROGATE;
buf++;
CHECK_FOR_SPACE_LEFT(1L,len);
buf[0] = END_OF_RECORD;
buf++;
return(buf);
}
/*----------------------------------------------------------------------*/
char*
readDiag(diag,buffer) /*!!ALLOCS - diag */
diagnosticRecord** diag;
char* buffer;
{
char* buf = buffer;
diagnosticRecord* d
= (diagnosticRecord*)s_malloc((size_t)sizeof(diagnosticRecord));
data_tag tag;
long len;
buf = readTag(&tag,buf);
buf = readBinaryInteger(&len,2L,buf);
d->DIAG[0] = buf[0];
d->DIAG[1] = buf[1];
d->DIAG[2] = '\0';
if (len > 3)
{ d->ADDINFO = (char*)s_malloc((size_t)(len - 3 + 1));
memcpy(d->ADDINFO,(char*)(buf + 2),(size_t)(len - 3));
d->ADDINFO[len - 3] = '\0';
}
else
d->ADDINFO = NULL;
d->SURROGATE = buf[len - 1];
*diag = d;
return(buf + len + 1);
}
/*----------------------------------------------------------------------*/
#define continueBit 0x80
#define dataMask 0x7F
#define dataBits 7
char*
writeCompressedInteger(num,buf,len)
unsigned long num;
char* buf;
long* len;
{
char aByte;
long i;
unsigned long size;
size = writtenCompressedIntSize(num);
CHECK_FOR_SPACE_LEFT(size,len);
for (i = size - 1; i >= 0; i--)
{ aByte = num & dataMask;
if (i != (size-1))
aByte = (char)(aByte | continueBit);
buf[i] = aByte;
num = num >> dataBits;
}
return(buf + size);
}
/*----------------------------------------------------------------------*/
char*
readCompressedInteger(num,buf)
unsigned long *num;
char* buf;
{
long i = 0;
unsigned char aByte;
*num = 0;
do
{ aByte = buf[i++];
*num = *num << dataBits;
*num += (aByte & dataMask);
}
while (aByte & continueBit);
return(buf + i);
}
/*----------------------------------------------------------------------*/
#define pad 128
char*
writeCompressedIntWithPadding(num,size,buffer,len)
unsigned long num;
unsigned long size;
char* buffer;
long* len;
{
char* buf = buffer;
unsigned long needed,padding;
long i;
CHECK_FOR_SPACE_LEFT(size,len);
needed = writtenCompressedIntSize(num);
padding = size - needed;
i = padding - 1;
for (i = padding - 1;i >= 0;i--)
{ buf[i] = pad;
}
buf = writeCompressedInteger(num,buf + padding,len);
return(buf);
}
/*----------------------------------------------------------------------*/
unsigned long
writtenCompressedIntSize(num)
unsigned long num;
{
if (num < CompressedInt1Byte)
return(1);
else if (num < CompressedInt2Byte)
return(2);
else if (num < CompressedInt3Byte)
return(3);
else
return(4);
}
/*----------------------------------------------------------------------*/
char*
writeTag(tag,buf,len)
data_tag tag;
char* buf;
long* len;
{
return(writeCompressedInteger(tag,buf,len));
}
/*----------------------------------------------------------------------*/
char*
readTag(tag,buf)
data_tag* tag;
char* buf;
{
return(readCompressedInteger(tag,buf));
}
/*----------------------------------------------------------------------*/
unsigned long
writtenTagSize(tag)
data_tag tag;
{
return(writtenCompressedIntSize(tag));
}
/*----------------------------------------------------------------------*/
data_tag
peekTag(buf)
char* buf;
{
data_tag tag;
readTag(&tag,buf);
return(tag);
}
/*----------------------------------------------------------------------*/
any*
makeAny(size,data)
unsigned long size;
char* data;
{
any* a = (any*)s_malloc((size_t)sizeof(any));
a->size = size;
a->bytes = data;
return(a);
}
/*----------------------------------------------------------------------*/
void
freeAny(a)
any* a;
{
if (a != NULL)
{ if (a->bytes != NULL)
s_free(a->bytes);
s_free(a);
}
}
/*----------------------------------------------------------------------*/
any*
duplicateAny(a)
any* a;
{
any* copy = NULL;
if (a == NULL)
return(NULL);
copy = (any*)s_malloc((size_t)sizeof(any));
copy->size = a->size;
if (a->bytes == NULL)
copy->bytes = NULL;
else
{ copy->bytes = (char*)s_malloc((size_t)copy->size);
memcpy(copy->bytes,a->bytes,(size_t)copy->size);
}
return(copy);
}
/*----------------------------------------------------------------------*/
char*
writeAny(a,tag,buffer,len)
any* a;
data_tag tag;
char* buffer;
long* len;
{
char* buf = buffer;
if (a == NULL)
return(buf);
buf = writeTag(tag,buf,len);
buf = writeCompressedInteger(a->size,buf,len);
CHECK_FOR_SPACE_LEFT(a->size,len);
memcpy(buf,a->bytes,(size_t)a->size);
return(buf+a->size);
}
/*----------------------------------------------------------------------*/
char*
readAny(anAny,buffer) /*!!ALLOCS at anAny */
any** anAny;
char* buffer;
{
char* buf = buffer;
any* a = (any*)s_malloc((size_t)sizeof(any));
data_tag tag;
buf = readTag(&tag,buf);
buf = readCompressedInteger(&a->size,buf);
a->bytes = (char*)s_malloc((size_t)a->size);
memcpy(a->bytes,buf,(size_t)a->size);
*anAny = a;
return(buf+a->size);
}
/*----------------------------------------------------------------------*/
unsigned long
writtenAnySize(tag,a)
data_tag tag;
any* a;
{
unsigned long size;
if (a == NULL)
return(0);
size = writtenTagSize(tag);
size += writtenCompressedIntSize(a->size);
size += a->size;
return(size);
}
/*----------------------------------------------------------------------*/
any*
stringToAny(s)
char* s;
{
any* a = NULL;
if (s == NULL)
return(NULL);
a = (any*)s_malloc((size_t)sizeof(any));
a->size = strlen(s);
a->bytes = (char*)s_malloc((size_t)a->size);
memcpy(a->bytes,s,(size_t)a->size);
return(a);
}
/*----------------------------------------------------------------------*/
char*
anyToString(a)
any* a;
{
char* s = NULL;
if (a == NULL)
return(NULL);
s = s_malloc((size_t)(a->size + 1));
memcpy(s,a->bytes,(size_t)a->size);
s[a->size] = '\0';
return(s);
}
/*----------------------------------------------------------------------*/
char*
writeString(s,tag,buffer,len)
char* s;
data_tag tag;
char* buffer;
long* len;
{
char* buf = buffer;
any* data = NULL;
if (s == NULL)
return(buffer);
data = (any*)s_malloc((size_t)sizeof(any));
data->size = strlen(s);
data->bytes = s;
buf = writeAny(data,tag,buf,len);
s_free(data);
return(buf);
}
/*----------------------------------------------------------------------*/
char*
readString(s ,buffer)
char** s ;
char* buffer;
{
any* data = NULL;
char* buf = readAny(&data,buffer);
*s = anyToString(data);
freeAny(data);
return(buf);
}
/*----------------------------------------------------------------------*/
unsigned long
writtenStringSize(tag,s)
data_tag tag;
char* s;
{
unsigned long size;
if (s == NULL)
return(0);
size = writtenTagSize(tag);
size += writtenCompressedIntSize(size);
size += strlen(s);
return(size);
}
/*----------------------------------------------------------------------*/
any*
longToAny(num)
long num;
{
char s[40];
sprintf(s,"%ld",num);
return(stringToAny(s));
}
/*----------------------------------------------------------------------*/
long
anyToLong(a)
any* a;
{
long num;
char* str = NULL;
str = anyToString(a);
sscanf(str,"%ld",&num);
s_free(str);
return(num);
}
/*----------------------------------------------------------------------*/
#define bitsPerByte 8
bit_map*
makeBitMap(unsigned long numBits,...)
{
va_list ap;
long i,j;
bit_map* bm = NULL;
va_start(ap,numBits);
bm = (bit_map*)s_malloc((size_t)sizeof(bit_map));
bm->size = (unsigned long)ceil((double)numBits / bitsPerByte);
bm->bytes = (char*)s_malloc((size_t)bm->size);
for (i = 0; i < bm->size; i++)
{ char aByte = 0;
for (j = 0; j < bitsPerByte; j++)
{ if ((i * bitsPerByte + j) < numBits)
{ boolean bit = false;
bit = (boolean)va_arg(ap,boolean);
if (bit)
{ aByte = aByte | (1 << (bitsPerByte - j - 1));
}
}
}
bm->bytes[i] = aByte;
}
va_end(ap);
return(bm);
}
/*----------------------------------------------------------------------*/
void
freeBitMap(bm)
bit_map* bm;
{
s_free(bm->bytes);
s_free(bm);
}
/*----------------------------------------------------------------------*/
boolean
bitAtPos(pos,bm)
long pos;
bit_map* bm;
{
if (pos > bm->size*bitsPerByte)
return false;
else
return((bm->bytes[(pos / bitsPerByte)] &
(0x80>>(pos % bitsPerByte))) ?
true : false);
}
/*----------------------------------------------------------------------*/
char*
writeBitMap(bm,tag,buffer,len)
bit_map* bm;
data_tag tag;
char* buffer;
long* len;
{
return(writeAny((any*)bm,tag,buffer,len));
}
/*----------------------------------------------------------------------*/
char*
readBitMap(bm,buffer)
bit_map** bm;
char* buffer;
{
return(readAny((any**)bm,buffer));
}
/*----------------------------------------------------------------------*/
char*
writeByte(aByte,buf,len)
unsigned long aByte;
char* buf;
long* len;
{
CHECK_FOR_SPACE_LEFT(1L,len);
buf[0] = aByte & 0xFF;
return(buf + 1);
}
/*----------------------------------------------------------------------*/
char*
readByte(aByte,buf)
unsigned char* aByte;
char* buf;
{
*aByte = buf[0];
return(buf + 1);
}
/*----------------------------------------------------------------------*/
char*
writeBoolean(flag,buf,len)
boolean flag;
char* buf;
long* len;
{
return(writeByte(flag,buf,len));
}
/*----------------------------------------------------------------------*/
char*
readBoolean(flag,buffer)
boolean* flag;
char* buffer;
{
unsigned char aByte;
char* buf = readByte(&aByte,buffer);
*flag = (aByte == true) ? true : false;
return(buf);
}
/*----------------------------------------------------------------------*/
char*
writePDUType(pduType,buf,len)
pdu_type pduType;
char* buf;
long* len;
{
return(writeBinaryInteger((long)pduType,(unsigned long)1,buf,len));
}
/*----------------------------------------------------------------------*/
char*
readPDUType(pduType,buf)
pdu_type* pduType;
char* buf;
{
return(readBinaryInteger((long*)pduType,(unsigned long)1,buf));
}
/*----------------------------------------------------------------------*/
pdu_type
peekPDUType(buf)
char* buf;
{
pdu_type pdu;
readPDUType(&pdu,buf + HEADER_LEN);
return(pdu);
}
/*----------------------------------------------------------------------*/
#define BINARY_INTEGER_BYTES sizeof(long)
/* Writes an integer num into the buf (which has len bytes left) in a width
of size, returns buff, and updates len */
char*
writeBinaryInteger(num,size,buf,len)
long num;
unsigned long size;
char* buf;
long* len;
{
long i;
char aByte;
if (size < 1 || size > BINARY_INTEGER_BYTES)
return(NULL);
CHECK_FOR_SPACE_LEFT(size,len);
for (i = size - 1; i >= 0; i--)
{ aByte = (char)(num & 255);
buf[i] = aByte;
num = num >> bitsPerByte;
}
return(buf + size);
}
/*----------------------------------------------------------------------*/
char*
readBinaryInteger(num,size,buf)
long* num;
unsigned long size;
char* buf;
{
long i;
unsigned char aByte;
if (size < 1 || size > BINARY_INTEGER_BYTES)
return(buf);
*num = 0;
for (i = 0; i < size; i++)
{ aByte = buf[i];
*num = *num << bitsPerByte;
*num += aByte;
}
return(buf + size);
}
/*----------------------------------------------------------------------*/
unsigned long
writtenCompressedBinIntSize(num)
long num;
{
if (num < 0L)
return(4);
else if (num < 256L)
return(1);
else if (num < 65536L)
return(2);
else if (num < 16777216L)
return(3);
else
return(4);
}
/*----------------------------------------------------------------------*/
char*
writeNum(num,tag,buffer,len)
long num;
data_tag tag;
char* buffer;
long* len;
{
char* buf = buffer;
long size = writtenCompressedBinIntSize(num);
if (num == UNUSED)
return(buffer);
buf = writeTag(tag,buf,len);
buf = writeCompressedInteger(size,buf,len);
buf = writeBinaryInteger(num,(unsigned long)size,buf,len);
return(buf);
}
/*----------------------------------------------------------------------*/
char*
readNum(num,buffer)
long* num;
char* buffer;
{
char* buf = buffer;
data_tag tag;
unsigned long size;
unsigned long val;
buf = readTag(&tag,buf);
buf = readCompressedInteger(&val,buf);
size = (unsigned long)val;
buf = readBinaryInteger(num,size,buf);
return(buf);
}
/*----------------------------------------------------------------------*/
unsigned long
writtenNumSize(tag,num)
data_tag tag;
long num;
{
long dataSize = writtenCompressedBinIntSize(num);
long size;
size = writtenTagSize(tag);
size += writtenCompressedIntSize(dataSize);
size += dataSize;
return(size);
}
/*----------------------------------------------------------------------*/
typedef void (voidfunc)();
void
doList(theList,func)
void** theList;
voidfunc *func;
{
register long i;
register void* ptr = NULL;
if (theList == NULL)
return;
for (i = 0,ptr = theList[i]; ptr != NULL; ptr = theList[++i])
(*func)(ptr);
}
/*----------------------------------------------------------------------*/
char*
writeProtocolVersion(buf,len)
char* buf;
long* len;
{
static bit_map* version = NULL;
if (version == NULL)
/* While this only NEEDS doing once, dont really care if done twice
simultaneously by different threads*/
{ version = makeBitMap((unsigned long)1,true);
}
return(writeBitMap(version,DT_ProtocolVersion,buf,len));
}
/*----------------------------------------------------------------------*/
char*
defaultImplementationID()
{
static char ImplementationID[] = "WAIS Inc";
return(ImplementationID);
}
/*----------------------------------------------------------------------*/
char*
defaultImplementationName()
{
static char ImplementationName[] = "Wide Area Information Servers Inc Z39.50";
return(ImplementationName);
}
/*----------------------------------------------------------------------*/
char*
defaultImplementationVersion()
{
static char ImplementationVersion[] = "2.0A";
return(ImplementationVersion);
}
/*----------------------------------------------------------------------*/