Copyright 1992 Regents of the University of California. All rights reserved.
Author: 1992 David A. Gates, U. C. Berkeley CAD Group
**********/
* Read and write dimension/index arrays via strings.
*/
#include "ngspice/ngspice.h"
#include "ngspice/dvec.h"
#include "dimens.h"
#include "ngspice/stringskip.h"
static int atodims_bracketed(const char *p, int *data, int *p_n_dim);
static int atodims_unbracketed(const char *p, int *data, int *p_n_dim);
static int get_bracketed_dim(const char *p, int *p_val);
static int atodims_csv(const char *p, int *data, int *p_n_dim);
static int get_dim(const char *p, int *p_val);
* Create a string of the form "12,1,10".
*
* Parameters
* dim_data: Array of sizes of dimensions, [12, 1, 10] for the example
* n_dim: Number of elements in the array, 3 in the example
* retstring: Address of buffer where the string is returned.
* Remarks
* It is assumed that the buffer in retstring is large enough, which for
* MAXDIMS, would require MAXDIMS * 11 bytes in the worst case assuming
* 32-bit ints. A looser but more general bound only assuming 8-bit bytes
* would be MAXDIMS * (3 * sizeof(int) + 1).
*/
void
dimstring(const int *dim_data, int n_dim, char *retstring)
{
if (dim_data == (int *) NULL || n_dim < 1) {
*retstring = '\0';
return;
}
retstring += sprintf(retstring, "%d", dim_data[0]);
int i;
for (i = 1; i < n_dim; i++) {
retstring += sprintf(retstring, ",%d", dim_data[i]);
}
}
* Create a string of the form "[12][1][10]" in retstring.
*
* Parameters
* dim_data: Array of sizes of dimensions, [12, 1, 10] for the example
* n_dim: Number of elements in the array, 3 in the example
* retstring: Address of buffer where the string is returned.
* Remarks
* It is assumed that the buffer in retstring is large enough, which for
* MAXDIMS, would require MAXDIMS * 12 + 1 bytes in the worst case assuming
* 32-bit ints. A looser but more general bound only assuming 8-bit bytes
* would be MAXDIMS * (3 * sizeof(int) + 2) + 1.
*/
void
indexstring(const int *dim_data, int n_dim, char *retstring)
{
if (dim_data == (int *) NULL || n_dim < 1) {
*retstring = '\0';
return;
}
int i;
for (i = 0; i < n_dim; i++) {
retstring += sprintf(retstring, "[%d]", dim_data[i]);
}
}
* Add one to anstrchr into an array with sizes in dims.
* Return 1 when all counters overflow at once.
*/
int
incindex(int *counts, int numcounts, const int *dims, int numdims)
{
int i, start;
if (!counts || numcounts < 1 || !dims || numdims < 1)
return 0;
start = numcounts - 1;
for (i = start; i >= 0; i--)
if (++counts[i] < dims[i])
break;
else
counts[i] = 0;
if (i == 0)
return (1);
else
return (0);
}
* Read a string of one of the following forms into a dimensions array:
* [12][1][10]
* [12,1,10]
* 12,1,10
* 12, 1, 10
* 12 , 1 , 10
* Basically, we require that all brackets be matched, that all numbers
* be separated by commas or by "][", that all whitespace is ignored, and
* the beginning [ and end ] are ignored if they exist. The only valid
* characters in the string are brackets, commas, spaces, and digits.
* If any dimension is blank, its entry in the array is set to 0.
*
* Return 0 on success, 1 on failure.
*/
int atodims(const char *p, int *data, int *p_n_dim)
{
if (!data || !p_n_dim) {
return 1;
}
if (!p) {
*p_n_dim = 0;
return 0;
}
p = skip_ws(p);
return *p == '[' ? atodims_bracketed(p, data, p_n_dim) :
atodims_unbracketed(p, data, p_n_dim);
}
* [1,2,3,4] or [1][2][3][4]. Whitespace is allowed anywhere except
* at the beginning of the string or between the digits of a dimension.
*
* Return codes
* 0: OK
* +1: Error
*/
static int atodims_bracketed(const char *p, int *data, int *p_n_dim)
{
* if the string is of form [] or [1,2...] or [1][2]... */
p = skip_ws(++p);
{
int rc;
if ((rc = get_dim(p, data)) <= 0) {
if (rc < 0) {
return +1;
}
if (*p == ']') {
*p_n_dim = 0;
return 0;
}
return +1;
}
p = skip_ws(p + rc);
switch (*p) {
case ',':
*p_n_dim = 1;
rc = atodims_csv(++p, data, p_n_dim);
if (rc <= 1) {
return +1;
}
* whitespace excluded? */
p = skip_ws(p + rc);
return *p != '\0';
case ']':
++p;
break;
default:
return +1;
}
}
unsigned int n_dim = 1;
for ( ; ; ) {
if (n_dim == MAXDIMS) {
return +1;
}
int rc = get_bracketed_dim(p, data + n_dim);
if (rc <= 0) {
*p_n_dim = (int) n_dim;
return !!rc;
}
p += rc;
++n_dim;
}
}
* 1,2,3,4. Whiltespace is allowed anywhere except
* at the beginning of the string or between the digits of a dimension.
*
* Return codes
* 0: OK
* +1: Error
*/
static int atodims_unbracketed(const char *p, int *data, int *p_n_dim)
{
*p_n_dim = 0;
if (*p == '\0') {
return 0;
}
return !!atodims_csv(p, data, p_n_dim);
}
* 1,2,3,4 and 1,2,3,4]. Whiltespace is allowed anywhere except
* at the beginning of the string or between the digits of a dimension.
* On entry, *p_n_dim is the number of dimensions already added to data
* and p points to the first number to be processed.
*
* Return codes
* -1: Error
* 0: OK, scan ended by '\0'
* >0: OK, scan ended by ']', returned value = # chars processed
*/
static int atodims_csv(const char *p, int *data, int *p_n_dim)
{
const char *p0 = p;
unsigned int n_dim = (unsigned int) *p_n_dim;
for ( ; ; ) {
int val;
p = skip_ws(p);
int rc = get_dim(p, &val);
if (rc <= 0) {
return -1;
}
if (n_dim >= MAXDIMS) {
return -1;
}
data[n_dim++] = val;
p = skip_ws(p + rc);
* end of regular list or bracketed list */
switch (*p) {
case ',':
++p;
break;
case ']':
*p_n_dim = (int) n_dim;
return (int) (p - p0) + 1;
case '\0':
*p_n_dim = (int) n_dim;
return 0;
default:
return -1;
}
}
}
* [1] where spaces may appear anywhere except between the digits of the
* number.
*
* Return codes
* -1: Error
* 0: String ended before '['
* >0: Number of characters processed
*/
static int get_bracketed_dim(const char *p, int *p_val)
{
const char *p0 = p;
p = skip_ws(p);
const char char_cur = *p;
if (char_cur == '\0') {
return 0;
}
if (char_cur != '[') {
return -1;
}
p = skip_ws(++p);
int rc = get_dim(p, p_val);
if (rc <= 0) {
return -1;
}
p = skip_ws(p + rc);
if (*p != ']') {
return -1;
}
return (int) (p - p0) + 1;
}
*
* Return codes
* -1: overflow
* 0: *p is not a digit
* >0: Number of characters processed
*/
static int get_dim(const char *p, int *p_val)
{
unsigned int val = 0;
const char *p0 = p;
for ( ; ; ++p) {
const char c_cur = *p;
unsigned int digit_cur = (unsigned int) (c_cur - '0');
unsigned int val_new;
if (digit_cur > 9) {
if ((*p_val = (int) val) < 0) {
return -1;
}
return (int) (p - p0);
}
if ((val_new = 10 * val + digit_cur) < val) {
return -1;
}
val = val_new;
}
}
#ifdef COMPILE_UNUSED_FUNCTIONS
* Count number of empty dimensions in an array.
*/
int
emptydims(int *data, int length)
{
int i, numempty = 0;
for (i = 0; i < length; i++)
if (data[i] == 0)
numempty++;
return (numempty);
}
* Skip to the first character that cannot be part of a dimension string.
*/
char *
skipdims(char *p)
{
if (!p)
return NULL;
while (*p && (*p == '[' || *p == ']' || *p == ',' ||
isspace_c(*p) || isdigit_c(*p)))
p++;
return (p);
}
#endif