TPCCLIB
Loading...
Searching...
No Matches
tac2xml.c
Go to the documentation of this file.
1
7/*****************************************************************************/
8#include "tpcclibConfig.h"
9/*****************************************************************************/
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <math.h>
14#include <unistd.h>
15/*****************************************************************************/
16#include "tpcextensions.h"
17#include "tpcift.h"
18#include "tpctac.h"
19/*****************************************************************************/
20
21/*****************************************************************************/
22static char *info[] = {
23 "Save TAC data in Excel compatible XML format. Each TAC file will have",
24 "its own sheet in the XML file.",
25 "TAC files may contain variable number of TACs and samples.",
26 " ",
27 "Usage: @P [options] outputfile tacfiles",
28 " ",
29 "Options:",
30 " -mid",
31 " Frame mid times are always used instead of frame start and end times.",
32 " -stdoptions", // List standard options like --help, -v, etc
33 " ",
34 "See also: tacformat, tacjoin, tacblend, tacadd, tacunit, tacnames",
35 " ",
36 "Keywords: TAC, tool, format, Excel, XML, plotting",
37 0};
38/*****************************************************************************/
39
40/*****************************************************************************/
41/* Turn on the globbing of the command line, since it is disabled by default in
42 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
43 In Unix&Linux wildcard command line processing is enabled by default. */
44/*
45#undef _CRT_glob
46#define _CRT_glob -1
47*/
48int _dowildcard = -1;
49/*****************************************************************************/
50
51/*****************************************************************************/
53
59 TAC *tac,
61 char *sheetname,
64 FILE *fp,
66 TPCSTATUS *status
67) {
68 int verbose=0; if(status!=NULL) verbose=status->verbose;
69 if(verbose>0) printf("%s(%s)\n", __func__, sheetname);
70 if(fp==NULL) {
71 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
73 }
74 if(tac==NULL || tac->tacNr<1 || tac->sampleNr<1) {
75 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_NO_DATA);
76 return TPCERROR_NO_DATA;
77 }
78
79 char tunit[128], cunit[128];
80 strcpy(tunit, unitName(tac->tunit));
81 strcpy(cunit, unitName(tac->cunit));
82
83 /* Make sure that TAC names are available */
84 if(verbose>2) printf("constructing TAC names\n");
85 tacEnsureNames(tac);
86
87 /* Start worksheet and table */
88 {
89 int n=0;
90 n=fprintf(fp, " <ss:Worksheet ss:Name=\"%s\">\n", sheetname);
91 n+=fprintf(fp, " <ss:Table>\n");
92 if(n<10) {
93 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
95 }
96 }
97
98 /* Set column widths */
99 {
100 int n=tac->tacNr+1;
101 if(tac->isframe) n++;
102 if(tacIsWeighted(tac)) n++;
103 for(int i=0; i<n; i++) fprintf(fp, " <ss:Column ss:Width=\"80\"/>\n");
104 }
105
106 /* Write the title line */
107 fprintf(fp, " <ss:Row ss:StyleID=\"1\">\n");
108 if(tac->isframe==0) {
109 fprintf(fp, " <ss:Cell>\n");
110 fprintf(fp, " <ss:Data ss:Type=\"String\">time[%s]</ss:Data>\n", tunit);
111 fprintf(fp, " </ss:Cell>\n");
112 } else {
113 fprintf(fp, " <ss:Cell>\n");
114 fprintf(fp, " <ss:Data ss:Type=\"String\">start[%s]</ss:Data>\n", tunit);
115 fprintf(fp, " </ss:Cell>\n");
116 fprintf(fp, " <ss:Cell>\n");
117 fprintf(fp, " <ss:Data ss:Type=\"String\">end[%s]</ss:Data>\n", cunit);
118 fprintf(fp, " </ss:Cell>\n");
119 }
120 for(int ri=0; ri<tac->tacNr; ri++) {
121 /* write TAC names */
122 fprintf(fp, " <ss:Cell>\n");
123 if(ri==0 && tac->isframe==0)
124 fprintf(fp, " <ss:Data ss:Type=\"String\">%s[%s]</ss:Data>\n", tac->c[ri].name, cunit);
125 else
126 fprintf(fp, " <ss:Data ss:Type=\"String\">%s</ss:Data>\n", tac->c[ri].name);
127 fprintf(fp, " </ss:Cell>\n");
128 }
129 if(tacIsWeighted(tac)) {
130 fprintf(fp, " <ss:Cell>\n");
131 fprintf(fp, " <ss:Data ss:Type=\"String\">weight</ss:Data>\n");
132 fprintf(fp, " </ss:Cell>\n");
133 }
134 if(fprintf(fp, " </ss:Row>\n")<1) {
135 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
137 }
138
139 /* Write data */
140 if(verbose>2) printf("writing data table\n");
141 for(int fi=0; fi<tac->sampleNr; fi++) {
142
143 fprintf(fp, " <ss:Row>\n");
144
145 /* Note: missing values are written as empty cells, with string type, because with
146 number type Excel seems to read those as zeroes. */
147
148 /* Time(s) (x, or x1 and x2) */
149 double v; if(tac->isframe==0) v=tac->x[fi]; else v=tac->x1[fi];
150 fprintf(fp, " <ss:Cell>\n");
151 if(isnan(v)) fprintf(fp, " <ss:Data ss:Type=\"String\"></ss:Data>\n");
152 else fprintf(fp, " <ss:Data ss:Type=\"Number\">%g</ss:Data>\n", v);
153 fprintf(fp, " </ss:Cell>\n");
154
155 if(tac->isframe) {
156 v=tac->x2[fi];
157 fprintf(fp, " <ss:Cell>\n");
158 if(isnan(v)) fprintf(fp, " <ss:Data ss:Type=\"String\"></ss:Data>\n");
159 else fprintf(fp, " <ss:Data ss:Type=\"Number\">%g</ss:Data>\n", v);
160 fprintf(fp, " </ss:Cell>\n");
161 }
162
163 /* Concentrations (y values) */
164 for(int ri=0; ri<tac->tacNr; ri++) {
165 fprintf(fp, " <ss:Cell>\n");
166 if(isnan(tac->c[ri].y[fi])) fprintf(fp, " <ss:Data ss:Type=\"String\"></ss:Data>\n");
167 else fprintf(fp, " <ss:Data ss:Type=\"Number\">%g</ss:Data>\n", tac->c[ri].y[fi]);
168 fprintf(fp, " </ss:Cell>\n");
169 }
170
171 /* Weight */
172 if(tacIsWeighted(tac)) {
173 fprintf(fp, " <ss:Cell>\n");
174 if(isnan(tac->w[fi])) fprintf(fp, " <ss:Data ss:Type=\"String\"></ss:Data>\n");
175 else fprintf(fp, " <ss:Data ss:Type=\"Number\">%g</ss:Data>\n", tac->w[fi]);
176 fprintf(fp, " </ss:Cell>\n");
177 }
178
179 fprintf(fp, " </ss:Row>\n");
180 }
181
182 /* Write table and worksheet end part */
183 fprintf(fp, " </ss:Table>\n");
184 if(fprintf(fp, " </ss:Worksheet>\n")<1) {
185 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_CANNOT_WRITE);
187 }
188
189 statusSet(status, __func__, __FILE__, __LINE__, TPCERROR_OK);
190 return(TPCERROR_OK);
191}
193/*****************************************************************************/
194
195/*****************************************************************************/
199int main(int argc, char **argv)
200{
201 int ai, help=0, version=0, verbose=1;
202 int mid_time=0; // Write mid frame time
203 char tacfile[FILENAME_MAX], outfile[FILENAME_MAX];
204 int fileNr=0, file1=0;
205
206
207 /*
208 * Get arguments
209 */
210 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
211 tacfile[0]=outfile[0]=(char)0;
212 /* Options */
213 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
214 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
215 char *cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
216 if(strncasecmp(cptr, "MIDDLE", 3)==0) {
217 mid_time=1; continue;
218 }
219 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
220 return(1);
221 } else break; // tac name argument may start with '-'
222
223 TPCSTATUS status; statusInit(&status);
224 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
225 status.verbose=verbose-3;
226
227 /* Print help or version? */
228 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
229 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
230 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
231
232 /* Process other arguments, starting from the first non-option */
233 if(ai<argc) strlcpy(outfile, argv[ai++], FILENAME_MAX);
234 for(; ai<argc; ai++) {
235 if(fileNr==0) file1=ai;
236 fileNr++;
237 }
238
239
240 /* In verbose mode print arguments and options */
241 if(verbose>1) {
242 for(ai=0; ai<argc; ai++) printf("%s ", argv[ai]);
243 printf("\n");
244 printf("fileNr := %d\n", fileNr);
245 printf("outfile := %s\n", outfile);
246 printf("mid_time := %d\n", mid_time);
247 fflush(stdout);
248 }
249
250 /* Is something missing? */
251 if(!outfile[0]) {tpcPrintUsage(argv[0], info, stdout); return(1);}
252 if(fileNr==0) {
253 fprintf(stderr, "Error: missing command-line argument; try %s --help\n", argv[0]);
254 return(1);
255 }
256
257
258 /* Check that output file name extension is .xml */
259 {
260 char *cptr=filenameGetExtension(outfile);
261 if(strcasecmp(cptr, ".XML")) {
262 fprintf(stderr, "Error: output file name extension must be .xml\n");
263 return(2);
264 }
265 }
266 /* Check that all input files do exist, and that their name does not match output file name */
267 for(ai=file1; ai<argc; ai++) {
268 strlcpy(tacfile, argv[ai], FILENAME_MAX);
269 if(access(tacfile, 0) == -1) {
270 fprintf(stderr, "Error: input file %s does not exist.\n", tacfile);
271 return(2);
272 }
273 if(strcasecmp(outfile, tacfile)==0) {
274 fprintf(stderr, "Error: input file would be overwritten.\n");
275 return(2);
276 }
277 }
278
279
280 /*
281 * Open XML file for writing
282 */
283 if(verbose>1) printf("opening %s\n", outfile);
284 FILE *fp; fp=fopen(outfile, "w");
285 if(fp==NULL) {
286 fprintf(stderr, "Error: cannot open file for writing.\n");
287 return(11);
288 }
289 /* Write XML header */
290 {
291 int n=fprintf(fp, "<?xml version=\"1.0\"?>\n");
292 if(n<1) {
293 fprintf(stderr, "Error: cannot write file.\n");
294 fclose(fp); return(12);
295 }
296 fprintf(fp, "<ss:Workbook xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\">\n");
297 fprintf(fp, " <ss:Styles>\n");
298 fprintf(fp, " <ss:Style ss:ID=\"1\">\n");
299 fprintf(fp, " <ss:Font ss:Bold=\"1\"/>\n");
300 fprintf(fp, " </ss:Style>\n");
301 fprintf(fp, " </ss:Styles>\n");
302 }
303
304 /*
305 * Go through all TAC files
306 */
307 int errorCounter=0;
308 for(ai=file1; ai<argc; ai++) {
309 strlcpy(tacfile, argv[ai], FILENAME_MAX);
310 if(verbose>1) {printf("%s\n", tacfile); fflush(stdout);}
311 /* Read TAC file */
312 TAC tac; tacInit(&tac);
313 if(tacRead(&tac, tacfile, &status)!=TPCERROR_OK) {
314 if(verbose<=1) {printf("%s\n", tacfile); fflush(stdout);}
315 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
316 tacFree(&tac); errorCounter++; break;
317 }
318 if(verbose>3) {
319 printf("fileformat := %s\n", tacFormattxt(tac.format));
320 printf("tacNr := %d\n", tac.tacNr);
321 printf("sampleNr := %d\n", tac.sampleNr);
322 printf("xunit := %s\n", unitName(tac.tunit));
323 printf("yunit := %s\n", unitName(tac.cunit));
324 }
325 /* Use mid times if requested */
326 if(mid_time) tac.isframe=0;
327 /* Make sheet name */
328 char sheetname[FILENAME_MAX]; strcpy(sheetname, tacfile);
329 filenameRmPath(sheetname); filenameRmExtensions(sheetname);
330 /* Write into XML */
331 int ret=TPCERROR_OK;
332 ret=tacWriteSheetIntoXML(&tac, sheetname, fp, &status);
333 if(ret!=TPCERROR_OK) {
334 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
335 tacFree(&tac); errorCounter++; break;
336 }
337 tacFree(&tac);
338 }
339
340 /* Write XML footer */
341 if(errorCounter==0) {
342 int n=fprintf(fp, "</ss:Workbook>\n");
343 if(n<1) {
344 fprintf(stderr, "Error: cannot write file.\n");
345 errorCounter++;
346 }
347 }
348
349 /* Close XML file */
350 fclose(fp);
351
352 /* Delete the file in case of errors */
353 if(errorCounter>0) {
354 remove(outfile);
355 return(12);
356 }
357
358 if(verbose>=0) {
359 printf("Contents of %d TAC files stored in %s\n", fileNr, outfile);
360 fflush(stdout);
361 }
362
363 return(0);
364}
365/*****************************************************************************/
366
367/*****************************************************************************/
369
char * filenameGetExtension(const char *s)
Get the last extension of a file name.
Definition filename.c:178
void filenameRmPath(char *s)
Definition filename.c:20
void filenameRmExtensions(char *s)
Definition filename.c:89
int tpcProcessStdOptions(const char *s, int *print_usage, int *print_version, int *verbose_level)
Definition proginfo.c:47
int tpcHtmlUsage(const char *program, char *text[], const char *path)
Definition proginfo.c:169
void tpcPrintBuild(const char *program, FILE *fp)
Definition proginfo.c:339
void tpcPrintUsage(const char *program, char *text[], FILE *fp)
Definition proginfo.c:114
void statusInit(TPCSTATUS *s)
Definition statusmsg.c:104
char * errorMsg(tpcerror e)
Definition statusmsg.c:68
void statusSet(TPCSTATUS *s, const char *func, const char *srcfile, int srcline, tpcerror error)
Definition statusmsg.c:142
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
char name[MAX_TACNAME_LEN+1]
Definition tpctac.h:81
double * y
Definition tpctac.h:75
Definition tpctac.h:87
double * x
Definition tpctac.h:97
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
double * w
Definition tpctac.h:111
int cunit
Definition tpctac.h:105
int isframe
Definition tpctac.h:95
TACC * c
Definition tpctac.h:117
int tunit
Definition tpctac.h:109
double * x2
Definition tpctac.h:101
double * x1
Definition tpctac.h:99
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
int tacWriteSheetIntoXML(TAC *tac, char *sheetname, FILE *fp, TPCSTATUS *status)
Definition tac2xml.c:57
void tacFree(TAC *tac)
Definition tac.c:106
void tacInit(TAC *tac)
Definition tac.c:24
int tacRead(TAC *d, const char *fname, TPCSTATUS *status)
Definition tacio.c:413
char * tacFormattxt(tacformat c)
Definition tacio.c:98
void tacEnsureNames(TAC *tac)
Definition tacname.c:50
int tacIsWeighted(TAC *tac)
Definition tacw.c:24
Header file for library libtpcextensions.
@ TPCERROR_OK
No error.
@ TPCERROR_NO_DATA
File contains no data.
@ TPCERROR_CANNOT_WRITE
Cannot write file.
char * unitName(int unit_code)
Definition units.c:143
Header file for library libtpcift.
Header file for library libtpctac.