Add full $ferror() support, bug fixes, etc.
This patch adds $ferror() support. This is enhanced over what the standard says needs to be supported. All file I/O routines set/clear the errno flag, This allows $ferror() to check when an invalid fd/MCD is passed to a system task. The $ferror() fd is only checked if errno is not set since all the other routines will set EBADF when they are called. This allows us to test the output from $fopen() which sets the fd to zero (an invalid fd) when it has a problem. The following bugs (changes) are also fixed: Fix $fdisplay*, $fwrite*, $fstrobe*, $fflush, $fclose to not accept 0 as a valid MCD. For the $fdisplay*, $fwrite* and $fstrobe tasks an invalid fd/MCD is now a warning instead of an error like the other file I/O routines. Modify $fputc() to be a function and return a value like $ungetc(). Modify $ungetc() to return a value like the standard dictates (-1 on error else 0) and pass the value as a full int to get EOF as an error. Remove some extra checks that could not happen in $fseek() and to be safe convert the numeric codes to the system symbolic values. Skip $fstrobe callback when the fd/MCD is closed. The standard says we need to cancel the callback, but we currently do not have the ability to do that so just skipping this will work for now. Free the argument handle when $fscanf() is called with an invalid fd (memory leak).
This commit is contained in:
parent
b0ac550791
commit
ce89a68735
|
|
@ -23,6 +23,7 @@
|
|||
# include "sys_priv.h"
|
||||
# include <assert.h>
|
||||
# include <string.h>
|
||||
# include <errno.h>
|
||||
# include <ctype.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
|
|
@ -1120,18 +1121,20 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8 *name)
|
|||
|
||||
/* Get the file/MC descriptor and verify it is valid. */
|
||||
if(name[1] == 'f') {
|
||||
errno = 0;
|
||||
vpiHandle arg = vpi_scan(argv);
|
||||
s_vpi_value val;
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(arg, &val);
|
||||
fd_mcd = val.value.integer;
|
||||
if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) ||
|
||||
( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF)) {
|
||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF) ||
|
||||
(! fd_mcd)) {
|
||||
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor/MCD (0x%x) given "
|
||||
"to %s.\n", fd_mcd, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
errno = EBADF;
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1180,10 +1183,15 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8 *name)
|
|||
*/
|
||||
static PLI_INT32 strobe_cb(p_cb_data cb)
|
||||
{
|
||||
char* result;
|
||||
char* result = NULL;
|
||||
unsigned int size, location=0;
|
||||
struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
|
||||
|
||||
/* We really need to cancel any $fstrobe() calls for a file when it
|
||||
* is closed, but for now we will just skip processing the result.
|
||||
* Which has the same basic effect. */
|
||||
if ((! IS_MCD(info->fd_mcd) && vpi_get_file(info->fd_mcd) != NULL) ||
|
||||
( IS_MCD(info->fd_mcd) && my_mcd_printf(info->fd_mcd, "") != EOF)) {
|
||||
/* Because %u and %z may put embedded NULL characters into the
|
||||
* returned string strlen() may not match the real size! */
|
||||
result = get_display(&size, info);
|
||||
|
|
@ -1197,6 +1205,7 @@ static PLI_INT32 strobe_cb(p_cb_data cb)
|
|||
}
|
||||
}
|
||||
my_mcd_printf(info->fd_mcd, "\n");
|
||||
}
|
||||
|
||||
free(info->filename);
|
||||
free(info->items);
|
||||
|
|
@ -1226,18 +1235,20 @@ static PLI_INT32 sys_strobe_calltf(PLI_BYTE8*name)
|
|||
|
||||
/* Get the file/MC descriptor and verify it is valid. */
|
||||
if(name[1] == 'f') {
|
||||
errno = 0;
|
||||
vpiHandle arg = vpi_scan(argv);
|
||||
s_vpi_value val;
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(arg, &val);
|
||||
fd_mcd = val.value.integer;
|
||||
if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) ||
|
||||
( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF)) {
|
||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
( IS_MCD(fd_mcd) && my_mcd_printf(fd_mcd, "") == EOF) ||
|
||||
(! fd_mcd)) {
|
||||
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor/MCD (0x%x) given "
|
||||
"to %s.\n", fd_mcd, name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
errno = EBADF;
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
206
vpi/sys_fileio.c
206
vpi/sys_fileio.c
|
|
@ -21,13 +21,13 @@
|
|||
# include "sys_priv.h"
|
||||
# include <assert.h>
|
||||
# include <ctype.h>
|
||||
# include <errno.h>
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
|
||||
#define IS_MCD(mcd) !((mcd)>>31&1)
|
||||
|
||||
|
||||
/*
|
||||
* Implement the $fopen system function.
|
||||
*/
|
||||
|
|
@ -83,6 +83,8 @@ static PLI_INT32 sys_fopen_calltf(PLI_BYTE8*name)
|
|||
vpiHandle fileh = vpi_scan(argv);
|
||||
char *fname;
|
||||
vpiHandle mode = vpi_scan(argv);
|
||||
errno = 0;
|
||||
|
||||
/* Get the mode handle if it exists. */
|
||||
if (mode) {
|
||||
char *esc_md;
|
||||
|
|
@ -180,7 +182,7 @@ static PLI_INT32 sys_fopenrwa_calltf(PLI_BYTE8*name)
|
|||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
s_vpi_value val;
|
||||
char *mode, *fname;
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* Get the mode. */
|
||||
mode = name + strlen(name) - 1;
|
||||
|
|
@ -210,6 +212,7 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name)
|
|||
s_vpi_value val;
|
||||
PLI_UINT32 fd_mcd;
|
||||
char *str = ""; /* This prevents the compiler from complaining. */
|
||||
errno = 0;
|
||||
|
||||
vpi_free_object(argv);
|
||||
|
||||
|
|
@ -219,15 +222,19 @@ static PLI_INT32 sys_fclose_calltf(PLI_BYTE8*name)
|
|||
fd_mcd = val.value.integer;
|
||||
|
||||
if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) ||
|
||||
( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF)) {
|
||||
( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF) ||
|
||||
(! fd_mcd)) {
|
||||
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor/MCD (0x%x) given to %s.\n",
|
||||
fd_mcd, name);
|
||||
errno = EBADF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We need to cancel any active $fstrobe()'s for this FD/MCD. */
|
||||
/* We need to cancel any active $fstrobe()'s for this FD/MCD.
|
||||
* For now we check in the strobe callback and skip the output
|
||||
* generation when needed. */
|
||||
vpi_mcd_close(fd_mcd);
|
||||
|
||||
return 0;
|
||||
|
|
@ -245,6 +252,7 @@ static PLI_INT32 sys_fflush_calltf(PLI_BYTE8*name)
|
|||
PLI_UINT32 fd_mcd;
|
||||
FILE *fp;
|
||||
char *str = ""; /* This prevents the compiler from complaining. */
|
||||
errno = 0;
|
||||
|
||||
/* If we have no argument then flush all the streams. */
|
||||
if (argv == 0) {
|
||||
|
|
@ -260,11 +268,13 @@ static PLI_INT32 sys_fflush_calltf(PLI_BYTE8*name)
|
|||
fd_mcd = val.value.integer;
|
||||
|
||||
if ((! IS_MCD(fd_mcd) && vpi_get_file(fd_mcd) == NULL) ||
|
||||
( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF)) {
|
||||
( IS_MCD(fd_mcd) && vpi_mcd_printf(fd_mcd, str) == EOF) ||
|
||||
(! fd_mcd)) {
|
||||
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor/MCD (0x%x) given to %s.\n",
|
||||
fd_mcd, name);
|
||||
errno = EBADF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -288,7 +298,7 @@ static PLI_INT32 sys_fputc_calltf(PLI_BYTE8*name)
|
|||
PLI_UINT32 fd_mcd;
|
||||
FILE *fp;
|
||||
unsigned char chr;
|
||||
(void) name; /* Not used! */
|
||||
errno = 0;
|
||||
|
||||
/* Get the character. */
|
||||
arg = vpi_scan(argv);
|
||||
|
|
@ -312,9 +322,12 @@ static PLI_INT32 sys_fputc_calltf(PLI_BYTE8*name)
|
|||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
|
||||
name);
|
||||
errno = EBADF;
|
||||
val.value.integer = EOF;
|
||||
} else
|
||||
} else {
|
||||
val.value.integer = fputc(chr, fp);
|
||||
if (val.value.integer != EOF) val.value.integer = 0;
|
||||
}
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
|
|
@ -378,7 +391,7 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name)
|
|||
FILE *fp;
|
||||
PLI_INT32 reg_size;
|
||||
char*text;
|
||||
(void) name; /* Not used! */
|
||||
errno = 0;
|
||||
|
||||
/* Get the register handle. */
|
||||
regh = vpi_scan(argv);
|
||||
|
|
@ -397,6 +410,7 @@ static PLI_INT32 sys_fgets_calltf(PLI_BYTE8*name)
|
|||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
|
||||
name);
|
||||
errno = EBADF;
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 0;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
|
@ -566,6 +580,7 @@ static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name)
|
|||
unsigned is_mem, idx, bpe, words;
|
||||
FILE *fp;
|
||||
s_vpi_vecval *vector;
|
||||
errno = 0;
|
||||
|
||||
/* Get the register/memory. */
|
||||
mem_reg = vpi_scan(argv);
|
||||
|
|
@ -583,6 +598,7 @@ static PLI_INT32 sys_fread_calltf(PLI_BYTE8*name)
|
|||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
|
||||
name);
|
||||
errno = EBADF;
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = 0;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
|
@ -693,8 +709,8 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
|||
s_vpi_value val;
|
||||
PLI_UINT32 fd_mcd;
|
||||
FILE *fp;
|
||||
unsigned char chr;
|
||||
(void) name; /* Not used! */
|
||||
int chr;
|
||||
errno = 0;
|
||||
|
||||
/* Get the character. */
|
||||
arg = vpi_scan(argv);
|
||||
|
|
@ -716,6 +732,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
|||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
|
||||
name);
|
||||
errno = EBADF;
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = EOF;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
|
@ -725,6 +742,7 @@ static PLI_INT32 sys_ungetc_calltf(PLI_BYTE8*name)
|
|||
/* ungetc the character and return the result. */
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = ungetc(chr, fp);
|
||||
if (val.value.integer != EOF) val.value.integer = 0;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
return 0;
|
||||
|
|
@ -763,7 +781,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!arg || !is_numeric_obj(arg)) {
|
||||
if (! is_numeric_obj(arg)) {
|
||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's second argument must be numeric.\n", name);
|
||||
|
|
@ -780,7 +798,7 @@ static PLI_INT32 sys_fseek_compiletf(PLI_BYTE8*name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!arg || !is_numeric_obj(arg)) {
|
||||
if (! is_numeric_obj(arg)) {
|
||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's third argument must be numeric.\n", name);
|
||||
|
|
@ -802,7 +820,7 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name)
|
|||
PLI_UINT32 fd_mcd;
|
||||
PLI_INT32 offset, oper;
|
||||
FILE *fp;
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* Get the file pointer. */
|
||||
arg = vpi_scan(argv);
|
||||
|
|
@ -824,15 +842,22 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name)
|
|||
oper = val.value.integer;
|
||||
|
||||
/* Check that the operation is in the valid range. */
|
||||
if ((oper < 0) || (oper > 2)) {
|
||||
switch (oper) {
|
||||
case 0:
|
||||
oper = SEEK_SET;
|
||||
break;
|
||||
case 1:
|
||||
oper = SEEK_CUR;
|
||||
break;
|
||||
case 2:
|
||||
oper = SEEK_END;
|
||||
break;
|
||||
default:
|
||||
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's operation must be 0, 1 or 2 given %d.\n",
|
||||
name, oper);
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = EOF;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
return 0;
|
||||
oper = -1; /* An invalid argument value. */
|
||||
}
|
||||
|
||||
/* Return EOF if this is not a valid fd. */
|
||||
|
|
@ -842,6 +867,7 @@ static PLI_INT32 sys_fseek_calltf(PLI_BYTE8*name)
|
|||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
|
||||
name);
|
||||
errno = EBADF;
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = EOF;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
|
@ -863,6 +889,7 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name)
|
|||
s_vpi_value val;
|
||||
PLI_UINT32 fd_mcd;
|
||||
FILE *fp;
|
||||
errno = 0;
|
||||
|
||||
/* Get the file pointer. */
|
||||
arg = vpi_scan(argv);
|
||||
|
|
@ -878,6 +905,7 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name)
|
|||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
|
||||
name);
|
||||
errno = EBADF;
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = EOF;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
|
@ -910,6 +938,119 @@ static PLI_INT32 sys_common_fd_calltf(PLI_BYTE8*name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement the $ferror system function.
|
||||
*/
|
||||
static PLI_INT32 sys_ferror_compiletf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv;
|
||||
vpiHandle arg;
|
||||
|
||||
argv = vpi_iterate(vpiArgument, callh);
|
||||
|
||||
/*
|
||||
* Check that there are two arguments and that the first is
|
||||
* numeric and that the second is a 640 bit or larger register.
|
||||
*
|
||||
* The parser requires that a function have at least one argument,
|
||||
* so argv should always be defined with one argument.
|
||||
*/
|
||||
assert(argv);
|
||||
|
||||
if (! is_numeric_obj(vpi_scan(argv))) {
|
||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's fd (first) argument must be numeric.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* Check that the second argument is given and that it is a 640 bit
|
||||
* or larger register. */
|
||||
arg = vpi_scan(argv);
|
||||
if (! arg) {
|
||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s requires a second (register) argument.\n", name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vpi_get(vpiType, arg) != vpiReg) {
|
||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's second argument must be a reg (>=640 bits).\n",
|
||||
name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
} else if (vpi_get(vpiSize, arg) < 640) {
|
||||
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("%s's second argument must have 640 bit or more.\n",
|
||||
name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
}
|
||||
|
||||
/* Make sure there are no extra arguments. */
|
||||
check_for_extra_args(argv, callh, name, "two arguments", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 sys_ferror_calltf(PLI_BYTE8 *name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||
vpiHandle reg;
|
||||
s_vpi_value val;
|
||||
char *msg;
|
||||
PLI_INT32 size;
|
||||
unsigned chars;
|
||||
PLI_UINT32 fd_mcd;
|
||||
|
||||
/* Get the file pointer. */
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(vpi_scan(argv), &val);
|
||||
fd_mcd = val.value.integer;
|
||||
|
||||
/* Get the register to put the string result and figure out how many
|
||||
* characters it will hold. */
|
||||
reg = vpi_scan(argv);
|
||||
size = vpi_get(vpiSize, reg);
|
||||
chars = size / 8;
|
||||
vpi_free_object(argv);
|
||||
|
||||
/* If we do not already have an error check that the fd is valid.
|
||||
* The assumption is that the other routines have set errno to
|
||||
* EBADF when they encounter a bad file descriptor, so we do not
|
||||
* need to check here. We also need to special case this since
|
||||
* $fopen() will return 0 (a bad file descriptor) when it has a
|
||||
* problem (sets errno). */
|
||||
if (!errno && !vpi_get_file(fd_mcd) ) {
|
||||
vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor (0x%x) given to %s.\n", fd_mcd,
|
||||
name);
|
||||
errno = EBADF;
|
||||
}
|
||||
|
||||
/* Return the error code. */
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = errno;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
|
||||
/* Only return the number of characters that will fit in the reg. */
|
||||
msg = (char *) malloc(chars);
|
||||
if (errno != 0) strncpy(msg, strerror(errno), chars-1);
|
||||
else strncpy(msg, "", chars-1);
|
||||
msg[chars-1] = '\0';
|
||||
val.format = vpiStringVal;
|
||||
val.value.str = msg;
|
||||
vpi_put_value(reg, &val, 0, vpiNoDelay);
|
||||
free(msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sys_fileio_register()
|
||||
{
|
||||
s_vpi_systf_data tf_data;
|
||||
|
|
@ -962,15 +1103,6 @@ void sys_fileio_register()
|
|||
tf_data.user_data = "$fflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
/*============================== fputc */
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$fputc";
|
||||
tf_data.calltf = sys_fputc_calltf;
|
||||
tf_data.compiletf = sys_two_numeric_args_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$fputc";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
/*============================== fgetc */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
|
|
@ -1041,6 +1173,16 @@ void sys_fileio_register()
|
|||
tf_data.user_data = "$rewind";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
/*============================== ferror */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.tfname = "$ferror";
|
||||
tf_data.calltf = sys_ferror_calltf;
|
||||
tf_data.compiletf = sys_ferror_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$ferror";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
/* $feof() is from 1364-2005. */
|
||||
/*============================== feof */
|
||||
tf_data.type = vpiSysFunc;
|
||||
|
|
@ -1052,4 +1194,14 @@ void sys_fileio_register()
|
|||
tf_data.user_data = "$feof";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
/* Icarus specific. */
|
||||
/*============================== fputc */
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
tf_data.tfname = "$fputc";
|
||||
tf_data.calltf = sys_fputc_calltf;
|
||||
tf_data.compiletf = sys_two_numeric_args_compiletf;
|
||||
tf_data.sizetf = 0;
|
||||
tf_data.user_data = "$fputc";
|
||||
vpi_register_systf(&tf_data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,17 +53,6 @@ static PLI_INT32 task_not_implemented_compiletf(PLI_BYTE8* name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static PLI_INT32 function_not_implemented_compiletf(PLI_BYTE8* name)
|
||||
{
|
||||
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||
|
||||
vpi_printf("%s:%d: SORRY: function %s() is not currently implemented.\n",
|
||||
vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh),
|
||||
name);
|
||||
vpi_control(vpiFinish, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to warn the user that the specified optional system
|
||||
* task/function is not available (from Annex C 1364-2005).
|
||||
|
|
@ -222,15 +211,6 @@ void sys_special_register(void)
|
|||
|
||||
tf_data.tfname = "$dumpportsflush";
|
||||
tf_data.user_data = "$dumpportsflush";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
/* These functions are not currently implemented. */
|
||||
tf_data.compiletf = function_not_implemented_compiletf;
|
||||
tf_data.type = vpiSysFunc;
|
||||
tf_data.sysfunctype = vpiIntFunc;
|
||||
|
||||
tf_data.tfname = "$ferror";
|
||||
tf_data.user_data = "$ferror";
|
||||
vpi_register_systf(&tf_data);
|
||||
|
||||
/* The following optional system tasks/functions are not implemented
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
# include "vpi_user.h"
|
||||
# include "sys_priv.h"
|
||||
# include <ctype.h>
|
||||
# include <errno.h>
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
|
|
@ -639,6 +640,7 @@ static PLI_INT32 sys_fscanf_calltf(PLI_BYTE8*name)
|
|||
s_vpi_value val;
|
||||
struct byte_source src;
|
||||
FILE *fd;
|
||||
errno = 0;
|
||||
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(vpi_scan(argv), &val);
|
||||
|
|
@ -648,9 +650,11 @@ static PLI_INT32 sys_fscanf_calltf(PLI_BYTE8*name)
|
|||
(int)vpi_get(vpiLineNo, callh));
|
||||
vpi_printf("invalid file descriptor (0x%x) given to %s.\n",
|
||||
val.value.integer, name);
|
||||
errno = EBADF;
|
||||
val.format = vpiIntVal;
|
||||
val.value.integer = EOF;
|
||||
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||
vpi_free_object(argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue