/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #include #include #define MAXPARMS 22 #define MAXP 120 #define MIN(a, b) (a MAXLEN) static Object format_object(Object *o, char *format); static Object format_field(Object *o, char *format); static String format_one(Object *in, char *format); static int tohex(char c); Error m_Format(Object *in, Object *out) { char *cp; out[0] = NULL; if (!in[0]) { DXSetError(ERROR_BAD_PARAMETER, "#10000", "template string"); return ERROR; } if (!DXExtractString(in[0], &cp)) { DXSetError(ERROR_BAD_PARAMETER, "#10200", "template"); return ERROR; } /* if all inputs are arrays or strings, just do a single format. * else, copy the inputs and recurse. (needs code here) out[0] = format_object(in+1, cp); */ out[0] = (Object)format_one(in+1, cp); return (out[0] ? OK : ERROR); } /* static Error sigh. */ static Object format_object(Object *o, char *format) { Object newo, subo; char *name; Matrix m; float position; Object subo2; int fixed, z; int i; if (o[0] == NULL) return (Object)format_one(o, format); switch (DXGetObjectClass(o[0])) { case CLASS_GROUP: /* for each member */ for (i=0; subo = DXGetEnumeratedMember((Group)*o, i, NULL); i++) { if (!format_object(&subo, format)) continue; } break; case CLASS_FIELD: /* even empty fields have to be copied */ if (DXEmptyField((Field)*o)) return DXCopy(*o, COPY_STRUCTURE); if (!(newo = DXCopy(*o, COPY_STRUCTURE))) return NULL; if (!(*o = (Object)format_field(&newo, format))) { DXDelete(newo); return NULL; } break; case CLASS_STRING: case CLASS_ARRAY: return (Object)format_one(o, format); case CLASS_XFORM: if (!DXGetXformInfo((Xform)*o, &subo, &m)) return NULL; if (!(newo=format_object(&subo, format))) return NULL; *o = (Object)DXNewXform(newo, m); break; case CLASS_SCREEN: if (!DXGetScreenInfo((Screen)*o, &subo, &fixed, &z)) return NULL; if (!(newo=format_object(&subo, format))) return NULL; *o = (Object)DXNewScreen(newo, fixed, z); break; case CLASS_CLIPPED: if (!DXGetClippedInfo((Clipped)*o, &subo, &subo2)) return NULL; if (!(newo=format_object(&subo, format))) return NULL; *o = (Object)DXNewClipped(newo, subo2); break; default: /* any remaining objects can't contain fields, so we can safely * pass them through unchanged. */ break; } return *o; } static Object format_field(Object *in, char *cp) { /* get the data component and alloc space for a list of str ptrs. */ /* for each entry, call format_one and collect the strings. */ /* call makestringlist and make that the new data component */ return (Object)format_one(in, cp); } static String format_one(Object *in, char *cp) { int input; int nitems; int i, *ip, num; float f, *fp; Vector v, *vp; double d; char buffer[BUFFERSIZE]; char *bp; char *s; char format[256]; Type type; void *p; input = 0; bp = buffer; while (*cp && !atEnd()) { switch (*cp) { case '%': cp++; /* * check for %% - formats as a single percent sign. */ if (*cp == '%') { *bp++ = *cp++; break; } /* * copy format control information (eg. "%3.2f", copy "%3.2") */ i = 0; format[i++] = '%'; if (*cp == '-') format[i++] = *cp++; while (isdigit(*cp)) format[i++] = *cp++; if (*cp == '.') { /* meta-data stuff should go here too */ format[i++] = *cp++; while (isdigit(*cp)) format[i++] = *cp++; } /* * process specific formatting command */ switch (*cp) { /* * string (%s) */ case 's': format[i++] = 's'; format[i] = '\0'; if (!DXExtractNthString(in[input], 0, &s)) { DXSetError(ERROR_BAD_PARAMETER, "#10000", "string"); return ERROR; } for (i = 0; DXExtractNthString(in[input], i, &s); i++) { if (i > 0) { *bp++ = ' '; } sprintf(bp, format, s); while (*bp) bp++; if (atEnd()) break; } input++; cp++; break; /* * character (%c) */ case 'c': format[i++] = 'c'; format[i] = '\0'; if (DXExtractNthString(in[input], 0, &s)) { for (i = 0; DXExtractNthString(in[input], i, &s); i++) { if (i > 0) { *bp++ = ' '; } sprintf(bp, format, s[0]); while (*bp) bp++; if (atEnd()) break; } } else if (DXExtractInteger(in[input], &i)) { sprintf(bp, format, i); while (*bp) bp++; if (atEnd()) break; } else if (DXQueryParameter(in[input], TYPE_INT, 1, &nitems)) { int *ip; ip = (int *)DXAllocateLocal(sizeof(int) * nitems); if (ip == NULL) return ERROR; if (!DXExtractParameter(in[input], TYPE_INT, 1, nitems, (Pointer)ip)) { DXFree((Pointer)ip); DXErrorReturn(ERROR_INTERNAL, "couldn't extract integer list"); } *bp++ = '{'; *bp++ = ' '; for(i = 0; i < nitems * 1; i++) { sprintf(bp, format, ip[i]); while (*bp) bp++; *bp++ = ' '; if (atEnd()) break; } *bp++ = '}'; DXFree((Pointer)ip); } else { DXSetError(ERROR_BAD_PARAMETER, "#10000", "character"); return ERROR; } input++; cp++; break; /* * integer (%d) */ case 'd': format[i++] = 'd'; format[i] = '\0'; if (DXExtractInteger(in[input], &i)) { sprintf(bp, format, i); while (*bp) bp++; if (atEnd()) break; } else if (DXQueryParameter(in[input], TYPE_INT, 1, &nitems)) { int *ip; ip = (int *)DXAllocateLocal(sizeof(int) * nitems); if (ip == NULL) return ERROR; if (!DXExtractParameter(in[input], TYPE_INT, 1, nitems, (Pointer)ip)) { DXFree((Pointer)ip); DXErrorReturn(ERROR_INTERNAL, "couldn't extract integer list"); } *bp++ = '{'; *bp++ = ' '; for(i = 0; i < nitems * 1; i++) { sprintf(bp, format, ip[i]); while (*bp) bp++; *bp++ = ' '; if (atEnd()) break; } *bp++ = '}'; DXFree((Pointer)ip); } else { DXSetError(ERROR_BAD_PARAMETER, "#10000", "integer"); return ERROR; } input++; cp++; break; /* * float or double (%f, %e or %g) */ case 'e': case 'f': case 'g': format[i++] = *cp; format[i] = '\0'; if (DXExtractFloat(in[input], &f)) { sprintf(bp, format, f); while (*bp) bp++; if (atEnd()) break; } else if (DXExtractParameter(in[input],TYPE_DOUBLE,0,1,&d)) { sprintf(bp,format,d); while (*bp) bp++; if (atEnd()) break; } else if (DXQueryParameter(in[input], TYPE_DOUBLE, 1, &nitems)) { if (DXQueryParameter(in[input], TYPE_FLOAT, 1, &nitems)) { type=TYPE_FLOAT; p = DXAllocateLocal(sizeof(float) * nitems); } else { type = TYPE_DOUBLE; p = DXAllocateLocal(sizeof(double) * nitems); } if (p == NULL) return ERROR; if (!DXExtractParameter(in[input], type, 1, nitems, (Pointer)p)) { DXFree((Pointer)p); DXErrorReturn(ERROR_INTERNAL, "couldn't extract float list"); } *bp++ = '{'; *bp++ = ' '; for(i=0; i 1) { *bp++ = '{'; *bp++ = ' '; } for(i = 0; i < nitems; i++) { *bp++ = '['; if (type == TYPE_FLOAT) sprintf(bp, format, ((float *)p)[i*2]); else sprintf(bp, format, ((double *)p)[i*2]); while (*bp) bp++; *bp++ = ','; *bp++ = ' '; if (type == TYPE_FLOAT) sprintf(bp, format, ((float *)p)[i*2 + 1]); else sprintf(bp, format, ((double *)p)[i*2 + 1]); while (*bp) bp++; *bp++ = ']'; if (nitems > 1) *bp++ = ' '; if (atEnd()) break; } if (nitems > 1) *bp++ = '}'; DXFree((Pointer)p); } else if (DXQueryParameter(in[input], TYPE_FLOAT, 3, &nitems)) { if (DXQueryParameter(in[input], TYPE_FLOAT, 3, &nitems)) { type = TYPE_FLOAT; p = DXAllocateLocal(sizeof(float) * 3 * nitems); } else { type = TYPE_DOUBLE; p = DXAllocateLocal(sizeof(double) * 3 * nitems); } if (p == NULL) return ERROR; if (!DXExtractParameter(in[input], type, 3, nitems, (Pointer)p)) { DXFree((Pointer)p); DXErrorReturn(ERROR_INTERNAL, "couldn't extract vector list"); } if (nitems > 1) { *bp++ = '{'; *bp++ = ' '; } for(i = 0; i < nitems; i++) { *bp++ = '['; if (type == TYPE_FLOAT) sprintf(bp, format, ((float *)p)[i*3]); else sprintf(bp, format, ((double *)p)[i*3]); while (*bp) bp++; *bp++ = ','; *bp++ = ' '; if (type == TYPE_FLOAT) sprintf(bp, format, ((float *)p)[i*3 + 1]); else sprintf(bp, format, ((double *)p)[i*3 + 1]); while (*bp) bp++; *bp++ = ','; *bp++ = ' '; if (type == TYPE_FLOAT) sprintf(bp, format, ((float *)p)[i*3 + 2]); else sprintf(bp, format, ((double *)p)[i*3 + 2]); while (*bp) bp++; *bp++ = ']'; if (nitems > 1) *bp++ = ' '; if (atEnd()) break; } if (nitems > 1) *bp++ = '}'; DXFree((Pointer)p); } else { DXSetError(ERROR_BAD_PARAMETER, "#10000", "floating point number"); return ERROR; } input++; cp++; break; /* * any other character following a % is copied through unchanged, * and doesn't update the arg count. */ default: *bp++ = *cp++; break; } if (input >= MAXPARMS) { DXSetError(ERROR_BAD_PARAMETER, "too many substitution characters"); return ERROR; } break; case '\\': cp++; /* * check for \\ - formats as a real backslash */ if (*cp == '\\') { *bp++ = *cp++; break; } /* * other things which can follow a backslash... */ switch (*cp) { /* the standard escapes */ case 'a': *bp++ = '\a'; cp++; break; case 'b': *bp++ = '\b'; cp++; break; case 'f': *bp++ = '\f'; cp++; break; case 'n': *bp++ = '\n'; cp++; break; case 'r': *bp++ = '\r'; cp++; break; case 't': *bp++ = '\t'; cp++; break; case 'v': *bp++ = '\v'; cp++; break; case '\\': *bp++ = '\\'; cp++; break; case '"': *bp++ = '"'; cp++; break; case '\'': *bp++ = '\''; cp++; break; case '?': *bp++ = '?'; cp++; break; /* hex codes - 0, 1 or 2 digits */ case 'x': cp++; if (!isxdigit(*cp)) { *bp++ = 'x'; break; } num = tohex(*cp++); if (isxdigit(*cp)) { num <<= 4; num += tohex(*cp++); } *bp++ = (char)num; break; /* octal codes - 1, 2 or 3 digits */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': num = (uint)(*cp++) - (uint)'0'; for (i=0; i<2; i++) { char tc = *cp; if (isdigit(tc) && tc != '8' && tc != '9') { num <<= 3; num += (uint)(*cp++) - (uint)'0'; } } *bp++ = (char)num; break; /* end of file */ case (char)EOF: *bp++ = '\0'; break; /* escaped end of line */ case '\n': cp++; break; /* any other char */ default: *bp++ = *cp++; break; } break; /* * any character in the string which isn't preceeded by % gets * copied here unchanged. */ default: *bp++ = *cp++; break; } } if (atEnd()) { DXSetError(ERROR_BAD_PARAMETER, "formatted output exceeds maximum format buffer length"); return ERROR; } *bp = '\0'; return (String)DXNewString(buffer); } /* check 'c' before calling this with isxdigit() because this does no * error checking. */ static int tohex(char c) { /* A-F */ if (isupper(c)) return 10 + (uint)(c) - (uint)'A'; /* a-f */ if (islower(c)) return 10 + (uint)(c) - (uint)'a'; /* 0-9 */ return (uint)(c) - (uint)'0'; }