Reads a multi-column table from a file.
Parses the specified file to populate the MC_TABLE structure with column information, auxiliary quantities, and table data.
42 {
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
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
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}
void ** zarray_2d(uint64_t size, uint64_t n1, uint64_t n2)
Allocates a 2D array with specified dimensions.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
int get_long(long *iptr, char *s)
Parses a long integer value from the given string.
int get_double(double *dptr, char *s)
Parses a double value from the given string.
FILE * fopen_e(char *file, char *open_mode, long mode)
Opens a file with error checking, messages, and aborts.
long is_blank(char *s)
Determine whether a string is composed entirely of whitespace characters.