/*****************************************************************************/ /*** ***/ /*** Copyright (c) 1990, Visual Edge Software Ltd. ***/ /*** ***/ /*** All rights reserved. This notice is intended as a precaution ***/ /*** against inadvertent publication, and shall not be deemed to con- ***/ /*** stitute an acknowledgment that publication has occurred nor to ***/ /*** imply any waiver of confidentiality. The year included in the ***/ /*** notice is the year of the creation of the work. ***/ /*** ***/ /*****************************************************************************/ /*************************************************************************** NAME: uxpm.c DESCRIPTION: Create Pixmaps from xpm format files, either by reading the file, or by including it and compiling it in. EXT REFERENCES: UxPixmapColorWidget, UxDisplay EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ #include #include #include #include #include #ifdef vms #include #else #include #endif #ifdef vms #include #else #include #endif #ifdef vms #include #else #include #endif #ifdef vms #include #else #include #endif #include #include #include #include #ifndef RUNTIME #include #include #include #endif /* ! RUNTIME */ #ifdef RUNTIME #include #endif /* RUNTIME */ #include #include #include #define CGETS(ms) UXCATGETS(MC_UXPM,MS_UXPM_,ms) #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* Various macros that extend the available operations on dstrings */ #define dclear(dstr) (dgetstr(dstr)[0] = '\0') #define dsize(dstr) ((dstr).size) #define dstrcpy(a, b) (dclear(a), dconcat(a, b)) #define dstrcmp(a, b) strcmp(dgetstr(a), dgetstr(b)) #define dstrdup(a) (strcpy(UxMalloc((dlen(a)+1)*sizeof (char)), dgetstr(a))) static char dummy[2] = " "; #define dappend_char(c, dstr) \ do { \ int length = dlen(dstr); \ if (length+2 <= dsize(dstr)) { \ dgetstr(dstr)[length++] = (c); \ dgetstr(dstr)[length] = '\0'; \ } \ else { \ dummy[0] = (c); \ dappend((dstr), &dummy[0]); \ } \ } while (0) /* The dstream is an abstract type that is a file with pushback */ typedef struct { FILE *stream; dstring pushbuf; } dstream; #define dstream_buf_is_empty(d) (dgetstr(d->pushbuf)[0]=='\0') #define dstream_unget_char(c, dst) dstream_push(c, dst) /* lexical_context is an abstract type that contains various info for lex() */ typedef struct { dstream dstr; dstring text; int lineno; int newlineflag; } lexical_context; /* pixmap_info is an abstract type that is the internal form of a pixmap file */ typedef struct { dstring name; dstring compare; int format; int width; int height; int ncolors; int chars_per_pixel; char **colors; char **pixels; } pixmap_info; #define MY_XPM_FORMAT 1 /* an xpm_entry records the association between extension names and indices */ /* the indices are unique integers to identify the fields of the pixmap_info */ typedef struct { char *extension; int index; } xpm_entry; #define XPM_UNKNOWN 0 #define XPM_FORMAT 1 #define XPM_WIDTH 2 #define XPM_HEIGHT 3 #define XPM_NCOLORS 4 #define XPM_CHARS_PER_PIXEL 5 #define XPM_COLORS 6 #define XPM_PIXELS 7 static xpm_entry xpm_table[] = { { "", XPM_UNKNOWN }, { "format", XPM_FORMAT }, { "width", XPM_WIDTH }, { "height", XPM_HEIGHT }, { "ncolors", XPM_NCOLORS }, { "chars_per_pixel", XPM_CHARS_PER_PIXEL }, { "colors", XPM_COLORS }, { "pixels", XPM_PIXELS }, { "paxformat", XPM_FORMAT }, { NULL, 0 } }; #define XPM_NINDICES (sizeof (xpm_table) / sizeof (xpm_entry) - 1) /* lex() token values */ #define TOK_ENDMARKER 0 #define TOK_LITERAL_SUP 256 /* not a real token */ #define TOK_NUMBER (TOK_LITERAL_SUP + 1) #define TOK_IDENT (TOK_LITERAL_SUP + 2) #define TOK_PREPROCHASH (TOK_LITERAL_SUP + 3) #define TOK_DEFINE (TOK_LITERAL_SUP + 4) #define TOK_STATIC (TOK_LITERAL_SUP + 5) #define TOK_CHAR (TOK_LITERAL_SUP + 6) #define TOK_STRING (TOK_LITERAL_SUP + 7) #define is_literal_token(t) ((t) < TOK_LITERAL_SUP && (t) > 0) /* a buffer to increase the efficiency of XDrawing points */ typedef struct { Display *display; Drawable d; GC gc; int ncolors; /* number of different colors to buffer */ int maxpoints; /* max number of points to buffer in each color */ int *pixels; /* pixel values for each color index */ int *npoints; /* current number of points in each color buffer */ XPoint **xpoints; /* pointer to pointers to color buffers of XPoints */ } point_buffer; #define MAX_POINTS_TO_BUFFER 256 /* strbuf's are used (as auto variables) to sprintf error messages into */ #define STRBUF_MAX 512 typedef char strbuf[STRBUF_MAX + 1]; #define strbuf_addr(a) (&(a)[0]) #define strbuf_max(a) (STRBUF_MAX) /* assume ints never print more characters than this: */ #define INT_MAX_CHARS 20 /*************************************************************************** NAME: get_xpm_index(s) INPUT: char *s : extension name, i.e. "chars_per_pixel" OUTPUT: --- RETURN: int : the index of the corresponding field in the pixmap_info structure DESCRIPTION: Looks up the string s in the xpm_table and returns the corresponding index. It will return the first match it finds (i.e. with the lowest subscript in the table), and returns XPM_UNKNOWN if no match is found. EXT REFERENCES: xpm_table EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int get_xpm_index(s) char *s; { xpm_entry *x; x = &xpm_table[0]; while (x->extension != NULL) { if (strcmp(s, x->extension)) return (x->index); x++; } return (XPM_UNKNOWN); } /*************************************************************************** NAME: get_xpm_name(index) INPUT: int index : an index returned from get_xpm_index() OUTPUT: --- RETURN: char * : the string name of the corresponding field in the pixmap_info structure DESCRIPTION: Looks up the index in the xpm_table and returns the string corresponding to the first matching index (more or less an inverse to get_xpm_index()) EXT REFERENCES: xpm_table EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static char *get_xpm_name(index) int index; { xpm_entry *x; x = &xpm_table[0]; while (x->extension != NULL) { if (x->index == index) return (x->extension); x++; } return (NULL); } /*************************************************************************** NAME: send_error(s) INPUT: char *s; - The error message OUTPUT: --- RETURN: int - always FALSE DESCRIPTION: This is the error sink for the whole module. If the code is being used in OLE or UIMX, then it probably just calls UxMsgWindow(). EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 27/90 ---------------------------------------------------------------------------*/ static int send_error(s) char *s; { #ifndef RUNTIME UxMsgWindow(s); #else fprintf(stderr, "%s\n", s); #endif return FALSE; } /*************************************************************************** NAME: split_name(name, name_part, indexptr) INPUT: dstring *name; OUTPUT: dstring *name_part; int *indexptr; RETURN: int : TRUE if a matching extension name is found FALSE otherwise DESCRIPTION: The xpm_table is searched for the longest name extension that matches the end of the given name. There must be an underscore in the name before the extension for a match to occur, i.e. ("fred_format" will match "format", but "fredformat" won't. If no match is found, FALSE is returned, and the contents of *indexptr and *name_part are undefined. If a match is found, TRUE is returned, *name_part is set to the name stripped of the matching extension (including the underscore), and *indexptr is set to the index of the matching extension, as defined by the xpm_table. If the name_part or indexptr information is not required, a NULL pointer may be passed in. Currently, name and name_part should refer to different dstrings. EXT REFERENCES: xpm_table EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int split_name(name, name_part, indexptr) dstring *name; dstring *name_part; int *indexptr; { #define NO_MATCH 0 #define PART_MATCH 1 #define FULL_MATCH 2 static int entry_length[XPM_NINDICES]; static int ready = FALSE; int match_flag[XPM_NINDICES]; int match_loc, match; int match_length; int length; char *nptr; char *nameptr; int i, j; if (!ready) { for (i=XPM_NINDICES; --i>=0; ) entry_length[i] = strlen(xpm_table[i].extension); ready = TRUE; } length = dlen(*name); for (i=XPM_NINDICES; --i>=0; ) { if (entry_length[i] >= 0 && entry_length[i] < length) { if (entry_length[i] > 0) match_flag[i] = PART_MATCH; else match_flag[i] = FULL_MATCH; } else match_flag[i] = NO_MATCH; } nameptr = dgetstr(*name); nptr = nameptr + length; i = 1; while (i <= length) { --nptr; match = FALSE; for (j=XPM_NINDICES; --j>=0; ) if (match_flag[j] == PART_MATCH) { match = TRUE; if (*nptr == xpm_table[j].extension[entry_length[j] - i]) { if (i >= entry_length[j]) match_flag[j] = FULL_MATCH; } else match_flag[j] = NO_MATCH; } if (!match) break; i++; } match_loc = -1; match_length = -1; for (i=XPM_NINDICES; --i>=0; ) if (match_flag[i]==FULL_MATCH && entry_length[i]>match_length) { match_loc = i; match_length = entry_length[i]; } nptr = &nameptr[length - match_length - 1]; if (match_loc>=0 && *nptr=='_') { if (indexptr != NULL) *indexptr = xpm_table[match_loc].index; dclear(*name_part); *nptr = '\0'; dconcat(*name_part, *name); *nptr = '_'; return (TRUE); } else return (FALSE); } /*************************************************************************** NAME: pixmap_info_create() INPUT: --- OUTPUT: --- RETURN: pixmap_info : a new pixmap_info structure DESCRIPTION: A new pixmap_info structure is returned by value. If this structure is assigned to a local variable, it should be destroyed by a call to pixmap_info_destroy() before it goes out of scope. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static pixmap_info pixmap_info_create() { pixmap_info p; p.name = dcreate(""); p.compare = dcreate(""); p.format = -1; p.width = -1; p.height = -1; p.ncolors = -1; p.chars_per_pixel = -1; p.colors = NULL; p.pixels = NULL; return (p); } /*************************************************************************** NAME: pixmap_info_complete(p, errflag) INPUT: pixmap_info *p; int errflag; OUTPUT: --- RETURN: int : TRUE if the pixmap_info is complete, FALSE otherwise. DESCRIPTION: Each relevant field of *p is checked to make sure that it has been set since it was initialized. pixmap_info fields can only be set to non-negative integers (for integer fields) or non-NULL addresses (for pointer fields), whereas they are initialized to -1 and NULL respectively. If errflag is nonzero, and there is an uninitialized field, an error message will be sent. The function does not examine any more fields once it has found one that is uninitialized. This function does not check whether the values make sense (e.g. a height of 0 causes no error), only whether they have been set. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int pixmap_info_complete(p, errflag) pixmap_info *p; int errflag; { return ( (p->format >= 0 || (errflag && send_error(CGETS(FORMAT)))) && (p->width >= 0 || (errflag && send_error(CGETS(WIDTH)))) && (p->height >= 0 || (errflag && send_error(CGETS(HEIGHT)))) && (p->ncolors >= 0 || (errflag && send_error(CGETS(NCOLORS)))) && (p->chars_per_pixel >= 0 || (errflag && send_error(CGETS(CHARS_PER_PIXEL)))) && (p->colors != NULL || (errflag && send_error(CGETS(COLOR_ARRAY)))) && (p->pixels != NULL || (errflag && send_error(CGETS(PIXEL_ARRAY)))) ); } /*************************************************************************** NAME: pixmap_info_destroy(p) INPUT: pixmap_info *p; OUTPUT: --- RETURN: void DESCRIPTION: Any dynamic storage associated with *p is deallocated. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static void pixmap_info_destroy(p) pixmap_info *p; { int i; dfree(p->name); dfree(p->compare); if (p->colors != NULL) { for (i=p->ncolors * 2; --i>=0; ) if (p->colors[i] != NULL) UxFree(p->colors[i]); UxFree((char *)p->colors); p->colors = NULL; } if (p->pixels != NULL) { for (i=p->height; --i>=0; ) if (p->pixels[i] != NULL) UxFree(p->pixels[i]); UxFree((char *)p->pixels); p->pixels = NULL; } } /*************************************************************************** NAME: pixmap_info_field(p, index) INPUT: pixmap_info *p; int index; OUTPUT: --- RETURN: int * A pointer to the selected field value, or NULL if no such field exists. DESCRIPTION: Given an index to an integer-valued pixmap_info field (obtained from xpm_get_index() or split_name()), this function returns a pointer to the corresponding field in *p. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int *pixmap_info_field(p, index) pixmap_info *p; int index; { int *r; switch (index) { case XPM_FORMAT: r = &p->format; break; case XPM_WIDTH: r = &p->width; break; case XPM_HEIGHT: r = &p->height; break; case XPM_NCOLORS: r = &p->ncolors; break; case XPM_CHARS_PER_PIXEL: r = &p->chars_per_pixel; break; default: r = NULL; break; } return (r); } /*************************************************************************** NAME: set_pixmap_info_field(p, index, value) INPUT: pixmap_info *p; int index; int value; OUTPUT: --- RETURN: int Success status: TRUE or FALSE DESCRIPTION: If index is the index of an integer valued field in the pixmap_info structure, then that field is set equal to the given value in *p, and TRUE is returned. Otherwise, FALSE is returned and *p is unchanged. If the field has previously been set since initialization, then a warning is sent. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int set_pixmap_info_field(p, index, value) pixmap_info *p; int index; int value; { int *vptr; if (value < 0) return (FALSE); vptr = pixmap_info_field(p, index); if (vptr != NULL) { if (*vptr >= 0) { strbuf a; char *format = CGETS(FIELD_REDEF); sprintf(strbuf_addr(a), format, strbuf_max(a) - strlen(format) - 1, get_xpm_name(index)); send_error(strbuf_addr(a)); } *vptr = value; return (TRUE); } else return (FALSE); } /*************************************************************************** NAME: dstream_create(stream) INPUT: FILE *stream; OUTPUT: --- RETURN: dstream the new dstream structure, by value. DESCRIPTION: A new dstream structure is initialized and associated with the given stream. The stream should be opened for reading before it is passed to dstream_create(). Initially, the pushback buffer will be empty. dstream structures should be "destroyed" by calling dstream_destroy() before they go out of scope. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static dstream dstream_create(stream) FILE *stream; { dstream d; d.stream = stream; d.pushbuf = dcreate(""); return (d); } /*************************************************************************** NAME: dstream_destroy(dst) INPUT: dstream *dst; OUTPUT: --- RETURN: void DESCRIPTION: Any dynamic storage associated with *dst is deallocated. Destroying a dstream does NOT close the associated file. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static void dstream_destroy(dst) dstream *dst; { dfree(dst->pushbuf); } /*************************************************************************** NAME: lexical_context_create(stream) INPUT: FILE *stream; OUTPUT: --- RETURN: lexical_context The new lexical context structure, by value. DESCRIPTION: A lexical_context structure is initialized and associated with the given stream. The stream should be opened for reading before calling lexical_context_create(). The line number is set to 1. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static lexical_context lexical_context_create(stream) FILE *stream; { lexical_context l; l.dstr = dstream_create(stream); l.text = dcreate(""); l.lineno = 1; l.newlineflag = TRUE; return (l); } /*************************************************************************** NAME: lexical_context_destroy(l) INPUT: lexical_context *l; OUTPUT: --- RETURN: void DESCRIPTION: Any dynamic storage associated with *l is deallocated. Destroying a lexical_context does NOT close the associated file. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static void lexical_context_destroy(l) lexical_context *l; { dstream_destroy(&l->dstr); dfree(l->text); } /*************************************************************************** NAME: dstream_push(c, dst) INPUT: char c; dstream *dst; OUTPUT: --- RETURN: int DESCRIPTION: Adds the character c to the head of the pushback stack of the dstream *dst. There is no fixed limit on the size of the pushback stack. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static void dstream_push(c, dst) char c; dstream *dst; { dappend_char(c, dst->pushbuf); } /*************************************************************************** NAME: dstream_push_dstring(d_string, d_stream) INPUT: dstring *d_string; dstream *d_stream; OUTPUT: --- RETURN: void DESCRIPTION: Pushes the entire string of the dstring *d_string onto the pushback stack of *d_stream. It's not very efficient. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static void dstream_push_dstring(d_string, d_stream) dstring *d_string; dstream *d_stream; { int len; char *s; len = dlen(*d_string); s = dgetstr(*d_string) + len; while (--len >= 0) dstream_push(*--s, d_stream); } /*************************************************************************** NAME: dstream_pop(dst) INPUT: dstream *dst; OUTPUT: --- RETURN: int the last-pushed character from *dst, or 0 if none. DESCRIPTION: The character at the head of the pushback stack is returned as an integer. If there is no such character, 0 is returned. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int dstream_pop(dst) dstream *dst; { int length; char *cptr; int c; length = dlen(dst->pushbuf); if (length > 0) { cptr = dgetstr(dst->pushbuf); c = cptr[length - 1]; cptr[length - 1] = '\0'; } else c = 0; return (c); } /*************************************************************************** NAME: dstream_next_char(stream, cptr) INPUT: dstream *stream; OUTPUT: char *cptr; RETURN: int more-characters flag: TRUE or FALSE DESCRIPTION: If the pushback stack of *stream is non-empty, then the head character (as returned by dstream_pop()) is returned. Otherwise, a character is gotten from the I/O stream associated with *stream. If this results in an EOF or error condition, FALSE is returned and *cptr is undefined. Otherwise, TRUE is returned, and if cptr is not NULL, *cptr is set to the character that was popped or read. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int dstream_next_char(stream, cptr) dstream *stream; char *cptr; { int c; int status; status = TRUE; if (dstream_buf_is_empty(stream)) { c = (int)getc(stream->stream); if (feof(stream->stream) || ferror(stream->stream)) status = FALSE; } else if (!(c = dstream_pop(stream))) status = FALSE; if (status == TRUE && cptr != NULL) *cptr = (char)c; return (status); } /*************************************************************************** NAME: dstream_scan_word(stream, s, text) INPUT: dstream *stream; char *s; OUTPUT: dstring *text; RETURN: int match status: TRUE or FALSE DESCRIPTION: The given dstream is read in an attempt to match the word given by s. s may consist of any characters except '\0'. The word must match completely up to the given length, and not be followed in the stream by a "continuation character", which is an alphanumeric or an underscore. This is slightly inconsistent, because there is no requirement that s consist of any such characters. On return, the dstring *text holds the matched characters, or is empty if the match failed. If the word is not matched, then all characters read are pushed back onto the input. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int dstream_scan_word(stream, s, text) dstream *stream; char *s; dstring *text; { char c; int status; dclear(*text); while (*s != '\0' && (status = dstream_next_char(stream, &c))) { if (c == *s++) dappend_char(c, *text); else { dstream_unget_char(c, stream); status = FALSE; break; } } if (status == TRUE) if (dstream_next_char(stream, &c)) { if (isalnum(c) || c=='_') /* continuation of the word */ status = FALSE; dstream_unget_char(c, stream); } if (status == FALSE) { dstream_push_dstring(text, stream); dclear(*text); } return (status); } #if 0 /*************************************************************************** NAME: describe_token(t) INPUT: int t; OUTPUT: --- RETURN: int returns t, unchanged. DESCRIPTION: Prints an english description of the token type to stdout, mainly for debugging purposes. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int describe_token(t) int t; { switch (t) { case TOK_ENDMARKER: printf("endmarker\n"); break; case TOK_NUMBER: printf("number\n"); break; case TOK_IDENT: printf("identifier\n"); break; case TOK_PREPROCHASH: printf("preprocessor #\n"); break; case TOK_DEFINE: printf("define\n"); break; case TOK_STATIC: printf("static\n"); break; case TOK_CHAR: printf("char\n"); break; case TOK_STRING: printf("string\n"); break; default: if (t < TOK_LITERAL_SUP) printf("literal '%c'\n", (char)t); else printf("unknown token # %d\n"); break; } return (t); } #endif /*************************************************************************** NAME: lex(l, newlineistoken) INPUT: lexical_context *l; int newlineistoken; OUTPUT: --- RETURN: int the next token value DESCRIPTION: lex() reads the stream associated with the lexical context *l, and scans the next token. If newlineistoken is FALSE, then newlines will not be reported as tokens; otherwise, they will be returned as tokens. Token values are one of the defined constants above, or a literal character value in the case of single character tokens. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int lex(l, newlineistoken) lexical_context *l; int newlineistoken; { char c; int got_token; int token_value; got_token = FALSE; dclear(l->text); while (!got_token) { if (dstream_scan_word(&l->dstr, "define", &l->text)) { got_token = TRUE; token_value = TOK_DEFINE; } else if (dstream_scan_word(&l->dstr, "static", &l->text)) { got_token = TRUE; token_value = TOK_STATIC; } else if (dstream_scan_word(&l->dstr, "char", &l->text)) { got_token = TRUE; token_value = TOK_CHAR; } if (!got_token) { if (!dstream_next_char(&l->dstr, &c)) break; if (isspace(c)) { if (c=='\n') { if (newlineistoken) { got_token = TRUE; token_value = '\n'; } l->newlineflag = TRUE; l->lineno++; } else l->newlineflag = FALSE; } else if (c=='#' && l->newlineflag) { got_token = TRUE; token_value = TOK_PREPROCHASH; } else if (isalpha(c) || c=='_') { dappend_char(c, l->text); while (dstream_next_char(&l->dstr, &c)) { if (isalnum(c) || c=='_') dappend_char(c, l->text); else { dstream_unget_char(c, &l->dstr); got_token = TRUE; token_value = TOK_IDENT; break; } } } else if (isdigit(c)) { int status; do dappend_char(c, l->text); while ((status=dstream_next_char(&l->dstr, &c)) && isdigit(c)); if (status) { got_token = TRUE; token_value = TOK_NUMBER; dstream_unget_char(c, &l->dstr); } } else if (c=='\"') { int status; dappend_char('\"', l->text); while ((status=dstream_next_char(&l->dstr, &c)) && c!='\"') dappend_char(c, l->text); if (status) { /* a complete string constant */ strcpy(dgetstr(l->text), dgetstr(l->text) + 1); got_token = TRUE; token_value = TOK_STRING; } else { /* end of input before matching " */ dstream_push_dstring(&l->text, &l->dstr); dclear(l->text); assert(dstream_next_char(&l->dstr, &c) && c=='\"'); dappend_char('\"', l->text); got_token = TRUE; token_value = '\"'; } } else { dappend_char(c, l->text); got_token = TRUE; token_value = c; } } } if (got_token) { l->newlineflag = (token_value == '\n'); return (token_value); } else return (TOK_ENDMARKER); } /*************************************************************************** NAME: parse_error(l, s) INPUT: lexical_context *l; char *s; OUTPUT: --- RETURN: int always returns FALSE DESCRIPTION: Used to signal a parser error. *l is the lexical_context which is being parsed, while s references a message string that should indicate the problem. An appropriate message is sent. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_error(l, s) lexical_context *l; char *s; { strbuf a; sprintf(strbuf_addr(a), s, dnstr(l->text), l->lineno); send_error(strbuf_addr(a)); return (FALSE); } /*************************************************************************** NAME: assert_token(l, t, flag) INPUT: lexical_context *l; int t; int flag; OUTPUT: --- RETURN: int TRUE if token matches, else FALSE DESCRIPTION: assert_token() should be called when there is only one legal token that can occur next on the input. The expected token value is passed in in t, while flag is passed to lex() as the newlineistoken parameter (q.v.). If the next token is equal to t, TRUE is returned; otherwise FALSE is returned, and an appropriate message is sent. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int assert_token(l, t, flag) lexical_context *l; int t; int flag; { if (lex(l, flag) != t) { if (is_literal_token(t) && isprint((char)t)) { strbuf a; sprintf(strbuf_addr(a), CGETS(EXPECT_CHAR), (char)t, dnstr(l->text), l->lineno); send_error(strbuf_addr(a)); } else { (void)parse_error(l, CGETS(SYNTAX_ERROR)); } return (FALSE); } else { return (TRUE); } } /*************************************************************************** NAME: parse_name(l, p, flag, indexptr) INPUT: lexical_context *l; pixmap_info *p; int flag; OUTPUT: int *indexptr; RETURN: int status: TRUE if no error, else FALSE DESCRIPTION: A name of the form _ is expected on the input. If it is found, then the identifier is taken to be the name of the pixmap described by *p. If *p has already got a name, then the new name must match the old one, or an error will occur; otherwise the new name is assigned to *p. If no error occurs, then *indexptr is set to the index of the name extension, as defined by split_name(). flag is passed to lex() as the newlineistoken parameter. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_name(l, p, flag, indexptr) lexical_context *l; pixmap_info *p; int flag; int *indexptr; { int rtrn; int token = lex(l, flag); int index; switch (token) { case TOK_IDENT: if (split_name(&l->text, &p->compare, &index)) { rtrn = TRUE; if (dlen(p->name)==0 && dlen(p->compare)>0) dstrcpy(p->name, p->compare); else if (dstrcmp(p->name, p->compare)!=0) rtrn = parse_error(l, CGETS(NAME_MISMATCH)); } else { rtrn = parse_error(l, CGETS(ILLEG_EXT)); } if (rtrn==TRUE) { if (indexptr != NULL) *indexptr = index; } break; default: rtrn = parse_error(l, CGETS(EXPECT_IDENT)); break; } return (rtrn); } /*************************************************************************** NAME: parse_number(l, flag, vptr) INPUT: lexical_context *l; int flag; OUTPUT: int *vptr; RETURN: int status: TRUE if no error, else FALSE DESCRIPTION: A base 10 integer is expected on the input of *l. If it is found, then TRUE is returned, and if vptr is not NULL, *vptr is set to the value of the integer. Otherwise, FALSE is returned and error messages are sent. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_number(l, flag, vptr) lexical_context *l; int flag; int *vptr; { int rtrn; int token = lex(l, flag); int value; switch (token) { case TOK_NUMBER: value = atoi(dnstr(l->text)); if (vptr!=NULL) *vptr = value; rtrn = TRUE; break; default: rtrn = parse_error(l, CGETS(EXPECT_INT)); break; } return (rtrn); } /*************************************************************************** NAME: parse_define(l, p) INPUT: lexical_context *l; pixmap_info *p; OUTPUT: --- RETURN: int status: TRUE if no error, else FALSE DESCRIPTION: A #define directive (minus the initial # sign) is expected on the input of *l. The name to be defined must be acceptable to parse_name(), and it must be defined to an integer value. If this is so, then the field in *p corresponding to the name extension is set to the integer value on the right hand side of the #define, using set_pixmap_info_field(). EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_define(l, p) lexical_context *l; pixmap_info *p; { int rtrn; int token = lex(l, TRUE); int index, value; switch (token) { case TOK_DEFINE: rtrn = ( parse_name(l, p, TRUE, &index) && parse_number(l, TRUE, &value) ); if (rtrn==TRUE) { if (index==XPM_FORMAT && value!=MY_XPM_FORMAT) rtrn = parse_error(l, CGETS(BAD_FORMAT)); else if (!set_pixmap_info_field(p, index, value)) rtrn = parse_error(l, CGETS(ILLEG_EXT)); } break; default: rtrn = parse_error(l, CGETS(EXPECT_DEFINE)); break; } return (rtrn); } /*************************************************************************** NAME: parse_string(l, sptr) INPUT: lexical_context *l; OUTPUT: char **sptr; RETURN: int status: TRUE if no error, else FALSE DESCRIPTION: A string constant is expected on the input of *l. If it is found, then if sptr is not NULL, the string is copied into dynamically allocated memory, and *sptr is set to the address of the new string. *sptr should be deallocated when it is no longer needed. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_string(l, sptr) lexical_context *l; char **sptr; { int rtrn; int token = lex(l, FALSE); switch (token) { case TOK_STRING: if (sptr != NULL) *sptr = dstrdup(l->text); /* freed later by pixmap_info_destroy */ rtrn = TRUE; break; default: rtrn = parse_error(l, CGETS(EXPECT_STRING)); break; } return (rtrn); } /*************************************************************************** NAME: parse_string_array(l, array, size) INPUT: lexical_context *l; int size; OUTPUT: char ***array; RETURN: int status: TRUE if no error, else FALSE DESCRIPTION: An array of strings, roughly corresponding to a C declaration, is expected on the input of *l. The form of the expected array is: '{' [ , ] ... '}'. There must be size strings in the array. The array parameter must be the legal address of a (char **), and it is set to point to dynamically allocated storage that holds the new array. On return, *array points to an array of size (char *)'s, each of which either points to a dynamically allocated string, or is NULL. It is the responsibility of the calling code to free all storage. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_string_array(l, array, size) lexical_context *l; char ***array; int size; { int rtrn; if (rtrn = assert_token(l, '{', FALSE)) { register int i; register char **aptr; *array = (char **)UxMalloc(size * sizeof (char *)); aptr = *array; for (i=size - 1; i>=0; --i) *aptr++ = (char *)NULL; for (i=0; rtrn==TRUE && incolors >= 0) { if (p->colors == NULL) rtrn = parse_string_array(l, &p->colors, 2 * p->ncolors); else rtrn = parse_error(l, CGETS(COLORS_REDEF)); } else { rtrn = parse_error(l, CGETS(UNKNOWN_NCOLORS)); } return (rtrn); } /*************************************************************************** NAME: parse_pixels(l, p) INPUT: lexical_context *l; pixmap_info *p; OUTPUT: --- RETURN: int status: TRUE if no error, else FALSE DESCRIPTION: A string array representing the pixel information of the pixmap described by *p is expected on the input of *l. If the height of the pixmap has not been previously specified, an error occurs. No sanity checking is done on the contents of the string array. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_pixels(l, p) lexical_context *l; pixmap_info *p; { int rtrn; if (p->height >= 0) { if (p->pixels == NULL) rtrn = parse_string_array(l, &p->pixels, p->height); else rtrn = parse_error(l, CGETS(PIXELS_REDEF)); } else { rtrn = parse_error(l, CGETS(UNKNOWN_HEIGHT)); } return (rtrn); } /*************************************************************************** NAME: parse_decl(l, p) INPUT: lexical_context *l; pixmap_info *p; OUTPUT: --- RETURN: int status: TRUE if no error, else FALSE DESCRIPTION: The end of a string array declaration is expected on the input of *l. This has the form: '*' '[' ']' '='. The name must be a legal name (as defined by parse_name()), and its extension must refer to the colors or pixels part of the pixmap_info structure. If this is so, then a string array is expected, and read into the appropriate field of *p. Finally, the string array must be followed by a semicolon. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_decl(l, p) lexical_context *l; pixmap_info *p; { int rtrn; int token = lex(l, FALSE); int index; switch (token) { case '*': if ((rtrn = parse_name(l, p, FALSE, &index))) { if (index==XPM_COLORS || index==XPM_PIXELS) { if ( assert_token(l, '[', FALSE) && assert_token(l, ']', FALSE) && assert_token(l, '=', FALSE) ) { switch (index) { case XPM_COLORS: rtrn = parse_colors(l, p); break; case XPM_PIXELS: rtrn = parse_pixels(l, p); break; } } else { rtrn = FALSE; } } else { rtrn = parse_error(l, CGETS(ILLEG_EXT)); } if (rtrn==TRUE) rtrn = assert_token(l, ';', FALSE); } break; default: rtrn = parse_error(l, CGETS(SYNTAX_ERROR)); break; } return (rtrn); } /*************************************************************************** NAME: parse_statement_list(l, p) INPUT: lexical_context *l; pixmap_info *p; OUTPUT: --- RETURN: int status: TRUE if no error, else FALSE DESCRIPTION: A sequence of 0 or more statements, followed by the endmarker token, is expected on the input of *l. A statement is a #define directive or a declaration of a string array. The information from the statements is read into *p. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_statement_list(l, p) lexical_context *l; pixmap_info *p; { int rtrn; int token = lex(l, FALSE); rtrn = TRUE; switch (token) { case TOK_ENDMARKER: rtrn = TRUE; break; case TOK_PREPROCHASH: rtrn = parse_define(l, p); break; case TOK_STATIC: rtrn = assert_token(l, TOK_CHAR, FALSE); case TOK_CHAR: if (rtrn==TRUE) rtrn = parse_decl(l, p); break; default: rtrn = parse_error(l, CGETS(SYNTAX_ERROR)); break; } if (token != TOK_ENDMARKER) rtrn = rtrn && parse_statement_list(l, p); return (rtrn); } /*************************************************************************** NAME: parse_pixmap_file(l, p) INPUT: lexical_context *l; pixmap_info *p; OUTPUT: --- RETURN: int DESCRIPTION: A list of statements is read from the input of *l, and the information from them is stored in *p. Any error causes early termination. If the list is successfully read, and the information in *p is complete, then TRUE is returned, otherwise FALSE is returned. Regardless of the return status, it is the responsibility of the calling code to destroy any unwanted information in *p. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int parse_pixmap_file(l, p) lexical_context *l; pixmap_info *p; { if (parse_statement_list(l, p)) { if (pixmap_info_complete(p, TRUE)) return (TRUE); else return (parse_error(l, CGETS(MISSING_DATA))); } return (FALSE); } /*************************************************************************** NAME: point_buffer_create(display, d, maxpoints, colors, ncolors) INPUT: Display *display; - the display of the drawable Drawable d; - the drawable to draw on int maxpoints; - buffer this many points per color XColor *colors; - use these colors int ncolors; - number of colors OUTPUT: --- RETURN: point_buffer * - the new point_buffer, by _reference_ DESCRIPTION: A new point_buffer is created for drawing points on the given drawable. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 25/90 ---------------------------------------------------------------------------*/ static point_buffer *point_buffer_create(display, d, maxpoints, colors, ncolors) Display *display; Drawable d; int maxpoints; XColor *colors; int ncolors; { int i; point_buffer *new; XGCValues gcv; new = (point_buffer *)UxMalloc(sizeof (point_buffer)); new->display = display; new->d = d; new->ncolors = ncolors; new->maxpoints = maxpoints; new->gc = XCreateGC(display, d, 0, &gcv); new->pixels = (int *)UxMalloc(ncolors * sizeof (int)); new->npoints = (int *)UxMalloc(ncolors * sizeof (int)); new->xpoints = (XPoint **)UxMalloc(ncolors * sizeof (XPoint *)); for (i=ncolors; --i>=0; ) { new->pixels[i] = colors[i].pixel; new->npoints[i] = 0; new->xpoints[i] = (XPoint *)UxMalloc(maxpoints * sizeof (XPoint)); } return (new); } /*************************************************************************** NAME: point_buffer_flush_color(b, color) INPUT: point_buffer *b; - the point_buffer to flush int color; - the color buffer number to flush OUTPUT: --- RETURN: int - FALSE if parameters are invalid, else TRUE DESCRIPTION: Draws all points in *b of the given color number, and erases them from the buffer. This would normally be called from point_buffer_flush(). EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 25/90 ---------------------------------------------------------------------------*/ static int point_buffer_flush_color(b, color) point_buffer *b; int color; { if (color<0 || color>=b->ncolors) return (FALSE); XSetForeground(b->display, b->gc, b->pixels[color]); XDrawPoints(b->display, b->d, b->gc, b->xpoints[color], b->npoints[color], CoordModeOrigin); b->npoints[color] = 0; return (TRUE); } /*************************************************************************** NAME: point_buffer_draw(b, x, y, color) INPUT: point_buffer *b; - the point_buffer to draw into int x; - the x co-ordinate of the point int y; - the y co-ordinate of the point int color; - the color buffer number to use OUTPUT: --- RETURN: int - FALSE for invalid parameters, else TRUE DESCRIPTION: Stores a point in *b for later drawing when the buffer containing the point is flushed. The buffer will be flushed when it is full, or by a call to point_buffer_flush() (or point_buffer_flush_color() with the same color number). The color number is not a pixel value, but the index of the desired color in the original array of XColors that was passed to point_buffer_create(). EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 25/90 ---------------------------------------------------------------------------*/ static int point_buffer_draw(b, x, y, color) point_buffer *b; int x; int y; int color; { if (color<0 || color>=b->ncolors) return (FALSE); if (b->npoints[color] >= b->maxpoints) { if (point_buffer_flush_color(b, color) == FALSE) UxInternalError (__FILE__, __LINE__, "Point buffer flush failed\n"); } b->xpoints[color][b->npoints[color]].x = x; b->xpoints[color][b->npoints[color]].y = y; b->npoints[color]++; return (TRUE); } /*************************************************************************** NAME: point_buffer_flush(b) INPUT: point_buffer *b; - the point_buffer to flush OUTPUT: --- RETURN: void DESCRIPTION: Draws all points in the point_buffer *b, and clears them. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 25/90 ---------------------------------------------------------------------------*/ static void point_buffer_flush(b) point_buffer *b; { int i; for (i=b->ncolors; --i>=0; ) { if (point_buffer_flush_color(b, i) == FALSE) UxInternalError (__FILE__, __LINE__, "Point buffer flush failed\n"); } } /*************************************************************************** NAME: point_buffer_destroy(b) INPUT: point_buffer *b; - the point_buffer to destroy OUTPUT: --- RETURN: void DESCRIPTION: Frees all dynamic storage and X resources associated with *b. (It does not free the Drawable). EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 25/90 ---------------------------------------------------------------------------*/ static void point_buffer_destroy(b) point_buffer *b; { int i; point_buffer_flush(b); XFreeGC(b->display, b->gc); UxFree((char *)b->pixels); UxFree((char *)b->npoints); for (i=b->ncolors; --i>=0; ) UxFree((char *)b->xpoints[i]); UxFree((char *)b->xpoints); UxFree((char *)b); } /*************************************************************************** NAME: XCreatePixmapFromData(display, d, colormap, width, height, depth, ncolors, chars_per_pixel, colors, pixels) INPUT: Display *display; Drawable d; Colormap colormap; unsigned int width, height; unsigned int depth; unsigned int ncolors; - number of different colors unsigned int chars_per_pixel; - chars per color id string char *colors[]; - array of color id and X colorname strings char *pixels[]; - array of strings containing color ids OUTPUT: --- RETURN: Pixmap the newly created pixmap, or NULL if failure. DESCRIPTION: A pixmap is created from the given data, which can be obtained either by including a .xpm format file in the program, or reading such a file into a pixmap_info structure, as is the case in XReadPixmapFile(). EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static Pixmap XCreatePixmapFromData(display, d, colormap, width, height, depth, ncolors, chars_per_pixel, colors, pixels) Display *display; Drawable d; Colormap colormap; unsigned int width, height; unsigned int depth; unsigned int ncolors; unsigned int chars_per_pixel; char *colors[]; char *pixels[]; { XColor *xcolors; int alloc_flag; Pixmap pixmap; int status; int y; int i; point_buffer *b; alloc_flag = FALSE; if (ncolors < 1 || width < 1 || height < 1 || depth < 1 || chars_per_pixel < 1) return ((Pixmap)NULL); /* Allocate (read-only) colors from the colormap */ xcolors = (XColor *)UxMalloc(ncolors * sizeof (XColor)); status = TRUE; for (i=ncolors - 1; i>=0; --i) { int index; /* * in the colors[] array, each even numbered entry is a color id string, * and the odd numbered entry that comes after it is the corresponding * color definition string, in an XParse-able form. Therefore, we * set index to be the subscript of the color id of the i'th color * in colors, so index+1 is the corresponding color definition string. */ index = i * 2; if (strlen(colors[index]) == chars_per_pixel) { if (!XParseColor(display, colormap, colors[index+1], &xcolors[i]) || !XAllocColor(display, colormap, &xcolors[i])) { strbuf a; char *format = CGETS(BAD_COLORNAME); sprintf(strbuf_addr(a), format, strbuf_max(a) - strlen(format) - 1, colors[index + 1]); send_error(strbuf_addr(a)); status = FALSE; break; } } else { strbuf a; char *format = CGETS(BAD_COLORSPEC); sprintf(strbuf_addr(a), format, strbuf_max(a) - strlen(format) - 1, colors[index]); send_error(strbuf_addr(a)); status = FALSE; break; } } /* done allocating colors */ if (status) { pixmap = XCreatePixmap(display, d, width, height, depth); b = point_buffer_create(display, pixmap, MAX_POINTS_TO_BUFFER, xcolors, ncolors); alloc_flag = TRUE; } UxFree((char *)xcolors); for (y=height - 1; status && y>=0; --y) { int length; char *cptr; int x; length = strlen(pixels[y]); if (length != chars_per_pixel * width) { strbuf a; char *format = CGETS(BAD_PIXEL_LEN); sprintf(strbuf_addr(a), format, y); send_error(strbuf_addr(a)); status = FALSE; break; } /* use cptr to step through the pixels string and decode colors */ cptr = pixels[y] + length - chars_per_pixel; for (x=width - 1; status && x>=0; cptr -= chars_per_pixel, --x) { register int i; char save = *(cptr + chars_per_pixel); *(cptr + chars_per_pixel) = '\0'; /* do not break out of the for loop until further notice ... */ switch (chars_per_pixel) { case 1: { char c = cptr[0]; for (i=2 * (ncolors - 1); i >= 0; i -= 2) if (c==colors[i][0]) break; } break; case 2: { char c1 = cptr[0]; char c2 = cptr[1]; for (i=2 * (ncolors - 1); i >= 0; i -= 2) if (c1==colors[i][0] && c2==colors[i][1]) break; } break; default: { for (i=2 * (ncolors - 1); i >= 0; i -= 2) if (strcmp(cptr, colors[i])==0) break; } break; } if (i >= 0) { if (point_buffer_draw(b, x, y, i/2) == FALSE) UxInternalError (__FILE__, __LINE__, "Point buffer draw failed\n"); } else { strbuf err; char *format = CGETS(BAD_PIXELSPEC); sprintf(strbuf_addr(err), format, strbuf_max(err) - 2 * INT_MAX_CHARS - strlen(format) -1, cptr, y, x); send_error(strbuf_addr(err)); status = FALSE; } *(cptr + chars_per_pixel) = save; /* it's ok to break now */ } } if (status==TRUE) point_buffer_flush(b); else { if (alloc_flag) XFreePixmap(display, pixmap); pixmap = (Pixmap)NULL; } if (alloc_flag) point_buffer_destroy(b); return (pixmap); } /*************************************************************************** NAME: XReadPixmapFile(display, d, colormap, filename, width, height, depth, pixmap) INPUT: Display *display; Drawable d; Colormap colormap; char *filename; unsigned int depth; OUTPUT: unsigned int *width, *height; Pixmap *pixmap; RETURN: int PixmapSuccess or a related error code (xpm.h). DESCRIPTION: If possible, a pixmap file in .xpm format is parsed from the file named by *filename, using parse_pixmap_file(). If the file is successfully parsed, then a pixmap is created using the new data, by calling XCreatePixmapFromData(). If the pixmap is successfully created, then *width, *height and *pixmap are set to the resultant width, height and pixmap ID, respectively. If such information is not required, any of the above three parameters may be NULL. EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ static int XReadPixmapFile(display, d, colormap, filename, width, height, depth, pixmap) Display *display; Drawable d; Colormap colormap; char *filename; unsigned int *width, *height; unsigned int depth; Pixmap *pixmap; { lexical_context l; pixmap_info p; FILE *stream; Pixmap my_pixmap; int status; stream = fopen(filename, "r"); if (stream==NULL) return (PixmapOpenFailed); l = lexical_context_create(stream); p = pixmap_info_create(); if (parse_pixmap_file(&l, &p)) { /* file successfully parsed */ my_pixmap = XCreatePixmapFromData(display, d, colormap, p.width, p.height, depth, p.ncolors, p.chars_per_pixel, p.colors, p.pixels); if (my_pixmap != (Pixmap)NULL) { if (pixmap != NULL) *pixmap = my_pixmap; if (width != NULL) *width = p.width; if (height != NULL) *height = p.height; status = PixmapSuccess; /* pixmap successfully created ! */ } else { status = PixmapFileInvalid; /* could not create pixmap ! */ } } else status = PixmapFileInvalid; pixmap_info_destroy(&p); lexical_context_destroy(&l); fclose(stream); return (status); } /* Externally visible entry points */ /*************************************************************************** NAME: UxCreatePixmapFromData(display, d, colormap, width, height, depth, ncolors, chars_per_pixel, colors, pixels) INPUT: Display *display; Drawable d; Colormap colormap; unsigned int width, height; unsigned int depth; unsigned int ncolors; unsigned int chars_per_pixel; char *colors[]; char *pixels[]; OUTPUT: --- RETURN: int ERROR or NO_ERROR DESCRIPTION: Just a wrapper for the static function XCreatePixmapFromData(). EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 23/90 ---------------------------------------------------------------------------*/ int UxCreatePixmapFromData(display, d, colormap, width, height, depth, ncolors, chars_per_pixel, colors, pixels, p) Display *display; Drawable d; Colormap colormap; unsigned int width, height; unsigned int depth; unsigned int ncolors; unsigned int chars_per_pixel; char *colors[]; char *pixels[]; Pixmap *p; { Pixmap pixmap; pixmap = XCreatePixmapFromData(display, d, colormap, width, height, depth, ncolors, chars_per_pixel, colors, pixels); if (pixmap != (Pixmap)NULL) { if (p != NULL) *p = pixmap; return (NO_ERROR); } else return (ERROR); } /*************************************************************************** NAME: UxReadPixmapFile(display, d, colormap, filename, width, height, depth, pixmap) INPUT: Display *display; Drawable d; Colormap colormap; char *filename; unsigned int depth; OUTPUT: unsigned int *width, *height; Pixmap *pixmap; RETURN: int NO_ERROR if PixmapSuccess, otherwise ERROR DESCRIPTION: Just a wrapper for the static function XReadPixmapFile(). EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 23/90 ---------------------------------------------------------------------------*/ int UxReadPixmapFile(display, d, colormap, filename, width, height, depth, pixmap) Display *display; Drawable d; Colormap colormap; char *filename; unsigned int *width, *height; unsigned int depth; Pixmap *pixmap; { if (XReadPixmapFile(display, d, colormap, filename, width, height, depth, pixmap)==PixmapSuccess) return (NO_ERROR); else return (ERROR); } /*************************************************************************** NAME: UxReadPixmapOrBitmapFile(display, d, colormap, filename, width, height, depth, pixmap, x_hot, y_hot) INPUT: Display *display; Drawable d; Colormap colormap; char *filename; unsigned int depth; OUTPUT: unsigned int *width, *height; - width & height, returned Pixmap *pixmap; int *x_hot, *y_hot; - hot-spot coordinates, returned RETURN: int ERROR or NO_ERROR DESCRIPTION: EXT REFERENCES: --- EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ int UxReadPixmapOrBitmapFile(display, d, colormap, filename, width, height, depth, pixmap, x_hot, y_hot, which) Display *display; Drawable d; Colormap colormap; char *filename; unsigned int *width, *height; unsigned int depth; Pixmap *pixmap; int *x_hot, *y_hot; int *which; { Pixmap my_pixmap; int my_width, my_height; int my_x_hot, my_y_hot; if(XReadBitmapFile(display, d, filename, &my_width, &my_height, &my_pixmap, &my_x_hot, &my_y_hot)==BitmapSuccess) { /* it's a bitmap ! */ if (pixmap != NULL) *pixmap = my_pixmap; if (width != NULL) *width = my_width; if (height != NULL) *height = my_height; if (x_hot != NULL) *x_hot = my_x_hot; if (y_hot != NULL) *y_hot = my_y_hot; if (which != NULL) *which = UX_IS_A_BITMAP; return (NO_ERROR); } else if (UxReadPixmapFile(display, d, colormap, filename, width, height, depth, pixmap)==NO_ERROR) { /* it's a pixmap ! Bull format pixmaps have no hot spot */ if (x_hot != NULL) *x_hot = -1; if (y_hot != NULL) *y_hot = -1; if (which != NULL) *which = UX_IS_A_PIXMAP; return (NO_ERROR); } return (ERROR); } /*************************************************************************** NAME: UxLoadPixmapFromPixmapOrBitmapFile(sw, fname, pixmap_ptr, width_ptr, height_ptr) INPUT: swidget sw; - swidget to get colors from char *fname; - the filename to load OUTPUT: Pixmap *pixmap_ptr; - ptr to a Pixmap variable unsigned *width_ptr, *height_ptr; - ptr to return width & height RETURN: int - ERROR or NO_ERROR DESCRIPTION: The named file is read as a Bitmap file, with XReadBitmapFile(). If an error results, it is then read as a Pixmap file. If another error results, ERROR is returned. Otherwise, a pixmap of the same depth as the root window of UxDisplay is returned in *pixmap_ptr, if that pointer is non-NULL. Bitmaps are 'deepened' to the appropriate depth. If width_ptr and height_ptr are non-NULL, then they are used to return the width and height of the resulting Pixmap. In the case of Bitmaps, an attempt is made to select appropriate colours. The filename should be expanded, if desired, before calling this function, since no processing of the filename is done here. EXT REFERENCES: UxPixmapColorWidget, UxDisplay EXT EFFECTS: --- CREATION: Apr 20/90 ---------------------------------------------------------------------------*/ int UxLoadPixmapFromPixmapOrBitmapFile(sw, fname, pixmap_ptr, width_ptr, height_ptr,fore,back) swidget sw; char *fname; Pixmap *pixmap_ptr; unsigned *width_ptr, *height_ptr; Pixel fore, back; { int screen, depth; unsigned width, height; int which; Window rw; GC pixmapGC; XGCValues gcv; Pixel UxName_to_pixel(); Pixmap pmap, qmap; Colormap c; if (fname == NULL) return(ERROR); screen = DefaultScreen(UxDisplay); rw = RootWindow(UxDisplay, screen); depth = DisplayPlanes(UxDisplay, screen); c = DefaultColormap(UxDisplay, screen); if (UxReadPixmapOrBitmapFile(UxDisplay, rw, c, fname, &width, &height, depth, &pmap, (int *)NULL, (int *)NULL, &which ) != NO_ERROR) return (ERROR); if (width_ptr != NULL) *width_ptr = width; if (height_ptr != NULL) *height_ptr = height; if (which == UX_IS_A_PIXMAP) { if (pixmap_ptr != NULL) *pixmap_ptr = pmap; else XFreePixmap(UxDisplay, pmap); return (NO_ERROR); } /* found a bitmap--must deepen it */ gcv.foreground = fore; gcv.background = back; pixmapGC=XCreateGC(UxDisplay, UxRootWindow, GCForeground | GCBackground, &gcv); qmap = XCreatePixmap(UxDisplay, rw, width, height, depth); XCopyPlane(UxDisplay, pmap, qmap, pixmapGC, 0, 0, width, height, 0, 0, 1L); XFreeGC(UxDisplay, pixmapGC); XFreePixmap(UxDisplay, pmap); if (pixmap_ptr != NULL) *pixmap_ptr = qmap; else XFreePixmap(UxDisplay, qmap); return (NO_ERROR); }