#include "config.h"
#include <string.h>
#include "libgfortran.h"
#include "io.h"
gfc_unit *current_unit;
static int sf_seen_eor = 0;
char scratch[SCRATCH_SIZE];
static char *line_buffer = NULL;
static unit_advance advance_status;
static st_option advance_opt[] = {
{"yes", ADVANCE_YES},
{"no", ADVANCE_NO},
{NULL}
};
static void (*transfer) (bt, void *, int);
typedef enum
{ FORMATTED_SEQUENTIAL, UNFORMATTED_SEQUENTIAL,
FORMATTED_DIRECT, UNFORMATTED_DIRECT
}
file_mode;
static file_mode
current_mode (void)
{
file_mode m;
if (current_unit->flags.access == ACCESS_DIRECT)
{
m = current_unit->flags.form == FORM_FORMATTED ?
FORMATTED_DIRECT : UNFORMATTED_DIRECT;
}
else
{
m = current_unit->flags.form == FORM_FORMATTED ?
FORMATTED_SEQUENTIAL : UNFORMATTED_SEQUENTIAL;
}
return m;
}
static char *
read_sf (int *length)
{
static char data[SCRATCH_SIZE];
char *base, *p, *q;
int n, unity;
if (*length > SCRATCH_SIZE)
p = base = line_buffer = get_mem (*length);
else
p = base = data;
memset(base,'\0',*length);
current_unit->bytes_left = options.default_recl;
unity = 1;
n = 0;
do
{
if (is_internal_unit())
{
unity = 1;
}
q = salloc_r (current_unit->s, &unity);
if (q == NULL)
break;
if (*q == '\n')
{
if (current_unit->unit_number == options.stdin_unit)
{
if (n <= 0)
continue;
}
if (current_unit->flags.pad == PAD_NO)
{
generate_error (ERROR_EOR, NULL);
return NULL;
}
current_unit->bytes_left = 0;
*length = n;
sf_seen_eor = 1;
break;
}
n++;
*p++ = *q;
sf_seen_eor = 0;
}
while (n < *length);
return base;
}
void *
read_block (int *length)
{
char *source;
int nread;
if (current_unit->flags.form == FORM_FORMATTED &&
current_unit->flags.access == ACCESS_SEQUENTIAL)
return read_sf (length);
if (current_unit->bytes_left < *length)
{
if (current_unit->flags.pad == PAD_NO)
{
generate_error (ERROR_EOR, NULL);
return NULL;
}
*length = current_unit->bytes_left;
}
current_unit->bytes_left -= *length;
nread = *length;
source = salloc_r (current_unit->s, &nread);
if (ioparm.size != NULL)
*ioparm.size += nread;
if (nread != *length)
{
if (current_unit->flags.pad == PAD_YES)
*length = nread;
else
{
generate_error (ERROR_EOR, NULL);
source = NULL;
}
}
return source;
}
void *
write_block (int length)
{
char *dest;
if (!is_internal_unit() && current_unit->bytes_left < length)
{
generate_error (ERROR_EOR, NULL);
return NULL;
}
current_unit->bytes_left -= length;
dest = salloc_w (current_unit->s, &length);
if (ioparm.size != NULL)
*ioparm.size += length;
return dest;
}
static void
unformatted_read (bt type, void *dest, int length)
{
void *source;
int w;
w = length;
source = read_block (&w);
if (source != NULL)
{
memcpy (dest, source, w);
if (length != w)
memset (((char *) dest) + w, ' ', length - w);
}
}
static void
unformatted_write (bt type, void *source, int length)
{
void *dest;
dest = write_block (length);
if (dest != NULL)
memcpy (dest, source, length);
}
const char *
type_name (bt type)
{
const char *p;
switch (type)
{
case BT_INTEGER:
p = "INTEGER";
break;
case BT_LOGICAL:
p = "LOGICAL";
break;
case BT_CHARACTER:
p = "CHARACTER";
break;
case BT_REAL:
p = "REAL";
break;
case BT_COMPLEX:
p = "COMPLEX";
break;
default:
internal_error ("type_name(): Bad type");
}
return p;
}
static void
write_constant_string (fnode * f)
{
char c, delimiter, *p, *q;
int length;
length = f->u.string.length;
if (length == 0)
return;
p = write_block (length);
if (p == NULL)
return;
q = f->u.string.p;
delimiter = q[-1];
for (; length > 0; length--)
{
c = *p++ = *q++;
if (c == delimiter && c != 'H')
q++;
}
}
static int
require_type (bt expected, bt actual, fnode * f)
{
char buffer[100];
if (actual == expected)
return 0;
st_sprintf (buffer, "Expected %s for item %d in formatted transfer, got %s",
type_name (expected), g.item_count, type_name (actual));
format_error (f, buffer);
return 1;
}
static void
formatted_transfer (bt type, void *p, int len)
{
int pos ,m ;
fnode *f;
int i, n;
int consume_data_flag;
n = (p == NULL) ? 0 : ((type != BT_COMPLEX) ? 1 : 2);
if (type == BT_COMPLEX)
type = BT_REAL;
if (g.reversion_flag && n > 0)
{
g.reversion_flag = 0;
next_record (0);
}
for (;;)
{
consume_data_flag = 1 ;
if (ioparm.library_return != LIBRARY_OK)
break;
f = next_format ();
if (f == NULL)
return;
switch (f->format)
{
case FMT_I:
if (n == 0)
goto need_data;
if (require_type (BT_INTEGER, type, f))
return;
if (g.mode == READING)
read_decimal (f, p, len);
else
write_i (f, p, len);
break;
case FMT_B:
if (n == 0)
goto need_data;
if (require_type (BT_INTEGER, type, f))
return;
if (g.mode == READING)
read_radix (f, p, len, 2);
else
write_b (f, p, len);
break;
case FMT_O:
if (n == 0)
goto need_data;
if (g.mode == READING)
read_radix (f, p, len, 8);
else
write_o (f, p, len);
break;
case FMT_Z:
if (n == 0)
goto need_data;
if (g.mode == READING)
read_radix (f, p, len, 16);
else
write_z (f, p, len);
break;
case FMT_A:
if (n == 0)
goto need_data;
if (require_type (BT_CHARACTER, type, f))
return;
if (g.mode == READING)
read_a (f, p, len);
else
write_a (f, p, len);
break;
case FMT_L:
if (n == 0)
goto need_data;
if (g.mode == READING)
read_l (f, p, len);
else
write_l (f, p, len);
break;
case FMT_D:
if (n == 0)
goto need_data;
if (require_type (BT_REAL, type, f))
return;
if (g.mode == READING)
read_f (f, p, len);
else
write_d (f, p, len);
break;
case FMT_E:
if (n == 0)
goto need_data;
if (require_type (BT_REAL, type, f))
return;
if (g.mode == READING)
read_f (f, p, len);
else
write_e (f, p, len);
break;
case FMT_EN:
if (n == 0)
goto need_data;
if (require_type (BT_REAL, type, f))
return;
if (g.mode == READING)
read_f (f, p, len);
else
write_en (f, p, len);
break;
case FMT_ES:
if (n == 0)
goto need_data;
if (require_type (BT_REAL, type, f))
return;
if (g.mode == READING)
read_f (f, p, len);
else
write_es (f, p, len);
break;
case FMT_F:
if (n == 0)
goto need_data;
if (require_type (BT_REAL, type, f))
return;
if (g.mode == READING)
read_f (f, p, len);
else
write_f (f, p, len);
break;
case FMT_G:
if (n == 0)
goto need_data;
if (g.mode == READING)
switch (type)
{
case BT_INTEGER:
read_decimal (f, p, len);
break;
case BT_LOGICAL:
read_l (f, p, len);
break;
case BT_CHARACTER:
read_a (f, p, len);
break;
case BT_REAL:
read_f (f, p, len);
break;
default:
goto bad_type;
}
else
switch (type)
{
case BT_INTEGER:
write_i (f, p, len);
break;
case BT_LOGICAL:
write_l (f, p, len);
break;
case BT_CHARACTER:
write_a (f, p, len);
break;
case BT_REAL:
write_d (f, p, len);
break;
default:
bad_type:
internal_error ("formatted_transfer(): Bad type");
}
break;
case FMT_STRING:
consume_data_flag = 0 ;
if (g.mode == READING)
{
format_error (f, "Constant string in input format");
return;
}
write_constant_string (f);
break;
case FMT_X:
case FMT_TR:
consume_data_flag = 0 ;
if (g.mode == READING)
read_x (f);
else
write_x (f);
break;
case FMT_T:
pos = f->u.n ;
pos= current_unit->recl - current_unit->bytes_left - pos;
case FMT_TL:
consume_data_flag = 0 ;
pos = f->u.n ;
if (pos < 0 || pos >= current_unit->recl )
{
generate_error (ERROR_EOR, "T Or TL edit position error");
break ;
}
m = pos - (current_unit->recl - current_unit->bytes_left);
if (m == 0)
break;
if (m > 0)
{
f->u.n = m;
if (g.mode == READING)
read_x (f);
else
write_x (f);
}
if (m < 0)
{
move_pos_offset (current_unit->s,m);
}
break;
case FMT_S:
consume_data_flag = 0 ;
g.sign_status = SIGN_S;
break;
case FMT_SS:
consume_data_flag = 0 ;
g.sign_status = SIGN_SS;
break;
case FMT_SP:
consume_data_flag = 0 ;
g.sign_status = SIGN_SP;
break;
case FMT_BN:
consume_data_flag = 0 ;
g.blank_status = BLANK_NULL;
break;
case FMT_BZ:
consume_data_flag = 0 ;
g.blank_status = BLANK_ZERO;
break;
case FMT_P:
consume_data_flag = 0 ;
g.scale_factor = f->u.k;
break;
case FMT_DOLLAR:
consume_data_flag = 0 ;
g.seen_dollar = 1;
break;
case FMT_SLASH:
consume_data_flag = 0 ;
for (i = 0; i < f->repeat; i++)
next_record (0);
break;
case FMT_COLON:
consume_data_flag = 0 ;
if (n == 0)
return;
break;
default:
internal_error ("Bad format node");
}
if (line_buffer != NULL)
{
free_mem (line_buffer);
line_buffer = NULL;
}
if ((consume_data_flag > 0) && (n > 0))
{
n--;
p = ((char *) p) + len;
}
}
return;
need_data:
unget_format (f);
}
void
transfer_integer (void *p, int kind)
{
g.item_count++;
if (ioparm.library_return != LIBRARY_OK)
return;
transfer (BT_INTEGER, p, kind);
}
void
transfer_real (void *p, int kind)
{
g.item_count++;
if (ioparm.library_return != LIBRARY_OK)
return;
transfer (BT_REAL, p, kind);
}
void
transfer_logical (void *p, int kind)
{
g.item_count++;
if (ioparm.library_return != LIBRARY_OK)
return;
transfer (BT_LOGICAL, p, kind);
}
void
transfer_character (void *p, int len)
{
g.item_count++;
if (ioparm.library_return != LIBRARY_OK)
return;
transfer (BT_CHARACTER, p, len);
}
void
transfer_complex (void *p, int kind)
{
g.item_count++;
if (ioparm.library_return != LIBRARY_OK)
return;
transfer (BT_COMPLEX, p, kind);
}
static void
us_read (void)
{
gfc_offset *p;
int n;
n = sizeof (gfc_offset);
p = (gfc_offset *) salloc_r (current_unit->s, &n);
if (p == NULL || n != sizeof (gfc_offset))
{
generate_error (ERROR_BAD_US, NULL);
return;
}
current_unit->bytes_left = *p;
}
static void
us_write (void)
{
gfc_offset *p;
int length;
length = sizeof (gfc_offset);
p = (gfc_offset *) salloc_w (current_unit->s, &length);
if (p == NULL)
{
generate_error (ERROR_OS, NULL);
return;
}
*p = 0;
if (sfree (current_unit->s) == FAILURE)
generate_error (ERROR_OS, NULL);
current_unit->bytes_left = current_unit->recl;
}
static void
pre_position (void)
{
if (current_unit->current_record)
return;
switch (current_mode ())
{
case UNFORMATTED_SEQUENTIAL:
if (g.mode == READING)
us_read ();
else
us_write ();
break;
case FORMATTED_SEQUENTIAL:
case FORMATTED_DIRECT:
case UNFORMATTED_DIRECT:
current_unit->bytes_left = current_unit->recl;
break;
}
current_unit->current_record = 1;
}
static void
data_transfer_init (int read_flag)
{
unit_flags u_flags;
g.mode = read_flag ? READING : WRITING;
if (ioparm.size != NULL)
*ioparm.size = 0;
current_unit = get_unit (read_flag);
if (current_unit == NULL)
{
memset (&u_flags, '\0', sizeof (u_flags));
u_flags.access = ACCESS_SEQUENTIAL;
u_flags.action = ACTION_READWRITE;
u_flags.form = FORM_UNSPECIFIED;
u_flags.delim = DELIM_UNSPECIFIED;
u_flags.blank = BLANK_UNSPECIFIED;
u_flags.pad = PAD_UNSPECIFIED;
u_flags.status = STATUS_UNKNOWN;
new_unit(&u_flags);
current_unit = get_unit (read_flag);
}
if (current_unit == NULL)
return;
if (is_internal_unit() && g.mode==WRITING)
empty_internal_buffer (current_unit->s);
if (read_flag && current_unit->flags.action == ACTION_WRITE)
generate_error (ERROR_BAD_ACTION,
"Cannot read from file opened for WRITE");
if (!read_flag && current_unit->flags.action == ACTION_READ)
generate_error (ERROR_BAD_ACTION, "Cannot write to file opened for READ");
if (ioparm.library_return != LIBRARY_OK)
return;
if (ioparm.format)
parse_format ();
if (ioparm.library_return != LIBRARY_OK)
return;
if (current_unit->flags.form == FORM_UNFORMATTED
&& (ioparm.format != NULL || ioparm.list_format))
generate_error (ERROR_OPTION_CONFLICT,
"Format present for UNFORMATTED data transfer");
if (ioparm.namelist_name != NULL && ionml != NULL)
{
if(ioparm.format != NULL)
generate_error (ERROR_OPTION_CONFLICT,
"A format cannot be specified with a namelist");
}
else if (current_unit->flags.form == FORM_FORMATTED &&
ioparm.format == NULL && !ioparm.list_format)
generate_error (ERROR_OPTION_CONFLICT,
"Missing format for FORMATTED data transfer");
if (is_internal_unit () && current_unit->flags.form == FORM_UNFORMATTED)
generate_error (ERROR_OPTION_CONFLICT,
"Internal file cannot be accessed by UNFORMATTED data transfer");
if (current_unit->flags.access == ACCESS_DIRECT && ioparm.rec == 0)
{
generate_error (ERROR_MISSING_OPTION,
"Direct access data transfer requires record number");
return;
}
if (current_unit->flags.access == ACCESS_SEQUENTIAL && ioparm.rec != 0)
{
generate_error (ERROR_OPTION_CONFLICT,
"Record number not allowed for sequential access data transfer");
return;
}
advance_status = (ioparm.advance == NULL) ? ADVANCE_UNSPECIFIED :
find_option (ioparm.advance, ioparm.advance_len, advance_opt,
"Bad ADVANCE parameter in data transfer statement");
if (advance_status != ADVANCE_UNSPECIFIED)
{
if (current_unit->flags.access == ACCESS_DIRECT)
generate_error (ERROR_OPTION_CONFLICT,
"ADVANCE specification conflicts with sequential access");
if (is_internal_unit ())
generate_error (ERROR_OPTION_CONFLICT,
"ADVANCE specification conflicts with internal file");
if (ioparm.format == NULL || ioparm.list_format)
generate_error (ERROR_OPTION_CONFLICT,
"ADVANCE specification requires an explicit format");
}
if (read_flag)
{
if (ioparm.eor != 0 && advance_status == ADVANCE_NO)
generate_error (ERROR_MISSING_OPTION,
"EOR specification requires an ADVANCE specification of NO");
if (ioparm.size != NULL && advance_status != ADVANCE_NO)
generate_error (ERROR_MISSING_OPTION,
"SIZE specification requires an ADVANCE specification of NO");
}
else
{
if (ioparm.end != 0)
generate_error (ERROR_OPTION_CONFLICT,
"END specification cannot appear in a write statement");
if (ioparm.eor != 0)
generate_error (ERROR_OPTION_CONFLICT,
"EOR specification cannot appear in a write statement");
if (ioparm.size != 0)
generate_error (ERROR_OPTION_CONFLICT,
"SIZE specification cannot appear in a write statement");
}
if (advance_status == ADVANCE_UNSPECIFIED)
advance_status = ADVANCE_YES;
if (ioparm.library_return != LIBRARY_OK)
return;
if (ioparm.rec)
{
if (ioparm.rec <= 0)
{
generate_error (ERROR_BAD_OPTION, "Record number must be positive");
return;
}
if (ioparm.rec >= current_unit->maxrec)
{
generate_error (ERROR_BAD_OPTION, "Record number too large");
return;
}
if (sseek (current_unit->s,
(ioparm.rec - 1) * current_unit->recl) == FAILURE)
generate_error (ERROR_OS, NULL);
}
g.blank_status = current_unit->flags.blank;
g.sign_status = SIGN_S;
g.scale_factor = 0;
g.seen_dollar = 0;
g.first_item = 1;
g.item_count = 0;
pre_position ();
if (read_flag)
{
if (current_unit->flags.form == FORM_UNFORMATTED)
transfer = unformatted_read;
else
{
if (ioparm.list_format)
{
transfer = list_formatted_read;
init_at_eol();
}
else
transfer = formatted_transfer;
}
}
else
{
if (current_unit->flags.form == FORM_UNFORMATTED)
transfer = unformatted_write;
else
{
if (ioparm.list_format)
transfer = list_formatted_write;
else
transfer = formatted_transfer;
}
}
if (read_flag)
{
if (current_unit->read_bad)
{
generate_error (ERROR_BAD_OPTION,
"Cannot READ after a nonadvancing WRITE");
return;
}
}
else
{
if (advance_status == ADVANCE_YES)
current_unit->read_bad = 1;
}
if (current_unit->flags.form == FORM_FORMATTED && !ioparm.list_format
&& ioparm.namelist_name == NULL && ionml == NULL)
formatted_transfer (0, NULL, 0);
}
#define MAX_READ 4096
static void
next_record_r (int done)
{
int rlength, length;
gfc_offset new;
char *p;
switch (current_mode ())
{
case UNFORMATTED_SEQUENTIAL:
current_unit->bytes_left += sizeof (gfc_offset);
case FORMATTED_DIRECT:
case UNFORMATTED_DIRECT:
if (current_unit->bytes_left == 0)
break;
if (is_seekable (current_unit->s))
{
new = file_position (current_unit->s) + current_unit->bytes_left;
if (sseek (current_unit->s, new) == FAILURE)
generate_error (ERROR_OS, NULL);
}
else
{
while (current_unit->bytes_left > 0)
{
rlength = length = (MAX_READ > current_unit->bytes_left) ?
MAX_READ : current_unit->bytes_left;
p = salloc_r (current_unit->s, &rlength);
if (p == NULL)
{
generate_error (ERROR_OS, NULL);
break;
}
current_unit->bytes_left -= length;
}
}
break;
case FORMATTED_SEQUENTIAL:
length = 1;
if (sf_seen_eor && done)
break;
do
{
p = salloc_r (current_unit->s, &length);
if (is_internal_unit() && p == NULL)
{
break;
}
if (p == NULL)
{
generate_error (ERROR_OS, NULL);
break;
}
if (length == 0)
{
current_unit->endfile = AT_ENDFILE;
break;
}
}
while (*p != '\n');
break;
}
if (current_unit->flags.access == ACCESS_SEQUENTIAL)
test_endfile (current_unit);
}
static void
next_record_w (int done)
{
gfc_offset c, m;
int length;
char *p;
switch (current_mode ())
{
case FORMATTED_DIRECT:
case UNFORMATTED_DIRECT:
if (current_unit->bytes_left == 0)
break;
length = current_unit->bytes_left;
p = salloc_w (current_unit->s, &length);
if (p == NULL)
goto io_error;
memset (p, ' ', current_unit->bytes_left);
if (sfree (current_unit->s) == FAILURE)
goto io_error;
break;
case UNFORMATTED_SEQUENTIAL:
m = current_unit->recl - current_unit->bytes_left;
c = file_position (current_unit->s);
length = sizeof (gfc_offset);
p = salloc_w (current_unit->s, &length);
if (p == NULL)
goto io_error;
*((gfc_offset *) p) = m;
if (sfree (current_unit->s) == FAILURE)
goto io_error;
p = salloc_w_at (current_unit->s, &length, c - m - length);
if (p == NULL)
generate_error (ERROR_OS, NULL);
*((gfc_offset *) p) = m;
if (sfree (current_unit->s) == FAILURE)
goto io_error;
if (sseek (current_unit->s, c + sizeof (gfc_offset)) == FAILURE)
goto io_error;
break;
case FORMATTED_SEQUENTIAL:
length = 1;
p = salloc_w (current_unit->s, &length);
if (!is_internal_unit())
{
if (p)
*p = '\n';
else
goto io_error;
}
if (sfree (current_unit->s) == FAILURE)
goto io_error;
break;
io_error:
generate_error (ERROR_OS, NULL);
break;
}
}
void
next_record (int done)
{
current_unit->read_bad = 0;
if (g.mode == READING)
next_record_r (done);
else
next_record_w (done);
current_unit->current_record = 0;
if (current_unit->flags.access == ACCESS_DIRECT)
current_unit->last_record = file_position (current_unit->s)
/ current_unit->recl;
else
current_unit->last_record++;
if (!done)
pre_position ();
}
static void
finalize_transfer (void)
{
if (setjmp (g.eof_jump))
{
generate_error (ERROR_END, NULL);
return;
}
if ((ionml != NULL) && (ioparm.namelist_name != NULL))
{
if (ioparm.namelist_read_mode)
namelist_read();
else
namelist_write();
}
transfer = NULL;
if (current_unit == NULL)
return;
if (ioparm.list_format && g.mode == READING)
finish_list_read ();
else
{
free_fnodes ();
if (advance_status == ADVANCE_NO)
{
flush (current_unit->s);
return;
}
next_record (1);
current_unit->current_record = 0;
}
sfree (current_unit->s);
}
void
st_read (void)
{
library_start ();
data_transfer_init (1);
if (current_unit->flags.access == ACCESS_SEQUENTIAL)
switch (current_unit->endfile)
{
case NO_ENDFILE:
break;
case AT_ENDFILE:
if (!is_internal_unit())
{
generate_error (ERROR_END, NULL);
current_unit->endfile = AFTER_ENDFILE;
}
break;
case AFTER_ENDFILE:
generate_error (ERROR_ENDFILE, NULL);
break;
}
}
void
st_read_done (void)
{
finalize_transfer ();
library_end ();
}
void
st_write (void)
{
library_start ();
data_transfer_init (0);
}
void
st_write_done (void)
{
finalize_transfer ();
if (current_unit != NULL && current_unit->flags.access == ACCESS_SEQUENTIAL)
switch (current_unit->endfile)
{
case AT_ENDFILE:
break;
case AFTER_ENDFILE:
current_unit->endfile = AT_ENDFILE;
break;
case NO_ENDFILE:
if (struncate (current_unit->s) == FAILURE)
generate_error (ERROR_OS, NULL);
current_unit->endfile = AT_ENDFILE;
break;
}
library_end ();
}
static void
st_set_nml_var (void * var_addr, char * var_name, int var_name_len,
int kind, bt type)
{
namelist_info *t1 = NULL, *t2 = NULL;
namelist_info *nml = (namelist_info *) get_mem (sizeof(
namelist_info ));
nml->mem_pos = var_addr;
nml->var_name = (char*) get_mem (var_name_len+1);
strncpy (nml->var_name,var_name,var_name_len);
nml->var_name[var_name_len] = 0;
nml->len = kind;
nml->type = type;
nml->next = NULL;
if (ionml == NULL)
ionml = nml;
else
{
t1 = ionml;
while (t1 != NULL)
{
t2 = t1;
t1 = t1->next;
}
t2->next = nml;
}
}
void
st_set_nml_var_int (void * var_addr, char * var_name, int var_name_len,
int kind)
{
st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_INTEGER);
}
void
st_set_nml_var_float (void * var_addr, char * var_name, int var_name_len,
int kind)
{
st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_REAL);
}
void
st_set_nml_var_char (void * var_addr, char * var_name, int var_name_len,
int kind)
{
st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_CHARACTER);
}
void
st_set_nml_var_complex (void * var_addr, char * var_name, int var_name_len,
int kind)
{
st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_COMPLEX);
}
void
st_set_nml_var_log (void * var_addr, char * var_name, int var_name_len,
int kind)
{
st_set_nml_var (var_addr, var_name, var_name_len, kind, BT_LOGICAL);
}