2 static char *RCSid() { return RCSid("$Id: binary.c,v 1.12.2.1 2007/10/02 18:20:30 sfeam Exp $"); }
6 * The addition of gnubin and binary, along with a small patch
7 * to command.c, will permit gnuplot to plot binary files.
8 * gnubin - contains the code that relies on gnuplot include files
9 * and other definitions
10 * binary - contains those things that are independent of those
11 * definitions and files
13 * With these routines, hidden line removal of your binary data is possible!
15 * Last update: 3/29/92 memory allocation bugs fixed. jvdwoude@hut.nl
16 * 3/09/92 spelling errors, general cleanup, use alloc with no
18 * 3/03/92 for Gnuplot 3.24.
19 * Created from code for written by RKC for gnuplot 2.0b.
21 * Copyright (c) 1991,1992 Robert K. Cunningham, MIT Lincoln Laboratory
25 /* NOTE: a significant fraction of these routines is not called from
26 * anywhere in gnuplot. They're provided as a utility library for
27 * people wanting to write binary files usable by gnuplot, as the
28 * bf_test.c demo does it. */
35 /* This routine scans the first block of the file to see if the file
36 * is a binary file. A file is considered binary if 10% of the
37 * characters in it are not in the ascii character set. (values <
38 * 128), or if a NUL is found. I hope this doesn't break when used on
39 * the bizzare PC's. */
41 is_binary_file(FILE *fp)
44 int odd; /* Contains a count of the odd characters */
47 unsigned char buffer[512];
49 if ((where = ftell(fp)) == -1) { /* Find out where we start */
50 fprintf(stderr, "Notice: Assuming unseekable data is not binary\n");
55 len = fread(buffer, sizeof(char), 512, fp);
56 if (len <= 0) /* Empty file is declared ascii */
61 /* now scan buffer to look for odd characters */
63 for (i = 0; i < len; i++, c++) {
64 if (!*c) { /* NUL _never_ allowed in text */
67 } else if ((*c & 128) || /* Meta-characters--we hope it's not formatting */
68 (*c == 127) || /* DEL */
70 *c != '\n' && *c != '\r' && *c != '\b' &&
71 *c != '\t' && *c != '\f' && *c != 27 /*ESC */ ))
75 fseek(fp, where, 0); /* Go back to where we started */
77 if (odd * 10 > len) /* allow 10% of the characters to be odd */
85 /*========================= I/O Routines ================================
86 These may be useful for situations other than just gnuplot. Note that I
87 have included the reading _and_ the writing routines, so others can create
88 the file as well as read the file.
91 #define START_ROWS 100 /* Each of these must be at least 1 */
95 /* This function reads a matrix from a stream
97 * This routine never returns anything other than vectors and arrays
98 * that range from 0 to some number. */
102 float GPFAR * GPFAR * GPFAR * ret_matrix,
104 float GPFAR * GPFAR * row_title,
105 float GPFAR * GPFAR * column_title)
107 float GPFAR * GPFAR * m, GPFAR * rt, GPFAR * ct;
108 int num_rows = START_ROWS;
111 float GPFAR * GPFAR * temp_array;
114 if (fread(&fdummy, sizeof(fdummy), 1, fin) != 1)
117 num_cols = (size_t) fdummy;
119 /* Choose a reasonable number of rows, allocate space for it and
120 * continue until this space runs out, then extend the matrix as
122 ct = alloc_vector(0, num_cols - 1);
123 fread(ct, sizeof(*ct), num_cols, fin);
125 rt = alloc_vector(0, num_rows - 1);
126 m = matrix(0, num_rows - 1, 0, num_cols - 1);
128 while (fread(&rt[current_row], sizeof(rt[current_row]), 1, fin) == 1) {
129 /* We've got another row */
130 if (fread(m[current_row], sizeof(*(m[current_row])), num_cols, fin) != num_cols)
131 return (FALSE); /* Not a True matrix */
134 if (current_row >= num_rows) { /* We've got to make a bigger rowsize */
135 temp_array = extend_matrix(m, 0, num_rows - 1, 0, num_cols - 1,
136 num_rows + ADD_ROWS - 1, num_cols - 1);
137 rt = extend_vector(rt, 0, num_rows + ADD_ROWS - 1);
139 num_rows += ADD_ROWS;
143 /* finally we force the matrix to be the correct row size */
144 /* bug fixed. procedure called with incorrect 6th argument.
146 temp_array = retract_matrix(m, 0, num_rows - 1, 0, num_cols - 1, current_row - 1, num_cols - 1);
147 /* Now save the things that change */
148 *ret_matrix = temp_array;
149 *row_title = retract_vector(rt, 0, current_row - 1);
151 *nr = current_row; /* Really the total number of rows */
156 /* This writes a matrix to a stream
158 * Note that our ranges are inclusive ranges--and we can specify
159 * subsets. This behaves similarly to the xrange and yrange operators
160 * in gnuplot that we all are familiar with.
165 float GPFAR * GPFAR *m,
166 int nrl, int nrh, int ncl, int nch,
167 float GPFAR *row_title,
168 float GPFAR *column_title)
174 float GPFAR *title = NULL;
176 length = (float) (col_length = nch - ncl + 1);
178 if ((status = fwrite((char *) &length, sizeof(float), 1, fout)) != 1) {
179 fprintf(stderr, "fwrite 1 returned %d\n", status);
183 column_title = title = alloc_vector(ncl, nch);
184 for (j = ncl; j <= nch; j++)
185 title[j] = (float) j;
187 fwrite((char *) column_title, sizeof(float), col_length, fout);
189 free_vector(title, ncl);
193 row_title = title = alloc_vector(nrl, nrh);
194 for (j = nrl; j <= nrh; j++)
195 title[j] = (float) j;
197 for (j = nrl; j <= nrh; j++) {
198 fwrite((char *) &row_title[j], sizeof(float), 1, fout);
199 fwrite((char *) (m[j] + ncl), sizeof(float), col_length, fout);
202 free_vector(title, nrl);
207 /*===================== Support routines ==============================*/
209 /* ******************************* VECTOR *******************************
210 * The following routines interact with vectors.
212 * If there is an error we don't really return - int_error breaks us out.
214 * This subroutine based on a subroutine listed in "Numerical Recipies in C",
215 * by Press, Flannery, Teukoilsky and Vetterling (1988).
219 alloc_vector(int nl, int nh)
223 if (! (vec = gp_alloc((nh - nl + 1) * sizeof(float), NULL))) {
224 int_error(NO_CARET, "not enough memory to create vector");
225 return NULL; /* Not reached */
232 * Free a vector allocated above
234 * This subroutine based on a subroutine listed in "Numerical Recipies in C",
235 * by Press, Flannery, Teukoilsky and Vetterling (1988).
239 free_vector(float GPFAR *vec, int nl)
244 /************ Routines to modify the length of a vector ****************/
246 extend_vector(float GPFAR *vec, int old_nl, int new_nh)
248 float GPFAR *new_v = gp_realloc((vec + old_nl),
249 (new_nh - old_nl + 1) * sizeof(new_v[0]),
250 "extend/retract vector");
251 return new_v - old_nl;
255 retract_vector(float GPFAR *v, int old_nl, int new_nh)
257 return extend_vector(v, old_nl, new_nh);
261 /* **************************** MATRIX ************************
263 * The following routines work with matricies
265 * I always get confused with this, so here I write it down:
266 * for nrl<= nri <=nrh and
267 * for ncl<= ncj <=nch
269 * This matrix is accessed as:
272 * where nri is the offset to the pointer to a vector where the
273 * ncjth element lies.
275 * If there is an error we don't really return - int_error breaks us out.
277 * This subroutine based on a subroutine listed in "Numerical Recipies in C",
278 * by Press, Flannery, Teukoilsky and Vetterling (1988).
281 float GPFAR * GPFAR *
282 matrix(int nrl, int nrh, int ncl, int nch)
285 float GPFAR * GPFAR * m;
287 m = gp_alloc((nrh - nrl + 1) * sizeof(m[0]), "matrix rows");
290 for (i = nrl; i <= nrh; i++) {
291 if (!(m[i] = gp_alloc((nch - ncl + 1) * sizeof(m[i][0]), NULL))) {
292 free_matrix(m, nrl, i - 1, ncl);
293 int_error(NO_CARET, "not enough memory to create matrix");
302 * Free a matrix allocated above
305 * This subroutine based on a subroutine listed in "Numerical Recipies in C",
306 * by Press, Flannery, Teukoilsky and Vetterling (1988).
311 float GPFAR * GPFAR * m,
312 int nrl, int nrh, int ncl)
316 for (i = nrl; i <= nrh; i++)
321 /* This routine takes a sub matrix and extends the number of rows and
322 * columns for a new matrix */
323 float GPFAR * GPFAR *
325 float GPFAR * GPFAR * a,
326 int nrl, int nrh, int ncl, int nch,
330 float GPFAR * GPFAR * m;
332 m = gp_realloc(a + nrl, (srh - nrl + 1) * sizeof(m[0]),
337 for (i = nrl; i <= nrh; i++) { /* Copy and extend rows */
338 if (!(m[i] = extend_vector(m[i], ncl, sch))) {
339 free_matrix(m, nrl, nrh, ncl);
340 int_error(NO_CARET, "not enough memory to extend matrix");
345 for (i = nrh + 1; i <= srh; i++) {
346 if (!(m[i] = gp_alloc((nch - ncl + 1) * sizeof(m[i][0]), NULL))) {
347 free_matrix(m, nrl, i - 1, nrl);
348 int_error(NO_CARET, "not enough memory to extend matrix");
355 /* this routine carves a large matrix down to size */
356 float GPFAR * GPFAR *
358 float GPFAR * GPFAR * a,
359 int nrl, int nrh, int ncl, int nch,
363 float GPFAR * GPFAR * m;
365 for (i = srh + 1; i <= nrh; i++) {
366 free_vector(a[i], ncl);
369 m = gp_realloc(a + nrl, (srh - nrl + 1) * sizeof(m[0]),
374 for (i = nrl; i <= srh; i++)
375 if (!(m[i] = retract_vector(m[i], ncl, sch))) {
377 free_matrix(m, nrl, srh, ncl);
378 int_error(NO_CARET, "not enough memory to retract matrix");
386 /* allocate a float matrix m[nrl...nrh][ncl...nch] that points to the
387 matrix declared in the standard C manner as a[nrow][ncol], where
388 nrow=nrh-nrl+1, ncol=nch-ncl+1. The routine should be called with
389 the address &a[0][0] as the first argument. This routine does
390 not free the memory used by the original array a but merely assigns
391 pointers to the rows. */
393 float GPFAR * GPFAR *
396 int nrl, int nrh, int ncl, int nch)
398 int i, j, ncol, nrow;
399 float GPFAR * GPFAR * m;
401 nrow = nrh - nrl + 1;
402 ncol = nch - ncl + 1;
403 m = gp_alloc((nrh - nrl + 1) * sizeof(m[0]),
408 for (i = 1, j = nrl + 1; i <= nrow - 1; i++, j++)
409 m[j] = m[j - 1] + ncol;
415 free_convert_matrix(float GPFAR * GPFAR * b, int nrl)