You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1121 lines
20 KiB
1121 lines
20 KiB
/* mystring.c Copyright (C) 2002 Georg Post
|
|
*
|
|
* This file is part of Numparam, see: readme.txt
|
|
* Free software under the terms of the GNU Lesser General Public License
|
|
* $Id$
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
#include <math.h>
|
|
#include <stdarg.h>
|
|
|
|
#include "config.h"
|
|
#ifdef HAS_WINDOWS
|
|
#include "wstdio.h"
|
|
#endif
|
|
|
|
#include "general.h"
|
|
|
|
#include "../error.h" /* controlled_exit() */
|
|
|
|
/***** primitive input-output ***/
|
|
|
|
int
|
|
ci_prefix (register char *p, register char *s)
|
|
{
|
|
while (*p)
|
|
{
|
|
if ((isupper (*p) ? tolower (*p) : *p) !=
|
|
(isupper (*s) ? tolower (*s) : *s))
|
|
return (0);
|
|
p++;
|
|
s++;
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
wc (char c)
|
|
{
|
|
fputc (c, stdout);
|
|
}
|
|
|
|
void
|
|
wln (void)
|
|
{
|
|
wc ('\n');
|
|
}
|
|
|
|
void
|
|
ws (char *s)
|
|
{
|
|
int k = 0;
|
|
|
|
while (s[k] != 0)
|
|
{
|
|
wc (s[k]);
|
|
k++;
|
|
}
|
|
}
|
|
|
|
void
|
|
wi (long i)
|
|
{
|
|
SPICE_DSTRING s ;
|
|
spice_dstring_init(&s) ;
|
|
nadd (&s, i);
|
|
ws ( spice_dstring_value(&s)) ;
|
|
spice_dstring_free(&s) ;
|
|
}
|
|
|
|
void
|
|
rs ( SPICE_DSTRINGPTR dstr_p)
|
|
{ /* basic line input, limit= 80 chars */
|
|
char c;
|
|
|
|
|
|
spice_dstring_reinit(dstr_p) ;
|
|
do
|
|
{
|
|
c = fgetc (stdin);
|
|
cadd (dstr_p, c);
|
|
}
|
|
while (!((c == Cr) || (c == '\n')));
|
|
/* return i */ ;
|
|
}
|
|
|
|
char
|
|
rc (void)
|
|
{
|
|
int ls;
|
|
char val ;
|
|
char *s_p ;
|
|
SPICE_DSTRING dstr ;
|
|
|
|
spice_dstring_init(&dstr) ;
|
|
rs (&dstr);
|
|
ls = spice_dstring_length (&dstr);
|
|
if (ls > 0){
|
|
s_p = spice_dstring_value(&dstr) ;
|
|
val = s_p[ls - 1] ;
|
|
} else {
|
|
val = 0 ;
|
|
}
|
|
spice_dstring_free(&dstr) ;
|
|
return val ;
|
|
|
|
}
|
|
|
|
/******* Strings ************
|
|
* are 0-terminated char arrays with a 2-byte trailer: max length.
|
|
* the string mini-library is "overflow-safe" under these conditions:
|
|
* use Str(n,s) macro: define and initialize a string s of maxlen n<255
|
|
* use sini() to initialize empty strings; sfix() for non-empty ones.
|
|
* the Sini() macro does automatic sizing, for automatic char arrays
|
|
* to allocate a string on the heap, use newstring(n).
|
|
* use maxlen() and length() to retrieve string max and actual length
|
|
* use: cadd, cins, sadd, sins, scopy, pscopy to manipulate them
|
|
* never put '\x0' characters inside strings !
|
|
*
|
|
* the 'killer idea' is the following:
|
|
* on string overflow and/or on heap allocation failure, a program
|
|
* MUST die. Now we only die on a heap failure as with dynamic
|
|
* string we cannot have a string overflow.
|
|
*/
|
|
|
|
void
|
|
sfix ( SPICE_DSTRINGPTR dstr_p, int len)
|
|
/* suppose s is allocated and filled with non-zero stuff */
|
|
{
|
|
/* This function will now eliminate the max field. The length of
|
|
* the string is going to be i-1 and a null is going to be added
|
|
* at the ith position to be compatible with old codel. Also no
|
|
* null characters will be present in the string leading up to the
|
|
* NULL so this will make it a valid string. */
|
|
int j;
|
|
char *s ;
|
|
|
|
spice_dstring_setlength( dstr_p, len ) ;
|
|
s = spice_dstring_value( dstr_p ) ;
|
|
for (j = 0; j < len; j++) /* eliminate null characters ! */
|
|
if (s[j] == 0)
|
|
s[j] = 1;
|
|
|
|
}
|
|
|
|
int
|
|
length (char *s)
|
|
{
|
|
int lg = 0;
|
|
|
|
while (s[lg])
|
|
lg++;
|
|
|
|
return lg;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* Function: add string t to dynamic string dstr_p.
|
|
* ----------------------------------------------------------------- */
|
|
unsigned char
|
|
sadd ( SPICE_DSTRINGPTR dstr_p, char *t)
|
|
{
|
|
spice_dstring_append( dstr_p, t, -1 ) ;
|
|
return 1 ;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* Function: add character c to dynamic string dstr_p.
|
|
* ----------------------------------------------------------------- */
|
|
unsigned char
|
|
cadd ( SPICE_DSTRINGPTR dstr_p, char c)
|
|
{
|
|
char tmp_str[2] ;
|
|
tmp_str[0] = c ;
|
|
tmp_str[1] = 0 ;
|
|
spice_dstring_append( dstr_p, tmp_str, -1 ) ;
|
|
return 1 ;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* Function: insert character c at front of dynamic string dstr_p
|
|
* ----------------------------------------------------------------- */
|
|
unsigned char
|
|
cins ( SPICE_DSTRINGPTR dstr_p, char c)
|
|
{
|
|
int i ;
|
|
int ls ;
|
|
char *s_p ;
|
|
|
|
ls = spice_dstring_length(dstr_p) ;
|
|
spice_dstring_setlength(dstr_p,ls+2) ; /* make sure we have space for char + EOS */
|
|
s_p = spice_dstring_value(dstr_p) ;
|
|
for (i = ls + 1; i >= 0; i--)
|
|
s_p[i + 1] = s_p[i];
|
|
s_p[0] = c;
|
|
return 1 ;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* Function: insert string t at front of dynamic string dstr_p
|
|
* ----------------------------------------------------------------- */
|
|
unsigned char
|
|
sins ( SPICE_DSTRINGPTR dstr_p, char *t)
|
|
{
|
|
int i ;
|
|
int ls ;
|
|
int lt ;
|
|
char *s_p ;
|
|
|
|
ls = spice_dstring_length(dstr_p) ;
|
|
lt = length (t) ;
|
|
spice_dstring_setlength(dstr_p,ls+lt+1) ; /* make sure we have space for string + EOS */
|
|
s_p = spice_dstring_value(dstr_p) ;
|
|
for (i = ls + 1; i >= 0; i--)
|
|
s_p[i + lt] = s_p[i];
|
|
|
|
for (i = 0; i < lt; i++)
|
|
s_p[i] = t[i];
|
|
return 1 ;
|
|
|
|
}
|
|
|
|
int
|
|
cpos (char c, char *s)
|
|
/* return position of c in s, or 0 if not found.
|
|
* BUG, Pascal inherited: first char is at 1, not 0 !
|
|
* No longer! Now position is C-based to make life easier.
|
|
*/
|
|
{
|
|
int i = 0;
|
|
while ((s[i] != c) && (s[i] != 0))
|
|
i++;
|
|
|
|
if (s[i] == c)
|
|
return i ;
|
|
else
|
|
return -1 ;
|
|
}
|
|
|
|
char
|
|
upcase (char c)
|
|
{
|
|
if ((c >= 'a') && (c <= 'z'))
|
|
return c + 'A' - 'a';
|
|
else
|
|
return c;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* Create copy of the dynamic string. Dynamic strings are always NULL
|
|
* terminated.
|
|
* ----------------------------------------------------------------- */
|
|
unsigned char
|
|
scopyd(SPICE_DSTRINGPTR s, SPICE_DSTRINGPTR t) /* returns success flag */
|
|
{
|
|
spice_dstring_reinit( s ) ;
|
|
spice_dstring_append( s, spice_dstring_value(t), -1 ) ;
|
|
return 1 ; /* Dstrings expand to any length */
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* Create copy of the string in the dynamic string. Dynamic strings
|
|
* are always NULLterminated.
|
|
* ----------------------------------------------------------------- */
|
|
unsigned char
|
|
scopys(SPICE_DSTRINGPTR s, char *t) /* returns success flag */
|
|
{
|
|
spice_dstring_reinit( s ) ;
|
|
spice_dstring_append( s, t, -1 ) ;
|
|
return 1 ; /* Dstrings expand to any length */
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* Create an upper case copy of a string and store it in a dynamic string.
|
|
* Dynamic strings are always NULL * terminated.
|
|
* ----------------------------------------------------------------- */
|
|
unsigned char
|
|
scopy_up (SPICE_DSTRINGPTR dstr_p, char *str) /* returns success flag */
|
|
{
|
|
char up[2] ; /* short string */
|
|
char *ptr ; /* position in string */
|
|
|
|
spice_dstring_reinit( dstr_p ) ;
|
|
up[1] = 0 ;
|
|
for( ptr = str ; ptr && *ptr ; ptr++ ){
|
|
up[0] = upcase ( *ptr );
|
|
spice_dstring_append( dstr_p, up, 1 ) ;
|
|
}
|
|
return 1 ; /* Dstrings expand to any length */
|
|
}
|
|
|
|
/* -----------------------------------------------------------------
|
|
* Create a lower case copy of a string and store it in a dynamic string.
|
|
* Dynamic strings are always NULL * terminated.
|
|
* ----------------------------------------------------------------- */
|
|
unsigned char
|
|
scopy_lower (SPICE_DSTRINGPTR dstr_p, char *str) /* returns success flag */
|
|
{
|
|
char low[2] ; /* short string */
|
|
char *ptr ; /* position in string */
|
|
|
|
spice_dstring_reinit( dstr_p ) ;
|
|
low[1] = 0 ;
|
|
for( ptr = str ; ptr && *ptr ; ptr++ ){
|
|
low[0] = lowcase ( *ptr );
|
|
spice_dstring_append( dstr_p, low, 1 ) ;
|
|
}
|
|
return 1 ; /* Dstrings expand to any length */
|
|
}
|
|
|
|
unsigned char
|
|
ccopy ( SPICE_DSTRINGPTR dstr_p, char c) /* returns success flag */
|
|
{
|
|
char *s_p ; /* current string */
|
|
|
|
sfix ( dstr_p, 1);
|
|
s_p = spice_dstring_value(dstr_p) ;
|
|
s_p[0] = c ;
|
|
return 1 ;
|
|
}
|
|
|
|
char *
|
|
pscopy (SPICE_DSTRINGPTR dstr_p, char *t, int start, int leng)
|
|
/* partial string copy, with C-based start - Because we now have a 0 based
|
|
* start and string may copy outselves, we may need to restore the first
|
|
* character of the original dstring because resetting string will wipe
|
|
* out first character. */
|
|
{
|
|
int i; /* counter */
|
|
int stop ; /* stop value */
|
|
char *s_p ; /* value of dynamic string */
|
|
|
|
stop = length(t) ;
|
|
|
|
if (start < stop) { /* nothing! */
|
|
if ((start + leng - 1) > stop) {
|
|
// leng = stop - start + 1;
|
|
leng = stop - start ;
|
|
}
|
|
_spice_dstring_setlength(dstr_p,leng) ;
|
|
s_p = spice_dstring_value(dstr_p) ;
|
|
for (i = 0; i < leng; i++)
|
|
s_p[i] = t[start + i];
|
|
s_p[leng] = '\0' ;
|
|
} else {
|
|
s_p = spice_dstring_reinit(dstr_p) ;
|
|
}
|
|
return s_p ;
|
|
}
|
|
|
|
char *
|
|
pscopy_up (SPICE_DSTRINGPTR dstr_p, char *t, int start, int leng)
|
|
/* partial string copy to upper case, with C convention for start. */
|
|
{
|
|
int i; /* counter */
|
|
int stop ; /* stop value */
|
|
char *s_p ; /* value of dynamic string */
|
|
|
|
stop = length(t) ;
|
|
|
|
if (start < stop) { /* nothing! */
|
|
if ((start + leng - 1) > stop) {
|
|
// leng = stop - start + 1;
|
|
leng = stop - start ;
|
|
}
|
|
_spice_dstring_setlength(dstr_p,leng) ;
|
|
s_p = spice_dstring_value(dstr_p) ;
|
|
for (i = 0; i < leng; i++)
|
|
s_p[i] = upcase ( t[start + i] ) ;
|
|
s_p[leng] = '\0' ;
|
|
} else {
|
|
s_p = spice_dstring_reinit(dstr_p) ;
|
|
}
|
|
return s_p ;
|
|
}
|
|
|
|
int
|
|
ord (char c)
|
|
{
|
|
return (c & 0xff);
|
|
} /* strip high byte */
|
|
|
|
int
|
|
pred (int i)
|
|
{
|
|
return (--i);
|
|
}
|
|
|
|
int
|
|
succ (int i)
|
|
{
|
|
return (++i);
|
|
}
|
|
|
|
unsigned char
|
|
nadd ( SPICE_DSTRINGPTR dstr_p, long n)
|
|
/* append a decimal integer to a string */
|
|
{
|
|
int d[25];
|
|
int j, k ;
|
|
char sg; /* the sign */
|
|
char load_str[2] ; /* used to load dstring */
|
|
k = 0;
|
|
|
|
if (n < 0)
|
|
{
|
|
n = -n;
|
|
sg = '-';
|
|
}
|
|
else
|
|
sg = '+';
|
|
|
|
while (n > 0)
|
|
{
|
|
d[k] = n % 10;
|
|
k++;
|
|
n = n / 10;
|
|
}
|
|
|
|
if (k == 0)
|
|
cadd (dstr_p, '0');
|
|
else {
|
|
load_str[1] = 0 ;
|
|
if (sg == '-')
|
|
{
|
|
load_str[0] = sg ;
|
|
spice_dstring_append( dstr_p, load_str, 1 ) ;
|
|
}
|
|
for (j = k - 1; j >= 0; j--) {
|
|
load_str[0] = d[j] + '0';
|
|
spice_dstring_append( dstr_p, load_str, 1 ) ;
|
|
}
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
unsigned char
|
|
naddll (SPICE_DSTRINGPTR dstr_p, long long n)
|
|
/* append a decimal integer (but a long long) to a string */
|
|
{
|
|
int d[25];
|
|
int j, k ;
|
|
char sg; /* the sign */
|
|
char load_str[2] ; /* used to load dstring */
|
|
k = 0;
|
|
|
|
if (n < 0)
|
|
{
|
|
n = -n;
|
|
sg = '-';
|
|
}
|
|
else
|
|
sg = '+';
|
|
|
|
while (n > 0)
|
|
{
|
|
d[k] = n % 10;
|
|
k++;
|
|
n = n / 10;
|
|
}
|
|
|
|
if (k == 0)
|
|
cadd (dstr_p, '0');
|
|
else {
|
|
load_str[1] = 0 ;
|
|
if (sg == '-')
|
|
{
|
|
load_str[0] = sg ;
|
|
spice_dstring_append( dstr_p, load_str, 1 ) ;
|
|
}
|
|
for (j = k - 1; j >= 0; j--) {
|
|
load_str[0] = d[j] + '0';
|
|
spice_dstring_append( dstr_p, load_str, 1 ) ;
|
|
}
|
|
}
|
|
|
|
return 1 ;
|
|
}
|
|
|
|
void
|
|
stri (long n, SPICE_DSTRINGPTR dstr_p)
|
|
/* convert integer to string */
|
|
{
|
|
spice_dstring_reinit( dstr_p ) ;
|
|
nadd (dstr_p, n) ;
|
|
}
|
|
|
|
void
|
|
rawcopy (void *a, void *b, int la, int lb)
|
|
/* dirty binary copy */
|
|
{
|
|
int j, n;
|
|
if (lb < la)
|
|
n = lb;
|
|
else
|
|
n = la;
|
|
|
|
for (j = 0; j < n; j++)
|
|
((char *) a)[j] = ((char *) b)[j];
|
|
}
|
|
|
|
int
|
|
scompare (char *a, char *b)
|
|
{
|
|
unsigned short j = 0;
|
|
int k = 0;
|
|
while ((a[j] == b[j]) && (a[j] != 0) && (b[j] != 0))
|
|
j++;
|
|
|
|
if (a[j] < b[j])
|
|
k = -1;
|
|
else if (a[j] > b[j])
|
|
k = 1;
|
|
|
|
return k;
|
|
}
|
|
|
|
unsigned char
|
|
steq (char *a, char *b) /* string a==b test */
|
|
{
|
|
unsigned short j = 0;
|
|
while ((a[j] == b[j]) && (a[j] != 0) && (b[j] != 0))
|
|
j++;
|
|
|
|
return ((a[j] == 0) && (b[j] == 0)) /* string equality test */ ;
|
|
}
|
|
|
|
unsigned char
|
|
stne (char *s, char *t)
|
|
{
|
|
return scompare (s, t) != 0;
|
|
}
|
|
|
|
int
|
|
hi (long w)
|
|
{
|
|
return (w & 0xff00) >> 8;
|
|
}
|
|
|
|
int
|
|
lo (long w)
|
|
{
|
|
return (w & 0xff);
|
|
}
|
|
|
|
char
|
|
lowcase (char c)
|
|
{
|
|
if ((c >= 'A') && (c <= 'Z'))
|
|
return (char) (c - 'A' + 'a');
|
|
else
|
|
return c;
|
|
}
|
|
|
|
unsigned char
|
|
alfa (char c)
|
|
{
|
|
return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || c == '_'
|
|
|| c == '[' || c == ']';
|
|
}
|
|
|
|
unsigned char
|
|
num (char c)
|
|
{
|
|
return (c >= '0') && (c <= '9');
|
|
}
|
|
|
|
unsigned char
|
|
alfanum (char c)
|
|
{
|
|
return alfa (c) || ((c >= '0') && (c <= '9'));
|
|
}
|
|
|
|
int
|
|
freadstr (FILE * f, SPICE_DSTRINGPTR dstr_p)
|
|
/* read a line from a file.
|
|
was BUG: long lines truncated without warning, ctrl chars are dumped.
|
|
Bug no more as we can only run out of memory. Removed max argument.
|
|
*/
|
|
{
|
|
char c;
|
|
char str_load[2] ;
|
|
int len = 0 ;
|
|
|
|
str_load[0] = 0 ;
|
|
str_load[1] = 0 ;
|
|
spice_dstring_reinit(dstr_p) ;
|
|
do
|
|
{
|
|
c = fgetc (f); /* tab is the only control char accepted */
|
|
if (((c >= ' ') || (c < 0) || (c == Tab)))
|
|
{
|
|
str_load[0] = c;
|
|
spice_dstring_append( dstr_p, str_load, 1 ) ;
|
|
}
|
|
}
|
|
while (!(feof (f) || (c == '\n')));
|
|
|
|
|
|
return len ;
|
|
}
|
|
|
|
char
|
|
freadc (FILE * f)
|
|
{
|
|
return fgetc (f);
|
|
}
|
|
|
|
long
|
|
freadi (FILE * f)
|
|
/* reads next integer, but returns 0 if none found. */
|
|
{
|
|
long z = 0;
|
|
unsigned char minus = 0;
|
|
char c;
|
|
|
|
do
|
|
{
|
|
c = fgetc (f);
|
|
}
|
|
while (!(feof (f) || !((c > 0) && (c <= ' ')))); /* skip space */
|
|
|
|
if (c == '-')
|
|
{
|
|
minus = 1;
|
|
c = fgetc (f);
|
|
}
|
|
|
|
while (num (c))
|
|
{
|
|
z = 10 * z + c - '0';
|
|
c = fgetc (f);
|
|
}
|
|
|
|
ungetc (c, f); /* re-push character lookahead */
|
|
|
|
if (minus)
|
|
z = -z;
|
|
|
|
return z;
|
|
}
|
|
|
|
char *
|
|
stupcase (char *s)
|
|
{
|
|
int i = 0;
|
|
|
|
while (s[i] != 0)
|
|
{
|
|
s[i] = upcase (s[i]);
|
|
i++;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
/***** pointer tricks: app won't use naked malloc(), free() ****/
|
|
|
|
void
|
|
dispose (void *p)
|
|
{
|
|
if (p != NULL)
|
|
free (p);
|
|
}
|
|
|
|
void *
|
|
new (long sz)
|
|
{
|
|
void *p;
|
|
if (sz <= 0)
|
|
return NULL;
|
|
else
|
|
{
|
|
p = tmalloc (sz);
|
|
if (p == NULL)
|
|
{ /* fatal error */
|
|
ws (" new() failure. Program halted.\n");
|
|
controlled_exit(EXIT_FAILURE);
|
|
}
|
|
return p;
|
|
}
|
|
}
|
|
|
|
/***** elementary math *******/
|
|
|
|
double
|
|
sqr (double x)
|
|
{
|
|
return x * x;
|
|
}
|
|
|
|
double
|
|
absf (double x)
|
|
{
|
|
if (x < 0.0)
|
|
return -x;
|
|
else
|
|
return x;
|
|
}
|
|
|
|
long
|
|
absi (long i)
|
|
{
|
|
if (i >= 0)
|
|
return (i);
|
|
else
|
|
return (-i);
|
|
}
|
|
|
|
void
|
|
strif (long i, int f, SPICE_DSTRINGPTR dstr_p)
|
|
/* formatting like str(i:f,s) in Turbo Pascal */
|
|
{
|
|
int j, k ;
|
|
char cs;
|
|
char t[32];
|
|
char load_str[2] ; /* load dstring */
|
|
k = 0;
|
|
|
|
if (i < 0)
|
|
{
|
|
i = -i;
|
|
cs = '-';
|
|
}
|
|
else
|
|
{
|
|
cs = ' ';
|
|
}
|
|
|
|
while (i > 0)
|
|
{
|
|
j = (int) (i % 10);
|
|
i = (long) (i / 10);
|
|
t[k] = (char)('0' + j);
|
|
k++;
|
|
}
|
|
|
|
if (k == 0)
|
|
{
|
|
t[k] = '0';
|
|
k++;
|
|
}
|
|
|
|
if (cs == '-')
|
|
t[k] = cs;
|
|
else
|
|
k--;
|
|
|
|
/* now the string is in 0...k in reverse order */
|
|
for (j = 1; j <= k; j++)
|
|
t[k + j] = t[k - j]; /* mirror image */
|
|
|
|
t[2 * k + 1] = 0; /* null termination */
|
|
load_str[1] = 0 ; /* not really needed */
|
|
spice_dstring_reinit(dstr_p) ;
|
|
|
|
if ((f > k) && (f < 40))
|
|
{ /* reasonable format */
|
|
for (j = k + 2; j <= f; j++)
|
|
{
|
|
load_str[0] = ' ';
|
|
spice_dstring_append( dstr_p, load_str, 1 ) ;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j <= k + 1; j++){
|
|
load_str[0] = t[k + j]; /* shift t down */
|
|
spice_dstring_append( dstr_p, load_str, 1 ) ;
|
|
}
|
|
}
|
|
|
|
unsigned char
|
|
odd (long x)
|
|
{
|
|
return (x & 1);
|
|
}
|
|
|
|
int
|
|
vali (char *s, long *i)
|
|
/* convert s to integer i. returns error code 0 if Ok */
|
|
/* BUG: almost identical to ival() with arg/return value swapped ... */
|
|
{
|
|
int k = 0, digit = 0, ls;
|
|
long z = 0;
|
|
unsigned char minus = 0, ok = 1;
|
|
char c;
|
|
ls = length (s);
|
|
|
|
do
|
|
{
|
|
c = s[k];
|
|
k++;
|
|
}
|
|
while (!((k >= ls) || !((c > 0) && (c <= ' ')))); /* skip space */
|
|
|
|
if (c == '-')
|
|
{
|
|
minus = 1;
|
|
c = s[k];
|
|
k++;
|
|
}
|
|
|
|
while (num (c))
|
|
{
|
|
z = 10 * z + c - '0';
|
|
c = s[k];
|
|
k++;
|
|
digit++;
|
|
}
|
|
|
|
if (minus)
|
|
z = -z;
|
|
|
|
*i = z;
|
|
ok = (digit > 0) && (c == 0); /* successful end of string */
|
|
|
|
if (ok)
|
|
return 0;
|
|
else
|
|
return k; /* one beyond error position */
|
|
}
|
|
|
|
static unsigned char
|
|
match (char *s, char *t, int n, int tstart, unsigned char testcase)
|
|
{
|
|
/* returns 0 if ( tstart is out of range. But n may be 0 ? */
|
|
/* 1 if s matches t[tstart...tstart+n] */
|
|
int i, j, lt;
|
|
unsigned char ok;
|
|
char a, b;
|
|
i = 0;
|
|
j = tstart;
|
|
lt = length (t);
|
|
ok = (tstart < lt);
|
|
|
|
while (ok && (i < n))
|
|
{
|
|
a = s[i];
|
|
b = t[j];
|
|
if (!testcase)
|
|
{
|
|
a = upcase (a);
|
|
b = upcase (b);
|
|
}
|
|
ok = (j < lt) && (a == b);
|
|
i++;
|
|
j++;
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
int
|
|
posi (char *sub, char *s, int opt)
|
|
/* find position of substring in s */
|
|
{
|
|
/* opt=0: like Turbo Pascal */
|
|
/* opt=1: like Turbo Pascal Pos, but case insensitive */
|
|
/* opt=2: position in space separated wordlist for scanners */
|
|
int a, b, k, j;
|
|
unsigned char ok, tstcase;
|
|
SPICE_DSTRING tstr ;
|
|
|
|
ok = 0;
|
|
spice_dstring_init(&tstr) ;
|
|
tstcase = (opt == 0);
|
|
|
|
if (opt <= 1)
|
|
scopys (&tstr, sub);
|
|
else
|
|
{
|
|
cadd (&tstr, ' ');
|
|
sadd (&tstr, sub);
|
|
cadd (&tstr, ' ');
|
|
}
|
|
|
|
a = spice_dstring_length(&tstr) ;
|
|
b = (int) (length (s) - a);
|
|
k = 0;
|
|
j = 1;
|
|
|
|
if (a > 0) /* ;} else { return 0 */
|
|
while ((k <= b) && (!ok))
|
|
{
|
|
ok = match ( spice_dstring_value(&tstr), s, a, k, tstcase); /* we must start at k=0 ! */
|
|
k++;
|
|
if (s[k] == ' ')
|
|
j++; /* word counter */ ;
|
|
}
|
|
|
|
if (opt == 2)
|
|
k = j;
|
|
|
|
if (ok)
|
|
return k;
|
|
else
|
|
return 0;
|
|
|
|
}
|
|
|
|
int
|
|
spos_(char *sub, char *s)
|
|
/* equivalent to Turbo Pascal pos().
|
|
BUG: counts 1 ... length(s), not from 0 like C
|
|
*/
|
|
{
|
|
char *ptr;
|
|
|
|
if ((ptr = strstr (s, sub)))
|
|
return strlen (s) - strlen (ptr) ;
|
|
else
|
|
return -1 ;
|
|
|
|
}
|
|
|
|
/**** float formatting with printf/scanf ******/
|
|
|
|
int
|
|
valr (char *s, double *r)
|
|
/* returns 0 if ok, else length of partial string ? */
|
|
{
|
|
int n = sscanf (s, "%lG", r);
|
|
if (n == 1)
|
|
return (0);
|
|
else
|
|
return (1);
|
|
}
|
|
|
|
void
|
|
strf (double x, int f1, int f2, SPICE_DSTRINGPTR dstr_p)
|
|
/* e-format if f2<0, else f2 digits after the point, total width=f1 */
|
|
/* if f1=0, also e-format with f2 digits */
|
|
{ /* default f1=17, f2=-1 */
|
|
int dlen ; /* length of digits */
|
|
char *dbuf_p ; /* beginning of sprintf buffer */
|
|
SPICE_DSTRING fmt ; /* format string */
|
|
SPICE_DSTRING dformat ; /* format float */
|
|
|
|
spice_dstring_init(&fmt) ;
|
|
spice_dstring_init(&dformat) ;
|
|
cadd (&fmt, '%');
|
|
if (f1 > 0)
|
|
{
|
|
nadd (&fmt, f1); /* f1 is the total width */
|
|
if (f2 < 0)
|
|
sadd (&fmt, "lE"); /* exponent format */
|
|
else
|
|
{
|
|
cadd (&fmt, '.');
|
|
nadd (&fmt, f2);
|
|
sadd (&fmt, "lg");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cadd (&fmt, '.');
|
|
nadd (&fmt, absi (f2 - 6)); /* note the 6 surplus positions */
|
|
cadd (&fmt, 'e');
|
|
}
|
|
|
|
dlen = 2 * (f1 + f2) + 1 ; /* be conservative */
|
|
dbuf_p = spice_dstring_setlength(&dformat, dlen) ;
|
|
sprintf (dbuf_p, spice_dstring_value(&fmt), x);
|
|
scopys( dstr_p, dbuf_p ) ;
|
|
|
|
spice_dstring_free(&fmt) ;
|
|
spice_dstring_free(&dformat) ;
|
|
}
|
|
|
|
double
|
|
rval (char *s, int *err)
|
|
/* returns err=0 if ok, else length of partial string ? */
|
|
{
|
|
double r = 0.0;
|
|
int n = sscanf (s, "%lG", &r);
|
|
|
|
if (n == 1)
|
|
(*err) = 0;
|
|
else
|
|
(*err) = 1;
|
|
|
|
return r;
|
|
}
|
|
|
|
long
|
|
ival (char *s, int *err)
|
|
/* value of s as integer string. error code err= 0 if Ok */
|
|
{
|
|
int k = 0, digit = 0, ls;
|
|
long z = 0;
|
|
unsigned char minus = 0, ok = 1;
|
|
char c;
|
|
ls = length (s);
|
|
|
|
do
|
|
{
|
|
c = s[k];
|
|
k++;
|
|
}
|
|
while (!((k >= ls) || !((c > 0) && (c <= ' ')))); /* skip space */
|
|
|
|
if (c == '-')
|
|
{
|
|
minus = 1;
|
|
c = s[k];
|
|
k++;
|
|
}
|
|
|
|
while (num (c))
|
|
{
|
|
z = 10 * z + c - '0';
|
|
c = s[k];
|
|
k++;
|
|
digit++;
|
|
}
|
|
|
|
if (minus)
|
|
z = -z;
|
|
|
|
ok = (digit > 0) && (c == 0); /* successful end of string */
|
|
|
|
if (ok)
|
|
(*err) = 0;
|
|
else
|
|
(*err) = k; /* one beyond error position */
|
|
|
|
return z;
|
|
}
|
|
|
|
#ifndef HAVE_LIBM
|
|
|
|
long
|
|
np_round (double x)
|
|
/* using <math.h>, it would be simpler: floor(x+0.5), see below */
|
|
{
|
|
double u;
|
|
long z;
|
|
int n;
|
|
// Str (40, s);
|
|
SPICE_DSTRING s ;
|
|
spice_dstring_init(&s) ;
|
|
u = 2e9;
|
|
if (x > u)
|
|
x = u;
|
|
else if (x < -u)
|
|
x = -u;
|
|
|
|
n = sprintf (s, "%-12.0f", x);
|
|
s[n] = 0;
|
|
sscanf (s, "%ld", &z);
|
|
return z;
|
|
}
|
|
|
|
long
|
|
np_trunc (double x)
|
|
{
|
|
long n = np_round (x);
|
|
if ((n > x) && (x >= 0.0))
|
|
n--;
|
|
else if ((n < x) && (x < 0.0))
|
|
n++;
|
|
|
|
return n;
|
|
}
|
|
|
|
double
|
|
frac (double x)
|
|
{
|
|
return x - np_trunc (x);
|
|
}
|
|
|
|
double
|
|
intp (double x)
|
|
{
|
|
double u = 2e9;
|
|
if ((x > u) || (x < -u))
|
|
return x;
|
|
else
|
|
return np_trunc (x);
|
|
}
|
|
|
|
#else /* use floor() and ceil() */
|
|
|
|
long
|
|
np_round (double r)
|
|
{
|
|
return (long) floor (r + 0.5);
|
|
}
|
|
|
|
long
|
|
np_trunc (double r)
|
|
{
|
|
if (r >= 0.0)
|
|
return (long) floor (r);
|
|
else
|
|
return (long) ceil (r);
|
|
}
|
|
|
|
double
|
|
frac (double x)
|
|
{
|
|
if (x >= 0.0)
|
|
return (x - floor (x));
|
|
else
|
|
return (x - ceil (x));
|
|
}
|
|
|
|
double
|
|
intp (double x) /* integral part */
|
|
{
|
|
if (x >= 0.0)
|
|
return floor (x);
|
|
else
|
|
return ceil (x);
|
|
}
|
|
|
|
#endif
|