SDDSlib
Loading...
Searching...
No Matches
mcTable.c
Go to the documentation of this file.
1/**
2 * @file mcTable.c
3 * @brief Read and write routines for Multi-Column Tables.
4 *
5 * This file contains functions to handle multi-column table operations,
6 * including reading from and writing to table files. It provides mechanisms
7 * to parse table headers, handle auxiliary quantities, and manage table data.
8 *
9 * @copyright
10 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
11 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
12 *
13 * @license
14 * This file is distributed under the terms of the Software License Agreement
15 * found in the file LICENSE included with this distribution.
16 *
17 * @author M. Borland, C. Saunders, R. Soliday
18 */
19
20#include "mdb.h"
21#include "column.h"
22#include <ctype.h>
23
24#define DEBUG 0
25
26static char buffer[1024];
27static char buffer1[1024];
28char *fgets_mc_skip(char *s, long slen, FILE *fp, char skip_char);
29void get_name_unit_descrip_format(char **name, char **unit, char **descrip, char **format, char *_buffer);
30
31/**
32 * @brief Reads a multi-column table from a file.
33 *
34 * Parses the specified file to populate the MC_TABLE structure with
35 * column information, auxiliary quantities, and table data.
36 *
37 * @param table Pointer to the MC_TABLE structure to populate.
38 * @param file Path to the table file to read.
39 * @param flags Flags to control warning messages and behavior.
40 * @return Returns 1 on success, 0 on failure.
41 */
42long get_mc_table(MC_TABLE *table, char *file, long flags) {
43 FILE *fpi;
44 long i, j, i_col;
45 char *ptr;
46
47 if (!(fpi = fopen_e(file, "r", 1)))
48 return (0);
49
50 if (!fgets_mc_skip(buffer, 1024, fpi, '!'))
51 bomb("unable to read first line of table file", NULL);
52 if (!(get_long(&table->n_cols, buffer)))
53 bomb("unable to scan number of columns in table file", NULL);
54 if (table->n_cols <= 0)
55 bomb("number of columns is invalid in table file", NULL);
56 table->n_lines_per_row = 1;
57 table->n_auxiliaries = 0;
58 if (get_long(&table->n_lines_per_row, buffer)) {
59 if (table->n_lines_per_row <= 0)
60 bomb("number of lines per row is invalid in table file", NULL);
61 if (get_long(&table->n_auxiliaries, buffer) &&
62 table->n_auxiliaries < 0)
63 bomb("number of auxiliary quantities is invalid in table file", NULL);
64 }
65
66#if DEBUG
67 printf("file %s\nn_cols = %ld n_lines_per_row = %ld n_auxiliaries = %ld\n",
68 file, table->n_cols, table->n_lines_per_row, table->n_auxiliaries);
69#endif
70
71 table->name = tmalloc(sizeof(char *) * table->n_cols);
72 table->unit = tmalloc(sizeof(char *) * table->n_cols);
73 table->description = tmalloc(sizeof(char *) * table->n_cols);
74 table->format = tmalloc(sizeof(char *) * table->n_cols);
75
76 for (i = 0; i < table->n_cols; i++) {
77 if (!fgets_mc_skip(buffer, 1024, fpi, '!'))
78 bomb("missing quantity name and units line in table file", NULL);
79 get_name_unit_descrip_format(table->name + i, table->unit + i,
80 table->description + i, table->format + i, buffer);
81 if (table->format[i] && !strchr(table->format[i], '%'))
82 table->format[i] = NULL;
83 }
84
85#if DEBUG
86 for (i = 0; i < table->n_cols; i++)
87 printf("column %ld: %s in %s--%s in format %s\n",
88 i, table->name[i], table->unit[i], table->description[i],
89 (table->format[i] ? table->format[i] : "{null}"));
90#endif
91
92 if (!fgets_mc_skip(buffer, 1024, fpi, '!'))
93 bomb("missing title string in table file", NULL);
94 cp_str(&table->title, buffer);
95
96 if (!fgets_mc_skip(buffer, 1024, fpi, '!'))
97 bomb("missing label string in table file", NULL);
98 cp_str(&table->label, buffer);
99
100#if DEBUG
101 printf("title: %s\nlabel: %s\n", table->title, table->label);
102#endif
103
104 if (table->n_auxiliaries) {
105#if DEBUG
106 printf("%ld auxuliary quantities are expected\n", table->n_auxiliaries);
107#endif
108 /* get auxiliary quantity names\units... */
109 table->aux_name = tmalloc(sizeof(char *) * table->n_auxiliaries);
110 table->aux_unit = tmalloc(sizeof(char *) * table->n_auxiliaries);
111 table->aux_description = tmalloc(sizeof(char *) * table->n_auxiliaries);
112 table->aux_value = tmalloc(sizeof(*(table->aux_value)) * table->n_auxiliaries);
113 for (i = 0; i < table->n_auxiliaries; i++) {
114 if (!fgets_mc_skip(buffer, 1024, fpi, '!'))
115 bomb("missing quantity name and units line in table file", NULL);
116 get_name_unit_descrip_format(table->aux_name + i, table->aux_unit + i,
117 table->aux_description + i, &ptr, buffer);
118 if ((!ptr || 1 != sscanf(ptr, "%lf", table->aux_value + i)) && flags & GMCT_WARN_MISSING_AUXVAL)
119 printf("warning: missing value for auxiliary quantity %s---zero assumed\n", table->aux_name[i]);
120 }
121 }
122
123#if DEBUG
124 for (i = 0; i < table->n_auxiliaries; i++) {
125 printf("auxiliary %ld: %s = %le %s---%s\n",
126 i, table->aux_name[i], table->aux_value[i], table->aux_unit[i],
127 table->aux_description[i]);
128 }
129#endif
130
131 if (!fgets_mc_skip(buffer, 1024, fpi, '!'))
132 bomb("missing number of data rows in table file", NULL);
133 if (!get_long(&table->n_rows, buffer) || table->n_rows < 0)
134 bomb("invalid number of data rows specified in table file", NULL);
135 if (table->n_rows == 0)
136 return (1);
137
138#if DEBUG
139 printf("n_rows = %ld\n", table->n_rows);
140#endif
141
142 table->value = (double **)zarray_2d(sizeof(double), table->n_cols, table->n_rows);
143 table->row_label = (char **)tmalloc(sizeof(char *) * table->n_rows);
144
145 for (i = 0; i < table->n_rows; i++) {
146 i_col = 0;
147 table->row_label[i] = NULL;
148 for (j = 0; j < table->n_lines_per_row && i_col < table->n_cols; j++) {
149 if (!fgets_mc_skip(buffer, 1024, fpi, '!'))
150 break;
151 strcpy(buffer1, buffer);
152#if DEBUG
153 printf("row %ld, line %ld:\n%s\n", i, j, buffer);
154#endif
155 while (i_col < table->n_cols && get_double(table->value[i_col] + i, buffer))
156 i_col++;
157 }
158
159 if (!is_blank(buffer)) {
160 cp_str(table->row_label + i, buffer);
161 while (isspace(*table->row_label[i]))
162 table->row_label[i]++;
163 } else
164 cp_str(table->row_label + i, "");
165
166 if (i_col == 0) {
167 if (flags & GMCT_WARN_WRONG_COUNT)
168 printf("warning: fewer data rows than expected in file %s\n", file);
169 break;
170 } else if (i_col != table->n_cols) {
171 if (flags & GMCT_WARN_INCOMPLETE_ROW) {
172 printf("warning: incomplete data row in file %s\n", file);
173 printf("line in question is:\n%s\n", buffer1);
174 printf("skipping to next line\n");
175 }
176 i--;
177 continue;
178 }
179#if DEBUG
180 printf("%ld: ", i);
181 for (i_col = 0; i_col < table->n_cols; i_col++)
182 printf("%.4le ", table->value[i_col][i]);
183 putchar('\n');
184#endif
185 }
186 if (i == table->n_rows && fgets_mc_skip(buffer, 1024, fpi, '!') && flags & GMCT_WARN_EXTRA_ROWS)
187 printf("warning: file %s contains extra rows, which are ignored\n",
188 file);
189 table->n_rows = i;
190 return (1);
191}
192
193/* routine: fgets_mc_skip()
194 * purpose: fgets() with skipping of lines according to a comment character
195 */
196
197char *fgets_mc_skip(
198 char *s, /* buffer for lines */
199 long slen, /* length of lines to read */
200 FILE *fp, /* file to read from */
201 char skip_char /* ignore lines that begin with this character */
202) {
203 do {
204 if (!fgets(s, slen, fp))
205 return (NULL);
206 chop_nl(s);
207 if (s[0] != skip_char)
208 break;
209 } while (1);
210 return (s);
211}
212
213long put_mc_table(char *file, MC_TABLE *table) {
214 FILE *fpo;
215 long i, j, wrap;
216
217 if (!(fpo = fopen(file, "w"))) {
218 printf("unable to write to file %s\n", file);
219 return (0);
220 }
221
222 if (table->n_lines_per_row < 1)
223 table->n_lines_per_row = 1;
224
225 put_mc_table_header(fpo, table);
226
227 wrap = table->n_cols / table->n_lines_per_row;
228 for (i = 0; i < table->n_rows; i++) {
229 j = 0;
230 while (j < table->n_cols) {
231 fprintf(fpo, (table->format && table->format[j] ? table->format[j] : "%le"),
232 table->value[j][i]);
233 if (j == table->n_cols - 1 && table->row_label && table->row_label[j])
234 fprintf(fpo, " %s", table->row_label[j]);
235 if (++j % wrap == 0)
236 fputc('\n', fpo);
237 else
238 fputs(" ", fpo);
239 }
240 }
241 fclose(fpo);
242 return (1);
243}
244
245long put_mc_table_header(FILE *fpo, MC_TABLE *table) {
246 long i;
247
248 fprintf(fpo, "%ld %ld %ld\n", table->n_cols, table->n_lines_per_row, table->n_auxiliaries);
249
250 for (i = 0; i < table->n_cols; i++)
251 fprintf(fpo, "%s\\%s\\%s\\%s\n",
252 table->name[i],
253 (table->unit[i] && (long)strlen(table->unit[i]) > 1) ? table->unit[i] : " ",
254 (table->description[i] && (long)strlen(table->description[i]) > 1) ? table->description[i] : " ",
255 (table->format[i] ? table->format[i] : ""));
256
257 fprintf(fpo, "%s\n%s\n",
258 (table->title && (long)strlen(table->title) > 1) ? table->title : " ",
259 (table->label && (long)strlen(table->label) > 1) ? table->label : " ");
260
261 for (i = 0; i < table->n_auxiliaries; i++)
262 fprintf(fpo, "%s\\%s\\%s\\%.16e\n", table->aux_name[i], table->aux_unit[i],
263 table->aux_description[i], table->aux_value[i]);
264
265 fprintf(fpo, "%ld\n", table->n_rows);
266 return (1);
267}
268
269void get_name_unit_descrip_format(char **name, char **unit, char **descrip, char **format, char *buf) {
270 char *ptr, *ptrn, *ptru, *ptrd, *ptrf;
271 char *blank_string;
272
273 cp_str(&blank_string, " ");
274
275 ptr = ptrn = buf;
276 ptru = ptrd = ptrf = NULL;
277 while ((ptr = strchr(ptr, '\\'))) {
278 if (ptr[1] == '\\')
279 ptr += 2;
280 else {
281 if (!ptru) {
282 *ptr = 0;
283 ptru = ++ptr;
284 } else if (!ptrd) {
285 *ptr = 0;
286 ptrd = ++ptr;
287 } else {
288 *ptr = 0;
289 ptrf = ++ptr;
290 break;
291 }
292 }
293 }
294 cp_str(name, ptrn);
295 trim_spaces(*name);
296 if (ptru) {
297 cp_str(unit, ptru);
298 trim_spaces(*unit);
299 } else
300 *unit = blank_string;
301 if (ptrd && !is_blank(ptrd)) {
302 cp_str(descrip, ptrd);
303 trim_spaces(*descrip);
304 } else
305 cp_str(descrip, *name);
306 if (ptrf) {
307 cp_str(format, ptrf);
308 trim_spaces(*format);
309 } else
310 *format = NULL;
311}
312
void ** zarray_2d(uint64_t size, uint64_t n1, uint64_t n2)
Allocates a 2D array with specified dimensions.
Definition array.c:93
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
int get_long(long *iptr, char *s)
Parses a long integer value from the given string.
Definition data_scan.c:255
int get_double(double *dptr, char *s)
Parses a double value from the given string.
Definition data_scan.c:40
FILE * fopen_e(char *file, char *open_mode, long mode)
Opens a file with error checking, messages, and aborts.
Definition fopen_e.c:30
long is_blank(char *s)
Determine whether a string is composed entirely of whitespace characters.
Definition is_blank.c:27
long get_mc_table(MC_TABLE *table, char *file, long flags)
Reads a multi-column table from a file.
Definition mcTable.c:42
char * trim_spaces(char *s)
Trims leading and trailing spaces from a string.
Definition trim_spaces.c:28