mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-27 20:03:03 +01:00
959 lines
20 KiB
C++
959 lines
20 KiB
C++
/*
|
|
* PROGRAM: JRD Access Method
|
|
* MODULE: map.c
|
|
* DESCRIPTION: Map GALAXY blr into RDB blr
|
|
*
|
|
* The contents of this file are subject to the Interbase Public
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code was created by Inprise Corporation
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
* Copyright (C) Inprise Corporation.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
|
|
#include "firebird.h"
|
|
#include ssdef
|
|
#include descrip
|
|
|
|
#include "../jrd/gds.h"
|
|
#include "../jrd/common.h"
|
|
#include "../jrd/gdsassert.h"
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#define BUGCHECK bugcheck
|
|
#define RDB$_SEGSTR_EOF 20480378
|
|
#define RDB$_SEGMENT 20480369
|
|
#define GDS$_MISC_INTERPRETED 1
|
|
|
|
/* Struct used to describe records that request mapping */
|
|
|
|
typedef struct msg {
|
|
struct msg *msg_next; /* Next message in request */
|
|
USHORT msg_number; /* Message number */
|
|
USHORT msg_gds_length; /* Length of GDS form */
|
|
USHORT msg_rdb_length; /* Length of RDB form */
|
|
USHORT msg_count; /* Number of fields */
|
|
struct msg_repeat {
|
|
USHORT msg_dtype; /* Parameter dtype */
|
|
USHORT msg_length; /* Parameter length */
|
|
} msg_rpt[];
|
|
} *MSG;
|
|
|
|
#include "../jrd/map_proto.h"
|
|
|
|
extern double MTH$CVT_D_G(), MTH$CVT_G_D();
|
|
|
|
static void bugcheck(int);
|
|
static BOOLEAN check_message(UCHAR **);
|
|
static MSG rebuild_message(UCHAR **, UCHAR **);
|
|
static int translate_status(STATUS *, STATUS *, SCHAR **);
|
|
|
|
#define WRKBUF_SIZ 256
|
|
#define DEFAULT_STATUS_FLAGS 0xF0000L
|
|
|
|
static SLONG user_codes[] = {
|
|
1,
|
|
#include "../include/gen/rdb_codes.h"
|
|
};
|
|
|
|
static SCHAR workbuf[1024];
|
|
|
|
|
|
void MAP_date_to_gds(SLONG * vms_date, SLONG * gds_date)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ d a t e _ t o _ g d s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Map a date to GDS date format from VMS format.
|
|
*
|
|
**************************************/
|
|
SLONG time;
|
|
|
|
lib$day(gds_date, vms_date, &time);
|
|
gds_date[1] = time * 100;
|
|
}
|
|
|
|
|
|
void MAP_date_to_rdb(SLONG * gds_date, SLONG * vms_date)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ d a t e _ t o _ r d b
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Map a date to VMS date format from GDS format.
|
|
*
|
|
**************************************/
|
|
SLONG time[2], zero[2], temp, temp2;
|
|
|
|
/* Compute time portion */
|
|
|
|
zero[0] = zero[1] = 0;
|
|
temp = 1000;
|
|
lib$emul(gds_date + 1, &temp, zero, time);
|
|
|
|
/* Compute date portion being careful of overflow */
|
|
|
|
temp = 60 * 10000000;
|
|
temp2 = gds_date[0] * 24 * 60;
|
|
lib$emul(&temp2, &temp, time, vms_date);
|
|
}
|
|
|
|
|
|
int MAP_gds_to_rdb(USHORT number, MSG msg, UCHAR * from, UCHAR * to)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ g d s _ t o _ r d b
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Given a message number, a GDS format record, and a buffer
|
|
* to hold an Rdb format record, check to see if a map record
|
|
* exists for the message, and if so do the mapping. If there
|
|
* is not a map record, return 0. If there is, return the length
|
|
* of the Rdb record.
|
|
*
|
|
**************************************/
|
|
VARY vary;
|
|
UCHAR *p, *q;
|
|
USHORT l;
|
|
struct msg_repeat *desc, *end;
|
|
|
|
/* Find the message. If none, return 0 and get out */
|
|
|
|
for (; msg; msg = msg->msg_next)
|
|
if (msg->msg_number == number)
|
|
break;
|
|
|
|
if (!msg)
|
|
return 0;
|
|
|
|
/* Map data. Whoppee */
|
|
|
|
for (desc = msg->msg_rpt, end = desc + msg->msg_count; desc < end; desc++)
|
|
switch (desc->msg_dtype) {
|
|
case blr_cstring:
|
|
q = from;
|
|
from += desc->msg_length;
|
|
vary = to;
|
|
to += desc->msg_length + 1;
|
|
l = strlen(q);
|
|
if (l > desc->msg_length - 1)
|
|
l = desc->msg_length - 1;
|
|
if (vary->vary_length = l) {
|
|
p = vary->vary_data;
|
|
do
|
|
*p++ = *q++;
|
|
while (--l);
|
|
}
|
|
break;
|
|
|
|
case blr_timestamp:
|
|
MAP_date_to_rdb(from, to);
|
|
from += desc->msg_length;
|
|
to += desc->msg_length;
|
|
break;
|
|
|
|
case blr_d_float:
|
|
*((double *) to) = MTH$CVT_D_G((double *) from);
|
|
from += desc->msg_length;
|
|
to += desc->msg_length;
|
|
break;
|
|
|
|
default:
|
|
if (l = desc->msg_length)
|
|
do
|
|
*to++ = *from++;
|
|
while (--l);
|
|
}
|
|
|
|
return msg->msg_rdb_length;
|
|
}
|
|
|
|
|
|
MSG MAP_parse_blr(UCHAR * org_blr,
|
|
USHORT org_blr_length,
|
|
UCHAR * new_blr,
|
|
USHORT * new_blr_length, SLONG * max_length)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ p a r s e _ b l r
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* The price of progress is incompatibility. GALAXY supports null
|
|
* terminated strings, but the Rdb world does not. To bridge the
|
|
* incompatibility, search out messages that contain verboten data
|
|
* types and build message blocks for the offending messages.
|
|
*
|
|
**************************************/
|
|
MSG msg, next;
|
|
UCHAR *end_org_blr, *new, *org, *last_copied;
|
|
SLONG max;
|
|
|
|
end_org_blr = org_blr + org_blr_length;
|
|
org = last_copied = org_blr;
|
|
new = new_blr;
|
|
msg = NULL;
|
|
|
|
/* Check version. It must be version 4 or 5 or else we can't handle this */
|
|
|
|
if (*org != blr_version4 && *org != blr_version5)
|
|
return NULL;
|
|
++org;
|
|
if (*org++ != blr_begin)
|
|
return NULL;
|
|
|
|
/* Process messages until something else is entered. If the message
|
|
requires translation, build both a msg mapping block and a new
|
|
blr message */
|
|
|
|
while (*org++ == blr_message)
|
|
if (check_message(&org)) {
|
|
while (last_copied < org)
|
|
*new++ = *last_copied++;
|
|
if (!(next = rebuild_message(&org, &new)))
|
|
return NULL;
|
|
next->msg_next = msg;
|
|
msg = next;
|
|
last_copied = org;
|
|
}
|
|
|
|
/* If we've process all messages and none require work, indicate that
|
|
nothing remains to be done and get out */
|
|
|
|
for (max = 0, next = msg; next; next = next->msg_next) {
|
|
max = MAX(max, next->msg_gds_length);
|
|
max = MAX(max, next->msg_rdb_length);
|
|
}
|
|
|
|
*max_length = max;
|
|
|
|
if (!msg)
|
|
return NULL;
|
|
|
|
/* The request needs to be rebuilt completely. We've already copied the
|
|
messages, now finish the rest of the request. */
|
|
|
|
while (last_copied < end_org_blr)
|
|
*new++ = *last_copied++;
|
|
|
|
*new_blr_length = new - new_blr;
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
int MAP_rdb_length(USHORT number, MSG msg)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ r d b _ l e n g t h
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Determine where a particular message type requires mapping,
|
|
* and if so, the Rdb length.
|
|
*
|
|
**************************************/
|
|
|
|
for (; msg; msg = msg->msg_next)
|
|
if (msg->msg_number == number)
|
|
return msg->msg_rdb_length;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int MAP_rdb_to_gds(USHORT number, MSG msg, UCHAR * from, UCHAR * to)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ r d b _ t o _ g d s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Given a message number, an Rdb format record, and a buffer
|
|
* to hold an GDS format record, check to see if a map record
|
|
* exists for the message, and if so do the mapping. If there
|
|
* is not a map record, return 0. If there is, return the length
|
|
* of the GDS record.
|
|
*
|
|
**************************************/
|
|
VARY vary;
|
|
UCHAR *p, *q;
|
|
USHORT l;
|
|
struct msg_repeat *desc, *end;
|
|
|
|
/* Find the message. If none, return 0 and get out */
|
|
|
|
for (; msg; msg = msg->msg_next)
|
|
if (msg->msg_number == number)
|
|
break;
|
|
|
|
if (!msg)
|
|
return 0;
|
|
|
|
/* Map data. Whoppee */
|
|
|
|
for (desc = msg->msg_rpt, end = desc + msg->msg_count; desc < end; desc++)
|
|
switch (desc->msg_dtype) {
|
|
case blr_cstring:
|
|
vary = from;
|
|
from += desc->msg_length + 1;
|
|
p = to;
|
|
to += desc->msg_length;
|
|
l = MIN(vary->vary_length, desc->msg_length - 1);
|
|
if (l) {
|
|
q = vary->vary_data;
|
|
do
|
|
*p++ = *q++;
|
|
while (--l);
|
|
}
|
|
*p = 0;
|
|
break;
|
|
|
|
case blr_timestamp:
|
|
MAP_date_to_gds(from, to);
|
|
from += desc->msg_length;
|
|
to += desc->msg_length;
|
|
break;
|
|
|
|
case blr_d_float:
|
|
*((double *) to) = MTH$CVT_G_D((double *) from);
|
|
from += desc->msg_length;
|
|
to += desc->msg_length;
|
|
break;
|
|
|
|
default:
|
|
if (l = desc->msg_length)
|
|
do
|
|
*to++ = *from++;
|
|
while (--l);
|
|
}
|
|
|
|
return msg->msg_gds_length;
|
|
}
|
|
|
|
|
|
void MAP_release(MSG msg)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ r e l e a s e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Release any mapping blocks.
|
|
*
|
|
**************************************/
|
|
MSG next;
|
|
|
|
while (next = msg) {
|
|
msg = msg->msg_next;
|
|
gds__free(next);
|
|
}
|
|
}
|
|
|
|
|
|
int MAP_status_to_gds(STATUS * vms_status, STATUS * gds_status)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ s t a t u s _ t o _ g d s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Translate an RDB status vector to a GDS error status vector.
|
|
*
|
|
**************************************/
|
|
STATUS code, number, length, gds_index, *tmp, temp[20];
|
|
USHORT shift, flag;
|
|
SCHAR msgbuff[WRKBUF_SIZ], *p, *q, *pw1, *pw2, flags[4], part;
|
|
struct dsc$descriptor_s desc, *dsc_ptr;
|
|
static SCHAR *messages[] = {
|
|
#include "../jrd/msgs.h"
|
|
0
|
|
};
|
|
|
|
tmp = temp;
|
|
pw1 = pw2 = workbuf;
|
|
|
|
gds_status[0] = gds_arg_gds;
|
|
code = vms_status[1];
|
|
|
|
if (code == 1)
|
|
return (gds_status[1] = SUCCESS);
|
|
|
|
p = msgbuff;
|
|
length = 0;
|
|
desc.dsc$b_class = DSC$K_CLASS_S;
|
|
desc.dsc$b_dtype = DSC$K_DTYPE_T;
|
|
desc.dsc$w_length = WRKBUF_SIZ;
|
|
desc.dsc$a_pointer = p;
|
|
sys$getmsg(code, &length, &desc, 15, flags);
|
|
p[length] = 0;
|
|
|
|
gds_index = (code >> 3) - 2560000;
|
|
|
|
if (gds_index < 0 || gds_index > gds_err_max) {
|
|
gds_status[1] = gds__random;
|
|
gds_status[2] = gds_arg_string;
|
|
gds_status[3] = pw1;
|
|
gds_status[4] = gds_arg_end;
|
|
while (*p)
|
|
*pw2++ = *p++;
|
|
return gds__random;
|
|
}
|
|
|
|
flag = FALSE;
|
|
vms_status = vms_status + 3;
|
|
|
|
if (*p == '%')
|
|
p++;
|
|
|
|
while (*pw2++ = *p) {
|
|
if (*p++ != '!')
|
|
continue;
|
|
|
|
pw2--;
|
|
switch (*p++) {
|
|
case 'O':
|
|
case 'Z':
|
|
case 'S':
|
|
BUGCHECK(234); /* msg 234 Unimplemented conversion, FAO directive O,Z,S */
|
|
|
|
case 'X':
|
|
case 'U':
|
|
if (*p++ != 'L')
|
|
BUGCHECK(235); /* msg 235 Unimplemented conversion, FAO directive X,U */
|
|
*tmp++ = gds_arg_number;
|
|
number = *tmp++ = *vms_status++;
|
|
flag = (number == 1) ? FALSE : TRUE;
|
|
sprintf(pw2, "%%x%x", number);
|
|
while (*pw2)
|
|
++pw2;
|
|
break;
|
|
|
|
case 'A':
|
|
if (*p == 'C') {
|
|
q = *vms_status++;
|
|
length = *q++;
|
|
}
|
|
else if (*p == 'D' || *p == 'F') {
|
|
length = *vms_status++;
|
|
q = *vms_status++;
|
|
}
|
|
else if (*p == 'S') {
|
|
dsc_ptr = *vms_status++;
|
|
length = dsc_ptr->dsc$w_length;
|
|
q = dsc_ptr->dsc$a_pointer;
|
|
}
|
|
else
|
|
BUGCHECK(236); /* msg 236 Error parsing RDB FAO msg string */
|
|
|
|
++p;
|
|
*tmp++ = gds_arg_cstring;
|
|
*tmp++ = length;
|
|
*tmp++ = pw2;
|
|
while (length--)
|
|
*pw2++ = *q++;
|
|
break;
|
|
|
|
case '%':
|
|
if (*p != 'S')
|
|
*pw2++ = *p;
|
|
else if (flag)
|
|
*pw2++ = 's';
|
|
p++;
|
|
break;
|
|
|
|
case '!':
|
|
*pw2++ = '!';
|
|
break;
|
|
|
|
#ifdef DEBUG
|
|
case '-':
|
|
case '+':
|
|
case '*':
|
|
case '>':
|
|
case '<':
|
|
case '/':
|
|
case '_':
|
|
case '^':
|
|
break;
|
|
|
|
default:
|
|
BUGCHECK(237); /* msg 237 Error parsing RDB FAO msg str */
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
/* So now we've parsed the message & made it into a string.
|
|
Further, we've neatly saved the args in order in tmp...!
|
|
Get gds_message into buffer, parse & fudge parms*/
|
|
|
|
gds_status[1] = code = gds__encode(gds_index, 0);
|
|
p = messages[gds_index];
|
|
tmp = temp;
|
|
gds_status = gds_status + 2;
|
|
flag = FALSE;
|
|
|
|
while (*p) {
|
|
if (*p++ != '%')
|
|
continue;
|
|
switch (*p) {
|
|
case 's':
|
|
*gds_status++ = gds_arg_cstring;
|
|
if (*tmp++ != gds_arg_cstring || flag) {
|
|
flag = TRUE;
|
|
*gds_status++ = 3;
|
|
*gds_status++ = pw2;
|
|
sprintf(pw2, "<?>");
|
|
break;
|
|
}
|
|
*gds_status++ = *tmp++;
|
|
*gds_status++ = *tmp++;
|
|
break;
|
|
|
|
case 'l':
|
|
++p;
|
|
case 'd':
|
|
*gds_status++ = gds_arg_number;
|
|
if (*tmp++ != gds_arg_number || flag) {
|
|
flag = TRUE;
|
|
*gds_status++ = -1;
|
|
break;
|
|
}
|
|
*gds_status++ = *tmp++;
|
|
break;
|
|
|
|
default:
|
|
BUGCHECK(238); /* msg 238 unknown parameter in RdB status vector */
|
|
}
|
|
}
|
|
*gds_status++ = gds_arg_interpreted;
|
|
*gds_status++ = pw1;
|
|
*gds_status++ = gds_arg_end;
|
|
|
|
return code;
|
|
}
|
|
|
|
|
|
int MAP_status_to_rdb(STATUS * status_vector, STATUS * user_status)
|
|
{
|
|
/**************************************
|
|
*
|
|
* M A P _ s t a t u s _ t o _ r d b
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Translate a status vector from the Groton world to the RDB world.
|
|
* Continue until the end of the GDS vector is reached or until
|
|
* we hit a code that we don't know.
|
|
*
|
|
**************************************/
|
|
STATUS *gds, *rdb;
|
|
SLONG total_longwds, ret_value;
|
|
SCHAR *buf_ptr;
|
|
|
|
total_longwds = 0;
|
|
gds = status_vector;
|
|
rdb = user_status + 1;
|
|
buf_ptr = workbuf;
|
|
|
|
while (*gds)
|
|
if (ret_value = translate_status(&gds, &rdb, &buf_ptr))
|
|
total_longwds += ret_value += 2;
|
|
else {
|
|
total_longwds += 2;
|
|
break;
|
|
}
|
|
|
|
user_status[0] = DEFAULT_STATUS_FLAGS + total_longwds; /* Hack, hack, hack... */
|
|
return user_status[1];
|
|
}
|
|
|
|
|
|
static void bugcheck(int number)
|
|
{
|
|
/**************************************
|
|
*
|
|
* b u g c h e c k
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* output an error message
|
|
*
|
|
**************************************/
|
|
int n;
|
|
SCHAR buffer[128], number_text[20];
|
|
USHORT flags;
|
|
|
|
n =
|
|
gds__msg_lookup(0, JRD_BUGCHK, number, sizeof(buffer), buffer,
|
|
&flags);
|
|
|
|
if (n < 1)
|
|
strcpy(buffer, "error code");
|
|
sprintf(number_text, " (%d)", number);
|
|
strcat(buffer, number_text);
|
|
|
|
gds__log(buffer);
|
|
}
|
|
|
|
|
|
static BOOLEAN check_message(UCHAR ** org_ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* c h e c k _ m e s s a g e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Parse a blr message. If the message contains a non-Rdb data type,
|
|
* return TRUE. Otherwise update the blr pointer and return FALSE.
|
|
*
|
|
**************************************/
|
|
UCHAR *org, dtype;
|
|
SSHORT count;
|
|
|
|
/* Throw away the message number then pick up the number of fields */
|
|
|
|
org = *org_ptr + 1;
|
|
count = *org++;
|
|
count |= *org++ << 16;
|
|
|
|
while (count--)
|
|
switch (dtype = *org++) {
|
|
case blr_timestamp:
|
|
case blr_cstring:
|
|
case blr_d_float:
|
|
return TRUE;
|
|
|
|
case blr_text:
|
|
case blr_varying:
|
|
*org++;
|
|
|
|
case blr_short:
|
|
case blr_long:
|
|
case blr_quad:
|
|
*org++;
|
|
}
|
|
|
|
*org_ptr = org;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
static MSG rebuild_message(UCHAR ** org_ptr, UCHAR ** new_ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r e b u i l d _ m e s s a g e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* A message contains an offensive gds datatype. Rebuild it as a
|
|
* valid Rdb message while building a msg block to drive the data
|
|
* mapping. If we succeed, return the MSG block. If we fail for
|
|
* any reason, return NULL;
|
|
*
|
|
**************************************/
|
|
MSG msg;
|
|
UCHAR *org, *new, *last_copied;
|
|
USHORT number, l, length, gds_length, rdb_length;
|
|
struct msg_repeat *desc, *end;
|
|
|
|
/* Do some housekeeping then pick up message number and count of parameters */
|
|
|
|
length = 0;
|
|
org = last_copied = *org_ptr;
|
|
new = *new_ptr;
|
|
number = *org++;
|
|
l = *org++;
|
|
l |= *org++ << 16;
|
|
msg = gds__alloc((SLONG)
|
|
(sizeof(struct msg) + l * sizeof(struct msg_repeat)));
|
|
/* FREE: by MAP_release() */
|
|
if (!msg)
|
|
return NULL; /* NO MEM */
|
|
|
|
|
|
msg->msg_number = number;
|
|
msg->msg_count = l;
|
|
msg->msg_gds_length = 0;
|
|
msg->msg_rdb_length = 0;
|
|
|
|
for (desc = msg->msg_rpt, end = desc + l; desc < end; desc++) {
|
|
switch (desc->msg_dtype = *org++) {
|
|
case blr_text:
|
|
gds_length = *org++;
|
|
gds_length += *org++ << 16;
|
|
rdb_length = gds_length;
|
|
break;
|
|
|
|
case blr_varying:
|
|
gds_length = 2 + *org++;
|
|
gds_length += *org++ << 16;
|
|
rdb_length = gds_length;
|
|
break;
|
|
|
|
case blr_short:
|
|
*org++;
|
|
rdb_length = gds_length = 2;
|
|
break;
|
|
|
|
case blr_long:
|
|
*org++;
|
|
|
|
case blr_float:
|
|
rdb_length = gds_length = 4;
|
|
break;
|
|
|
|
case blr_quad:
|
|
*org++;
|
|
|
|
case blr_timestamp:
|
|
case blr_double:
|
|
rdb_length = gds_length = 8;
|
|
break;
|
|
|
|
case blr_d_float:
|
|
while (last_copied < org)
|
|
*new++ = *last_copied++;
|
|
new[-1] = blr_double;
|
|
rdb_length = gds_length = 8;
|
|
break;
|
|
|
|
case blr_cstring:
|
|
while (last_copied < org)
|
|
*new++ = *last_copied++;
|
|
new[-1] = blr_varying;
|
|
gds_length = *org++;
|
|
gds_length |= *org++ << 16;
|
|
rdb_length = gds_length + 1;
|
|
l = rdb_length - 2;
|
|
*new++ = l;
|
|
*new++ = l >> 16;
|
|
last_copied = org;
|
|
break;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
desc->msg_length = gds_length;
|
|
msg->msg_gds_length += gds_length;
|
|
msg->msg_rdb_length += rdb_length;
|
|
}
|
|
|
|
/* We're done processing parameters. Copy anything passed over, update
|
|
pointers, and return */
|
|
|
|
while (last_copied < org)
|
|
*new++ = *last_copied++;
|
|
|
|
*org_ptr = org;
|
|
*new_ptr = new;
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
static int translate_status(
|
|
STATUS * status_vector,
|
|
STATUS * user_status, SCHAR ** buf_ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* t r a n s l a t e _ s t a t u s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Translate a single status message.
|
|
* Return the number of FAO arguments.
|
|
* If we don't know the status code, return it to caller.
|
|
*
|
|
**************************************/
|
|
STATUS *gds, *rdb, code, *count_addr;
|
|
USHORT fac = 0, class_ = 0;
|
|
SSHORT count, length;
|
|
SCHAR msgbuff[WRKBUF_SIZ], *p, *q, *pw1, *pw2, flags[4];
|
|
struct dsc$descriptor_s desc, *desc_ptr;
|
|
|
|
p = msgbuff;
|
|
pw1 = pw2 = *buf_ptr;
|
|
gds = *status_vector;
|
|
rdb = *user_status;
|
|
count = 0;
|
|
|
|
if (*gds == gds_arg_interpreted) {
|
|
q = gds[1];
|
|
rdb[0] = GDS$_MISC_INTERPRETED;
|
|
rdb[1] = DEFAULT_STATUS_FLAGS + 1;
|
|
rdb[2] = strlen(q);
|
|
rdb[3] = gds[1];
|
|
return 2;
|
|
}
|
|
|
|
if (*gds++ != gds_arg_gds)
|
|
BUGCHECK(239); /* msg 239 Interbase status vector inconsistent */
|
|
|
|
code = gds__decode(*gds, &fac, &class_);
|
|
|
|
if ((code < 0) || (code > gds_err_max)) {
|
|
rdb[0] = *gds;
|
|
rdb[1] = DEFAULT_STATUS_FLAGS;
|
|
return 0;
|
|
}
|
|
|
|
code = *rdb++ = user_codes[code];
|
|
|
|
length = 0;
|
|
desc.dsc$b_class = DSC$K_CLASS_S;
|
|
desc.dsc$b_dtype = DSC$K_DTYPE_T;
|
|
desc.dsc$w_length = WRKBUF_SIZ;
|
|
desc.dsc$a_pointer = p;
|
|
sys$getmsg(code, &length, &desc, 15, flags);
|
|
|
|
p[length] = 0;
|
|
count_addr = rdb++;
|
|
++gds;
|
|
|
|
/* GDS message parameters should be the same in number, order & datatype
|
|
as those RDB expects. If not, be real unpleasant about it. */
|
|
|
|
while (*p) {
|
|
if (*p++ != '!')
|
|
continue;
|
|
|
|
switch (*p) {
|
|
case 'O':
|
|
case 'X':
|
|
case 'Z':
|
|
case 'U':
|
|
case 'S':
|
|
if ((*gds++) != gds_arg_number)
|
|
BUGCHECK(240); /* msg 240 Interbase/RdB message parameter inconsistency */
|
|
*rdb++ = *gds++;
|
|
++count;
|
|
break;
|
|
|
|
case 'A':
|
|
++p;
|
|
switch (*gds++) {
|
|
case gds_arg_cstring:
|
|
length = *pw2++ = *gds++;
|
|
q = *gds++;
|
|
do
|
|
(*pw2++ = *q++);
|
|
while (--length);
|
|
break;
|
|
|
|
case gds_arg_string:
|
|
++pw2;
|
|
length = 0;
|
|
q = *gds++;
|
|
while (*pw2++ = *q++)
|
|
++length;
|
|
*pw1 = length;
|
|
break;
|
|
|
|
default:
|
|
BUGCHECK(240); /* msg 240 Interbase/RdB message parameter inconsistency */
|
|
}
|
|
|
|
if (*p == 'C')
|
|
*rdb++ = pw1;
|
|
else if (*p == 'D' || *p == 'F') {
|
|
*rdb++ = *pw1++;
|
|
*rdb++ = pw1;
|
|
++count;
|
|
}
|
|
else if (*p == 'S') {
|
|
*rdb++ = pw2;
|
|
desc_ptr = (struct dsc$descriptor *) pw2;
|
|
desc_ptr->dsc$b_class = DSC$K_CLASS_S;
|
|
desc_ptr->dsc$b_dtype = DSC$K_DTYPE_T;
|
|
desc_ptr->dsc$w_length = *pw1++;
|
|
desc_ptr->dsc$a_pointer = pw1;
|
|
pw2 += sizeof(struct dsc$descriptor);
|
|
}
|
|
else
|
|
BUGCHECK(241); /* msg 241 error parsing RDB FAO message string */
|
|
|
|
pw1 = pw2;
|
|
++count;
|
|
break;
|
|
|
|
case '%':
|
|
++p;
|
|
if (*p == 'S')
|
|
break;
|
|
BUGCHECK(242); /* msg 242 unimplemented FAO directive */
|
|
|
|
case '!':
|
|
++p;
|
|
break;
|
|
|
|
#ifdef DEBUG
|
|
case '-':
|
|
case '+':
|
|
break;
|
|
|
|
case '*':
|
|
case '>':
|
|
case '<':
|
|
case '/':
|
|
case '_':
|
|
case '^':
|
|
++p;
|
|
break;
|
|
|
|
default:
|
|
BUGCHECK(241); /* msg 241 error parsing RDB FAO message string */
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
*buf_ptr = pw2;
|
|
count_addr[0] = DEFAULT_STATUS_FLAGS + count;
|
|
*status_vector = gds;
|
|
*user_status = rdb;
|
|
|
|
return count;
|
|
}
|