8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 15:23:03 +01:00
firebird-mirror/src/gpre/int_cxx.cpp
2001-12-24 02:51:06 +00:00

789 lines
18 KiB
C++

//____________________________________________________________
//
// PROGRAM: C preprocess
// MODULE: int.cpp
// DESCRIPTION: Code generate for internal JRD modules
//
// 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): ______________________________________.
// TMN (Mike Nordell) 11.APR.2001 - Reduce compiler warnings in generated code
//
//
//____________________________________________________________
//
// $Id: int_cxx.cpp,v 1.3 2001-12-24 02:50:49 tamlin Exp $
//
#include "firebird.h"
#include "../jrd/ib_stdio.h"
#include "../jrd/common.h"
#include <stdarg.h>
#include "../jrd/gds.h"
#include "../gpre/gpre.h"
#include "../gpre/gpre_proto.h"
#include "../gpre/lang_proto.h"
#include "../jrd/gds_proto.h"
static void align(int);
static void asgn_from(REF, int);
static void asgn_to(REF);
static void gen_at_end(ACT, int);
static int gen_blr(int *, int, TEXT *);
static void gen_compile(REQ, int);
static void gen_database(ACT, int);
static void gen_emodify(ACT, int);
static void gen_estore(ACT, int);
static void gen_endfor(ACT, int);
static void gen_erase(ACT, int);
static void gen_for(ACT, int);
static TEXT *gen_name(TEXT *, REF);
static void gen_raw(REQ);
static void gen_receive(REQ, POR);
static void gen_request(REQ);
static void gen_routine(ACT, int);
static void gen_s_end(ACT, int);
static void gen_s_fetch(ACT, int);
static void gen_s_start(ACT, int);
static void gen_send(REQ, POR, int);
static void gen_start(REQ, POR, int);
static void gen_type(ACT, int);
static void gen_variable(ACT, int);
static void make_port(POR, int);
static void printa(int, TEXT *, ...);
static int first_flag = 0;
#define INDENT 3
#define BEGIN printa (column, "{")
#define END printa (column, "}")
#if !(defined JPN_SJIS || defined JPN_EUC)
#define GDS_VTOV "gds__vtov"
#define JRD_VTOF "jrd_vtof"
#define VTO_CALL "%s ((SCHAR*)%s, (SCHAR*)%s, %d);"
#else
#define GDS_VTOV "gds__vtov2"
#define JRD_VTOF "jrd_vtof2"
#define VTO_CALL "%s (%s, %s, %d, %d);"
#endif
//____________________________________________________________
//
//
void INT_CXX_action( ACT action, int column)
{
// Put leading braces where required
switch (action->act_type) {
case ACT_for:
case ACT_insert:
case ACT_modify:
case ACT_store:
case ACT_s_fetch:
case ACT_s_start:
BEGIN;
align(column);
}
switch (action->act_type) {
case ACT_at_end:
gen_at_end(action, column);
return;
case ACT_b_declare:
case ACT_database:
gen_database(action, column);
return;
case ACT_endfor:
gen_endfor(action, column);
break;
case ACT_endmodify:
gen_emodify(action, column);
break;
case ACT_endstore:
gen_estore(action, column);
break;
case ACT_erase:
gen_erase(action, column);
return;
case ACT_for:
gen_for(action, column);
return;
case ACT_hctef:
break;
case ACT_insert:
case ACT_routine:
gen_routine(action, column);
return;
case ACT_s_end:
gen_s_end(action, column);
return;
case ACT_s_fetch:
gen_s_fetch(action, column);
return;
case ACT_s_start:
gen_s_start(action, column);
break;
case ACT_type:
gen_type(action, column);
return;
case ACT_variable:
gen_variable(action, column);
return;
default:
return;
}
// Put in a trailing brace for those actions still with us
END;
}
//____________________________________________________________
//
// Align output to a specific column for output.
//
static void align( int column)
{
int i;
if (column < 0)
return;
ib_putc('\n', out_file);
for (i = column / 8; i; --i)
ib_putc('\t', out_file);
for (i = column % 8; i; --i)
ib_putc(' ', out_file);
}
//____________________________________________________________
//
// Build an assignment from a host language variable to
// a port variable.
//
static void asgn_from( REF reference, int column)
{
FLD field;
TEXT *value, variable[20], temp[20];
for (; reference; reference = reference->ref_next) {
field = reference->ref_field;
align(column);
gen_name(variable, reference);
if (reference->ref_source)
value = gen_name(temp, reference->ref_source);
else
value = reference->ref_value;
/* To avoid chopping off a double byte kanji character in between
the two bytes, generate calls to gds__ftof2 gds$_vtof2,
gds$_vtov2 and jrd_vtof2 wherever necessary */
if (!field || field->fld_dtype == dtype_text)
ib_fprintf(out_file, VTO_CALL,
JRD_VTOF,
value, variable, field->fld_length, sw_interp);
else if (!field || field->fld_dtype == dtype_cstring)
ib_fprintf(out_file, VTO_CALL,
GDS_VTOV,
value, variable, field->fld_length, sw_interp);
else
ib_fprintf(out_file, "%s = %s;", variable, value);
}
}
//____________________________________________________________
//
// Build an assignment to a host language variable from
// a port variable.
//
static void asgn_to( REF reference)
{
FLD field;
REF source;
TEXT s[20];
source = reference->ref_friend;
field = source->ref_field;
gen_name(s, source);
#if (! (defined JPN_SJIS || defined JPN_EUC) )
if (!field || field->fld_dtype == dtype_text)
ib_fprintf(out_file, "gds__ftov (%s, %d, %s, sizeof (%s));",
s,
field->fld_length,
reference->ref_value, reference->ref_value);
else if (!field || field->fld_dtype == dtype_cstring)
ib_fprintf(out_file, "gds__vtov ((SCHAR*)%s, (SCHAR*)%s, sizeof (%s));",
s, reference->ref_value, reference->ref_value);
#else
// To avoid chopping off a double byte kanji character in between
// the two bytes, generate calls to gds__ftof2 gds$_vtof2 and
// gds$_vtov2 wherever necessary
if (!field || field->fld_dtype == dtype_text)
ib_fprintf(out_file, "gds__ftov2 (%s, %d, %s, sizeof (%s), %d);",
s,
field->fld_length,
reference->ref_value, reference->ref_value, sw_interp);
else if (!field || field->fld_dtype == dtype_cstring)
ib_fprintf(out_file, "gds__vtov2 (%s, %s, sizeof (%s), %d);",
s, reference->ref_value, reference->ref_value, sw_interp);
#endif
else
ib_fprintf(out_file, "%s = %s;", reference->ref_value, s);
}
//____________________________________________________________
//
// Generate code for AT END clause of FETCH.
//
static void gen_at_end( ACT action, int column)
{
REQ request;
TEXT s[20];
request = action->act_request;
printa(column, "if (!%s) ", gen_name(s, request->req_eof));
}
//____________________________________________________________
//
// Callback routine for BLR pretty printer.
//
static int gen_blr( int *user_arg, int offset, TEXT * string)
{
ib_fprintf(out_file, "%s\n", string);
return TRUE;
}
//____________________________________________________________
//
// Generate text to compile a request.
//
static void gen_compile( REQ request, int column)
{
DBB db;
SYM symbol;
column += INDENT;
db = request->req_database;
symbol = db->dbb_name;
ib_fprintf(out_file, "if (!%s)", request->req_handle);
align(column);
ib_fprintf(out_file,
"%s = (BLK) CMP_compile2 (tdbb, (UCHAR*)jrd_%d, TRUE);",
request->req_handle, request->req_ident);
}
//____________________________________________________________
//
// Generate insertion text for the database statement.
//
static void gen_database( ACT action, int column)
{
REQ request;
if (first_flag++ != 0)
return;
align(0);
for (request = requests; request; request = request->req_next)
gen_request(request);
}
//____________________________________________________________
//
// Generate substitution text for END_MODIFY.
//
static void gen_emodify( ACT action, int column)
{
UPD modify;
REF reference, source;
FLD field;
TEXT s1[20], s2[20];
modify = (UPD) action->act_object;
for (reference = modify->upd_port->por_references; reference;
reference = reference->ref_next) {
if (!(source = reference->ref_source))
continue;
field = reference->ref_field;
align(column);
#if (! (defined JPN_SJIS || defined JPN_EUC) )
if (field->fld_dtype == dtype_text)
ib_fprintf(out_file, "jrd_ftof (%s, %d, %s, %d);",
gen_name(s1, source),
field->fld_length,
gen_name(s2, reference), field->fld_length);
else if (field->fld_dtype == dtype_cstring)
ib_fprintf(out_file, "gds__vtov ((SCHAR*)%s, (SCHAR*)%s, %d);",
gen_name(s1, source),
gen_name(s2, reference), field->fld_length);
#else
/* To avoid chopping off a double byte kanji character in between
the two bytes, generate calls to gds__ftof2 gds$_vtof2 and
gds$_vtov2 wherever necessary
Cannot find where jrd_fof is defined. It needs Japanization too */
if (field->fld_dtype == dtype_text)
ib_fprintf(out_file, "jrd_ftof (%s, %d, %s, %d);",
gen_name(s1, source),
field->fld_length,
gen_name(s2, reference), field->fld_length);
else if (field->fld_dtype == dtype_cstring)
ib_fprintf(out_file, "gds__vtov2 (%s, %s, %d, %d);",
gen_name(s1, source),
gen_name(s2, reference), field->fld_length, sw_interp);
#endif
else
ib_fprintf(out_file, "%s = %s;",
gen_name(s1, reference), gen_name(s2, source));
}
gen_send(action->act_request, modify->upd_port, column);
}
//____________________________________________________________
//
// Generate substitution text for END_STORE.
//
static void gen_estore( ACT action, int column)
{
REQ request;
request = action->act_request;
align(column);
gen_compile(request, column);
gen_start(request, request->req_primary, column);
}
//____________________________________________________________
//
// Generate definitions associated with a single request.
//
static void gen_endfor( ACT action, int column)
{
REQ request;
request = action->act_request;
column += INDENT;
if (request->req_sync)
gen_send(request, request->req_sync, column);
END;
}
//____________________________________________________________
//
// Generate substitution text for ERASE.
//
static void gen_erase( ACT action, int column)
{
UPD erase;
erase = (UPD) action->act_object;
gen_send(erase->upd_request, erase->upd_port, column);
}
//____________________________________________________________
//
// Generate substitution text for FOR statement.
//
static void gen_for( ACT action, int column)
{
REQ request;
TEXT s[20];
gen_s_start(action, column);
align(column);
request = action->act_request;
ib_fprintf(out_file, "while (1)");
column += INDENT;
BEGIN;
align(column);
gen_receive(action->act_request, request->req_primary);
align(column);
ib_fprintf(out_file, "if (!%s) break;", gen_name(s, request->req_eof));
}
//____________________________________________________________
//
// Generate a name for a reference. Name is constructed from
// port and parameter idents.
//
static TEXT *gen_name( TEXT * string, REF reference)
{
sprintf(string, "jrd_%d.jrd_%d",
reference->ref_port->por_ident, reference->ref_ident);
return string;
}
//____________________________________________________________
//
// Generate BLR in raw, numeric form. Ugly but dense.
//
static void gen_raw( REQ request)
{
UCHAR *blr, c;
TEXT buffer[80], *p;
int blr_length;
blr = request->req_blr;
blr_length = request->req_length;
p = buffer;
align(0);
while (--blr_length) {
c = *blr++;
if ((c >= 'A' && c <= 'Z') || c == '$' || c == '_')
sprintf(p, "'%c',", c);
else
sprintf(p, "%d,", c);
while (*p)
p++;
if (p - buffer > 60) {
ib_fprintf(out_file, "%s\n", buffer);
p = buffer;
*p = 0;
}
}
ib_fprintf(out_file, "%s%d", buffer, blr_eoc);
}
//____________________________________________________________
//
// Generate a send or receive call for a port.
//
static void gen_receive( REQ request, POR port)
{
ib_fprintf(out_file,
"EXE_receive (tdbb, (REQ)%s, %d, %d, (UCHAR*)&jrd_%d);",
request->req_handle, port->por_msg_number, port->por_length,
port->por_ident);
}
//____________________________________________________________
//
// Generate definitions associated with a single request.
//
static void gen_request( REQ request)
{
if (!(request->req_flags & REQ_exp_hand))
ib_fprintf(out_file, "static void\t*%s;\t/* request handle */\n",
request->req_handle);
ib_fprintf(out_file, "static CONST UCHAR\tjrd_%d [%d] =",
request->req_ident, request->req_length);
align(INDENT);
ib_fprintf(out_file, "{\t/* blr string */\n", request->req_ident);
if (sw_raw)
gen_raw(request);
else
gds__print_blr(request->req_blr, (FPTR_VOID) gen_blr, 0, 0);
printa(INDENT, "};\t/* end of blr string */\n");
}
//____________________________________________________________
//
// Process routine head. If there are requests in the
// routine, insert local definitions.
//
static void gen_routine( ACT action, int column)
{
REQ request;
POR port;
for (request = (REQ) action->act_object; request;
request = request->req_routine) for (port = request->req_ports; port;
port = port->por_next)
make_port(port, column + INDENT);
}
//____________________________________________________________
//
// Generate substitution text for END_STREAM.
//
static void gen_s_end( ACT action, int column)
{
REQ request;
request = action->act_request;
printa(column, "EXE_unwind (tdbb, %s);", request->req_handle);
}
//____________________________________________________________
//
// Generate substitution text for FETCH.
//
static void gen_s_fetch( ACT action, int column)
{
REQ request;
request = action->act_request;
if (request->req_sync)
gen_send(request, request->req_sync, column);
gen_receive(action->act_request, request->req_primary);
}
//____________________________________________________________
//
// Generate text to compile and start a stream. This is
// used both by START_STREAM and FOR
//
static void gen_s_start( ACT action, int column)
{
REQ request;
POR port;
request = action->act_request;
gen_compile(request, column);
if (port = request->req_vport)
asgn_from(port->por_references, column);
gen_start(request, port, column);
}
//____________________________________________________________
//
// Generate a send or receive call for a port.
//
static void gen_send( REQ request, POR port, int column)
{
align(column);
ib_fprintf(out_file, "EXE_send (tdbb, (REQ)%s, %d, %d, (UCHAR*)&jrd_%d);",
request->req_handle,
port->por_msg_number, port->por_length, port->por_ident);
}
//____________________________________________________________
//
// Generate a START.
//
static void gen_start( REQ request, POR port, int column)
{
align(column);
ib_fprintf(out_file, "EXE_start (tdbb, (REQ)%s, %s);",
request->req_handle, request->req_trans);
if (port)
gen_send(request, port, column);
}
//____________________________________________________________
//
// Substitute for a variable reference.
//
static void gen_type( ACT action, int column)
{
printa(column, "%ld", action->act_object);
}
//____________________________________________________________
//
// Substitute for a variable reference.
//
static void gen_variable( ACT action, int column)
{
TEXT s[20];
align(column);
ib_fprintf(out_file, gen_name(s, action->act_object));
}
//____________________________________________________________
//
// Insert a port record description in output.
//
static void make_port( POR port, int column)
{
FLD field;
REF reference;
SYM symbol;
TEXT *name, s[50];
printa(column, "struct {");
for (reference = port->por_references; reference;
reference = reference->ref_next) {
align(column + INDENT);
field = reference->ref_field;
symbol = field->fld_symbol;
name = symbol->sym_string;
switch (field->fld_dtype) {
case dtype_short:
ib_fprintf(out_file, " SSHORT jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
case dtype_long:
ib_fprintf(out_file, " SLONG jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
// ** Begin sql date/time/timestamp *
case dtype_sql_date:
ib_fprintf(out_file, " ISC_DATE jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
case dtype_sql_time:
ib_fprintf(out_file, " ISC_TIME jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
case dtype_timestamp:
ib_fprintf(out_file, " ISC_TIMESTAMP jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
// ** End sql date/time/timestamp *
case dtype_int64:
ib_fprintf(out_file, " ISC_INT64 jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
case dtype_quad:
case dtype_blob:
ib_fprintf(out_file, " GDS__QUAD jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
case dtype_cstring:
case dtype_text:
ib_fprintf(out_file, " TEXT jrd_%d [%d];\t/* %s */",
reference->ref_ident, field->fld_length, name);
break;
case dtype_float:
ib_fprintf(out_file, " float jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
case dtype_double:
ib_fprintf(out_file, " double jrd_%d;\t/* %s */",
reference->ref_ident, name);
break;
default:
sprintf(s, "datatype %d unknown for field %s, msg %d",
field->fld_dtype, name, port->por_msg_number);
CPR_error(s);
return;
}
}
align(column);
ib_fprintf(out_file, "} jrd_%d;", port->por_ident);
}
//____________________________________________________________
//
// Print a fixed string at a particular column.
//
static void printa( int column, TEXT * string, ...)
{
va_list ptr;
VA_START(ptr, string);
align(column);
ib_vfprintf(out_file, string, ptr);
}