home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (c) 1992 The Geometry Center; University of Minnesota
- 1300 South Second Street; Minneapolis, MN 55454, USA;
-
- This file is part of geomview/OOGL. geomview/OOGL is free software;
- you can redistribute it and/or modify it only under the terms given in
- the file COPYING, which you should have received along with this file.
- This and other related software may be obtained via anonymous ftp from
- geom.umn.edu; email: software@geom.umn.edu. */
- static char *copyright = "Copyright (C) 1992 The Geometry Center";
-
- /* Authors: Charlie Gunn, Stuart Levy, Tamara Munzner, Mark Phillips */
-
- /* $Header: /usrb/gcg/ngrap/src/lib/oogl/util/RCS/futil.c,v 1.25 1993/11/10 20:26:51 slevy Exp $ */
-
- /*
- * Geometry object routines
- *
- * Utility routines, useful for many objects
- *
- * int
- * fgetnf(file, nfloats, floatp, binary)
- * Read an array of floats from a file in "ascii" or "binary" format.
- * Returns number of floats successfully read, should = nfloats.
- * "Binary" means "IEEE 32-bit floating-point" format.
- *
- * int
- * fgetni(FILE *file, int nints, int *intsp, int binary)
- * Read an array of ints from a file in "ascii" or "binary" format.
- * Returns number of ints successfully read, should = nints.
- * "Binary" means "32-bit big-endian" integer format.
- *
- * int
- * fgetns(FILE *file, int nshorts, short *intsp, int binary)
- * Read an array of shorts from a file in "ascii" or "binary" format.
- * Returns number of shorts successfully read, should = nints.
- * "Binary" means "16-bit big-endian" integer format.
- *
- * int
- * fexpectstr(FILE *file, char *string)
- * Expect the given string to appear immediately on file.
- * Return 0 if the complete string is found,
- * else the offset+1 of the last matched char within string.
- * The first unmatched char is ungetc'd.
- *
- * int
- * fexpecttoken(FILE *file, char *string)
- * Expect the given string to appear on the file, possibly after
- * skipping some white space and comments.
- * Return 0 if found, else the offset+1 of last matched char in string.
- * The first unmatched char is ungetc'd.
- *
- * int fnextc(FILE *f, int flags)
- * Advances f to the next "interesting" character and
- * returns it. The returned char is ungetc'ed so the next getc()
- * will yield the same value.
- * Interesting depends on flags:
- * 0 : Skip blanks, tabs, newlines, and comments (#...\n).
- * 1 : Skip blanks, tabs, and comments, but newlines are interesting
- * (including the \n that terminates a comment).
- * 2 : Skip blanks, tabs, and newlines, but stop at #.
- * 3 : Skip blanks and tabs but stop at # or \n.
- *
- * int async_fnextc(FILE *f, int flags)
- * Like fnextc() above, but guarantees not to block if no data is
- * immediately available. It returns either an interesting character,
- * EOF, or the special code NODATA (== -2).
- *
- * int async_getc(FILE *f)
- * Like getc(), but guarantees not to block. Returns NODATA if
- * nothing is immediately available.
- *
- * char *ftoken(FILE *f, int flags)
- * Skips uninteresting characters with fnextc(f, flags),
- * then returns a "token" - string of consecutive interesting characters.
- * Returns NULL if EOF is reached with no token, or if
- * flags specifies stopping at end-of-line and this is encountered with
- * no token found.
- * The token is effectively statically allocated and will be
- * overwritten by the next ftoken() call.
- *
- * char *fdelimtok(char *delims, FILE *f, int flags)
- * Like ftoken(), but specially handles the characters in delims[].
- * If one appears at the beginning of the token, it's returned as
- * a single-character token.
- * If a member of delims[] appears after other characters have been
- * accumulated, it's considered to terminate the token.
- * So successive calls to fdelimtok("()", f, 0)
- * on a file containing (fred smith)
- * would return "(", "fred", "smith", and ")".
- * Behavior is undefined if one of the predefined delimiters
- * (white space or #) appears in delims[]. Explicit quoting
- * (with ", ' or \) overrides detection of delimiters.
- *
- * int fgettransform(FILE *f, int ntransforms, float *transforms, int binary)
- * Reads 4x4 matrices from FILE. Returns the number of matrices found,
- * up to ntransforms. Returns 0 if no numbers are found.
- * On finding incomplete matrices (not a multiple of 16 floats)
- * returns -1, regardless of whether any whole matrices were found.
- * Matrices are expected in the form used to transform a row vector
- * multiplied on the left, i.e. p * T -> p'; thus Euclidean translations
- * appear in the last row.
- *
- * int fputtransform(FILE *f, int ntransforms, float *transforms, int binary)
- * Writes 4x4 matrices to FILE. Returns the number written, i.e.
- * ntransforms unless an error occurs.
- *
- * int fputnf(FILE *f, int nfloats, float *fv, int binary)
- * Writes 'nfloats' floats to the given file. ASCII is in %g format,
- * separated by blanks.
- *
- * FILE *fstropen(str, len, mode)
- * Opens a string (buffer) as a "file".
- * Mode is "r" or "w" as usual.
- * Reads should return EOF on encountering end-of-string,
- * writes past end-of-string should also yield an error return.
- * fclose() should be used to free the FILE after use.
- */
-
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <stdlib.h>
- #include <string.h>
- #ifdef sgi
- #include <unistd.h>
- #include <malloc.h>
- #endif /* -nils XXX */
- #include <ctype.h>
- #include "ooglutil.h"
-
- int
- fnextc(FILE *f, int flags)
- {
- register int c;
-
- c = getc(f);
- for(;;) {
- switch(c) {
- case EOF:
- return(EOF);
-
- case ' ':
- case '\t':
- break; /* Always skip blanks and tabs */
-
- case '#':
- if(flags & 2) /* 2: stop on comments, else skip */
- goto fim;
-
- while((c = getc(f)) != '\n' && c != EOF)
- ;
- continue; /* Rescan this c */
-
- case '\n':
- if(!(flags & 1)) /* 1: stop on \n's, else skip them */
- break;
- /* flags&1 => fall into default */
-
- default:
- fim:
- ungetc(c, f);
- return(c);
- }
-
- c = getc(f);
- }
- }
-
-
- float f_pow10[11] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10 };
-
- #define fPow10(n) ((unsigned)(n) > 10 ? fpow10(n) : f_pow10[n])
-
- float
- fpow10(int n)
- {
- register int k;
- register float v;
-
- if((k = n) < 0)
- k = -k;
- v = f_pow10[k & 7];
- if(k >= 8) {
- float unit = 1e8;
-
- k >>= 3;
- for(;;) {
- if(k & 1)
- v *= unit;
- if((k >>= 1) == 0)
- break;
- unit *= unit;
- }
- }
- return(n < 0 ? 1.0/v : v);
- }
-
- /*
- * Read an array of white-space-separated floats from file 'f' in ASCII, fast.
- * Returns the number successfully read.
- */
- int
- fgetnf(register FILE *f, int maxf, float *fv, int binary)
- {
- int ngot;
- float v;
- register int c = EOF;
- register long n;
- long w;
- int s, es, nd, any;
-
- if(binary) {
- #if m68k || mc68000 || mips || sparc
- /* Easy -- our native floating point == big-endian IEEE */
- return fread((char *)fv, sizeof(float), maxf, f);
- #else /* not native big-endian IEEE */
- for(n=0; n<maxf && fread((char *)&w,sizeof(long),1,f) > 0; n++)
- *(long *)&fv[n] = ntohl(w);
- return n;
- #endif /* not native big-endian IEEE */
- }
-
- /* Read ASCII format floats */
- for(ngot = 0; ngot < maxf; ngot++) {
- if(fnextc(f, 0) == EOF)
- return(ngot);
- n = 0;
- s = 0;
- nd = 0;
- any = 0;
- if((c = getc(f)) == '-') {
- s = 1;
- c = getc(f);
- }
- while(c >= '0' && c <= '9') {
- n = n*10 + c - '0';
- nd++;
- if(n >= 214748364) { /* 2^31 / 10 */
- v = any ? v*fPow10(nd) + (float)n : (float)n;
- nd = n = 0;
- any = 1;
- }
- c = getc(f);
- }
- v = any ? v*fPow10(nd) + (float)n : (float)n;
- any += nd;
- if(c == '.') {
- nd = n = 0;
- while((c = getc(f)) >= '0' && c <= '9') {
- n = n*10 + c - '0';
- nd++;
- if(n >= 214748364) {
- v += (float)n / fPow10(nd);
- n = 0;
- }
- }
- v += (float)n / fPow10(nd);
- }
- if(any == 0 && nd == 0)
- break;
- if(c == 'e' || c == 'E') {
- es = nd = 0;
- switch(c = getc(f)) {
- case '-':
- es = 1; /* And fall through */
- case '+':
- c = getc(f);
- }
- n = 0;
- while(c >= '0' && c <= '9') {
- n = n*10 + c - '0';
- nd++;
- c = getc(f);
- }
- if(nd == 0)
- break;
- if(es) v /= fPow10(n);
- else v *= fPow10(n);
- }
- fv[ngot] = s ? -v : v;
- }
- if(c!=EOF) ungetc(c, f);
- return(ngot);
- }
-
-
- int
- fgetni(register FILE *f, int maxi, int *iv, int binary)
- {
- int ngot;
- register int c = EOF;
- register long n;
- long w;
- int s, any;
-
- if(binary) {
- #if m68k || mc68000 || mips || sparc
- /* Easy -- our native floating point == big-endian IEEE */
- return fread((char *)iv, sizeof(int), maxi, f);
- #else /* not native big-endian int's */
- for(n = 0; n < maxi && fread(&w,4,1,f) > 0; n++)
- iv[n] = ntohl(w);
- return n;
- #endif /* not native big-endian int's */
- }
-
- /* Read ASCII format floats */
- for(ngot = 0; ngot < maxi; ngot++) {
- if(fnextc(f, 0) == EOF)
- return(ngot);
- n = 0;
- s = 0;
- any = 0;
- if((c = getc(f)) == '-') {
- s = 1;
- c = getc(f);
- }
- while(c >= '0' && c <= '9') {
- n = n*10 + c - '0';
- any = 1;
- c = getc(f);
- }
- if(!any)
- break;
- iv[ngot] = s ? -n : n;
- }
- if(c!=EOF) ungetc(c, f);
- return(ngot);
- }
-
- int
- fgetns(register FILE *f, int maxs, short *sv, int binary)
- {
- int ngot;
- register int c = EOF;
- register long n;
- short w;
- int s, any;
-
- if(binary) {
- #if m68k || mc68000 || mips || sparc
- /* Easy -- our native floating point == big-endian IEEE */
- return fread((char *)sv, sizeof(short), maxs, f);
- #else /* not native big-endian int's */
- for(n = 0; n < maxs && fread(&w,2,1,f) > 0; n++)
- sv[n] = ntohs(w);
- return n;
- #endif /* not native big-endian int's */
- }
-
- /* Read ASCII format floats */
- for(ngot = 0; ngot < maxs; ngot++) {
- if(fnextc(f, 0) == EOF)
- return(ngot);
- n = s = any = 0;
- if((c = getc(f)) == '-') {
- s = 1;
- c = getc(f);
- }
- while(c >= '0' && c <= '9') {
- n = n*10 + c - '0';
- any = 1;
- c = getc(f);
- }
- if(!any)
- break;
- sv[ngot] = s ? -n : n;
- }
- if(c!=EOF) ungetc(c, f);
- return(ngot);
- }
-
- /*
- * Check for a string on a file.
- * If found, return 0.
- * If not, return the offset of the last matched char +1
- * and ungetc the failed char so the caller can see it.
- */
- int
- fexpectstr(register FILE *file, char *str)
- {
- register char *p = str;
- register int c;
-
- while(*p != '\0') {
- if((c = getc(file)) != *p++) {
- if(c != EOF)
- ungetc(c, file);
- return(p - str);
- }
- }
- return 0;
- }
-
- /*
- * Check for a string on a file, skipping leading blanks.
- */
- int
- fexpecttoken(register FILE *file, char *str)
- {
- (void) fnextc(file, 0);
- return fexpectstr(file, str);
- }
-
- int fescape(FILE *f)
- {
- int n, k, c = fgetc(f);
-
- switch(c) {
- case 'n': return '\n';
- case 'b': return '\b';
- case 't': return '\t';
- case 'r': return '\r';
- }
- if(c < '0' || c > '7')
- return c;
-
- n = c-'0'; k = 2;
- while((c = fgetc(f)) >= '0' && c <= '7') {
- n = n*8 | c-'0';
- if(--k <= 0)
- return n;
- }
- if(c != EOF) ungetc(c, f);
- return n;
- }
-
- /*
- * Get a token, return a string or NULL.
- * Tokens may be "quoted" or 'quoted'; backslashes accepted.
- * The string is statically allocated and should be copied if
- * needed before the next call to ftoken().
- */
- char *
- ftoken(FILE *file, int flags)
- {
- static char *token = NULL;
- static int troom = 0;
- register int c;
- register char *p;
- register int term;
-
- if((term = fnextc(file, flags)) == EOF)
- return NULL;
-
- if(token == NULL) {
- troom = 50;
- token = malloc(troom * sizeof(char));
- if(token == NULL)
- return NULL;
- }
-
- p = token;
- switch(term) {
- case '"':
- case '\'':
- (void) fgetc(file);
- for(;;) {
- if((c = getc(file)) == EOF || c == term)
- break;
- else if(c == '\\')
- c = fescape(file);
- *p++ = c;
- if(p == &token[troom]) {
- token = realloc(token, troom * 2);
- if(token == NULL)
- return NULL;
- p = &token[troom];
- troom *= 2;
- }
- }
- break;
-
- default:
- if(isspace(term))
- return NULL;
- while((c = getc(file)) != EOF && !isspace(c)) {
- if(c == '\\')
- c = fescape(file);
- *p++ = c;
- if(p == &token[troom]) {
- token = realloc(token, troom * 2);
- if(token == NULL)
- return NULL;
- p = &token[troom];
- troom *= 2;
- }
- }
- break;
- }
- *p = '\0';
- return token;
- }
-
-
- /*
- * Get a token, return a string or NULL.
- * Tokens may be "quoted" or 'quoted'; backslashes accepted.
- * The string is statically allocated and should be copied if
- * needed before the next call to ftoken().
- */
- char *
- fdelimtok(char *delims, FILE *file, int flags)
- {
- static char *token = NULL;
- static int troom = 0;
- register int c;
- register char *p;
- register char *q;
- register int term;
-
- if((term = fnextc(file, flags)) == EOF)
- return NULL;
-
- if(token == NULL) {
- troom = 50;
- token = malloc(troom * sizeof(char));
- if(token == NULL)
- return NULL;
- }
-
- p = token;
- switch(term) {
- case '"':
- case '\'':
- (void) fgetc(file);
- for(;;) {
- if((c = getc(file)) == EOF || c == term)
- break;
- else if(c == '\\')
- c = fescape(file);
- *p++ = c;
- if(p == &token[troom]) {
- token = realloc(token, troom * 2);
- if(token == NULL)
- return NULL;
- p = &token[troom];
- troom *= 2;
- }
- }
- break;
-
- default:
- if(isspace(term))
- return NULL;
- while((c = getc(file)) != EOF && !isspace(c)) {
- if(c == '\\')
- c = fescape(file);
- *p = c;
- if(++p == &token[troom]) {
- token = realloc(token, troom * 2);
- if(token == NULL)
- return NULL;
- p = &token[troom];
- troom *= 2;
- }
- for(q = delims; *q && c != *q; q++)
- ;
- if(*q) {
- if(p > token+1) {
- p--;
- ungetc(c, file);
- }
- break;
- }
- }
- break;
- }
- *p = '\0';
- return token;
- }
-
-
- /*
- * Load one or more Transforms from a file.
- * Return 1 on success, 0 on failure.
- */
- int
- fgettransform(FILE *file, int ntrans, float *trans /* float trans[ntrans][4][4] */, int binary)
- {
- register float *T;
- int nt;
-
- for(nt = 0; nt < ntrans; nt++) {
- T = trans + 16*nt;
- switch(fgetnf(file, 16, T, binary)) {
- case 16:
- break;
-
- case 0:
- return nt;
-
- default:
- return -1;
- }
- }
- return ntrans;
- }
-
- int
- fputnf(FILE *file, int count, float *v, int binary)
- {
- register int i;
- long w;
- if(binary) {
- #if m68k || mc68000 || mips || sparc
- return fwrite(v, sizeof(float), count, file);
- #else
- for(i = 0; i < count; i++) {
- w = htonl(*(long *)&v[i]);
- fwrite(&w, sizeof(float), 1, file);
- }
- return count;
- #endif
- }
-
- fprintf(file, "%g", v[0]);
- for(i = 1; i < count; i++)
- fprintf(file, " %g", v[i]);
- return count;
- }
-
- int
- fputtransform(FILE *file, int ntrans, float *trans, int binary)
- {
- register int i, n;
- register float *p;
-
- if(binary) {
- #if m68k || mc68000 || mips || sparc
- return fwrite(trans, 4*4*sizeof(float), ntrans, file);
- #else
- OOGLError(1, "fputtransform: need code to handle binary writes for this architecture.");
- return 0;
- #endif
- }
-
- /* ASCII. */
-
- for(n = 0; n < ntrans; n++) {
- p = trans + n*16;
- for(i = 0; i < 4; i++, p += 4) {
- fprintf(file, " %12.8g %12.8g %12.8g %12.8g\n",
- p[0], p[1], p[2], p[3]);
- }
- if(ferror(file))
- return n;
- fprintf(file, "\n");
- }
- return ntrans;
- }
-
- /*
- * Given a file pointer, return a string attempting to show the context
- * of its current position. If no data is available, returns the empty string.
- */
- char *
- fcontext(register FILE *f)
- {
- static char *cont = NULL;
- static char dflt[] = "";
- char buf[1024];
- int npre, npost, nlpre, nlpost, tab, len;
- int predots = 4, postdots = 4;
- register char *p, *q;
- char *lastline, *lastnonblank;
-
- if(f == NULL)
- return dflt;
- if(feof(f))
- return "> END OF FILE\n";
- if(f->_cnt <= 0 || f->_base == NULL || f->_ptr == NULL)
- return dflt;
-
- p = (char *)f->_ptr;
- for(npre = nlpre = 0; --p >= (char *)f->_base && npre < 128; npre++) {
- if(*p == '\n') {
- if(++nlpre > 2 || npre > 60) {
- predots = 0;
- break;
- }
- } else if(*p & 0x80 || *p == 0) /* binary data? */
- break;
- }
- strcpy(buf, "> ... ");
- q = buf + 2 + predots;
- tab = 2 + predots;
- for(p = (char *)f->_ptr - npre; p < (char *)f->_ptr; ) {
- switch(*q++ = *p++) {
- case '\n': case '\r': *q++ = '>'; *q++ = ' '; tab = 2; break;
- case '\t': tab += 8-(tab&7); break;
- default: tab++;
- }
- }
- len = npre;
- npost = nlpost = 0;
- lastline = lastnonblank = q;
- for(p = (char *)f->_ptr; p < (char *)f->_ptr + f->_cnt && len < 128; len++, q++) {
- *q = *p++;
- if(*q == '\n') {
- if(nlpost == 0) {
- while(--tab > 0) *++q = '-'; /* Point ---^ to error */
- *++q = '^'; *++q = '\n';
- }
- if((++nlpost >= 2 || len > 80) && len > 32) {
- postdots = 0;
- break;
- }
- lastline = q;
- *++q = '>'; *++q = ' ';
- } else if(*q & 0x80 || *q == 0) /* Binary data */
- break;
- else if(isprint(*q))
- lastnonblank = q;
- }
- if(postdots && lastnonblank < lastline) {
- q = lastline; /* Suppress trailing white space */
- postdots = 0; /* to avoid final ``> ...'' */
- }
- strcpy(q, " ...\n" + 4-postdots);
- if(nlpost == 0) {
- q += strlen(q);
- while(--tab > 0) *q++ = '-';
- strcpy(q, "^\n");
- }
- if(cont) free(cont);
- return (cont = strdup(buf));
- }
-
-
- /*
- * This one is stdio dependent, but will probably work on a fair variety of
- * implementations.
- */
- FILE *
- fstropen(char *str, int len, char *mode)
- {
- FILE *f;
-
- f = fopen("/dev/null", mode); /* How else do I get a FILE *? */
- if(f == NULL)
- return NULL;
- setbuf(f, NULL);
- close(fileno(f));
-
- f->_file = -1;
- f->_cnt = len;
- f->_ptr = f->_base =
- (unsigned char *)
- #if defined(sgi) || defined(sun4) /* SGI/MIPS Nazi C compiler! */
- (unsigned char *)
- #endif
- str;
- f->_flag &= ~(_IONBF|_IOMYBUF|_IOEOF|_IOERR);
- return f;
- }
-
- struct stdio_mark {
- FILE *f;
- long fpos;
- FILE fcopy;
- char fchars[8];
- };
-
- struct stdio_mark *
- stdio_setmark(register struct stdio_mark *mark, register FILE *stream)
- {
- if(mark == NULL)
- mark = OOGLNewE(struct stdio_mark, "stdio_setmark mark");
- mark->f = stream;
- mark->fpos = isatty(fileno(stream)) ? -1 : ftell(stream);
- mark->fcopy = *stream;
- memcpy(mark->fchars, mark->f->_base, sizeof(mark->fchars));
- return mark;
- }
-
- int
- stdio_seekmark(register struct stdio_mark *mark)
- {
- if(mark->fpos == -1 || fseek(mark->f, mark->fpos, 0) == -1) {
- /* Maybe it'mark a pipe or socket, so seeks fail.
- * Try repositioning inside the stdio buffer.
- * This is a stdio-dependent kludge, but might work.
- */
- if(mark->f->_base == mark->fcopy._base &&
- memcmp(mark->fchars, mark->f->_base, sizeof(mark->fchars)) == 0) {
- /* Buffer looks unchanged. Reset pointers. */
- *(mark->f) = mark->fcopy;
- } else {
- return 0; /* Failed */
- }
- }
- return 1; /* Succeeded */
- }
-
- int
- async_getc(register FILE *f)
- {
- fd_set fds;
- static struct timeval notime = { 0, 0 };
- if(f->_cnt > 0)
- return getc(f);
- FD_ZERO(&fds);
- FD_SET(fileno(f), &fds);
- if(select(fileno(f)+1, &fds, NULL, NULL, ¬ime) == 1)
- return fgetc(f);
- return NODATA;
- }
-
- int
- async_fnextc(register FILE *f, register int flags)
- {
- register int c;
-
- c = async_getc(f);
- for(;;) {
- switch(c) {
- case EOF:
- case NODATA:
- return(c);
-
- case ' ':
- case '\t':
- break; /* Always skip blanks and tabs */
-
- case '#':
- if(flags & 2) /* 2: stop on comments, else skip */
- goto fim;
-
- while((c = getc(f)) != '\n' && c != EOF)
- ;
- continue; /* Rescan this c */
-
- case '\n':
- if(!(flags & 1)) /* 1: stop on \n's, else skip them */
- break;
- /* flags&1 => fall into default */
-
- default:
- fim:
- ungetc(c, f);
- return(c);
- }
-
- c = async_getc(f);
- }
- }
-