From: hbabcock <hba...@us...> - 2006-06-24 21:26:19
|
Update of /cvsroot/plplot/plplot/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30256/src Modified Files: plbuf.c Log Message: Changed the gnome canvas driver so that it would work with the new memory based plot buffer. Fixed a bug in the new version of plbuf.c. Added J. Dishaw to the list of authors for plbuf.c Index: plbuf.c =================================================================== RCS file: /cvsroot/plplot/plplot/src/plbuf.c,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- plbuf.c 18 Jun 2006 01:15:23 -0000 1.12 +++ plbuf.c 24 Jun 2006 21:26:16 -0000 1.13 @@ -5,6 +5,7 @@ Copyright (C) 1992 Maurice LeBrun Copyright (C) 2004 Alan W. Irwin Copyright (C) 2005 Thomas J. Duck + Copyright (C) 2006 Jim Dishaw This file is part of PLplot. @@ -31,6 +32,7 @@ #include <string.h> /* Function prototypes */ +void * plbuf_save(PLStream *pls, void *state); static int rd_command (PLStream *pls, U_CHAR *p_c); static void rd_data (PLStream *pls, void *buf, size_t buf_size); @@ -942,3 +944,282 @@ pls->plbuf_top += buf_size; #endif } + +/* plbuf_save(state) + * + * Saves the current state of the plot into a save buffer. + * This code was originally in gcw.c and gcw-lib.c. The original + * code used a temporary file for the plot buffer and memory + * to perserve colormaps. That method does not offer a clean + * break between using memory buffers and file buffers. This + * function preserves the same functionality by returning a data + * structure that saves the plot buffer and colormaps seperately. + * + * The caller passes an existing save buffer for reuse or NULL + * to force the allocation of a new buffer. Since one malloc() + * is used for everything, the entire save buffer can be freed + * with one free() call. + * + */ +struct _color_map { + PLColor *cmap; + PLINT icol; + PLINT ncol; +}; + +struct _state { + size_t size; /* Size of the save buffer */ + int valid; /* Flag to indicate a valid save state */ +#ifdef BUFFERED_FILE + FILE *plbufFile; +#else + void *plbuf_buffer; + size_t plbuf_buffer_size; + size_t plbuf_top; + size_t plbuf_readpos; +#endif + struct _color_map *color_map; +}; + +void * plbuf_save(PLStream *pls, void *state) +{ + size_t save_size; + struct _state *plot_state = (struct _state *)state; + unsigned int i; + U_CHAR *buf; /* Assume that this is byte-sized */ + + if(pls->plbuf_write) { + pls->plbuf_write = FALSE; + pls->plbuf_read = TRUE; + + /* Determine the size of the buffer required to save everything. We + * assume that there are only two colormaps, but have written the code + * that more than two can be handled with minimal changes. + */ + save_size = sizeof(struct _state) + + 2 * sizeof(struct _color_map) + + pls->ncol0 * sizeof(PLColor) + + pls->ncol1 * sizeof(PLColor); + +#ifndef BUFFERED_FILE + /* Only copy as much of the plot buffer that is being used */ + save_size += pls->plbuf_top; +#endif + + /* If a buffer exists, determine if we need to resize it */ + if( state != NULL ) { + /* We have a save buffer, is it smaller than the current size requirement? */ + if(plot_state->size < save_size) { + /* Yes, reallocate a larger one */ + if((plot_state = (struct _state *)realloc(state, save_size)) == NULL) { + /* NOTE: If realloc fails, then plot_state ill be NULL. + * This will leave the original buffer untouched, thus we + * mark it as invalid and return it back to the caller. + */ + plwarn("plbuf: Unable to reallocate sufficient memory to save state"); + plot_state->valid = 0; + + return state; + } + plot_state->size = save_size; + } + } else { + /* A buffer does not exist, so we need to allocate one */ + if((plot_state = (struct _state *)malloc(save_size)) == NULL) { + plwarn("plbuf: Unable to allocate sufficient memory to save state"); + + return NULL; + } + plot_state->size = save_size; + +#ifdef BUFFERED_FILE + /* Make sure the FILE pointer is NULL in order to preven bad things from happening... */ + plot_state->plbufFile = NULL; +#endif + } + + /* At this point we have an appropriately sized save buffer. + * We need to invalidate the state of the save buffer, since it + * will not be valid until after everything is copied. We use + * this approach vice freeing the memory and returning a NULL pointer + * in order to prevent allocating and freeing memory needlessly. + */ + plot_state->valid = 0; + + /* Point buf to the space after the struct _state */ + buf = (U_CHAR *)(plot_state + 1); + +#ifdef BUFFERED_FILE + /* Remove the old tempfile, if it exists */ + if( plot_state->plbufFile != NULL ) { + fclose(plot_state->plbufFile); + } + + /* Copy the plot buffer to a tempfile */ + if((plot_state->plbufFile = tmpfile()) == NULL) { + /* Throw a warning since this might be a permissions problem + * and we may not want to force an exit + */ + plwarn("plbuf: Unable to open temporary file to save state"); + return (void *)plot_state; + } else { + U_CHAR tmp; + + rewind(pls->plbufFile); + while(count = fread(&tmp, sizeof(U_CHAR), 1, pls->plbufFile)) { + if(fwrite(&tmp, sizeof(U_CHAR), 1, plot_state->plbufFile)!=count) { + /* Throw a warning since this might be a permissions problem + * and we may not want to force an exit + */ + plwarn("plbuf: Unable to write to temporary file"); + fclose(plot_state->plbufFile); + plot_state->plbufFile = NULL; + return (void *)plot_state; + } + } + } +#else + /* Again, note, that we only copy the portion of the plot buffer that is being used */ + plot_state->plbuf_buffer_size = pls->plbuf_top; + plot_state->plbuf_top = pls->plbuf_top; + plot_state->plbuf_readpos = 0; + + /* Create a pointer that points in the space we allocated after struct _state */ + plot_state->plbuf_buffer = (void *)buf; + buf += pls->plbuf_top; + + /* Copy the plot buffer to our new buffer. Again, I must stress, that we only + * are copying the portion of the plot buffer that is being used + */ + if(memcpy(plot_state->plbuf_buffer, pls->plbuf_buffer, pls->plbuf_top ) == NULL) { + /* This should never be NULL */ + plwarn("plbuf: Got a NULL in memcpy!"); + return (void *)plot_state; + } +#endif + + pls->plbuf_write = TRUE; + pls->plbuf_read = FALSE; + + /* Save the colormaps. First create a pointer that points in the space we allocated + * after the plot buffer */ + plot_state->color_map = (struct _color_map *)buf; + buf += sizeof(struct _color_map) * 2; + + /* Then we need to make space for the colormaps themselves */ + plot_state->color_map[0].cmap = (PLColor *)buf; + buf += sizeof(PLColor) * pls->ncol0; + plot_state->color_map[1].cmap = (PLColor *)buf; + buf += sizeof(PLColor) * pls->ncol1; + + /* Save cmap 0 */ + plot_state->color_map[0].icol = pls->icol0; + plot_state->color_map[0].ncol = pls->ncol0; + for (i = 0; i < pls->ncol0; i++) { + pl_cpcolor(&(plot_state->color_map[0].cmap[i]), &pls->cmap0[i]); + } + + /* Save cmap 1 */ + plot_state->color_map[1].icol = pls->icol1; + plot_state->color_map[1].ncol = pls->ncol1; + for (i = 0; i < pls->ncol1; i++) { + pl_cpcolor(&(plot_state->color_map[1].cmap[i]), &pls->cmap1[i]); + } + + plot_state->valid = 1; + return (void *)plot_state; + } + + return NULL; +} + +/* plbuf_restore(PLStream *, state) + * + * Restores the passed state + */ +void plbuf_restore(PLStream *pls, void *state) +{ + struct _state *new_state; + +#ifdef BUFFERED_FILE + pls->plbufFile = new_state->save_file; +#else + pls->plbuf_buffer = new_state->plbuf_buffer; + pls->plbuf_buffer_size = new_state->plbuf_buffer_size; + pls->plbuf_top = new_state->plbuf_top; + pls->plbuf_readpos = new_state->plbuf_readpos; +#endif + /* cmap 0 */ + pls->cmap0 = new_state->color_map[0].cmap; + pls->icol0 = new_state->color_map[0].icol; + pls->ncol0 = new_state->color_map[0].ncol; + /* cmap 1 */ + pls->cmap1 = new_state->color_map[1].cmap; + pls->icol1 = new_state->color_map[1].icol; + pls->ncol1 = new_state->color_map[1].ncol; +} + +/* plbuf_switch(PLStream *, state) + * + * Makes the passed state the current one. Preserves the previous state + * by returning a save buffer. + * + * NOTE: The current implementation can cause a memory leak under the + * following scenario: + * 1) plbuf_save() is called + * 2) plbuf_switch() is called + * 3) Commands are called which cause the plot buffer to grow + * 4) plbuf_swtich() is called + */ +void * plbuf_switch(PLStream *pls, void *state) +{ + struct _state *new_state = (struct _state *)state; + struct _state *prev_state; + size_t save_size; + + /* No saved state was passed, return a NULL--we hope the caller + * is smart enough to notice + */ + if(state == NULL) return NULL; + + if(! new_state->valid) { + plwarn("plbuf: Attempting to switch to an invalid saved state"); + return NULL; + } + + save_size = sizeof(struct _state) + + 2 * sizeof(struct _color_map); + + if((prev_state = (struct _state *)malloc(save_size)) == NULL) { + plwarn("plbuf: Unable to allocate memory to save state"); + return NULL; + } + + /* Set some housekeeping variables */ + prev_state->size = save_size; + prev_state->valid = 1; + + /* Preserve the existing state */ +#ifdef BUFFERED_FILE + prev_state->plbufFile = pls->plbufFile; +#else + prev_state->plbuf_buffer = pls->plbuf_buffer; + prev_state->plbuf_buffer_size = pls->plbuf_buffer_size; + prev_state->plbuf_top = pls->plbuf_top; + prev_state->plbuf_readpos = pls->plbuf_readpos; +#endif + /* cmap 0 */ + prev_state->color_map[0].cmap = pls->cmap0; + prev_state->color_map[0].icol = pls->icol0; + prev_state->color_map[0].ncol = pls->ncol0; + /* cmap 1 */ + prev_state->color_map[1].cmap = pls->cmap1; + prev_state->color_map[1].icol = pls->icol1; + prev_state->color_map[1].ncol = pls->ncol1; + + plbuf_restore(pls, new_state); + + return (void *) prev_state; +} + + |