626 lines
13 KiB
C
626 lines
13 KiB
C
/* "NETGEN", a netlist-specification tool for VLSI
|
|
Copyright (C) 1989, 1990 Massimo A. Sivilotti
|
|
Author's address: mass@csvax.cs.caltech.edu;
|
|
Caltech 256-80, Pasadena CA 91125.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation (any version).
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file copying. If not, write to
|
|
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
/* pdutils.c -- various public-domain versions of useful functions */
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#ifdef IBMPC
|
|
#include <alloc.h>
|
|
#endif
|
|
|
|
#if defined(__STDC__) || defined(IBMPC)
|
|
#include <stdarg.h>
|
|
#else
|
|
#include <varargs.h>
|
|
#endif
|
|
|
|
#include "netgen.h"
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* Random number generators */
|
|
/* */
|
|
/*************************************************************************/
|
|
|
|
/* See NUMERICAL RECIPES IN C */
|
|
|
|
#include <math.h>
|
|
|
|
#define M 714025L
|
|
#define IA 1366
|
|
#define IC 150889L
|
|
|
|
static long idum = -1; /* needs to be initialized to avoid seg fault if 0 */
|
|
|
|
float ran2(void)
|
|
{
|
|
static long iy,ir[98];
|
|
static int iff=0;
|
|
int j;
|
|
void nrerror();
|
|
|
|
if (idum < 0 || iff == 0) {
|
|
iff=1;
|
|
if ((idum=(IC-(idum)) % M) < 0) idum = -idum;
|
|
for (j=1;j<=97;j++) {
|
|
idum=(IA*idum+IC) % M;
|
|
ir[j]=idum;
|
|
}
|
|
idum=(IA*idum+IC) % M;
|
|
iy=idum;
|
|
}
|
|
j=(int)(1 + 97.0*iy/M); /* the cast was added by Glenn for C++ */
|
|
if (j > 97 || j < 1) perror("RAN2: This cannot happen.");
|
|
iy=ir[j];
|
|
idum=(IA*idum+IC) % M;
|
|
ir[j]=idum;
|
|
return (float) iy/M;
|
|
}
|
|
|
|
#undef M
|
|
#undef IA
|
|
#undef IC
|
|
|
|
#if 0
|
|
int Random(int max)
|
|
{
|
|
int i;
|
|
float f;
|
|
f = ran2();
|
|
i = f * max;
|
|
printf("Random(%d) computes %f, returns: %d\n", max, f, i);
|
|
return(i);
|
|
}
|
|
#else
|
|
int Random(int max)
|
|
{
|
|
return(ran2() * max);
|
|
}
|
|
#endif
|
|
|
|
long RandomSeed(long seed)
|
|
/* initialize idum to some negative integer */
|
|
{
|
|
long oldidum;
|
|
|
|
oldidum = idum;
|
|
if (seed == 0) seed = -1;
|
|
if (seed > 0) seed = -seed;
|
|
idum = seed;
|
|
return(oldidum);
|
|
}
|
|
|
|
float RandomUniform(void)
|
|
{
|
|
return(ran2());
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/* */
|
|
/* String manipulation routines for deficient libraries */
|
|
/* */
|
|
/*************************************************************************/
|
|
|
|
|
|
#ifdef NEED_STRSTR
|
|
/* strstr - find first occurrence of wanted in s */
|
|
/* return pointer to found location, or NULL if none */
|
|
char *strstr(char *s, char *wanted)
|
|
{
|
|
register char *scan;
|
|
register int len;
|
|
register char firstc;
|
|
/* deleted by Glenn -- Not necessary (and conflict with declarations in .h)
|
|
extern int strcmp();
|
|
extern int strlen();
|
|
*/
|
|
|
|
/*
|
|
* The odd placement of the two tests is so "" is findable.
|
|
* Also, we inline the first char for speed.
|
|
* The ++ on scan has been moved down for optimization.
|
|
*/
|
|
firstc = *wanted;
|
|
len = strlen(wanted);
|
|
for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
|
|
if (*scan++ == '\0')
|
|
return(NULL);
|
|
return(scan);
|
|
}
|
|
#endif
|
|
|
|
#ifdef NEED_STRCASECMP
|
|
/* strcasecmp - compare string s1 to s2, case insensitive */
|
|
/* returns <0 for <, 0 for ==, >0 for > */
|
|
int strcasecmp(char *s1, char *s2)
|
|
{
|
|
register char *scan1;
|
|
register char *scan2;
|
|
|
|
scan1 = s1;
|
|
scan2 = s2;
|
|
while (*scan1 != '\0' && toupper(*scan1) == toupper(*scan2)) {
|
|
scan1++;
|
|
scan2++;
|
|
}
|
|
|
|
/*
|
|
* The following case analysis is necessary so that characters
|
|
* which look negative collate low against normal characters but
|
|
* high against the end-of-string NUL.
|
|
*/
|
|
if (*scan1 == '\0' && *scan2 == '\0')
|
|
return(0);
|
|
else if (*scan1 == '\0')
|
|
return(-1);
|
|
else if (*scan2 == '\0')
|
|
return(1);
|
|
else
|
|
return(*scan1 - *scan2);
|
|
}
|
|
#endif
|
|
|
|
#ifdef NEED_STRING
|
|
/*
|
|
* char *strtok(s,delim);
|
|
*
|
|
* Get next token from string s (NULL on 2nd, 3rd, etc. calls),
|
|
* where tokens are nonempty strings separated by runs of
|
|
* chars from delim. Writes NULs into s to end tokens. delim need not
|
|
* remain constant from call to call.
|
|
*/
|
|
|
|
static char *scanpoint = NULL;
|
|
|
|
char *strtok(char *s, char *delim)
|
|
{
|
|
register char *scan;
|
|
char *tok;
|
|
register char *dscan;
|
|
|
|
if (s == NULL && scanpoint == NULL)
|
|
return(NULL);
|
|
if (s != NULL)
|
|
scan = s;
|
|
else
|
|
scan = scanpoint;
|
|
|
|
/*
|
|
* Scan leading delimiters.
|
|
*/
|
|
for (; *scan != '\0'; scan++) {
|
|
for (dscan = delim; *dscan != '\0'; dscan++)
|
|
if (*scan == *dscan)
|
|
break;
|
|
if (*dscan == '\0')
|
|
break;
|
|
}
|
|
if (*scan == '\0') {
|
|
scanpoint = NULL;
|
|
return(NULL);
|
|
}
|
|
|
|
tok = scan;
|
|
|
|
/*
|
|
* Scan token.
|
|
*/
|
|
for (; *scan != '\0'; scan++) {
|
|
for (dscan = delim; *dscan != '\0';) /* ++ moved down. */
|
|
if (*scan == *dscan++) {
|
|
scanpoint = scan+1;
|
|
*scan = '\0';
|
|
return(tok);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Reached end of string.
|
|
*/
|
|
scanpoint = NULL;
|
|
return(tok);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* strcspn - find length of initial segment of s consisting entirely
|
|
* of characters not from reject
|
|
*/
|
|
|
|
int strcspn(char *s, char *reject)
|
|
{
|
|
register char *scan;
|
|
register char *rscan;
|
|
register int count;
|
|
|
|
count = 0;
|
|
for (scan = s; *scan != '\0'; scan++) {
|
|
for (rscan = reject; *rscan != '\0';) /* ++ moved down. */
|
|
if (*scan == *rscan++)
|
|
return(count);
|
|
count++;
|
|
}
|
|
return(count);
|
|
}
|
|
|
|
|
|
/*
|
|
* strpbrk - find first occurrence of any char from breakat in s
|
|
*/
|
|
|
|
|
|
char *strpbrk(char *s, char *breakat)
|
|
/* found char, or NULL if none */
|
|
{
|
|
register char *sscan;
|
|
register char *bscan;
|
|
|
|
for (sscan = s; *sscan != '\0'; sscan++) {
|
|
for (bscan = breakat; *bscan != '\0';) /* ++ moved down. */
|
|
if (*sscan == *bscan++)
|
|
return(sscan);
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef NEED_STRTOL
|
|
long strtol(char *str, char **ptr, int base)
|
|
/* extremely poor emulator */
|
|
{
|
|
long result;
|
|
int fields;
|
|
|
|
if (ptr != NULL) *ptr = str;
|
|
fields = sscanf(str,"%ld",&result);
|
|
if (fields == 1) {
|
|
if (ptr != NULL) *ptr = str+1; /* bogus, but why not */
|
|
return(result);
|
|
}
|
|
return(0);
|
|
}
|
|
#endif
|
|
|
|
#ifdef NEED_VPRINTF
|
|
|
|
#if 1
|
|
|
|
/* Portable vsprintf by Robert A. Larson <blarson@skat.usc.edu> */
|
|
|
|
/* Copyright 1989 Robert A. Larson.
|
|
* Distribution in any form is allowed as long as the author
|
|
* retains credit, changes are noted by their author and the
|
|
* copyright message remains intact. This program comes as-is
|
|
* with no warentee of fitness for any purpouse.
|
|
*
|
|
* Thanks to Doug Gwen, Chris Torek, and others who helped clarify
|
|
* the ansi printf specs.
|
|
*
|
|
* Please send any bug fixes and improvments to blarson@skat.usc.edu .
|
|
* The use of goto is NOT a bug.
|
|
*/
|
|
|
|
/* Feb 7, 1989 blarson First usenet release */
|
|
|
|
/* This code implements the vsprintf function, without relying on
|
|
* the existance of _doprint or other system specific code.
|
|
*
|
|
* Define NOVOID if void * is not a supported type.
|
|
*
|
|
* Two compile options are available for efficency:
|
|
* INTSPRINTF should be defined if sprintf is int and returns
|
|
* the number of chacters formated.
|
|
* LONGINT should be defined if sizeof(long) == sizeof(int)
|
|
*
|
|
* They only make the code smaller and faster, they need not be
|
|
* defined.
|
|
*
|
|
* UNSIGNEDSPECIAL should be defined if unsigned is treated differently
|
|
* than int in argument passing. If this is definded, and LONGINT is not,
|
|
* the compiler must support the type unsingned long.
|
|
*
|
|
* Most quirks and bugs of the available sprintf fuction are duplicated,
|
|
* however * in the width and precision fields will work correctly
|
|
* even if sprintf does not support this, as will the n format.
|
|
*
|
|
* Bad format strings, or those with very long width and precision
|
|
* fields (including expanded * fields) will cause undesired results.
|
|
*/
|
|
|
|
#ifdef OSK /* os9/68k can take advantage of both */
|
|
#define LONGINT
|
|
#define INTSPRINTF
|
|
#endif
|
|
|
|
/* This must be a typedef not a #define! */
|
|
#ifdef NOVOID
|
|
typedef char *pointer;
|
|
#else
|
|
typedef void *pointer;
|
|
#endif
|
|
|
|
#ifdef INTSPRINTF
|
|
#define Sprintf(string,format,arg) (sprintf((string),(format),(arg)))
|
|
#else
|
|
#define Sprintf(string,format,arg) (\
|
|
sprintf((string),(format),(arg)),\
|
|
strlen(string)\
|
|
)
|
|
#endif
|
|
|
|
typedef int *intp;
|
|
|
|
int vsprintf(dest, format, args)
|
|
char *dest;
|
|
register char *format;
|
|
va_list args;
|
|
{
|
|
register char *dp = dest;
|
|
register char c;
|
|
register char *tp;
|
|
char tempfmt[64];
|
|
#ifndef LONGINT
|
|
int longflag;
|
|
#endif
|
|
|
|
tempfmt[0] = '%';
|
|
while(c = *format++) {
|
|
if(c=='%') {
|
|
tp = &tempfmt[1];
|
|
#ifndef LONGINT
|
|
longflag = 0;
|
|
#endif
|
|
continue_format:
|
|
switch(c = *format++) {
|
|
case 's':
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
dp += Sprintf(dp, tempfmt, va_arg(args, char *));
|
|
break;
|
|
case 'u':
|
|
case 'x':
|
|
case 'o':
|
|
case 'X':
|
|
#ifdef UNSIGNEDSPECIAL
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
#ifndef LONGINT
|
|
if(longflag)
|
|
dp += Sprintf(dp, tempfmt, va_arg(args, unsigned long));
|
|
else
|
|
#endif
|
|
dp += Sprintf(dp, tempfmt, va_arg(args, unsigned));
|
|
break;
|
|
#endif
|
|
case 'd':
|
|
case 'c':
|
|
case 'i':
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
#ifndef LONGINT
|
|
if(longflag)
|
|
dp += Sprintf(dp, tempfmt, va_arg(args, long));
|
|
else
|
|
#endif
|
|
dp += Sprintf(dp, tempfmt, va_arg(args, int));
|
|
break;
|
|
case 'f':
|
|
case 'e':
|
|
case 'E':
|
|
case 'g':
|
|
case 'G':
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
dp += Sprintf(dp, tempfmt, va_arg(args, double));
|
|
break;
|
|
case 'p':
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
dp += Sprintf(dp, tempfmt, va_arg(args, pointer));
|
|
break;
|
|
case '-':
|
|
case '+':
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
case '.':
|
|
case ' ':
|
|
case '#':
|
|
case 'h':
|
|
*tp++ = c;
|
|
goto continue_format;
|
|
case 'l':
|
|
#ifndef LONGINT
|
|
longflag = 1;
|
|
*tp++ = c;
|
|
#endif
|
|
goto continue_format;
|
|
case '*':
|
|
tp += Sprintf(tp, "%d", va_arg(args, int));
|
|
goto continue_format;
|
|
case 'n':
|
|
*va_arg(args, intp) = dp - dest;
|
|
break;
|
|
case '%':
|
|
default:
|
|
*dp++ = c;
|
|
break;
|
|
}
|
|
} else *dp++ = c;
|
|
}
|
|
*dp = '\0';
|
|
return dp - dest;
|
|
}
|
|
|
|
/* Portable vfprintf and vprintf by Robert A. Larson <blarson@skat.usc.edu> */
|
|
|
|
int vfprintf(dest, format, args)
|
|
FILE *dest;
|
|
register char *format;
|
|
va_list args;
|
|
{
|
|
register char c;
|
|
register char *tp;
|
|
register int count = 0;
|
|
char tempfmt[64];
|
|
#ifndef LONGINT
|
|
int longflag;
|
|
#endif
|
|
|
|
tempfmt[0] = '%';
|
|
while(c = *format++) {
|
|
if(c=='%') {
|
|
tp = &tempfmt[1];
|
|
#ifndef LONGINT
|
|
longflag = 0;
|
|
#endif
|
|
continue_format:
|
|
switch(c = *format++) {
|
|
case 's':
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
count += fprintf(dest, tempfmt, va_arg(args, char *));
|
|
break;
|
|
case 'u':
|
|
case 'x':
|
|
case 'o':
|
|
case 'X':
|
|
#ifdef UNSIGNEDSPECIAL
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
#ifndef LONGINT
|
|
if(longflag)
|
|
count += fprintf(dest, tempfmt, va_arg(args, unsigned long));
|
|
else
|
|
#endif
|
|
count += fprintf(dest, tempfmt, va_arg(args, unsigned));
|
|
break;
|
|
#endif
|
|
case 'd':
|
|
case 'c':
|
|
case 'i':
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
#ifndef LONGINT
|
|
if(longflag)
|
|
count += fprintf(dest, tempfmt, va_arg(args, long));
|
|
else
|
|
#endif
|
|
count += fprintf(dest, tempfmt, va_arg(args, int));
|
|
break;
|
|
case 'f':
|
|
case 'e':
|
|
case 'E':
|
|
case 'g':
|
|
case 'G':
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
count += fprintf(dest, tempfmt, va_arg(args, double));
|
|
break;
|
|
case 'p':
|
|
*tp++ = c;
|
|
*tp = '\0';
|
|
count += fprintf(dest, tempfmt, va_arg(args, pointer));
|
|
break;
|
|
case '-':
|
|
case '+':
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
case '.':
|
|
case ' ':
|
|
case '#':
|
|
case 'h':
|
|
*tp++ = c;
|
|
goto continue_format;
|
|
case 'l':
|
|
#ifndef LONGINT
|
|
longflag = 1;
|
|
*tp++ = c;
|
|
#endif
|
|
goto continue_format;
|
|
case '*':
|
|
tp += Sprintf(tp, "%d", va_arg(args, int));
|
|
goto continue_format;
|
|
case 'n':
|
|
*va_arg(args, intp) = count;
|
|
break;
|
|
case '%':
|
|
default:
|
|
putc(c, dest);
|
|
count++;
|
|
break;
|
|
}
|
|
} else {
|
|
putc(c, dest);
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int vprintf(format, args)
|
|
char *format;
|
|
va_list args;
|
|
{
|
|
return vfprintf(stdout, format, args);
|
|
}
|
|
|
|
|
|
#else
|
|
/* this code works on machines that have _doprnt (Vaxes, etc) */
|
|
|
|
int vfprintf(FILE *fp, char *fmt, va_list args)
|
|
{
|
|
_doprnt(fmt, args, fp);
|
|
return(ferror(fp)? EOF: 0);
|
|
}
|
|
|
|
int vsprintf(char *str, char *fmt, va_list args)
|
|
{
|
|
struct _iobuf _strbuf;
|
|
|
|
_strbuf._flag = _IOWRT+_IOSTRG;
|
|
_strbuf._ptr = str;
|
|
_strbuf._cnt = 32767;
|
|
_doprnt(fmt, args, &_strbuf);
|
|
putc('\0', &_strbuf);
|
|
return(strlen(str));
|
|
}
|
|
#endif
|
|
#endif /* NEED_VPRINTF */
|