2000-04-27 22:03:57 +02:00
|
|
|
/**********
|
|
|
|
|
Copyright 1990 Regents of the University of California. All rights reserved.
|
|
|
|
|
**********/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* String functions
|
|
|
|
|
*/
|
|
|
|
|
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/ngspice.h"
|
2011-12-17 18:16:29 +01:00
|
|
|
#include "ngspice/stringutil.h"
|
2016-03-21 17:42:25 +01:00
|
|
|
#include "ngspice/stringskip.h"
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/dstring.h"
|
2000-04-27 22:03:57 +02:00
|
|
|
|
2014-03-29 13:11:56 +01:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
int
|
2015-12-22 15:31:54 +01:00
|
|
|
prefix(const char *p, const char *s)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
|
|
|
|
while (*p && (*p == *s))
|
|
|
|
|
p++, s++;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!*p)
|
|
|
|
|
return (TRUE);
|
|
|
|
|
else
|
|
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Create a copy of a string. */
|
|
|
|
|
|
|
|
|
|
char *
|
2010-04-11 10:49:05 +02:00
|
|
|
copy(const char *str)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
|
|
|
|
char *p;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2012-07-28 19:53:55 +02:00
|
|
|
if (!str)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2010-11-19 19:52:44 +01:00
|
|
|
if ((p = TMALLOC(char, strlen(str) + 1)) != NULL)
|
2017-03-25 16:48:22 +01:00
|
|
|
(void) strcpy(p, str);
|
2000-04-27 22:03:57 +02:00
|
|
|
return(p);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-09 12:25:37 +02:00
|
|
|
|
|
|
|
|
/* copy a substring, from 'str' to 'end'
|
|
|
|
|
* including *str, excluding *end
|
|
|
|
|
*/
|
2010-04-11 10:49:05 +02:00
|
|
|
char *
|
|
|
|
|
copy_substring(const char *str, const char *end)
|
|
|
|
|
{
|
2010-11-06 21:14:21 +01:00
|
|
|
size_t n = (size_t) (end - str);
|
2010-04-11 10:49:05 +02:00
|
|
|
char *p;
|
|
|
|
|
|
2010-11-19 19:52:44 +01:00
|
|
|
if ((p = TMALLOC(char, n + 1)) != NULL) {
|
2010-04-11 10:49:05 +02:00
|
|
|
(void) strncpy(p, str, n);
|
|
|
|
|
p[n] = '\0';
|
|
|
|
|
}
|
|
|
|
|
return(p);
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-29 13:11:56 +01:00
|
|
|
|
2014-04-12 21:00:56 +02:00
|
|
|
char *
|
|
|
|
|
tvprintf(const char *fmt, va_list args)
|
2014-03-29 13:11:56 +01:00
|
|
|
{
|
|
|
|
|
char buf[1024];
|
|
|
|
|
char *p = buf;
|
|
|
|
|
int size = sizeof(buf);
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
|
|
|
|
|
int nchars;
|
2014-04-12 21:00:56 +02:00
|
|
|
va_list ap;
|
2014-03-29 13:11:56 +01:00
|
|
|
|
2014-04-12 21:00:56 +02:00
|
|
|
va_copy(ap, args);
|
|
|
|
|
nchars = vsnprintf(p, (size_t) size, fmt, ap);
|
|
|
|
|
va_end(ap);
|
2014-03-29 13:11:56 +01:00
|
|
|
|
|
|
|
|
if (nchars == -1) { // compatibility to old implementations
|
|
|
|
|
size *= 2;
|
|
|
|
|
} else if (size < nchars + 1) {
|
|
|
|
|
size = nchars + 1;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p == buf)
|
|
|
|
|
p = TMALLOC(char, size);
|
|
|
|
|
else
|
|
|
|
|
p = TREALLOC(char, p, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (p == buf) ? copy(p) : p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-04-12 21:00:56 +02:00
|
|
|
char *
|
|
|
|
|
tprintf(const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
char *rv;
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
rv = tvprintf(fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Determine whether sub is a substring of str. */
|
|
|
|
|
/* Like strstr( ) XXX */
|
|
|
|
|
|
|
|
|
|
int
|
2015-12-22 15:31:54 +01:00
|
|
|
substring(const char *sub, const char *str)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
2015-12-22 15:31:54 +01:00
|
|
|
const char *s, *t;
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
while (*str) {
|
|
|
|
|
if (*str == *sub) {
|
2017-03-25 16:48:22 +01:00
|
|
|
t = str;
|
2000-04-27 22:03:57 +02:00
|
|
|
for (s = sub; *s; s++) {
|
|
|
|
|
if (!*t || (*s != *t++))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (*s == '\0')
|
|
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
str++;
|
|
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
return (FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Append one character to a string. Don't check for overflow. */
|
|
|
|
|
/* Almost like strcat( ) XXX */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
appendc(char *s, char c)
|
|
|
|
|
{
|
|
|
|
|
while (*s)
|
|
|
|
|
s++;
|
|
|
|
|
*s++ = c;
|
|
|
|
|
*s = '\0';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Try to identify an integer that begins a string. Stop when a non-
|
|
|
|
|
* numeric character is reached.
|
|
|
|
|
*/
|
|
|
|
|
/* Like atoi( ) XXX */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
scannum(char *str)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
while (isdigit_c(*str))
|
2000-04-27 22:03:57 +02:00
|
|
|
i = i * 10 + *(str++) - '0';
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
return(i);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Case insensitive str eq. */
|
|
|
|
|
/* Like strcasecmp( ) XXX */
|
|
|
|
|
|
|
|
|
|
int
|
2015-12-22 15:31:54 +01:00
|
|
|
cieq(const char *p, const char *s)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
|
|
|
|
while (*p) {
|
2016-03-08 21:24:40 +01:00
|
|
|
if ((isupper_c(*p) ? tolower_c(*p) : *p) !=
|
|
|
|
|
(isupper_c(*s) ? tolower_c(*s) : *s))
|
2000-04-27 22:03:57 +02:00
|
|
|
return(FALSE);
|
|
|
|
|
p++;
|
|
|
|
|
s++;
|
|
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
return (*s ? FALSE : TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
/* Case insensitive prefix. */
|
|
|
|
|
|
|
|
|
|
int
|
2015-12-22 15:31:54 +01:00
|
|
|
ciprefix(const char *p, const char *s)
|
2000-04-27 22:03:57 +02:00
|
|
|
{
|
|
|
|
|
while (*p) {
|
2016-03-08 21:24:40 +01:00
|
|
|
if ((isupper_c(*p) ? tolower_c(*p) : *p) !=
|
|
|
|
|
(isupper_c(*s) ? tolower_c(*s) : *s))
|
2000-04-27 22:03:57 +02:00
|
|
|
return(FALSE);
|
|
|
|
|
p++;
|
|
|
|
|
s++;
|
|
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
return (TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
void
|
|
|
|
|
strtolower(char *str)
|
|
|
|
|
{
|
|
|
|
|
if (str)
|
2010-11-04 21:01:46 +01:00
|
|
|
while (*str) {
|
2017-03-25 16:48:22 +01:00
|
|
|
if (isupper_c(*str))
|
2016-03-08 21:24:40 +01:00
|
|
|
*str = tolower_c(*str);
|
2010-11-04 21:01:46 +01:00
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2010-11-04 21:01:46 +01:00
|
|
|
void
|
|
|
|
|
strtoupper(char *str)
|
|
|
|
|
{
|
|
|
|
|
if (str)
|
|
|
|
|
while (*str) {
|
2017-03-25 16:48:22 +01:00
|
|
|
if (islower_c(*str))
|
2016-03-08 21:24:40 +01:00
|
|
|
*str = toupper_c(*str);
|
2010-11-04 21:01:46 +01:00
|
|
|
str++;
|
|
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-08-11 22:53:33 +02:00
|
|
|
#ifdef CIDER
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-08-11 22:53:33 +02:00
|
|
|
/*
|
|
|
|
|
* Imported from cider file support/strmatch.c
|
|
|
|
|
* Original copyright notice:
|
|
|
|
|
* Author: 1991 David A. Gates, U. C. Berkeley CAD Group
|
|
|
|
|
*
|
|
|
|
|
*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-08-11 22:53:33 +02:00
|
|
|
/*
|
|
|
|
|
* Case-insensitive test of whether p is a prefix of s and at least the
|
|
|
|
|
* first n characters are the same
|
|
|
|
|
*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-08-11 22:53:33 +02:00
|
|
|
int
|
2017-03-25 16:56:22 +01:00
|
|
|
cinprefix(char *p, char *s, int n)
|
2003-08-11 22:53:33 +02:00
|
|
|
{
|
2017-03-25 16:48:22 +01:00
|
|
|
if (!p || !s)
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
|
if ((isupper_c(*p) ? tolower_c(*p) : *p) != (isupper_c(*s) ? tolower_c(*s) : *s))
|
|
|
|
|
return(0);
|
|
|
|
|
p++;
|
|
|
|
|
s++;
|
|
|
|
|
n--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n > 0)
|
|
|
|
|
return(0);
|
|
|
|
|
else
|
|
|
|
|
return(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-08-11 22:53:33 +02:00
|
|
|
/*
|
|
|
|
|
* Case-insensitive match of prefix string p against string s
|
|
|
|
|
* returns the number of matching characters
|
2017-03-25 16:48:22 +01:00
|
|
|
*
|
2003-08-11 22:53:33 +02:00
|
|
|
*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
|
|
|
|
int
|
2017-03-25 16:56:22 +01:00
|
|
|
cimatch(char *p, char *s)
|
2003-08-11 22:53:33 +02:00
|
|
|
{
|
2017-03-25 16:56:22 +01:00
|
|
|
int n = 0;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
|
|
|
|
if (!p || !s)
|
|
|
|
|
return(0);
|
|
|
|
|
|
|
|
|
|
while (*p) {
|
|
|
|
|
if ((isupper_c(*p) ? tolower_c(*p) : *p) != (isupper_c(*s) ? tolower_c(*s) : *s))
|
|
|
|
|
return(n);
|
|
|
|
|
p++;
|
|
|
|
|
s++;
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(n);
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-11 22:53:33 +02:00
|
|
|
#endif /* CIDER */
|
|
|
|
|
|
|
|
|
|
|
2004-01-10 22:39:36 +01:00
|
|
|
/*-------------------------------------------------------------------------*
|
2017-03-25 16:48:22 +01:00
|
|
|
* gettok skips over whitespace and returns the next token found. This is
|
|
|
|
|
* the original version. It does not "do the right thing" when you have
|
2004-01-10 22:39:36 +01:00
|
|
|
* parens or commas anywhere in the nodelist. Note that I left this unmodified
|
|
|
|
|
* since I didn't want to break any fcns which called it from elsewhere than
|
|
|
|
|
* subckt.c. -- SDB 12.3.2003.
|
|
|
|
|
*-------------------------------------------------------------------------*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2000-04-27 22:03:57 +02:00
|
|
|
char *
|
|
|
|
|
gettok(char **s)
|
|
|
|
|
{
|
|
|
|
|
char c;
|
|
|
|
|
int paren;
|
2017-03-25 16:48:22 +01:00
|
|
|
char *beg, *token; /* return token */
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
paren = 0;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2016-03-21 18:04:39 +01:00
|
|
|
*s = skip_ws(*s);
|
2000-04-27 22:03:57 +02:00
|
|
|
if (!**s)
|
|
|
|
|
return (NULL);
|
2017-03-25 16:48:22 +01:00
|
|
|
|
|
|
|
|
beg = *s;
|
2016-03-08 21:20:11 +01:00
|
|
|
while ((c = **s) != '\0' && !isspace_c(c)) {
|
2017-03-25 16:48:22 +01:00
|
|
|
if (c == '(')
|
|
|
|
|
paren += 1;
|
|
|
|
|
else if (c == ')')
|
|
|
|
|
paren -= 1;
|
|
|
|
|
else if (c == ',' && paren < 1)
|
|
|
|
|
break;
|
|
|
|
|
(*s)++;
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
token = copy_substring(beg, *s);
|
|
|
|
|
|
2016-03-08 21:20:11 +01:00
|
|
|
while (isspace_c(**s) || **s == ',')
|
2000-04-27 22:03:57 +02:00
|
|
|
(*s)++;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
|
|
|
|
return (token);
|
2000-04-27 22:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-15 21:09:53 +02:00
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*
|
2017-03-25 16:48:22 +01:00
|
|
|
* nexttok skips over whitespaces and the next token in s
|
|
|
|
|
* returns NULL if there is nothing left to skip.
|
|
|
|
|
* It replaces constructs like txfree(gettok(&actstring)) by
|
|
|
|
|
* actstring = nexttok(actstring). This is derived from the original gettok version.
|
|
|
|
|
* It does not "do the right thing" when
|
|
|
|
|
* you have parens or commas anywhere in the nodelist.
|
|
|
|
|
*-------------------------------------------------------------------------*/
|
|
|
|
|
|
2017-03-19 20:11:01 +01:00
|
|
|
char *
|
2016-11-01 11:30:08 +01:00
|
|
|
nexttok(const char *s)
|
2016-06-15 21:09:53 +02:00
|
|
|
{
|
2017-03-19 20:11:01 +01:00
|
|
|
int paren = 0;
|
2016-06-15 21:09:53 +02:00
|
|
|
|
2017-03-19 20:11:01 +01:00
|
|
|
s = skip_ws(s);
|
|
|
|
|
if (!*s)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
for (; *s && !isspace_c(*s); s++)
|
2017-03-19 20:11:01 +01:00
|
|
|
if (*s == '(')
|
2016-06-15 21:09:53 +02:00
|
|
|
paren += 1;
|
2017-03-19 20:11:01 +01:00
|
|
|
else if (*s == ')')
|
2016-06-15 21:09:53 +02:00
|
|
|
paren -= 1;
|
2017-03-19 20:11:01 +01:00
|
|
|
else if (*s == ',' && paren < 1)
|
2016-06-15 21:09:53 +02:00
|
|
|
break;
|
2017-03-19 20:11:01 +01:00
|
|
|
|
|
|
|
|
while (isspace_c(*s) || *s == ',')
|
|
|
|
|
s++;
|
|
|
|
|
|
2016-11-01 11:30:08 +01:00
|
|
|
return (char *) s;
|
2016-06-15 21:09:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-07-10 13:27:57 +02:00
|
|
|
/*-------------------------------------------------------------------------*
|
2017-03-25 16:48:22 +01:00
|
|
|
* gettok skips over whitespaces or '=' and returns the next token found,
|
2010-07-10 13:27:57 +02:00
|
|
|
* if the token is something like i(xxx), v(yyy), or v(xxx,yyy)
|
|
|
|
|
* -- h_vogt 10.07.2010.
|
|
|
|
|
*-------------------------------------------------------------------------*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2010-07-10 13:27:57 +02:00
|
|
|
char *
|
|
|
|
|
gettok_iv(char **s)
|
|
|
|
|
{
|
|
|
|
|
char c;
|
|
|
|
|
int paren;
|
2017-03-25 16:48:22 +01:00
|
|
|
char *token; /* return token */
|
|
|
|
|
SPICE_DSTRING buf; /* allow any length string */
|
2010-07-10 13:27:57 +02:00
|
|
|
|
|
|
|
|
paren = 0;
|
2017-03-25 16:48:22 +01:00
|
|
|
while ((isspace_c(**s)) || (**s == '='))
|
2010-07-10 13:27:57 +02:00
|
|
|
(*s)++;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2010-07-10 13:27:57 +02:00
|
|
|
if ((!**s) || ((**s != 'v') && (**s != 'i') && (**s != 'V') && (**s != 'I')))
|
|
|
|
|
return (NULL);
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2010-07-10 13:27:57 +02:00
|
|
|
// initialize string
|
|
|
|
|
spice_dstring_init(&buf);
|
|
|
|
|
// add v or i to buf
|
2017-03-25 16:48:22 +01:00
|
|
|
spice_dstring_append_char(&buf, *(*s)++);
|
|
|
|
|
|
2010-07-24 20:51:06 +02:00
|
|
|
while ((c = **s) != '\0') {
|
2015-09-22 21:12:31 +02:00
|
|
|
if (c == '(')
|
2010-07-10 13:27:57 +02:00
|
|
|
paren += 1;
|
2015-09-22 21:12:31 +02:00
|
|
|
else if (c == ')')
|
2010-07-10 13:27:57 +02:00
|
|
|
paren -= 1;
|
2017-03-25 16:48:22 +01:00
|
|
|
if (isspace_c(c))
|
2010-08-15 20:26:56 +02:00
|
|
|
(*s)++;
|
2010-07-10 13:27:57 +02:00
|
|
|
else {
|
2017-03-25 16:48:22 +01:00
|
|
|
spice_dstring_append_char(&buf, *(*s)++);
|
|
|
|
|
if (paren == 0)
|
|
|
|
|
break;
|
2010-07-10 13:27:57 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2016-03-08 21:20:11 +01:00
|
|
|
while (isspace_c(**s) || **s == ',')
|
2010-07-10 13:27:57 +02:00
|
|
|
(*s)++;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
|
|
|
|
token = copy(spice_dstring_value(&buf));
|
|
|
|
|
spice_dstring_free(&buf);
|
|
|
|
|
return (token);
|
2010-07-10 13:27:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*-------------------------------------------------------------------------*
|
|
|
|
|
* gettok_noparens was added by SDB on 4.21.2003.
|
2004-01-10 22:39:36 +01:00
|
|
|
* It acts like gettok, except that it treats parens and commas like
|
2017-03-25 16:48:22 +01:00
|
|
|
* whitespace while looking for the POLY token. That is, it stops
|
|
|
|
|
* parsing and returns when it finds one of those chars. It is called from
|
2004-01-10 22:39:36 +01:00
|
|
|
* 'translate' (subckt.c).
|
2003-07-23 21:36:39 +02:00
|
|
|
*-------------------------------------------------------------------------*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
char *
|
|
|
|
|
gettok_noparens(char **s)
|
|
|
|
|
{
|
|
|
|
|
char c;
|
2017-03-25 16:48:22 +01:00
|
|
|
char *beg, *token; /* return token */
|
2003-07-23 21:36:39 +02:00
|
|
|
|
2016-03-21 18:04:39 +01:00
|
|
|
*s = skip_ws(*s);
|
2004-01-10 22:39:36 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
if (!**s)
|
2004-01-10 22:39:36 +01:00
|
|
|
return (NULL); /* return NULL if we come to end of line */
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
beg = *s;
|
|
|
|
|
while ((c = **s) != '\0' &&
|
|
|
|
|
!isspace_c(c) &&
|
|
|
|
|
(**s != '(') &&
|
|
|
|
|
(**s != ')') &&
|
|
|
|
|
(**s != ',')
|
|
|
|
|
) {
|
|
|
|
|
(*s)++;
|
2003-07-23 21:36:39 +02:00
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
token = copy_substring(beg, *s);
|
2004-01-10 22:39:36 +01:00
|
|
|
|
2016-03-21 18:04:39 +01:00
|
|
|
*s = skip_ws(*s);
|
2004-01-10 22:39:36 +01:00
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
return (token);
|
2004-01-10 22:39:36 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2007-12-29 22:13:23 +01:00
|
|
|
char *
|
|
|
|
|
gettok_instance(char **s)
|
|
|
|
|
{
|
|
|
|
|
char c;
|
2017-03-25 16:48:22 +01:00
|
|
|
char *beg, *token; /* return token */
|
2007-12-29 22:13:23 +01:00
|
|
|
|
2016-03-21 18:04:39 +01:00
|
|
|
*s = skip_ws(*s);
|
2007-12-29 22:13:23 +01:00
|
|
|
|
|
|
|
|
if (!**s)
|
|
|
|
|
return (NULL); /* return NULL if we come to end of line */
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
beg = *s;
|
|
|
|
|
while ((c = **s) != '\0' &&
|
|
|
|
|
!isspace_c(c) &&
|
|
|
|
|
(**s != '(') &&
|
|
|
|
|
(**s != ')')
|
|
|
|
|
) {
|
|
|
|
|
(*s)++;
|
2007-12-29 22:13:23 +01:00
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
token = copy_substring(beg, *s);
|
2013-12-21 20:15:51 +01:00
|
|
|
|
2007-12-29 22:13:23 +01:00
|
|
|
/* Now iterate up to next non-whitespace char */
|
2016-03-21 18:04:39 +01:00
|
|
|
*s = skip_ws(*s);
|
2011-12-21 22:33:47 +01:00
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
return (token);
|
2011-12-21 22:33:47 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2011-12-21 22:33:47 +01:00
|
|
|
/* get the next token starting at next non white spice, stopping
|
2012-07-19 23:16:15 +02:00
|
|
|
at p, if inc_p is true, then including p, else excluding p,
|
2012-07-21 22:23:49 +02:00
|
|
|
return NULL if p is not found.
|
|
|
|
|
If '}', ']' or ')' and nested is true, find corresponding p
|
|
|
|
|
|
2011-12-21 22:33:47 +01:00
|
|
|
*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2011-12-21 22:33:47 +01:00
|
|
|
char *
|
2012-07-21 22:23:49 +02:00
|
|
|
gettok_char(char **s, char p, bool inc_p, bool nested)
|
2011-12-21 22:33:47 +01:00
|
|
|
{
|
|
|
|
|
char c;
|
2017-03-25 16:48:22 +01:00
|
|
|
char *beg, *token; /* return token */
|
2011-12-21 22:33:47 +01:00
|
|
|
|
2016-03-21 18:04:39 +01:00
|
|
|
*s = skip_ws(*s);
|
2011-12-21 22:33:47 +01:00
|
|
|
|
|
|
|
|
if (!**s)
|
|
|
|
|
return (NULL); /* return NULL if we come to end of line */
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
beg = *s;
|
|
|
|
|
if (nested && ((p == '}') || (p == ')') || (p == ']'))) {
|
2012-07-21 22:23:49 +02:00
|
|
|
char q;
|
|
|
|
|
int count = 0;
|
|
|
|
|
/* find opening bracket */
|
2017-03-25 16:48:22 +01:00
|
|
|
if (p == '}')
|
2012-08-06 19:50:23 +02:00
|
|
|
q = '{';
|
2017-03-25 16:48:22 +01:00
|
|
|
else if (p == ']')
|
2012-08-06 19:50:23 +02:00
|
|
|
q = '[';
|
|
|
|
|
else
|
|
|
|
|
q = '(';
|
2012-07-21 22:23:49 +02:00
|
|
|
/* add string in front of q, excluding q */
|
2017-03-25 16:48:22 +01:00
|
|
|
while ((c = **s) != '\0' && (**s != q)) {
|
|
|
|
|
(*s)++;
|
2012-07-21 22:23:49 +02:00
|
|
|
}
|
|
|
|
|
/* return if nested bracket found, excluding its character */
|
2017-03-25 16:48:22 +01:00
|
|
|
while ((c = **s) != '\0') {
|
|
|
|
|
if (c == q)
|
|
|
|
|
count++;
|
|
|
|
|
else if (c == p)
|
|
|
|
|
count--;
|
2012-07-21 22:23:49 +02:00
|
|
|
if (count == 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
(*s)++;
|
2012-07-21 22:23:49 +02:00
|
|
|
}
|
2011-12-21 22:33:47 +01:00
|
|
|
}
|
2012-07-21 22:23:49 +02:00
|
|
|
else
|
|
|
|
|
/* just look for p and return string, excluding p */
|
2017-03-25 16:48:22 +01:00
|
|
|
while ((c = **s) != '\0' && (**s != p)) {
|
|
|
|
|
(*s)++;
|
2012-07-21 22:23:49 +02:00
|
|
|
}
|
|
|
|
|
|
2012-07-19 23:16:15 +02:00
|
|
|
if (c == '\0')
|
|
|
|
|
/* p not found */
|
|
|
|
|
return (NULL);
|
2012-07-21 22:23:49 +02:00
|
|
|
|
2011-12-21 22:33:47 +01:00
|
|
|
if (inc_p)
|
2012-07-21 22:23:49 +02:00
|
|
|
/* add p */
|
2017-03-25 16:48:22 +01:00
|
|
|
(*s)++;
|
2013-12-21 20:15:51 +01:00
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
token = copy_substring(beg, *s);
|
2011-12-21 22:33:47 +01:00
|
|
|
|
|
|
|
|
/* Now iterate up to next non-whitespace char */
|
2016-03-21 18:04:39 +01:00
|
|
|
*s = skip_ws(*s);
|
2007-12-29 22:13:23 +01:00
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
return (token);
|
2007-12-29 22:13:23 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2004-01-10 22:39:36 +01:00
|
|
|
/*-------------------------------------------------------------------------*
|
|
|
|
|
* gettok_node was added by SDB on 12.3.2003
|
|
|
|
|
* It acts like gettok, except that it treats parens and commas like
|
|
|
|
|
* whitespace (i.e. it ignores them). Use it when parsing through netnames
|
|
|
|
|
* (node names) since they may be grouped using ( , ).
|
|
|
|
|
*-------------------------------------------------------------------------*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2004-01-10 22:39:36 +01:00
|
|
|
char *
|
|
|
|
|
gettok_node(char **s)
|
|
|
|
|
{
|
|
|
|
|
char c;
|
2017-03-25 16:48:22 +01:00
|
|
|
char *token; /* return token */
|
2004-01-10 22:39:36 +01:00
|
|
|
|
2013-10-13 22:41:49 +02:00
|
|
|
if (*s == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2016-03-08 21:20:11 +01:00
|
|
|
while (isspace_c(**s) ||
|
2017-03-25 16:48:22 +01:00
|
|
|
(**s == '(') ||
|
|
|
|
|
(**s == ')') ||
|
|
|
|
|
(**s == ',')
|
|
|
|
|
)
|
2004-01-10 22:39:36 +01:00
|
|
|
(*s)++; /* iterate over whitespace and ( , ) */
|
|
|
|
|
|
|
|
|
|
if (!**s)
|
|
|
|
|
return (NULL); /* return NULL if we come to end of line */
|
|
|
|
|
|
2013-10-18 21:29:38 +02:00
|
|
|
token = *s;
|
2017-03-25 16:48:22 +01:00
|
|
|
while ((c = **s) != '\0' &&
|
|
|
|
|
!isspace_c(c) &&
|
|
|
|
|
(**s != '(') &&
|
|
|
|
|
(**s != ')') &&
|
|
|
|
|
(**s != ',')
|
|
|
|
|
) { /* collect chars until whitespace or ( , ) */
|
2013-10-18 21:29:38 +02:00
|
|
|
(*s)++;
|
2004-01-10 22:39:36 +01:00
|
|
|
}
|
|
|
|
|
|
2013-10-18 21:29:38 +02:00
|
|
|
token = copy_substring(token, *s);
|
|
|
|
|
|
2004-01-10 22:39:36 +01:00
|
|
|
/* Now iterate up to next non-whitespace char */
|
2016-03-08 21:20:11 +01:00
|
|
|
while (isspace_c(**s) ||
|
2017-03-25 16:48:22 +01:00
|
|
|
(**s == '(') ||
|
|
|
|
|
(**s == ')') ||
|
|
|
|
|
(**s == ',')
|
|
|
|
|
)
|
2004-01-10 22:39:36 +01:00
|
|
|
(*s)++; /* iterate over whitespace and ( , ) */
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
return (token);
|
2003-07-23 21:36:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
/*-------------------------------------------------------------------------*
|
|
|
|
|
* get_l_paren iterates the pointer forward in a string until it hits
|
2017-03-25 16:48:22 +01:00
|
|
|
* the position after the next left paren "(". It returns 0 if it found a left
|
2004-01-10 22:39:36 +01:00
|
|
|
* paren, and 1 if no left paren is found. It is called from 'translate'
|
|
|
|
|
* (subckt.c).
|
2003-07-23 21:36:39 +02:00
|
|
|
*-------------------------------------------------------------------------*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
int
|
|
|
|
|
get_l_paren(char **s)
|
|
|
|
|
{
|
2017-03-25 16:48:22 +01:00
|
|
|
while (**s && (**s != '('))
|
2003-07-23 21:36:39 +02:00
|
|
|
(*s)++;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
if (!**s)
|
|
|
|
|
return (1);
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
(*s)++;
|
|
|
|
|
|
|
|
|
|
if (!**s)
|
|
|
|
|
return (1);
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*
|
|
|
|
|
* get_r_paren iterates the pointer forward in a string until it hits
|
2017-03-25 16:48:22 +01:00
|
|
|
* the position after the next right paren ")". It returns 0 if it found a right
|
2004-01-10 22:39:36 +01:00
|
|
|
* paren, and 1 if no right paren is found. It is called from 'translate'
|
|
|
|
|
* (subckt.c).
|
2003-07-23 21:36:39 +02:00
|
|
|
*-------------------------------------------------------------------------*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
int
|
|
|
|
|
get_r_paren(char **s)
|
|
|
|
|
{
|
2017-03-25 16:48:22 +01:00
|
|
|
while (**s && (**s != ')'))
|
2003-07-23 21:36:39 +02:00
|
|
|
(*s)++;
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2003-07-23 21:36:39 +02:00
|
|
|
if (!**s)
|
|
|
|
|
return (1);
|
|
|
|
|
|
|
|
|
|
(*s)++;
|
|
|
|
|
|
|
|
|
|
if (!**s)
|
|
|
|
|
return (1);
|
2017-03-25 16:48:22 +01:00
|
|
|
else
|
2003-07-23 21:36:39 +02:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-02 23:00:25 +01:00
|
|
|
/*-------------------------------------------------------------------------*
|
|
|
|
|
* this function strips all white space inside parens
|
|
|
|
|
* is needed in gettoks (dotcards.c) for right processing of expressions
|
|
|
|
|
* like ".plot v( 5,4) v(6)"
|
|
|
|
|
*-------------------------------------------------------------------------*/
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2007-12-02 23:00:25 +01:00
|
|
|
char *
|
|
|
|
|
stripWhiteSpacesInsideParens(char *str)
|
|
|
|
|
{
|
2017-03-25 16:48:22 +01:00
|
|
|
char *token; /* return token */
|
|
|
|
|
SPICE_DSTRING buf; /* allow any length string */
|
|
|
|
|
int i = 0; /* index into string */
|
2007-12-02 23:00:25 +01:00
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
while ((str[i] == ' ') || (str[i] == '\t'))
|
2007-12-02 23:00:25 +01:00
|
|
|
i++;
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
spice_dstring_init(&buf);
|
|
|
|
|
for (i = i; str[i] != '\0'; i++) {
|
|
|
|
|
if (str[i] != '(') {
|
|
|
|
|
spice_dstring_append_char(&buf, str[i]);
|
2007-12-02 23:00:25 +01:00
|
|
|
} else {
|
2017-03-25 16:48:22 +01:00
|
|
|
spice_dstring_append_char(&buf, str[i]);
|
|
|
|
|
while ((str[i++] != ')')) {
|
|
|
|
|
if (str[i] != ' ')
|
|
|
|
|
spice_dstring_append_char(&buf, str[i]);
|
2007-12-02 23:00:25 +01:00
|
|
|
}
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-25 16:48:22 +01:00
|
|
|
|
|
|
|
|
token = copy(spice_dstring_value(&buf));
|
|
|
|
|
spice_dstring_free(&buf);
|
|
|
|
|
return (token);
|
2007-12-02 23:00:25 +01:00
|
|
|
}
|
2000-04-27 22:03:57 +02:00
|
|
|
|
|
|
|
|
|
2008-04-06 21:36:06 +02:00
|
|
|
bool
|
2017-03-25 16:48:22 +01:00
|
|
|
isquote(char ch)
|
2008-04-06 21:36:06 +02:00
|
|
|
{
|
2017-03-25 16:48:22 +01:00
|
|
|
return (ch == '\'' || ch == '"');
|
2008-04-06 21:36:06 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2008-04-06 21:36:06 +02:00
|
|
|
bool
|
2017-03-25 16:48:22 +01:00
|
|
|
is_arith_char(char c)
|
2008-04-06 21:36:06 +02:00
|
|
|
{
|
2017-03-25 16:48:22 +01:00
|
|
|
if (c != '\0' && strchr("+-*/()<>?:|&^!%\\", c))
|
|
|
|
|
return TRUE;
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
2008-04-06 21:36:06 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2008-04-06 21:36:06 +02:00
|
|
|
bool
|
2017-03-25 16:48:22 +01:00
|
|
|
str_has_arith_char(char *s)
|
2008-04-06 21:36:06 +02:00
|
|
|
{
|
2017-03-25 16:48:22 +01:00
|
|
|
while (*s && *s != '\0') {
|
|
|
|
|
if (is_arith_char(*s))
|
|
|
|
|
return TRUE;
|
|
|
|
|
s++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
2008-04-06 21:36:06 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-25 16:48:22 +01:00
|
|
|
|
2008-04-06 21:36:06 +02:00
|
|
|
int
|
2017-03-25 16:48:22 +01:00
|
|
|
get_comma_separated_values(char *values[], char *str) {
|
|
|
|
|
int count = 0;
|
|
|
|
|
char *ptr, *comma_ptr, keep;
|
|
|
|
|
|
|
|
|
|
while ((comma_ptr = strchr(str, ',')) != NULL) {
|
|
|
|
|
ptr = comma_ptr - 1;
|
|
|
|
|
while (isspace_c(*ptr))
|
|
|
|
|
ptr--;
|
|
|
|
|
ptr++; keep = *ptr; *ptr = '\0';
|
|
|
|
|
values[count++] = strdup(str);
|
|
|
|
|
*ptr = keep;
|
|
|
|
|
str = skip_ws(comma_ptr + 1);
|
|
|
|
|
}
|
2008-04-06 21:36:06 +02:00
|
|
|
values[count++] = strdup(str);
|
2017-03-25 16:48:22 +01:00
|
|
|
return count;
|
2008-04-06 21:36:06 +02:00
|
|
|
}
|
2014-08-09 15:35:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
check if the given token matches a model name
|
2017-03-25 16:48:22 +01:00
|
|
|
either exact
|
|
|
|
|
then return 1
|
2014-08-09 15:35:31 +02:00
|
|
|
or
|
2017-03-25 16:48:22 +01:00
|
|
|
modulo a trailing model binning extension '\.[0-9]+'
|
|
|
|
|
then return 2
|
2014-08-09 15:35:31 +02:00
|
|
|
*/
|
|
|
|
|
|
2014-08-09 15:35:31 +02:00
|
|
|
int
|
2014-08-09 15:35:31 +02:00
|
|
|
model_name_match(const char *token, const char *model_name)
|
|
|
|
|
{
|
|
|
|
|
const char *p;
|
|
|
|
|
size_t token_len = strlen(token);
|
|
|
|
|
|
|
|
|
|
if (strncmp(token, model_name, token_len) != 0)
|
2014-08-09 15:35:31 +02:00
|
|
|
return 0;
|
2014-08-09 15:35:31 +02:00
|
|
|
|
|
|
|
|
p = model_name + token_len;
|
|
|
|
|
|
|
|
|
|
// exact match
|
|
|
|
|
if (*p == '\0')
|
2014-08-09 15:35:31 +02:00
|
|
|
return 1;
|
2014-08-09 15:35:31 +02:00
|
|
|
|
|
|
|
|
// check for .
|
|
|
|
|
if (*p++ != '.')
|
2014-08-09 15:35:31 +02:00
|
|
|
return 0;
|
2014-08-09 15:35:31 +02:00
|
|
|
|
|
|
|
|
// minimum one trailing char
|
|
|
|
|
if (*p == '\0')
|
2014-08-09 15:35:31 +02:00
|
|
|
return 0;
|
2014-08-09 15:35:31 +02:00
|
|
|
|
|
|
|
|
// all of them digits
|
|
|
|
|
for (; *p; p++)
|
2016-03-08 21:20:11 +01:00
|
|
|
if (!isdigit_c(*p))
|
2014-08-09 15:35:31 +02:00
|
|
|
return 0;
|
2014-08-09 15:35:31 +02:00
|
|
|
|
2014-08-09 15:35:31 +02:00
|
|
|
return 2;
|
2014-08-09 15:35:31 +02:00
|
|
|
}
|