Browse Source

New interpreter commands strstr, strslice, fopen, fread and fclose.

pre-master-46
Giles Atkinson 3 years ago
parent
commit
3ba314d4bc
  1. 2
      src/frontend/Makefile.am
  2. 181
      src/frontend/com_fileio.c
  3. 9
      src/frontend/com_fileio.h
  4. 51
      src/frontend/com_strcmp.c
  5. 5
      src/frontend/com_strcmp.h
  6. 49
      src/frontend/commands.c
  7. 4
      visualc/vngspice.vcxproj

2
src/frontend/Makefile.am

@ -34,6 +34,8 @@ libfte_la_SOURCES = \
com_dump.h \ com_dump.h \
com_echo.c \ com_echo.c \
com_echo.h \ com_echo.h \
com_fileio.c \
com_fileio.h \
com_ghelp.c \ com_ghelp.c \
com_ghelp.h \ com_ghelp.h \
com_gnuplot.h \ com_gnuplot.h \

181
src/frontend/com_fileio.c

@ -0,0 +1,181 @@
/* Commands for opening and reading arbitrary files. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "ngspice/ngspice.h"
#include "ngspice/bool.h"
#include "ngspice/wordlist.h"
#include "com_strcmp.h"
#include "variable.h"
/* Track open files with these structures, indexed by the underlying
* descriptor. Not many should be needed.
*/
#define MAX_OPEN_FILES 20
#define MAX_TEXT_LINE 8192
static struct {
FILE *fp;
char *name;
} Open_Files[MAX_OPEN_FILES];
/* Check whether error messages should be suppressed. That is useful when
* opening a file to see if it exists.
*/
static int verbose(void)
{
return !cp_getvar("silent_fileio", CP_BOOL, NULL, 0);
}
/* fopen handle file_name [mode]
*
* For example: fopen handle result.txt r
*
* The underlying file descriptor (or -1) is returned in the variable "handle".
*/
void com_fopen(wordlist *wl)
{
char *var, *file_name, *mode;
FILE *fp;
int fd;
var = wl->wl_word;
wl = wl->wl_next;
file_name = cp_unquote(wl->wl_word);
wl = wl->wl_next;
mode = wl ? cp_unquote(wl->wl_word) : "r";
fp = fopen(file_name, mode);
if (fp) {
fd = fileno(fp);
if (fd < MAX_OPEN_FILES) {
if (Open_Files[fd].fp) // Not expected!
fclose(Open_Files[fd].fp);
if (Open_Files[fd].name)
tfree(Open_Files[fd].name);
Open_Files[fd].fp = fp;
Open_Files[fd].name = copy(file_name);
} else {
fclose(fp);
fprintf(stderr,
"com_fopen() cannot open %s: too many open files\n",
file_name);
fd = -1;
}
} else {
fd = -1;
if (verbose()) {
fprintf(stderr, "com_fopen() cannot open %s: %s\n",
file_name, strerror(errno));
}
}
tfree(file_name);
if (wl)
tfree(mode);
cp_vset(var, CP_NUM, &fd);
}
/* Command looks like:
* fread result handle [length]
* where handle is a small positive integer, result names a variable
* and length is the name of a variable used to return the length of the line.
* The returned length is -1 at EOF, -2 on failure.
*/
void com_fread(wordlist *wl)
{
char *handle, *result, *lvar;
int fd, length;
char buf[MAX_TEXT_LINE];
result = cp_unquote(wl->wl_word);
wl = wl->wl_next;
handle = cp_unquote(wl->wl_word);
fd = atoi(handle);
tfree(handle);
wl = wl->wl_next;
if (wl)
lvar = cp_unquote(wl->wl_word);
else
lvar = NULL;
if (fd >= 0 && fd < MAX_OPEN_FILES) {
if (!Open_Files[fd].fp) {
/* Allow stdin, for example. */
Open_Files[fd].fp = fdopen(fd, "r");
if (!Open_Files[fd].fp && verbose()) {
fprintf(stderr, "com_fread() cannot open handle %d\n", fd);
goto err;
}
}
if (fgets(buf, sizeof buf, Open_Files[fd].fp)) {
length = strlen(buf);
if (length > 0 && buf[length - 1] == '\n') {
--length;
if (length > 0 && buf[length - 1] == '\r') {
/* Windows CRLF line termination. */
--length;
}
buf[length] = '\0';
} else if (verbose()) {
fprintf(stderr,
"com_fread() found line in %s "
"too long for buffer\n",
Open_Files[fd].name);
}
} else {
if (feof(Open_Files[fd].fp)) {
length = -1;
} else if (verbose()) {
fprintf(stderr,
"com_fread() error reading %s: %s\n",
Open_Files[fd].name, strerror(errno));
length = -2;
}
*buf = '\0';
}
} else if (verbose()) {
fprintf(stderr,
"com_fread(): file handle %d is not in accepted range.\n",
fd);
err:
length = -1;
*buf = '\0';
}
cp_vset(result, CP_STRING, buf);
tfree(result);
if (lvar) {
cp_vset(lvar, CP_NUM, &length);
tfree(lvar);
}
}
void com_fclose(wordlist *wl)
{
char *handle;
int fd;
handle = cp_unquote(wl->wl_word);
fd = atoi(handle);
tfree(handle);
if (fd <= 2 || fd >= MAX_OPEN_FILES)
return;
if (Open_Files[fd].fp) {
fclose(Open_Files[fd].fp);
Open_Files[fd].fp = NULL;
}
if (Open_Files[fd].name)
tfree(Open_Files[fd].name);
}

9
src/frontend/com_fileio.h

@ -0,0 +1,9 @@
#ifndef ngspice_COM_FILEIO_H
#define ngspice_COM_FILEIO_H
extern void com_fopen(wordlist *wl);
extern void com_fread(wordlist *wl);
extern void com_fclose(wordlist *wl);
#endif

51
src/frontend/com_strcmp.c

@ -23,3 +23,54 @@ com_strcmp(wordlist *wl)
tfree(s2); tfree(s2);
cp_vset(var, CP_NUM, &i); cp_vset(var, CP_NUM, &i);
} }
/* These must be more evil still. */
void com_strstr(wordlist *wl)
{
char *var, *s1, *s2;
int i;
s1 = cp_unquote(wl->wl_next->wl_word);
s2 = cp_unquote(wl->wl_next->wl_next->wl_word);
if (*s2) {
var = strstr(s1, s2); // Search for s2 in s1
if (var)
i = var - s1; // Offset to match
else
i = -1;
} else {
i = strlen(s1); // Length
}
tfree(s1);
tfree(s2);
cp_vset(wl->wl_word, CP_NUM, &i);
}
void com_strslice(wordlist *wl)
{
char *var, *s1, *tp, tmp;
int offset, length, actual;
var = wl->wl_word;
wl = wl->wl_next;
s1 = cp_unquote(wl->wl_word);
wl = wl->wl_next;
offset = atoi(wl->wl_word);
length = atoi(wl->wl_next->wl_word);
actual = strlen(s1);
if (offset < 0)
offset = actual + offset;
if (length + offset > actual)
length = actual - offset;
if (length > 0 && offset >= 0) {
tp = s1 + offset + length;
tmp = *tp;
*tp = '\0';
cp_vset(var, CP_STRING, s1 + offset);
*tp = tmp;
} else {
cp_vset(var, CP_STRING, "");
}
tfree(s1);
}

5
src/frontend/com_strcmp.h

@ -1,7 +1,8 @@
#ifndef ngspice_COM_STRCMP_H #ifndef ngspice_COM_STRCMP_H
#define ngspice_COM_STRCMP_H #define ngspice_COM_STRCMP_H
void com_strcmp(wordlist *wl);
extern void com_strcmp(wordlist *wl);
extern void com_strstr(wordlist *wl);
extern void com_strslice(wordlist *wl);
#endif #endif

49
src/frontend/commands.c

@ -82,6 +82,7 @@
#include "resource.h" #include "resource.h"
#include "diff.h" #include "diff.h"
#include "com_strcmp.h" #include "com_strcmp.h"
#include "com_fileio.h"
#include "ngspice/randnumb.h" #include "ngspice/randnumb.h"
#include "../spicelib/analysis/com_optran.h" #include "../spicelib/analysis/com_optran.h"
#include "com_wr_ic.h" #include "com_wr_ic.h"
@ -613,6 +614,30 @@ struct comm spcp_coms[] = {
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3, { 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
NULL, NULL,
"varname s1 s2 : Set $varname to strcmp(s1, s2)." } , "varname s1 s2 : Set $varname to strcmp(s1, s2)." } ,
{ "strstr", com_strstr, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
NULL,
"varname s1 s2 : Set $varname to strstr(s1, s2)." } ,
{ "strslice", com_strslice, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 4, 4,
NULL,
"varname s1 offset length : "
"Set $varname to s1[offset ... offset+length]" } ,
{ "fopen", com_fopen, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 2, 3,
NULL,
"handle file_name [mode] : "
"Open file_name with mode, return handle in $handle" } ,
{ "fread", com_fread, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 2, 3,
NULL,
"handle result [length] : "
"Read a line from open file handle, "
"data in $result, status in $length" } ,
{ "fclose", com_fclose, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 1, 1,
NULL,
"handle : Close open file" } ,
{ "linearize", com_linearize, FALSE, FALSE, { "linearize", com_linearize, FALSE, FALSE,
{ 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS,
NULL, NULL,
@ -1033,6 +1058,30 @@ struct comm nutcp_coms[] = {
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3, { 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
NULL, NULL,
"varname s1 s2 : Set $varname to strcmp(s1, s2)." } , "varname s1 s2 : Set $varname to strcmp(s1, s2)." } ,
{ "strstr", com_strstr, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 3, 3,
NULL,
"varname s1 s2 : Set $varname to strstr(s1, s2)." } ,
{ "strslice", com_strslice, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 4, 4,
NULL,
"varname s1 offset length : "
"Set $varname to s1[offset ... offset+length]" } ,
{ "fopen", com_fopen, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 2, 3,
NULL,
"handle file_name [mode] : "
"Open file_name with mode, return handle in $handle" } ,
{ "fread", com_fread, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 2, 3,
NULL,
"handle result [length] : "
"Read a line from open file handle, "
"data in $result, status in $length" } ,
{ "fclose", com_fclose, FALSE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 1, 1,
NULL,
"handle : Close open file" } ,
{ "linearize", com_linearize, TRUE, FALSE, { "linearize", com_linearize, TRUE, FALSE,
{ 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS,
NULL, NULL,

4
visualc/vngspice.vcxproj

@ -885,6 +885,7 @@
<ClInclude Include="..\src\frontend\com_shift.h" /> <ClInclude Include="..\src\frontend\com_shift.h" />
<ClInclude Include="..\src\frontend\com_state.h" /> <ClInclude Include="..\src\frontend\com_state.h" />
<ClInclude Include="..\src\frontend\com_strcmp.h" /> <ClInclude Include="..\src\frontend\com_strcmp.h" />
<ClInclude Include="..\src\frontend\com_fileio.h" />
<ClInclude Include="..\src\frontend\com_unset.h" /> <ClInclude Include="..\src\frontend\com_unset.h" />
<ClInclude Include="..\src\frontend\com_wr_ic.h" /> <ClInclude Include="..\src\frontend\com_wr_ic.h" />
<ClInclude Include="..\src\frontend\control.h" /> <ClInclude Include="..\src\frontend\control.h" />
@ -1498,6 +1499,7 @@
<ClCompile Include="..\src\frontend\com_shift.c" /> <ClCompile Include="..\src\frontend\com_shift.c" />
<ClCompile Include="..\src\frontend\com_state.c" /> <ClCompile Include="..\src\frontend\com_state.c" />
<ClCompile Include="..\src\frontend\com_strcmp.c" /> <ClCompile Include="..\src\frontend\com_strcmp.c" />
<ClCompile Include="..\src\frontend\com_fileio.c" />
<ClCompile Include="..\src\frontend\com_sysinfo.c" /> <ClCompile Include="..\src\frontend\com_sysinfo.c" />
<ClCompile Include="..\src\frontend\com_unset.c" /> <ClCompile Include="..\src\frontend\com_unset.c" />
<ClCompile Include="..\src\frontend\com_wr_ic.c" /> <ClCompile Include="..\src\frontend\com_wr_ic.c" />
@ -2894,4 +2896,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project>
</Project>
Loading…
Cancel
Save