PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/ngspice-23/src/misc/string.c

#
C | 558 lines | 407 code | 71 blank | 80 comment | 144 complexity | 363e41f2be6ba9715abd830fe6127751 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-2.0, LGPL-2.1
  1. /**********
  2. Copyright 1990 Regents of the University of California. All rights reserved.
  3. **********/
  4. /*
  5. * String functions
  6. */
  7. #include "ngspice.h"
  8. #include "stringutil.h"
  9. #include "dstring.h"
  10. int
  11. prefix(register char *p, register char *s)
  12. {
  13. while (*p && (*p == *s))
  14. p++, s++;
  15. if (!*p)
  16. return (TRUE);
  17. else
  18. return (FALSE);
  19. }
  20. /* Create a copy of a string. */
  21. char *
  22. copy(const char *str)
  23. {
  24. char *p;
  25. if ((p = TMALLOC(char, strlen(str) + 1)) != NULL)
  26. (void) strcpy(p, str);
  27. return(p);
  28. }
  29. char *
  30. copy_substring(const char *str, const char *end)
  31. {
  32. size_t n = (size_t) (end - str);
  33. char *p;
  34. if ((p = TMALLOC(char, n + 1)) != NULL) {
  35. (void) strncpy(p, str, n);
  36. p[n] = '\0';
  37. }
  38. return(p);
  39. }
  40. /* Determine whether sub is a substring of str. */
  41. /* Like strstr( ) XXX */
  42. int
  43. substring(register char *sub, register char *str)
  44. {
  45. char *s, *t;
  46. while (*str) {
  47. if (*str == *sub) {
  48. t = str;
  49. for (s = sub; *s; s++) {
  50. if (!*t || (*s != *t++))
  51. break;
  52. }
  53. if (*s == '\0')
  54. return (TRUE);
  55. }
  56. str++;
  57. }
  58. return (FALSE);
  59. }
  60. /* Append one character to a string. Don't check for overflow. */
  61. /* Almost like strcat( ) XXX */
  62. void
  63. appendc(char *s, char c)
  64. {
  65. while (*s)
  66. s++;
  67. *s++ = c;
  68. *s = '\0';
  69. return;
  70. }
  71. /* Try to identify an integer that begins a string. Stop when a non-
  72. * numeric character is reached.
  73. */
  74. /* Like atoi( ) XXX */
  75. int
  76. scannum(char *str)
  77. {
  78. int i = 0;
  79. while(isdigit(*str))
  80. i = i * 10 + *(str++) - '0';
  81. return(i);
  82. }
  83. /* Case insensitive str eq. */
  84. /* Like strcasecmp( ) XXX */
  85. int
  86. cieq(register char *p, register char *s)
  87. {
  88. while (*p) {
  89. if ((isupper(*p) ? tolower(*p) : *p) !=
  90. (isupper(*s) ? tolower(*s) : *s))
  91. return(FALSE);
  92. p++;
  93. s++;
  94. }
  95. return (*s ? FALSE : TRUE);
  96. }
  97. /* Case insensitive prefix. */
  98. int
  99. ciprefix(register char *p, register char *s)
  100. {
  101. while (*p) {
  102. if ((isupper(*p) ? tolower(*p) : *p) !=
  103. (isupper(*s) ? tolower(*s) : *s))
  104. return(FALSE);
  105. p++;
  106. s++;
  107. }
  108. return (TRUE);
  109. }
  110. void
  111. strtolower(char *str)
  112. {
  113. if (str)
  114. while (*str) {
  115. if(isupper(*str))
  116. *str = (char) tolower(*str);
  117. str++;
  118. }
  119. }
  120. void
  121. strtoupper(char *str)
  122. {
  123. if (str)
  124. while (*str) {
  125. if(islower(*str))
  126. *str = (char) toupper(*str);
  127. str++;
  128. }
  129. }
  130. #ifdef CIDER
  131. /*
  132. * Imported from cider file support/strmatch.c
  133. * Original copyright notice:
  134. * Author: 1991 David A. Gates, U. C. Berkeley CAD Group
  135. *
  136. */
  137. /*
  138. * Case-insensitive test of whether p is a prefix of s and at least the
  139. * first n characters are the same
  140. */
  141. int
  142. cinprefix(
  143. register char *p, register char *s,
  144. register int n)
  145. {
  146. if (!p || !s) return( 0 );
  147. while (*p) {
  148. if ((isupper(*p) ? tolower(*p) : *p) != (isupper(*s) ? tolower(*s) : *s))
  149. return( 0 );
  150. p++;
  151. s++;
  152. n--;
  153. }
  154. if (n > 0)
  155. return( 0 );
  156. else
  157. return( 1 );
  158. }
  159. /*
  160. * Case-insensitive match of prefix string p against string s
  161. * returns the number of matching characters
  162. *
  163. */
  164. int
  165. cimatch(
  166. register char *p, register char *s)
  167. {
  168. register int n = 0;
  169. if (!p || !s) return( 0 );
  170. while (*p) {
  171. if ((isupper(*p) ? tolower(*p) : *p) != (isupper(*s) ? tolower(*s) : *s))
  172. return( n );
  173. p++;
  174. s++;
  175. n++;
  176. }
  177. return( n );
  178. }
  179. #endif /* CIDER */
  180. /*-------------------------------------------------------------------------*
  181. * gettok skips over whitespace and returns the next token found. This is
  182. * the original version. It does not "do the right thing" when you have
  183. * parens or commas anywhere in the nodelist. Note that I left this unmodified
  184. * since I didn't want to break any fcns which called it from elsewhere than
  185. * subckt.c. -- SDB 12.3.2003.
  186. *-------------------------------------------------------------------------*/
  187. char *
  188. gettok(char **s)
  189. {
  190. char c;
  191. int paren;
  192. char *token ; /* return token */
  193. SPICE_DSTRING buf ; /* allow any length string */
  194. paren = 0;
  195. while (isspace(**s))
  196. (*s)++;
  197. if (!**s)
  198. return (NULL);
  199. spice_dstring_init(&buf) ;
  200. while ((c = **s) != '\0' && !isspace(c)) {
  201. if (c == '('/*)*/)
  202. paren += 1;
  203. else if (c == /*(*/')')
  204. paren -= 1;
  205. else if (c == ',' && paren < 1)
  206. break;
  207. spice_dstring_append_char( &buf, *(*s)++ ) ;
  208. }
  209. while (isspace(**s) || **s == ',')
  210. (*s)++;
  211. token = copy( spice_dstring_value(&buf) ) ;
  212. spice_dstring_free(&buf) ;
  213. return ( token ) ;
  214. }
  215. /*-------------------------------------------------------------------------*
  216. * gettok skips over whitespaces or '=' and returns the next token found,
  217. * if the token is something like i(xxx), v(yyy), or v(xxx,yyy)
  218. * -- h_vogt 10.07.2010.
  219. *-------------------------------------------------------------------------*/
  220. char *
  221. gettok_iv(char **s)
  222. {
  223. char c;
  224. int paren;
  225. char *token ; /* return token */
  226. SPICE_DSTRING buf ; /* allow any length string */
  227. paren = 0;
  228. while ((isspace(**s)) || (**s=='='))
  229. (*s)++;
  230. if ((!**s) || ((**s != 'v') && (**s != 'i') && (**s != 'V') && (**s != 'I')))
  231. return (NULL);
  232. // initialize string
  233. spice_dstring_init(&buf);
  234. // add v or i to buf
  235. spice_dstring_append_char( &buf, *(*s)++ ) ;
  236. while ((c = **s) != '\0') {
  237. if (c == '('/*)*/)
  238. paren += 1;
  239. else if (c == /*(*/')')
  240. paren -= 1;
  241. if (isspace(c))
  242. (*s)++;
  243. else {
  244. spice_dstring_append_char( &buf, *(*s)++ ) ;
  245. if (paren == 0) break;
  246. }
  247. }
  248. while (isspace(**s) || **s == ',')
  249. (*s)++;
  250. token = copy( spice_dstring_value(&buf) ) ;
  251. spice_dstring_free(&buf) ;
  252. return ( token ) ;
  253. }
  254. /*-------------------------------------------------------------------------*
  255. * gettok_noparens was added by SDB on 4.21.2003.
  256. * It acts like gettok, except that it treats parens and commas like
  257. * whitespace while looking for the POLY token. That is, it stops
  258. * parsing and returns when it finds one of those chars. It is called from
  259. * 'translate' (subckt.c).
  260. *-------------------------------------------------------------------------*/
  261. char *
  262. gettok_noparens(char **s)
  263. {
  264. char c;
  265. char *token ; /* return token */
  266. SPICE_DSTRING buf ; /* allow any length string */
  267. while ( isspace(**s) )
  268. (*s)++; /* iterate over whitespace */
  269. if (!**s)
  270. return (NULL); /* return NULL if we come to end of line */
  271. spice_dstring_init(&buf) ;
  272. while ((c = **s) != '\0' &&
  273. !isspace(c) &&
  274. ( **s != '(' ) &&
  275. ( **s != ')' ) &&
  276. ( **s != ',')
  277. ) {
  278. spice_dstring_append_char( &buf, *(*s)++ ) ;
  279. }
  280. /* Now iterate up to next non-whitespace char */
  281. while ( isspace(**s) )
  282. (*s)++;
  283. token = copy( spice_dstring_value(&buf) ) ;
  284. spice_dstring_free(&buf) ;
  285. return ( token ) ;
  286. }
  287. char *
  288. gettok_instance(char **s)
  289. {
  290. char c;
  291. char *token ; /* return token */
  292. SPICE_DSTRING buf ; /* allow any length string */
  293. while ( isspace(**s) )
  294. (*s)++; /* iterate over whitespace */
  295. if (!**s)
  296. return (NULL); /* return NULL if we come to end of line */
  297. spice_dstring_init(&buf) ;
  298. while ((c = **s) != '\0' &&
  299. !isspace(c) &&
  300. ( **s != '(' ) &&
  301. ( **s != ')' )
  302. ) {
  303. spice_dstring_append_char( &buf, *(*s)++ ) ;
  304. }
  305. /* Now iterate up to next non-whitespace char */
  306. while ( isspace(**s) )
  307. (*s)++;
  308. token = copy( spice_dstring_value(&buf) ) ;
  309. spice_dstring_free(&buf) ;
  310. return ( token ) ;
  311. }
  312. /*-------------------------------------------------------------------------*
  313. * gettok_node was added by SDB on 12.3.2003
  314. * It acts like gettok, except that it treats parens and commas like
  315. * whitespace (i.e. it ignores them). Use it when parsing through netnames
  316. * (node names) since they may be grouped using ( , ).
  317. *-------------------------------------------------------------------------*/
  318. char *
  319. gettok_node(char **s)
  320. {
  321. char c;
  322. char *token ; /* return token */
  323. SPICE_DSTRING buf ; /* allow any length string */
  324. while (isspace(**s) ||
  325. ( **s == '(' ) ||
  326. ( **s == ')' ) ||
  327. ( **s == ',')
  328. )
  329. (*s)++; /* iterate over whitespace and ( , ) */
  330. if (!**s)
  331. return (NULL); /* return NULL if we come to end of line */
  332. spice_dstring_init(&buf) ;
  333. while ((c = **s) != '\0' &&
  334. !isspace(c) &&
  335. ( **s != '(' ) &&
  336. ( **s != ')' ) &&
  337. ( **s != ',')
  338. ) { /* collect chars until whitespace or ( , ) */
  339. spice_dstring_append_char( &buf, *(*s)++ ) ;
  340. }
  341. /* Now iterate up to next non-whitespace char */
  342. while (isspace(**s) ||
  343. ( **s == '(' ) ||
  344. ( **s == ')' ) ||
  345. ( **s == ',')
  346. )
  347. (*s)++; /* iterate over whitespace and ( , ) */
  348. token = copy( spice_dstring_value(&buf) ) ;
  349. spice_dstring_free(&buf) ;
  350. return ( token ) ;
  351. }
  352. /*-------------------------------------------------------------------------*
  353. * get_l_paren iterates the pointer forward in a string until it hits
  354. * the position after the next left paren "(". It returns 0 if it found a left
  355. * paren, and 1 if no left paren is found. It is called from 'translate'
  356. * (subckt.c).
  357. *-------------------------------------------------------------------------*/
  358. int
  359. get_l_paren(char **s)
  360. {
  361. while (**s && ( **s != '(' ) )
  362. (*s)++;
  363. if (!**s)
  364. return (1);
  365. (*s)++;
  366. if (!**s)
  367. return (1);
  368. else
  369. return 0;
  370. }
  371. /*-------------------------------------------------------------------------*
  372. * get_r_paren iterates the pointer forward in a string until it hits
  373. * the position after the next right paren ")". It returns 0 if it found a right
  374. * paren, and 1 if no right paren is found. It is called from 'translate'
  375. * (subckt.c).
  376. *-------------------------------------------------------------------------*/
  377. int
  378. get_r_paren(char **s)
  379. {
  380. while (**s && ( **s != ')' ) )
  381. (*s)++;
  382. if (!**s)
  383. return (1);
  384. (*s)++;
  385. if (!**s)
  386. return (1);
  387. else
  388. return 0;
  389. }
  390. /*-------------------------------------------------------------------------*
  391. * this function strips all white space inside parens
  392. * is needed in gettoks (dotcards.c) for right processing of expressions
  393. * like ".plot v( 5,4) v(6)"
  394. *-------------------------------------------------------------------------*/
  395. char *
  396. stripWhiteSpacesInsideParens(char *str)
  397. {
  398. char *token ; /* return token */
  399. SPICE_DSTRING buf ; /* allow any length string */
  400. int i = 0 ; /* index into string */
  401. while ( (str[i] == ' ') || (str[i] == '\t') )
  402. i++;
  403. spice_dstring_init(&buf) ;
  404. for(i=i; str[i]!='\0'; i++)
  405. {
  406. if ( str[i] != '(' ) {
  407. spice_dstring_append_char( &buf, str[i] ) ;
  408. } else {
  409. spice_dstring_append_char( &buf, str[i] ) ;
  410. while ( (str[i++] != ')') ) {
  411. if ( str[i] != ' ' ) spice_dstring_append_char( &buf, str[i] ) ;
  412. }
  413. i--;
  414. }
  415. }
  416. token = copy( spice_dstring_value(&buf) ) ;
  417. spice_dstring_free(&buf) ;
  418. return ( token ) ;
  419. }
  420. #ifndef HAVE_BCOPY
  421. #ifndef bcopy
  422. void
  423. bcopy(const void *vfrom, void *vto, size_t num)
  424. {
  425. register const char *from=vfrom;
  426. register char *to=vto;
  427. while (num-- > 0)
  428. *to++ = *from++;
  429. return;
  430. }
  431. #endif
  432. #endif
  433. #ifndef HAVE_BZERO
  434. #ifndef bzero
  435. void
  436. bzero(void *vptr, size_t num)
  437. {
  438. register char *ptr=vptr;
  439. while (num-- > 0)
  440. *ptr++ = '\0';
  441. return;
  442. }
  443. #endif
  444. #endif
  445. bool
  446. isquote( char ch )
  447. {
  448. return ( ch == '\'' || ch == '"' );
  449. }
  450. bool
  451. is_arith_char( char c )
  452. {
  453. if ( c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '<' ||
  454. c == '>' || c == '?' || c == '|' || c == '&' || c == '^')
  455. return TRUE;
  456. else
  457. return FALSE;
  458. }
  459. bool
  460. str_has_arith_char( char *s )
  461. {
  462. while ( *s && *s != '\0' ) {
  463. if ( is_arith_char(*s) ) return TRUE;
  464. s++;
  465. }
  466. return FALSE;
  467. }
  468. int
  469. get_comma_separated_values( char *values[], char *str ) {
  470. int count = 0;
  471. char *ptr, *comma_ptr, keep;
  472. while ( ( comma_ptr = strstr( str, "," ) ) != NULL ) {
  473. ptr = comma_ptr - 1;
  474. while ( isspace(*ptr) ) ptr--;
  475. ptr++; keep = *ptr; *ptr = '\0';
  476. values[count++] = strdup(str);
  477. *ptr = keep;
  478. str = comma_ptr + 1;
  479. while ( isspace(*str) ) str++;
  480. }
  481. values[count++] = strdup(str);
  482. return count;
  483. }