/* Clip the given polygon to drawing coords defined by BoundingBox. * This routine uses the Sutherland-Hodgman algorithm. When calling * this function, you must make sure that you reserved enough * memory for the output polygon. out_length can be as big as * 2*(in_length - 1) */ void clip_polygon(gpiPoint *in, gpiPoint *out, int in_length, int *out_length) { int i; gpiPoint clip_boundary[5]; static gpiPoint *tmp_corners = NULL; if (!clip_area) { memcpy(out, in, in_length * sizeof(gpiPoint)); *out_length = in_length; return; } tmp_corners = gp_realloc(tmp_corners, 2 * in_length * sizeof(gpiPoint), "clip_polygon"); /* vertices of the rectangular clipping window starting from top-left in counterclockwise direction */ clip_boundary[0].x = clip_area->xleft; /* top left */ clip_boundary[0].y = clip_area->ytop; clip_boundary[1].x = clip_area->xleft; /* bottom left */ clip_boundary[1].y = clip_area->ybot; clip_boundary[2].x = clip_area->xright; /* bottom right */ clip_boundary[2].y = clip_area->ybot; clip_boundary[3].x = clip_area->xright; /* top right */ clip_boundary[3].y = clip_area->ytop; clip_boundary[4] = clip_boundary[0]; memcpy(tmp_corners, in, in_length * sizeof(gpiPoint)); for(i = 0; i < 4; i++) { clip_polygon_to_boundary(tmp_corners, out, in_length, out_length, clip_boundary+i); memcpy(tmp_corners, out, *out_length * sizeof(gpiPoint)); in_length = *out_length; } }
/* * iso_extend() reallocates a iso_curve structure to hold "num" * points. This will either expand or shrink the storage. */ void iso_extend(struct iso_curve *ip, int num) { if (num == ip->p_max) return; #if defined(DOS16) || defined(WIN16) /* Make sure we do not allocate more than 64k points in msdos since * indexing is done with 16-bit int * Leave some bytes for malloc maintainance. */ if (num > 32700) int_error(NO_CARET, "Array index must be less than 32k in msdos"); #endif /* 16bit (Win)Doze */ if (num > 0) { if (ip->points == NULL) { ip->points = (struct coordinate GPHUGE *) gp_alloc(num * sizeof(struct coordinate), "iso curve points"); } else { ip->points = (struct coordinate GPHUGE *) gp_realloc(ip->points, num * sizeof(struct coordinate), "expanding curve points"); } ip->p_max = num; } else { if (ip->points != (struct coordinate GPHUGE *) NULL) free(ip->points); ip->points = (struct coordinate GPHUGE *) NULL; ip->p_max = 0; } }
/* * In-line data blocks are implemented as a here-document: * $FOO << EOD * data line 1 * data line 2 * ... * EOD * * The data block name must begin with $ followed by a letter. * The string EOD is arbitrary; lines of data will be read from the input stream * until the leading characters on the line match the given character string. * No attempt is made to parse the data at the time it is read in. */ void datablock_command() { FILE *fin; char *name, *eod; int nlines; int nsize = 4; struct udvt_entry *datablock; char dataline[MAX_LINE_LEN+1]; if (!isletter(c_token+1)) int_error(c_token, "illegal datablock name"); /* Create or recycle a datablock with the requested name */ name = parse_datablock_name(); datablock = add_udv_by_name(name); if (!datablock->udv_undef) gpfree_datablock(&datablock->udv_value); datablock->udv_undef = FALSE; datablock->udv_value.type = DATABLOCK; datablock->udv_value.v.data_array = NULL; if (!equals(c_token, "<<") || !isletter(c_token+1)) int_error(c_token, "data block name must be followed by << EODmarker"); c_token++; eod = gp_alloc(token[c_token].length +2, "datablock"); copy_str(&eod[0], c_token, token[c_token].length + 2); c_token++; /* Read in and store data lines until EOD */ fin = (lf_head == NULL) ? stdin : lf_head->fp; if (!fin) int_error(NO_CARET,"attempt to define data block from invalid context"); for (nlines = 0; fgets(dataline, MAX_LINE_LEN, fin); nlines++) { int n; if (!strncmp(eod, dataline, strlen(eod))) break; /* Allocate space for data lines plus at least 2 empty lines at the end. */ if (nlines >= nsize-4) { nsize *= 2; datablock->udv_value.v.data_array = gp_realloc( datablock->udv_value.v.data_array, nsize * sizeof(char *), "datablock"); memset(&datablock->udv_value.v.data_array[nlines], 0, (nsize - nlines) * sizeof(char *)); } /* Strip trailing newline character */ n = strlen(dataline); if (n > 0 && dataline[n - 1] == '\n') dataline[n - 1] = NUL; datablock->udv_value.v.data_array[nlines] = gp_strdup(dataline); } inline_num += nlines + 1; /* Update position in input file */ free(eod); return; }
double * redim_vec(double **v, int n) { if (n < 1) *v = NULL; else *v = gp_realloc(*v, n * sizeof((*v)[0]), "vec"); return *v; }
static void extend_at() { size_t newsize = sizeof(struct at_type) + at_size * sizeof(struct at_entry); at = gp_realloc(at, newsize, "extend_at"); at_size += MAX_AT_LEN; FPRINTF((stderr, "Extending at size to %d\n", at_size)); }
/* append string src to dest re-allocates memory if necessary, (re-)determines the length of the destination string only if len==0 */ size_t strappend(char **dest, size_t *size, size_t len, const char *src) { size_t destlen = (len != 0) ? len : strlen(*dest); size_t srclen = strlen(src); if (destlen + srclen + 1 > *size) { *size *= 2; *dest = (char *) gp_realloc(*dest, *size, "strappend"); } memcpy(*dest + destlen, src, srclen + 1); return destlen + srclen; }
void extend_token_table() { if (token_table_size == 0) { /* first time */ token = (struct lexical_unit *) gp_alloc(MAX_TOKENS * sizeof(struct lexical_unit), "token table"); token_table_size = MAX_TOKENS; } else { token = gp_realloc(token, (token_table_size + MAX_TOKENS) * sizeof(struct lexical_unit), "extend token table"); token_table_size += MAX_TOKENS; FPRINTF((stderr, "extending token table to %d elements\n", token_table_size)); } }
struct at_type * perm_at() { struct at_type *at_ptr; size_t len; (void) temp_at(); len = sizeof(struct at_type) + (at->a_count - MAX_AT_LEN) * sizeof(struct at_entry); at_ptr = (struct at_type *) gp_realloc(at, len, "perm_at"); at = NULL; /* invalidate at pointer */ return (at_ptr); }
/* * m_capture() is similar to capture(), but it mallocs storage for the * string. */ void m_capture(char **str, int start, int end) { int i, e; char *s; e = token[end].start_index + token[end].length; *str = gp_realloc(*str, (e - token[start].start_index + 1), "string"); s = *str; for (i = token[start].start_index; i < e && gp_input_line[i] != NUL; i++) *s++ = gp_input_line[i]; *s = NUL; }
/* support for dynamic size of input line */ void extend_input_line() { if (input_line_len == 0) { /* first time */ input_line = gp_alloc(MAX_LINE_LEN, "input_line"); input_line_len = MAX_LINE_LEN; input_line[0] = NUL; } else { input_line = gp_realloc(input_line, input_line_len + MAX_LINE_LEN, "extend input line"); input_line_len += MAX_LINE_LEN; FPRINTF((stderr, "extending input line to %d chars\n", input_line_len)); } }
static void extend_cur_line() { char *new_line; /* extent input line length */ new_line = gp_realloc(cur_line, line_len + MAXBUF, NULL); if (!new_line) { reset_termio(); int_error(NO_CARET, "Can't extend readline length"); } cur_line = new_line; line_len += MAXBUF; FPRINTF((stderr, "\nextending readline length to %d chars\n", line_len)); }
/* Output time given in seconds from year 2000 into string */ void f_strftime(union argument *arg) { struct value fmt, val; char *fmtstr, *buffer; int fmtlen, buflen, length; (void) arg; /* Avoid compiler warnings */ /* Retrieve parameters from top of stack */ pop(&val); pop(&fmt); if ( fmt.type != STRING ) int_error(NO_CARET, "First parameter to strftime must be a format string"); /* Prepare format string. * Make sure the resulting string not empty by adding a space. * Otherwise, the return value of gstrftime doesn't give enough * information. */ fmtlen = strlen(fmt.v.string_val) + 1; fmtstr = gp_alloc(fmtlen + 1, "f_strftime: fmt"); strncpy(fmtstr, fmt.v.string_val, fmtlen); strncat(fmtstr, " ", fmtlen); buflen = 80 + 2*fmtlen; buffer = gp_alloc(buflen, "f_strftime: buffer"); /* Get time_str */ length = gstrftime(buffer, buflen, fmtstr, real(&val)); if (length == 0 || length >= buflen) int_error(NO_CARET, "Resulting string is too long"); /* Remove trailing space */ assert(buffer[length-1] == ' '); buffer[length-1] = NUL; buffer = gp_realloc(buffer, strlen(buffer)+1, "f_strftime"); FPRINTF((stderr," strftime result = \"%s\"\n",buffer)); gpfree_string(&val); gpfree_string(&fmt); free(fmtstr); push(Gstring(&val, buffer)); }
/* retrieve path relative to gnuplot executable */ LPSTR RelativePathToGnuplot(const char * path) { #ifdef UNICODE LPSTR ansi_dir = AnsiText(szPackageDir, encoding); LPSTR rel_path = (char *) gp_realloc(ansi_dir, strlen(ansi_dir) + strlen(path) + 1, "RelativePathToGnuplot"); if (rel_path == NULL) { free(ansi_dir); return (LPSTR) path; } #else char * rel_path = (char * ) gp_alloc(strlen(szPackageDir) + strlen(path) + 1, "RelativePathToGnuplot"); strcpy(rel_path, szPackageDir); #endif /* szPackageDir is guaranteed to have a trailing backslash */ strcat(rel_path, path); return rel_path; }
/* expand tilde in path * path cannot be a static array! * tilde must be the first character in *pathp; * we may change that later */ void gp_expand_tilde(char **pathp) { if (!*pathp) int_error(NO_CARET, "Cannot expand empty path"); if ((*pathp)[0] == '~' && (*pathp)[1] == DIRSEP1) { if (user_homedir) { size_t n = strlen(*pathp); *pathp = gp_realloc(*pathp, n + strlen(user_homedir), "tilde expansion"); /* include null at the end ... */ memmove(*pathp + strlen(user_homedir) - 1, *pathp, n + 1); memcpy(*pathp, user_homedir, strlen(user_homedir)); } else int_warn(NO_CARET, "HOME not set - cannot expand tilde"); } }
/* * m_quote_capture() is similar to m_capture(), but it removes * quotes from either end of the string. */ void m_quote_capture(char **str, int start, int end) { int i, e; char *s; e = token[end].start_index + token[end].length - 1; *str = gp_realloc(*str, (e - token[start].start_index + 1), "string"); s = *str; for (i = token[start].start_index + 1; i < e && gp_input_line[i] != NUL; i++) *s++ = gp_input_line[i]; *s = NUL; if (gp_input_line[token[start].start_index] == '"') parse_esc(*str); else parse_sq(*str); }
FILE * loadpath_fopen(const char *filename, const char *mode) { FILE *fp; #if defined(PIPES) if (*filename == '<') { restrict_popen(); if ((fp = popen(filename + 1, "r")) == (FILE *) NULL) return (FILE *) 0; } else #endif /* PIPES */ if ((fp = fopen(filename, mode)) == (FILE *) NULL) { /* try 'loadpath' variable */ char *fullname = NULL, *path; while ((path = get_loadpath()) != NULL) { /* length of path, dir separator, filename, \0 */ fullname = gp_realloc(fullname, strlen(path) + 1 + strlen(filename) + 1, "loadpath_fopen"); strcpy(fullname, path); PATH_CONCAT(fullname, filename); if ((fp = fopen(fullname, mode)) != NULL) { free(fullname); fullname = NULL; /* reset loadpath internals! * maybe this can be replaced by calling get_loadpath with * a NULL argument and some loadpath_handler internal logic */ while (get_loadpath()); break; } } if (fullname) free(fullname); } #ifdef _Windows if (fp != NULL) setmode(fileno(fp), _O_BINARY); #endif return fp; }
/*{{{ static char *df_gets() */ static char *df_gets() { int len = 0; /* HBB 20000526: prompt user for inline data, if in interactive mode */ if (mixed_data_fp && interactive) fputs("input data ('e' ends) > ", stderr); if (!fgets(line, max_line_len, data_fp)) return NULL; if (mixed_data_fp) ++inline_num; for (;;) { len += strlen(line + len); if (len > 0 && line[len - 1] == '\n') { /* we have read an entire text-file line. * Strip the trailing linefeed and return */ line[len - 1] = 0; return line; } /* buffer we provided may not be full - dont grab extra * memory un-necessarily. This may trap a problem with last * line in file not being properly terminated - each time * through a replot loop, it was doubling buffer size */ if ((max_line_len - len) < 32) line = gp_realloc(line, max_line_len *= 2, "datafile line buffer"); if (!fgets(line + len, max_line_len - len, data_fp)) return line; /* unexpected end of file, but we have something to do */ } /* NOTREACHED */ return NULL; }
/* * iso_extend() reallocates a iso_curve structure to hold "num" * points. This will either expand or shrink the storage. */ void iso_extend(struct iso_curve *ip, int num) { if (num == ip->p_max) return; if (num > 0) { if (ip->points == NULL) { ip->points = (struct coordinate GPHUGE *) gp_alloc(num * sizeof(struct coordinate), "iso curve points"); } else { ip->points = (struct coordinate GPHUGE *) gp_realloc(ip->points, num * sizeof(struct coordinate), "expanding curve points"); } if (num > ip->p_max) memset( &(ip->points[ip->p_max]), 0, (num - ip->p_max) * sizeof(struct coordinate)); ip->p_max = num; } else { if (ip->points != (struct coordinate GPHUGE *) NULL) free(ip->points); ip->points = (struct coordinate GPHUGE *) NULL; ip->p_max = 0; } }
void edf_filetype_function(void) { FILE *fp; char *header = NULL; int header_size = 0; char *p; int k; /* open (header) file */ fp = loadpath_fopen(df_filename, "rb"); if (!fp) os_error(NO_CARET, "Can't open data file \"%s\"", df_filename); /* read header: it is a multiple of 512 B ending by "}\n" */ while (header_size == 0 || strncmp(&header[header_size-2],"}\n",2)) { int header_size_prev = header_size; if (header_size > 12*512) /* protection against indefinite loop */ os_error(NO_CARET, "Damaged EDF header of %s: not multiple of 512 B.\n", df_filename); header_size += 512; if (!header) header = gp_alloc(header_size+1, "EDF header"); else header = gp_realloc(header, header_size+1, "EDF header"); header[header_size_prev] = 0; /* protection against empty file */ fread(header+header_size_prev, 512, 1, fp); header[header_size] = 0; /* end of string: protection against strstr later on */ } fclose(fp); /* make sure there is a binary record structure for each image */ if (df_num_bin_records < 1) df_add_binary_records(1-df_num_bin_records, DF_CURRENT_RECORDS); /* otherwise put here: number of images (records) from this file */ if ((p = edf_findInHeader(header, "EDF_BinaryFileName"))) { int plen = strcspn(p, " ;\n"); df_filename = gp_realloc(df_filename, plen+1, "datafile name"); strncpy(df_filename, p, plen); df_filename[plen] = '\0'; if ((p = edf_findInHeader(header, "EDF_BinaryFilePosition"))) df_bin_record[0].scan_skip[0] = atoi(p); else df_bin_record[0].scan_skip[0] = 0; } else df_bin_record[0].scan_skip[0] = header_size; /* skip header */ /* set default values */ df_bin_record[0].scan_dir[0] = 1; df_bin_record[0].scan_dir[1] = -1; df_bin_record[0].scan_generate_coord = TRUE; df_bin_record[0].cart_scan[0] = DF_SCAN_POINT; df_bin_record[0].cart_scan[1] = DF_SCAN_LINE; df_extend_binary_columns(1); df_set_skip_before(1,0); df_set_skip_after(1,0); df_no_use_specs = 1; use_spec[0].column = 1; /* now parse the header */ if ((p = edf_findInHeader(header, "Dim_1"))) df_bin_record[0].scan_dim[0] = atoi(p); if ((p = edf_findInHeader(header, "Dim_2"))) df_bin_record[0].scan_dim[1] = atoi(p); if ((p = edf_findInHeader(header, "DataType"))) { k = lookup_table4_nth(edf_datatype_table, p); if (k >= 0) { /* known EDF DataType */ int s = edf_datatype_table[k].sajzof; switch (edf_datatype_table[k].signum) { case 0: df_set_read_type(1,SIGNED_TEST(s)); break; case 1: df_set_read_type(1,UNSIGNED_TEST(s)); break; case 2: df_set_read_type(1,FLOAT_TEST(s)); break; } } } if ((p = edf_findInHeader(header, "ByteOrder"))) { k = lookup_table_nth(edf_byteorder_table, p); if (k >= 0) df_bin_file_endianess = edf_byteorder_table[k].value; } /* Origin vs center: EDF specs allows only Center, but it does not hurt if Origin is supported as well; however, Center rules if both specified. */ if ((p = edf_findInHeader(header, "Origin_1"))) { df_bin_record[0].scan_cen_or_ori[0] = atof(p); df_bin_record[0].scan_trans = DF_TRANSLATE_VIA_ORIGIN; } if ((p = edf_findInHeader(header, "Origin_2"))) { df_bin_record[0].scan_cen_or_ori[1] = atof(p); df_bin_record[0].scan_trans = DF_TRANSLATE_VIA_ORIGIN; } if ((p = edf_findInHeader(header, "Center_1"))) { df_bin_record[0].scan_cen_or_ori[0] = atof(p); df_bin_record[0].scan_trans = DF_TRANSLATE_VIA_CENTER; } if ((p = edf_findInHeader(header, "Center_2"))) { df_bin_record[0].scan_cen_or_ori[1] = atof(p); df_bin_record[0].scan_trans = DF_TRANSLATE_VIA_CENTER; } /* now pixel sizes and raster orientation */ if ((p = edf_findInHeader(header, "PSize_1"))) df_bin_record[0].scan_delta[0] = atof(p); if ((p = edf_findInHeader(header, "PSize_2"))) df_bin_record[0].scan_delta[1] = atof(p); if ((p = edf_findInHeader(header, "RasterAxes"))) { k = lookup_table_nth(edf_rasteraxes_table, p); switch (k) { case EDF_RASTER_AXES_XrightYup: df_bin_record[0].scan_dir[0] = 1; df_bin_record[0].scan_dir[1] = 1; df_bin_record[0].cart_scan[0] = DF_SCAN_POINT; df_bin_record[0].cart_scan[1] = DF_SCAN_LINE; break; default: /* also EDF_RASTER_AXES_XrightYdown */ df_bin_record[0].scan_dir[0] = 1; df_bin_record[0].scan_dir[1] = -1; df_bin_record[0].cart_scan[0] = DF_SCAN_POINT; df_bin_record[0].cart_scan[1] = DF_SCAN_LINE; } } free(header); }
void mcs_interp(struct curve_points *plot) { /* These track the original (pre-sorted) data points */ int N = plot->p_count; struct coordinate *p = gp_realloc(plot->points, (N+1) * sizeof(coordinate), "mcs"); int i; /* These will track the resulting smoothed curve */ struct coordinate *new_points = gp_alloc((samples_1+1) * sizeof(coordinate), "mcs"); double sxmin = AXIS_LOG_VALUE(plot->x_axis, X_AXIS.min); double sxmax = AXIS_LOG_VALUE(plot->x_axis, X_AXIS.max); double xstart, xend, xstep; xstart = GPMAX(p[0].x, sxmin); xend = GPMIN(p[N-1].x, sxmax); xstep = (xend - xstart) / (samples_1 - 1); /* Calculate spline coefficients */ #define DX xlow #define SLOPE xhigh #define C1 ylow #define C2 yhigh #define C3 z for (i = 0; i < N-1; i++) { p[i].DX = p[i+1].x - p[i].x; p[i].SLOPE = (p[i+1].y - p[i].y) / p[i].DX; } p[N-1].SLOPE = 0; p[0].C1 = p[0].SLOPE; for (i = 0; i < N-1; i++) { if (p[i].SLOPE * p[i+1].SLOPE <= 0) { p[i+1].C1 = 0; } else { double sum = p[i].DX + p[i+1].DX; p[i+1].C1 = (3. * sum) / ((sum + p[i+1].DX) / p[i].SLOPE + (sum + p[i].DX) / p[i+1].SLOPE); } } p[N].C1 = p[N-1].SLOPE; for (i = 0; i < N; i++) { double temp = p[i].C1 + p[i+1].C1 - 2*p[i].SLOPE; p[i].C2 = (p[i].SLOPE - p[i].C1 -temp) / p[i].DX; p[i].C3 = temp / (p[i].DX * p[i].DX); } /* Use the coefficients C1, C2, C3 to interpolate over the requested range */ for (i = 0; i < samples_1; i++) { double x = xstart + i * xstep; double y; TBOOLEAN exact = FALSE; if (x == p[N-1].x) { /* Exact value for right-most point of original data */ y = p[N-1].y; exact = TRUE; } else { int low = 0; int mid; int high = N-1; while (low <= high) { mid = floor((low + high) / 2); if (p[mid].x < x) low = mid + 1; else if (p[mid].x > x) high = mid - 1; else { /* Exact value for some point in original data */ y = p[mid].y; exact = TRUE; break; } } if (!exact) { int j = GPMAX(0, high); double diff = x - p[j].x; y = p[j].y + p[j].C1 * diff + p[j].C2 * diff * diff + p[j].C3 * diff * diff * diff; } } /* FIXME: Log x? autoscale x? */ new_points[i].x = x; new_points[i].type = INRANGE; STORE_WITH_LOG_AND_UPDATE_RANGE(new_points[i].y, y, new_points[i].type, plot->y_axis, plot->noautoscale, NOOP, NOOP); } /* Replace original data with the interpolated curve */ free(p); plot->points = new_points; plot->p_count = samples_1; plot->p_max = samples_1 + 1; #undef DX #undef SLOPE #undef C1 #undef C2 #undef C3 }
void statsrequest(void) { int i; int columns; int columnsread; double v[2]; static char *file_name = NULL; /* Vars to hold data and results */ long n; /* number of records retained */ long max_n; static double *data_x = NULL; static double *data_y = NULL; /* values read from file */ long invalid; /* number of missing/invalid records */ long blanks; /* number of blank lines */ long doubleblanks; /* number of repeated blank lines */ long out_of_range; /* number pts rejected, because out of range */ struct file_stats res_file; struct sgl_column_stats res_x, res_y; struct two_column_stats res_xy; float *matrix; /* matrix data. This must be float. */ int nc, nr; /* matrix dimensions. */ int index; /* Vars for variable handling */ static char *prefix = NULL; /* prefix for user-defined vars names */ /* Vars that control output */ TBOOLEAN do_output = TRUE; /* Generate formatted output */ c_token++; /* Parse ranges */ AXIS_INIT2D(FIRST_X_AXIS, 0); AXIS_INIT2D(FIRST_Y_AXIS, 0); parse_range(FIRST_X_AXIS); parse_range(FIRST_Y_AXIS); /* Initialize */ columnsread = 2; invalid = 0; /* number of missing/invalid records */ blanks = 0; /* number of blank lines */ doubleblanks = 0; /* number of repeated blank lines */ out_of_range = 0; /* number pts rejected, because out of range */ n = 0; /* number of records retained */ nr = 0; /* Matrix dimensions */ nc = 0; max_n = INITIAL_DATA_SIZE; free(data_x); free(data_y); data_x = vec(max_n); /* start with max. value */ data_y = vec(max_n); if ( !data_x || !data_y ) int_error( NO_CARET, "Internal error: out of memory in stats" ); n = invalid = blanks = doubleblanks = out_of_range = nr = 0; /* Get filename */ free ( file_name ); file_name = try_to_get_string(); if ( !file_name ) int_error(c_token, "missing filename"); /* =========================================================== v923z: insertion for treating matrices EAM: only handles ascii matrix with uniform grid, and fails to apply any input data transforms =========================================================== */ if ( almost_equals(c_token, "mat$rix") ) { df_open(file_name, 3, NULL); index = df_num_bin_records - 1; /* We take these values as set by df_determine_matrix_info See line 1996 in datafile.c */ nc = df_bin_record[index].scan_dim[0]; nr = df_bin_record[index].scan_dim[1]; n = nc * nr; matrix = (float *)df_bin_record[index].memory_data; /* Fill up a vector, so that we can use the existing code. */ if ( !redim_vec(&data_x, n ) ) { int_error( NO_CARET, "Out of memory in stats: too many datapoints (%d)?", n ); } for( i=0; i < n; i++ ) { data_y[i] = (double)matrix[i]; } /* We can close the file here, there is nothing else to do */ df_close(); /* We will invoke single column statistics for the matrix */ columns = 1; } else { /* Not a matrix */ columns = df_open(file_name, 2, NULL); /* up to 2 using specs allowed */ if (columns < 0) int_error(NO_CARET, "Can't read data file"); if (columns > 2 ) int_error(c_token, "Need 0 to 2 using specs for stats command"); /* If the user has set an explicit locale for numeric input, apply it here so that it affects data fields read from the input file. */ /* v923z: where exactly should this be? here or before the matrix case? * I think, we should move everything here to before trying to open the file. * There is no point in trying to read anything, if the axis is logarithmic, e.g. */ set_numeric_locale(); /* For all these below: we could save the state, switch off, then restore */ if ( axis_array[FIRST_X_AXIS].log || axis_array[FIRST_Y_AXIS].log ) int_error( NO_CARET, "Stats command not available with logscale active"); if ( axis_array[FIRST_X_AXIS].datatype == DT_TIMEDATE || axis_array[FIRST_Y_AXIS].datatype == DT_TIMEDATE ) int_error( NO_CARET, "Stats command not available in timedata mode"); if ( polar ) int_error( NO_CARET, "Stats command not available in polar mode" ); if ( parametric ) int_error( NO_CARET, "Stats command not available in parametric mode" ); /* The way readline and friends work is as follows: - df_open will return the number of columns requested in the using spec so that "columns" will be 0, 1, or 2 (no using, using 1, using 1:2) - readline always returns the same number of columns (for us: 1 or 2) - using 1:2 = return two columns, skipping lines w/ bad data - using 1 = return sgl column (supply zeros (0) for the second col) - no using = return two columns (first two), fail on bad data We need to know how many columns to process. If columns==1 or ==2 (that is, if there was a using spec), all is clear and we use the value of columns. But: if columns is 0, then we need to figure out the number of cols read from the return value of readline. If readline ever returns 1, we take that; only if it always returns 2 do we assume two cols. */ while( (i = df_readline(v, 2)) != DF_EOF ) { columnsread = ( i > columnsread ? i : columnsread ); if ( n >= max_n ) { max_n = (max_n * 3) / 2; /* increase max_n by factor of 1.5 */ /* Some of the reallocations went bad: */ if ( 0 || !redim_vec(&data_x, max_n) || !redim_vec(&data_y, max_n) ) { df_close(); int_error( NO_CARET, "Out of memory in stats: too many datapoints (%d)?", max_n ); } } /* if (need to extend storage space) */ switch (i) { case DF_MISSING: case DF_UNDEFINED: /* Invalids are only recognized if the syntax is like this: stats "file" using ($1):($2) If the syntax is simply: stats "file" using 1:2 then df_readline simply skips invalid records (does not return anything!) Status: 2009-11-02 */ invalid += 1; continue; case DF_FIRST_BLANK: blanks += 1; continue; case DF_SECOND_BLANK: blanks += 1; doubleblanks += 1; continue; case 0: int_error( NO_CARET, "bad data on line %d of file %s", df_line_number, df_filename ? df_filename : "" ); break; case 1: /* Read single column successfully */ if ( validate_data(v[0], FIRST_Y_AXIS) ) { data_y[n] = v[0]; n++; } else { out_of_range++; } break; case 2: /* Read two columns successfully */ if ( validate_data(v[0], FIRST_X_AXIS) && validate_data(v[1], FIRST_Y_AXIS) ) { data_x[n] = v[0]; data_y[n] = v[1]; n++; } else { out_of_range++; } break; } } /* end-while : done reading file */ df_close(); /* now resize fields to actual length: */ redim_vec(&data_x, n); redim_vec(&data_y, n); /* figure out how many columns where really read... */ if ( columns == 0 ) columns = columnsread; } /* end of case when the data file is not a matrix */ /* Now finished reading user input; return to C locale for internal use*/ reset_numeric_locale(); /* PKJ - TODO: similar for logscale, polar/parametric, timedata */ /* No data! Try to explain why. */ if ( n == 0 ) { if ( out_of_range > 0 ) int_error( NO_CARET, "All points out of range" ); else int_error( NO_CARET, "No valid data points found in file" ); } /* Parse the remainder of the command line: 0 to 2 tokens possible */ while( !(END_OF_COMMAND) ) { if ( almost_equals( c_token, "out$put" ) ) { do_output = TRUE; c_token++; } else if ( almost_equals( c_token, "noout$put" ) ) { do_output = FALSE; c_token++; } else if ( almost_equals(c_token, "pre$fix") || equals(c_token, "name")) { c_token++; free ( prefix ); prefix = try_to_get_string(); if (!legal_identifier(prefix) || !strcmp ("GPVAL_", prefix)) int_error( --c_token, "illegal prefix" ); } else { int_error( c_token, "Expecting [no]output or prefix"); } } /* Set defaults if not explicitly set by user */ if (!prefix) prefix = gp_strdup("STATS_"); i = strlen(prefix); if (prefix[i-1] != '_') { prefix = gp_realloc(prefix, i+2, "prefix"); strcat(prefix,"_"); } /* Do the actual analysis */ res_file = analyze_file( n, out_of_range, invalid, blanks, doubleblanks ); if ( columns == 1 ) { res_y = analyze_sgl_column( data_y, n, nr ); } if ( columns == 2 ) { /* If there are two columns, then the data file is not a matrix */ res_x = analyze_sgl_column( data_x, n, 0 ); res_y = analyze_sgl_column( data_y, n, 0 ); res_xy = analyze_two_columns( data_x, data_y, res_x, res_y, n ); } /* Store results in user-accessible variables */ /* Clear out any previous use of these variables */ del_udv_by_name( prefix, TRUE ); file_variables( res_file, prefix ); if ( columns == 1 ) { sgl_column_variables( res_y, prefix, "" ); } if ( columns == 2 ) { sgl_column_variables( res_x, prefix, "_x" ); sgl_column_variables( res_y, prefix, "_y" ); two_column_variables( res_xy, prefix ); } /* Output */ if ( do_output ) { file_output( res_file ); if ( columns == 1 ) sgl_column_output( res_y, res_file.records ); else two_column_output( res_x, res_y, res_xy, res_file.records ); } /* Cleanup */ free(data_x); free(data_y); data_x = NULL; data_y = NULL; free( file_name ); file_name = NULL; free( prefix ); prefix = NULL; }
void mcs_interp(struct curve_points *plot) { /* These track the original (pre-sorted) data points */ int N = plot->p_count; struct coordinate *p = gp_realloc(plot->points, (N+1) * sizeof(coordinate), "mcs"); int i; /* These will track the resulting smoothed curve (>= 3X original count) */ /* Larger number of samples gives smoother curve (no surprise!) */ int Nsamp = (samples_1 > 2*N) ? samples_1 : 2*N; int Ntot = N + Nsamp; struct coordinate *new_points = gp_alloc((Ntot) * sizeof(coordinate), "mcs"); double xstart = GPMAX(p[0].x, X_AXIS.min); double xend = GPMIN(p[N-1].x, X_AXIS.max); double xstep = (xend - xstart) / (Nsamp - 1); /* Load output x coords for sampling */ for (i=0; i<N; i++) new_points[i].x = p[i].x; for ( ; i<Ntot; i++) new_points[i].x = xstart + (i-N)*xstep; /* Sort output x coords */ qsort(new_points, Ntot, sizeof(struct coordinate), compare_points); /* Displace any collisions */ for (i=1; i<Ntot-1; i++) { double delta = new_points[i].x - new_points[i-1].x; if (new_points[i+1].x - new_points[i].x < delta/1000.) new_points[i].x -= delta/2.; } /* Calculate spline coefficients */ #define DX xlow #define SLOPE xhigh #define C1 ylow #define C2 yhigh #define C3 z for (i = 0; i < N-1; i++) { p[i].DX = p[i+1].x - p[i].x; p[i].SLOPE = (p[i+1].y - p[i].y) / p[i].DX; } p[N-1].SLOPE = 0; p[0].C1 = p[0].SLOPE; for (i = 0; i < N-1; i++) { if (p[i].SLOPE * p[i+1].SLOPE <= 0) { p[i+1].C1 = 0; } else { double sum = p[i].DX + p[i+1].DX; p[i+1].C1 = (3. * sum) / ((sum + p[i+1].DX) / p[i].SLOPE + (sum + p[i].DX) / p[i+1].SLOPE); } } p[N].C1 = p[N-1].SLOPE; for (i = 0; i < N; i++) { double temp = p[i].C1 + p[i+1].C1 - 2*p[i].SLOPE; p[i].C2 = (p[i].SLOPE - p[i].C1 -temp) / p[i].DX; p[i].C3 = temp / (p[i].DX * p[i].DX); } /* Use the coefficients C1, C2, C3 to interpolate over the requested range */ for (i = 0; i < Ntot; i++) { double x = new_points[i].x; double y; TBOOLEAN exact = FALSE; if (x == p[N-1].x) { /* Exact value for right-most point of original data */ y = p[N-1].y; exact = TRUE; } else { int low = 0; int mid; int high = N-1; while (low <= high) { mid = floor((low + high) / 2); if (p[mid].x < x) low = mid + 1; else if (p[mid].x > x) high = mid - 1; else { /* Exact value for some point in original data */ y = p[mid].y; exact = TRUE; break; } } if (!exact) { int j = GPMAX(0, high); double diff = x - p[j].x; y = p[j].y + p[j].C1 * diff + p[j].C2 * diff * diff + p[j].C3 * diff * diff * diff; } } xstart = X_AXIS.min; xend = X_AXIS.max; if (inrange(x, xstart, xend)) new_points[i].type = INRANGE; else new_points[i].type = OUTRANGE; /* FIXME: simpler test for outrange would be sufficient */ STORE_AND_UPDATE_RANGE(new_points[i].y, y, new_points[i].type, plot->y_axis, plot->noautoscale, NOOP); } /* Replace original data with the interpolated curve */ free(p); plot->points = new_points; plot->p_count = Ntot; plot->p_max = Ntot + 1; #undef DX #undef SLOPE #undef C1 #undef C2 #undef C3 }
/* * char *fontpath_handler (int, char *) * */ char * fontpath_handler(int action, char *path) { /* fontpath variable * the path elements are '\0' separated (!) * this way, reading out fontpath is very * easy to implement */ static char *fontpath; /* index pointer, end of fontpath, * env section of fontpath, current limit, in that order */ static char *p, *last, *envptr, *limit; if (!fontpath_init_done) { fontpath_init_done = TRUE; init_fontpath(); } switch (action) { case ACTION_CLEAR: /* Clear fontpath, fall through to init */ FPRINTF((stderr, "Clear fontpath\n")); free(fontpath); fontpath = p = last = NULL; /* HBB 20000726: 'limit' has to be initialized to NULL, too! */ limit = NULL; case ACTION_INIT: /* Init fontpath from environment */ FPRINTF((stderr, "Init fontpath from environment\n")); assert(fontpath == NULL); if (!fontpath) { char *envlib = getenv("GNUPLOT_FONTPATH"); if (envlib) { /* get paths from environment */ int len = strlen(envlib); fontpath = gp_strdup(envlib); /* point to end of fontpath */ last = fontpath + len; /* convert all PATHSEPs to \0 */ PATHSEP_TO_NUL(fontpath); } #if defined(HAVE_DIRENT_H) || defined(_Windows) else { /* set hardcoded paths */ const struct path_table *curr_fontpath = fontpath_tbl; while (curr_fontpath->dir) { char *currdir = NULL; char *envbeg = NULL; # if defined(PIPES) char *cmdbeg = NULL; # endif TBOOLEAN subdirs = FALSE; currdir = gp_strdup( curr_fontpath->dir ); while ( (envbeg=strstr(currdir, "$(")) # if defined(PIPES) || (cmdbeg=strstr( currdir, "$`" )) # endif ) { /* Read environment variables */ if (envbeg) { char *tmpdir = NULL; char *envend = NULL, *envval = NULL; unsigned int envlen; envend = strchr(envbeg+2,')'); envend[0] = '\0'; envval = getenv(envbeg+2); envend[0] = ')'; envlen = envval ? strlen(envval) : 0; tmpdir = gp_alloc(strlen(currdir)+envlen +envbeg-envend+1, "expand fontpath"); strncpy(tmpdir,currdir,envbeg-currdir); if (envval) strcpy(tmpdir+(envbeg-currdir),envval); strcpy(tmpdir+(envbeg-currdir+envlen), envend+1); free(currdir); currdir = tmpdir; } # if defined(PIPES) /* Read environment variables */ else if (cmdbeg) { char *tmpdir = NULL; char *envend = NULL; char envval[256]; unsigned int envlen; FILE *fcmd; envend = strchr(cmdbeg+2,'`'); envend[0] = '\0'; restrict_popen(); fcmd = popen(cmdbeg+2,"r"); if (fcmd) { fgets(envval,255,fcmd); if (envval[strlen(envval)-1]=='\n') envval[strlen(envval)-1]='\0'; pclose(fcmd); } envend[0] = '`'; envlen = strlen(envval); tmpdir = gp_alloc(strlen(currdir)+envlen +cmdbeg-envend+1, "expand fontpath"); strncpy(tmpdir,currdir,cmdbeg-currdir); if (*envval) strcpy(tmpdir+(cmdbeg-currdir),envval); strcpy(tmpdir+(cmdbeg-currdir+envlen), envend+1); free(currdir); currdir = tmpdir; } # endif } if ( currdir[strlen(currdir)-1] == '!' ) { /* search subdirectories */ /* delete ! from directory name */ currdir[strlen(currdir)-1] = '\0'; subdirs = TRUE; } if ( existdir( currdir ) ) { size_t plen; if ( subdirs ) /* add ! to directory name again */ currdir[strlen(currdir)] = '!'; plen = strlen(currdir); if (fontpath) { size_t elen = strlen(fontpath); fontpath = gp_realloc(fontpath, elen + 1 + plen + 1, "expand fontpath"); last = fontpath+elen; *last = PATHSEP; ++last; *last = '\0'; } else { fontpath = gp_alloc(plen + 1, "expand fontpath"); last = fontpath; } strcpy(last, currdir ); last += plen; } curr_fontpath++; if (currdir) { free(currdir); currdir = NULL; } } /* convert all PATHSEPs to \0 */ if (fontpath) PATHSEP_TO_NUL(fontpath); } #endif /* HAVE_DIRENT_H */ } /* else: already initialised; int_warn (?) */ /* point to env portion of fontpath */ envptr = fontpath; break; case ACTION_SET: /* set the fontpath */ FPRINTF((stderr, "Set fontpath\n")); if (path && *path != NUL) { /* length of env portion */ size_t elen = last - envptr; size_t plen = strlen(path); if (fontpath && envptr) { /* we are prepending a path name; because * realloc() preserves only the contents up * to the minimum of old and new size, we move * the part to be preserved to the beginning * of the string; use memmove() because strings * may overlap */ memmove(fontpath, envptr, elen + 1); } fontpath = gp_realloc(fontpath, elen + 1 + plen + 1, "expand fontpath"); /* now move env part back to the end to make space for * the new path */ memmove(fontpath + plen + 1, fontpath, elen + 1); strcpy(fontpath, path); /* separate new path(s) and env path(s) */ fontpath[plen] = PATHSEP; /* adjust pointer to env part and last */ envptr = &fontpath[plen+1]; last = envptr + elen; PATHSEP_TO_NUL(fontpath); } /* else: NULL = empty */ break; case ACTION_SHOW: /* print the current, full fontpath */ FPRINTF((stderr, "Show fontpath\n")); if (fontpath) { fputs("\tfontpath is ", stderr); PRINT_PATHLIST(fontpath, envptr); if (envptr) { /* env part */ fputs("\tsystem fontpath is ", stderr); PRINT_PATHLIST(envptr, last); } } else fputs("\tfontpath is empty\n", stderr); break; case ACTION_SAVE: /* we don't save the font path taken from the * environment, so don't go beyond envptr when * extracting the path elements */ limit = envptr; case ACTION_GET: /* subsequent calls to get_fontpath() return all * elements of the fontpath until exhausted */ FPRINTF((stderr, "Get fontpath\n")); if (!fontpath) return NULL; if (!p) { /* init section */ p = fontpath; if (!limit) limit = last; } else { /* skip over '\0' */ p += strlen(p) + 1; } if (p >= limit) limit = p = NULL; return p; case ACTION_NULL: /* just return */ default: break; } /* should always be ignored - points to the * first path in the list */ return fontpath; }
char * locale_handler(int action, char *newlocale) { struct tm tm; int i; switch(action) { case ACTION_CLEAR: case ACTION_INIT: free(current_locale); #ifdef HAVE_LOCALE_H setlocale(LC_TIME, ""); setlocale(LC_CTYPE, ""); current_locale = gp_strdup(setlocale(LC_TIME,NULL)); #else current_locale = gp_strdup(INITIAL_LOCALE); #endif break; case ACTION_SET: #ifdef HAVE_LOCALE_H if (setlocale(LC_TIME, newlocale)) { free(current_locale); current_locale = gp_strdup(setlocale(LC_TIME,NULL)); } else { int_error(c_token, "Locale not available"); } /* we can do a *lot* better than this ; eg use system functions * where available; create values on first use, etc */ memset(&tm, 0, sizeof(struct tm)); for (i = 0; i < 7; ++i) { tm.tm_wday = i; /* hope this enough */ strftime(full_day_names[i], sizeof(full_day_names[i]), "%A", &tm); strftime(abbrev_day_names[i], sizeof(abbrev_day_names[i]), "%a", &tm); } for (i = 0; i < 12; ++i) { tm.tm_mon = i; /* hope this enough */ strftime(full_month_names[i], sizeof(full_month_names[i]), "%B", &tm); strftime(abbrev_month_names[i], sizeof(abbrev_month_names[i]), "%b", &tm); } #else current_locale = gp_realloc(current_locale, strlen(newlocale) + 1, "locale"); strcpy(current_locale, newlocale); #endif /* HAVE_LOCALE_H */ break; case ACTION_SHOW: #ifdef HAVE_LOCALE_H fprintf(stderr, "\tgnuplot LC_CTYPE %s\n", setlocale(LC_CTYPE,NULL)); fprintf(stderr, "\tgnuplot encoding %s\n", encoding_names[encoding]); fprintf(stderr, "\tgnuplot LC_TIME %s\n", setlocale(LC_TIME,NULL)); fprintf(stderr, "\tgnuplot LC_NUMERIC %s\n", numeric_locale ? numeric_locale : "C"); #else fprintf(stderr, "\tlocale is \"%s\"\n", current_locale); #endif break; case ACTION_GET: default: break; } return current_locale; }
/* convert a struct value to a string */ char * value_to_str(struct value *val, TBOOLEAN need_quotes) { static int i = 0; static char * s[4] = {NULL, NULL, NULL, NULL}; static size_t c[4] = {0, 0, 0, 0}; static const int minbufsize = 54; int j = i; i = (i + 1) % 4; if (s[j] == NULL) { s[j] = (char *) gp_alloc(minbufsize, "value_to_str"); c[j] = minbufsize; } switch (val->type) { case INTGR: sprintf(s[j], "%d", val->v.int_val); break; case CMPLX: if (isnan(val->v.cmplx_val.real)) sprintf(s[j], "NaN"); else if (val->v.cmplx_val.imag != 0.0) sprintf(s[j], "{%s, %s}", num_to_str(val->v.cmplx_val.real), num_to_str(val->v.cmplx_val.imag)); else return num_to_str(val->v.cmplx_val.real); break; case STRING: if (val->v.string_val) { if (!need_quotes) { return val->v.string_val; } else { char * cstr = conv_text(val->v.string_val); size_t reqsize = strlen(cstr) + 3; if (reqsize > c[j]) { /* Don't leave c[j[ non-zero if realloc fails */ s[j] = (char *) gp_realloc(s[j], reqsize + 20, NULL); if (s[j] != NULL) { c[j] = reqsize + 20; } else { c[j] = 0; int_error(NO_CARET, "out of memory"); } } sprintf(s[j], "\"%s\"", cstr); } } else { s[j][0] = NUL; } break; case DATABLOCK: { char **dataline = val->v.data_array; int nlines = 0; if (dataline != NULL) { while (*dataline++ != NULL) nlines++; } sprintf(s[j], "<%d line data block>", nlines); break; } default: int_error(NO_CARET, "unknown type in value_to_str()"); } return s[j]; }
/* * char *loadpath_handler (int, char *) * */ char * loadpath_handler(int action, char *path) { /* loadpath variable * the path elements are '\0' separated (!) * this way, reading out loadpath is very * easy to implement */ static char *loadpath; /* index pointer, end of loadpath, * env section of loadpath, current limit, in that order */ static char *p, *last, *envptr, *limit; #ifdef X11 char *appdir; #endif switch (action) { case ACTION_CLEAR: /* Clear loadpath, fall through to init */ FPRINTF((stderr, "Clear loadpath\n")); free(loadpath); loadpath = p = last = NULL; /* HBB 20000726: 'limit' has to be initialized to NULL, too! */ limit = NULL; case ACTION_INIT: /* Init loadpath from environment */ FPRINTF((stderr, "Init loadpath from environment\n")); assert(loadpath == NULL); if (!loadpath) { char *envlib = getenv("GNUPLOT_LIB"); if (envlib) { int len = strlen(envlib); loadpath = gp_strdup(envlib); /* point to end of loadpath */ last = loadpath + len; /* convert all PATHSEPs to \0 */ PATHSEP_TO_NUL(loadpath); } /* else: NULL = empty */ } /* else: already initialised; int_warn (?) */ /* point to env portion of loadpath */ envptr = loadpath; break; case ACTION_SET: /* set the loadpath */ FPRINTF((stderr, "Set loadpath\n")); if (path && *path != NUL) { /* length of env portion */ size_t elen = last - envptr; size_t plen = strlen(path); if (loadpath && envptr) { /* we are prepending a path name; because * realloc() preserves only the contents up * to the minimum of old and new size, we move * the part to be preserved to the beginning * of the string; use memmove() because strings * may overlap */ memmove(loadpath, envptr, elen + 1); } loadpath = gp_realloc(loadpath, elen + 1 + plen + 1, "expand loadpath"); /* now move env part back to the end to make space for * the new path */ memmove(loadpath + plen + 1, loadpath, elen + 1); strcpy(loadpath, path); /* separate new path(s) and env path(s) */ loadpath[plen] = PATHSEP; /* adjust pointer to env part and last */ envptr = &loadpath[plen+1]; last = envptr + elen; PATHSEP_TO_NUL(loadpath); } /* else: NULL = empty */ break; case ACTION_SHOW: /* print the current, full loadpath */ FPRINTF((stderr, "Show loadpath\n")); if (loadpath) { fputs("\tloadpath is ", stderr); PRINT_PATHLIST(loadpath, envptr); if (envptr) { /* env part */ fputs("\tloadpath from GNUPLOT_LIB is ", stderr); PRINT_PATHLIST(envptr, last); } } else fputs("\tloadpath is empty\n", stderr); #ifdef GNUPLOT_SHARE_DIR fprintf(stderr,"\tgnuplotrc is read from %s\n",GNUPLOT_SHARE_DIR); #endif #ifdef X11 if ((appdir = getenv("XAPPLRESDIR"))) { fprintf(stderr,"\tenvironmental path for X11 application defaults: \"%s\"\n", appdir); } #ifdef XAPPLRESDIR else { fprintf(stderr,"\tno XAPPLRESDIR found in the environment,\n"); fprintf(stderr,"\t falling back to \"%s\"\n", XAPPLRESDIR); } #endif #endif break; case ACTION_SAVE: /* we don't save the load path taken from the * environment, so don't go beyond envptr when * extracting the path elements */ limit = envptr; case ACTION_GET: /* subsequent calls to get_loadpath() return all * elements of the loadpath until exhausted */ FPRINTF((stderr, "Get loadpath\n")); if (!loadpath) return NULL; if (!p) { /* init section */ p = loadpath; if (!limit) limit = last; } else { /* skip over '\0' */ p += strlen(p) + 1; } if (p >= limit) limit = p = NULL; return p; break; case ACTION_NULL: /* just return */ default: break; } /* should always be ignored - points to the * first path in the list */ return loadpath; }
/* * Binned histogram of input values. * plot FOO using N:(1) bins{=<nbins>} {binrange=[binlow:binhigh]} with boxes * If no binrange is given, the range is taken from the x axis range. * In the latter case "set xrange" may exclude some data points, * while "set auto x" will include all data points. */ void make_bins(struct curve_points *plot, int nbins, double binlow, double binhigh) { int i, binno; double *bin; double bottom, top, binwidth, range; struct axis *xaxis = &axis_array[plot->x_axis]; struct axis *yaxis = &axis_array[plot->y_axis]; double ymax = 0; int N = plot->p_count; /* Divide the range on X into the requested number of bins. * NB: This range is independent of the values of the points. */ if (binlow == 0 && binhigh == 0) { bottom = xaxis->data_min; top = xaxis->data_max; } else { bottom = binlow; top = binhigh; } bottom = axis_log_value(xaxis, bottom); top = axis_log_value(xaxis, top); binwidth = (top - bottom) / (nbins - 1); bottom -= binwidth/2.; top += binwidth/2.; range = top - bottom; bin = gp_alloc(nbins*sizeof(double), "bins"); for (i=0; i<nbins; i++) bin[i] = 0; for (i=0; i<N; i++) { if (plot->points[i].type == UNDEFINED) continue; binno = floor(nbins * (plot->points[i].x - bottom) / range); /* FIXME: Should outrange points be dumped in the first/last bin? */ if (0 <= binno && binno < nbins) bin[binno] += axis_de_log_value(yaxis, plot->points[i].y); } if (xaxis->autoscale & AUTOSCALE_MIN) { if (xaxis->min > bottom) xaxis->min = bottom; } if (xaxis->autoscale & AUTOSCALE_MAX) { if (xaxis->max < top) xaxis->max = top; } /* Replace the original data with one entry per bin. * new x = midpoint of bin * new y = number of points in the bin */ plot->p_count = nbins; plot->points = gp_realloc( plot->points, nbins * sizeof(struct coordinate), "curve_points"); for (i=0; i<nbins; i++) { double bincent = bottom + (0.5 + (double)i) * binwidth; plot->points[i].type = INRANGE; plot->points[i].x = bincent; plot->points[i].xlow = bincent - binwidth/2.; plot->points[i].xhigh = bincent + binwidth/2.; plot->points[i].y = axis_log_value(yaxis, bin[i]); plot->points[i].ylow = plot->points[i].y; plot->points[i].yhigh = plot->points[i].y; plot->points[i].z = 0; /* FIXME: leave it alone? */ if (inrange(axis_de_log_value(xaxis, bincent), xaxis->min, xaxis->max)) { if (ymax < bin[i]) ymax = bin[i]; } else { plot->points[i].type = OUTRANGE; } FPRINTF((stderr, "bin[%d] %g %g\n", i, plot->points[i].x, plot->points[i].y)); } if (yaxis->autoscale & AUTOSCALE_MIN) { if (yaxis->min > 0) yaxis->min = 0; } if (yaxis->autoscale & AUTOSCALE_MAX) { if (yaxis->max < ymax) yaxis->max = ymax; } /* Clean up */ free(bin); }
/* EAM July 2004 (revised to dynamic buffer July 2005) * There are probably an infinite number of things that can * go wrong if the user mis-matches arguments and format strings * in the call to sprintf, but I hope none will do worse than * result in a garbage output string. */ void f_sprintf(union argument *arg) { struct value a[10], *args; struct value num_params; struct value result; char *buffer; int bufsize; char *next_start, *outpos, tempchar; int next_length; char *prev_start; int prev_pos; int i, remaining; int nargs = 0; enum DATA_TYPES spec_type; /* Retrieve number of parameters from top of stack */ pop(&num_params); nargs = num_params.v.int_val; if (nargs > 10) { /* Fall back to slow but sure allocation */ args = gp_alloc(sizeof(struct value)*nargs, "sprintf args"); } else args = a; for (i=0; i<nargs; i++) pop(&args[i]); /* pop next argument */ /* Make sure we got a format string of some sort */ if (args[nargs-1].type != STRING) int_error(NO_CARET,"First parameter to sprintf must be a format string"); /* Allocate space for the output string. If this isn't */ /* long enough we can reallocate a larger space later. */ bufsize = 80 + strlen(args[nargs-1].v.string_val); buffer = gp_alloc(bufsize, "f_sprintf"); /* Copy leading fragment of format into output buffer */ outpos = buffer; next_start = args[nargs-1].v.string_val; next_length = strcspn(next_start,"%"); strncpy(outpos, next_start, next_length); next_start += next_length; outpos += next_length; /* Format the remaining sprintf() parameters one by one */ prev_start = next_start; prev_pos = next_length; remaining = nargs - 1; /* If the user has set an explicit LC_NUMERIC locale, apply it */ /* to sprintf calls during expression evaluation. */ set_numeric_locale(); /* Each time we start this loop we are pointing to a % character */ while (remaining-->0 && next_start[0] && next_start[1]) { struct value *next_param = &args[remaining]; /* Check for %%; print as literal and don't consume a parameter */ if (!strncmp(next_start,"%%",2)) { next_start++; do { *outpos++ = *next_start++; } while(*next_start && *next_start != '%'); remaining++; continue; } next_length = strcspn(next_start+1,"%") + 1; tempchar = next_start[next_length]; next_start[next_length] = '\0'; spec_type = sprintf_specifier(next_start); /* string value <-> numerical value check */ if ( spec_type == STRING && next_param->type != STRING ) int_error(NO_CARET,"f_sprintf: attempt to print numeric value with string format"); if ( spec_type != STRING && next_param->type == STRING ) int_error(NO_CARET,"f_sprintf: attempt to print string value with numeric format"); #ifdef HAVE_SNPRINTF /* Use the format to print next arg */ switch(spec_type) { case INTGR: snprintf(outpos,bufsize-(outpos-buffer), next_start, (int)real(next_param)); break; case CMPLX: snprintf(outpos,bufsize-(outpos-buffer), next_start, real(next_param)); break; case STRING: snprintf(outpos,bufsize-(outpos-buffer), next_start, next_param->v.string_val); break; default: int_error(NO_CARET,"internal error: invalid spec_type"); } #else /* FIXME - this is bad; we should dummy up an snprintf equivalent */ switch(spec_type) { case INTGR: sprintf(outpos, next_start, (int)real(next_param)); break; case CMPLX: sprintf(outpos, next_start, real(next_param)); break; case STRING: sprintf(outpos, next_start, next_param->v.string_val); break; default: int_error(NO_CARET,"internal error: invalid spec_type"); } #endif next_start[next_length] = tempchar; next_start += next_length; outpos = &buffer[strlen(buffer)]; /* Check whether previous parameter output hit the end of the buffer */ /* If so, reallocate a larger buffer, go back and try it again. */ if (strlen(buffer) >= bufsize-2) { bufsize *= 2; buffer = gp_realloc(buffer, bufsize, "f_sprintf"); next_start = prev_start; outpos = buffer + prev_pos; remaining++; continue; } else { prev_start = next_start; prev_pos = outpos - buffer; } } /* Copy the trailing portion of the format, if any */ /* We could just call snprintf(), but it doesn't check for */ /* whether there really are more variables to handle. */ i = bufsize - (outpos-buffer); while (*next_start && --i > 0) { if (*next_start == '%' && *(next_start+1) == '%') next_start++; *outpos++ = *next_start++; } *outpos = '\0'; FPRINTF((stderr," snprintf result = \"%s\"\n",buffer)); push(Gstring(&result, buffer)); free(buffer); /* Free any strings from parameters we have now used */ for (i=0; i<nargs; i++) gpfree_string(&args[i]); if (args != a) free(args); /* Return to C locale for internal use */ reset_numeric_locale(); }
char * readline(const char *prompt) { int cur_char; char *new_line; /* start with a string of MAXBUF chars */ if (line_len != 0) { free(cur_line); line_len = 0; } cur_line = gp_alloc(MAXBUF, "readline"); line_len = MAXBUF; /* set the termio so we can do our own input processing */ set_termio(); /* print the prompt */ fputs(prompt, stderr); cur_line[0] = '\0'; cur_pos = 0; max_pos = 0; cur_entry = NULL; /* get characters */ for (;;) { cur_char = special_getc(); /* Accumulate ascii (7bit) printable characters * and all leading 8bit characters. */ if ((isprint(cur_char) || (((cur_char & 0x80) != 0) && (cur_char != EOF))) && (cur_char != 0x09) /* TAB is a printable character in some locales */ ) { size_t i; if (max_pos + 1 >= line_len) { extend_cur_line(); } for (i = max_pos; i > cur_pos; i--) { cur_line[i] = cur_line[i - 1]; } user_putc(cur_char); cur_line[cur_pos] = cur_char; cur_pos += 1; max_pos += 1; cur_line[max_pos] = '\0'; if (cur_pos < max_pos) { switch (encoding) { case S_ENC_UTF8: if ((cur_char & 0xc0) == 0) fix_line(); /* Normal ascii character */ else if ((cur_char & 0xc0) == 0xc0) ; /* start of a multibyte sequence. */ else if (((cur_char & 0xc0) == 0x80) && ((unsigned char)(cur_line[cur_pos-2]) >= 0xe0)) ; /* second byte of a >2 byte sequence */ else { /* Last char of multi-byte sequence */ fix_line(); } break; default: fix_line(); break; } } /* else interpret unix terminal driver characters */ #ifdef VERASE } else if (cur_char == term_chars[VERASE]) { /* ^H */ delete_backward(); #endif /* VERASE */ #ifdef VEOF } else if (cur_char == term_chars[VEOF]) { /* ^D? */ if (max_pos == 0) { reset_termio(); return ((char *) NULL); } delete_forward(); #endif /* VEOF */ #ifdef VKILL } else if (cur_char == term_chars[VKILL]) { /* ^U? */ clear_line(prompt); #endif /* VKILL */ #ifdef VWERASE } else if (cur_char == term_chars[VWERASE]) { /* ^W? */ delete_previous_word(); #endif /* VWERASE */ #ifdef VREPRINT } else if (cur_char == term_chars[VREPRINT]) { /* ^R? */ putc(NEWLINE, stderr); /* go to a fresh line */ redraw_line(prompt); #endif /* VREPRINT */ #ifdef VSUSP } else if (cur_char == term_chars[VSUSP]) { reset_termio(); kill(0, SIGTSTP); /* process stops here */ set_termio(); /* print the prompt */ redraw_line(prompt); #endif /* VSUSP */ } else { /* do normal editing commands */ /* some of these are also done above */ switch (cur_char) { case EOF: reset_termio(); return ((char *) NULL); case 001: /* ^A */ while (cur_pos > 0) backspace(); break; case 002: /* ^B */ if (cur_pos > 0) backspace(); break; case 005: /* ^E */ while (cur_pos < max_pos) { user_putc(cur_line[cur_pos]); cur_pos += 1; } break; case 006: /* ^F */ if (cur_pos < max_pos) { step_forward(); } break; #if defined(HAVE_DIRENT_H) || defined(WIN32) case 011: /* ^I / TAB */ tab_completion(TRUE); /* next tab completion */ break; case 034: /* remapped by wtext.c or ansi_getc from Shift-Tab */ tab_completion(FALSE); /* previous tab completion */ break; #endif case 013: /* ^K */ clear_eoline(prompt); max_pos = cur_pos; break; case 020: /* ^P */ if (history != NULL) { if (cur_entry == NULL) { cur_entry = history; clear_line(prompt); copy_line(cur_entry->line); } else if (cur_entry->prev != NULL) { cur_entry = cur_entry->prev; clear_line(prompt); copy_line(cur_entry->line); } } break; case 016: /* ^N */ if (cur_entry != NULL) { cur_entry = cur_entry->next; clear_line(prompt); if (cur_entry != NULL) copy_line(cur_entry->line); else cur_pos = max_pos = 0; } break; case 014: /* ^L */ case 022: /* ^R */ putc(NEWLINE, stderr); /* go to a fresh line */ redraw_line(prompt); break; #ifndef DEL_ERASES_CURRENT_CHAR case 0177: /* DEL */ case 023: /* Re-mapped from CSI~3 in ansi_getc() */ #endif case 010: /* ^H */ delete_backward(); break; case 004: /* ^D */ if (max_pos == 0) { reset_termio(); return ((char *) NULL); } /* intentionally omitting break */ #ifdef DEL_ERASES_CURRENT_CHAR case 0177: /* DEL */ case 023: /* Re-mapped from CSI~3 in ansi_getc() */ #endif delete_forward(); break; case 025: /* ^U */ clear_line(prompt); break; case 027: /* ^W */ delete_previous_word(); break; case '\n': /* ^J */ case '\r': /* ^M */ cur_line[max_pos + 1] = '\0'; #ifdef OS2 while (cur_pos < max_pos) { user_putc(cur_line[cur_pos]); cur_pos += 1; } #endif putc(NEWLINE, stderr); /* Shrink the block down to fit the string ? * if the alloc fails, we still own block at cur_line, * but this shouldn't really fail. */ new_line = (char *) gp_realloc(cur_line, strlen(cur_line) + 1, "line resize"); if (new_line) cur_line = new_line; /* else we just hang on to what we had - it's not a problem */ line_len = 0; FPRINTF((stderr, "Resizing input line to %d chars\n", strlen(cur_line))); reset_termio(); return (cur_line); default: break; } } } }
/* * Binned histogram of input values. * * plot FOO using N:(1) bins{=<nbins>} {binrange=[binlow:binhigh]} * {binwidth=<width>} with boxes * * This option is EXPERIMENTAL, details may change before inclusion in a stable * gnuplot release. * * If no binrange is given, binlow and binhigh are taken from the x range of the data. * In either of these cases binlow is the midpoint x-coordinate of the first bin * and binhigh is the midpoint x-coordinate of the last bin. * Points that lie exactly on a bin boundary are assigned to the upper bin. * Bin assignments are not affected by "set xrange". * Notes: * binwidth = (binhigh-binlow) / (nbins-1) * xmin = binlow - binwidth/2 * xmax = binhigh + binwidth/2 * first bin holds points with (xmin =< x < xmin + binwidth) * last bin holds points with (xmax-binwidth =< x < binhigh + binwidth) */ void make_bins(struct curve_points *plot, int nbins, double binlow, double binhigh, double binwidth) { int i, binno; double *bin; double bottom, top, range; struct axis *xaxis = &axis_array[plot->x_axis]; struct axis *yaxis = &axis_array[plot->y_axis]; double ymax = 0; int N = plot->p_count; /* Find the range of points to be binned */ if (binlow != binhigh) { /* Explicit binrange [min:max] in the plot command */ bottom = binlow; top = binhigh; } else { /* Take binrange from the data itself */ bottom = VERYLARGE; top = -VERYLARGE; for (i=0; i<N; i++) { if (bottom > plot->points[i].x) bottom = plot->points[i].x; if (top < plot->points[i].x) top = plot->points[i].x; } if (top <= bottom) int_warn(NO_CARET, "invalid bin range [%g:%g]", bottom, top); } /* If a fixed binwidth was provided, find total number of bins */ if (binwidth > 0) { double temp; nbins = 1 + (top - bottom) / binwidth; temp = nbins * binwidth - (top - bottom); bottom -= temp/2.; top += temp/2.; } /* otherwise we use (N-1) intervals between midpoints of bin 1 and bin N */ else { binwidth = (top - bottom) / (nbins - 1); bottom -= binwidth/2.; top += binwidth/2.; } range = top - bottom; FPRINTF((stderr,"make_bins: %d bins from %g to %g, binwidth %g\n", nbins, bottom, top, binwidth)); bin = gp_alloc(nbins*sizeof(double), "bins"); for (i=0; i<nbins; i++) bin[i] = 0; for (i=0; i<N; i++) { if (plot->points[i].type == UNDEFINED) continue; binno = floor(nbins * (plot->points[i].x - bottom) / range); if (0 <= binno && binno < nbins) bin[binno] += plot->points[i].y; } if (xaxis->autoscale & AUTOSCALE_MIN) { if (xaxis->min > bottom) xaxis->min = bottom; } if (xaxis->autoscale & AUTOSCALE_MAX) { if (xaxis->max < top) xaxis->max = top; } /* Replace the original data with one entry per bin. * new x = midpoint of bin * new y = number of points in the bin */ plot->p_count = nbins; plot->points = gp_realloc( plot->points, nbins * sizeof(struct coordinate), "curve_points"); for (i=0; i<nbins; i++) { double bincent = bottom + (0.5 + (double)i) * binwidth; plot->points[i].type = INRANGE; plot->points[i].x = bincent; plot->points[i].xlow = bincent - binwidth/2.; plot->points[i].xhigh = bincent + binwidth/2.; plot->points[i].y = bin[i]; plot->points[i].ylow = plot->points[i].y; plot->points[i].yhigh = plot->points[i].y; plot->points[i].z = 0; /* FIXME: leave it alone? */ if (inrange(bincent, xaxis->min, xaxis->max)) { if (ymax < bin[i]) ymax = bin[i]; } else { plot->points[i].type = OUTRANGE; } FPRINTF((stderr, "bin[%d] %g %g\n", i, plot->points[i].x, plot->points[i].y)); } if (yaxis->autoscale & AUTOSCALE_MIN) { if (yaxis->min > 0) yaxis->min = 0; } if (yaxis->autoscale & AUTOSCALE_MAX) { if (yaxis->max < ymax) yaxis->max = ymax; } /* Clean up */ free(bin); }