TPCCLIB
Loading...
Searching...
No Matches
tacren.c
Go to the documentation of this file.
1
8/*****************************************************************************/
9#include "tpcclibConfig.h"
10/*****************************************************************************/
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <ctype.h>
15#include <math.h>
16/*****************************************************************************/
17#include "tpcextensions.h"
18#include "tpcift.h"
19#include "tpctac.h"
20/*****************************************************************************/
21
22/*****************************************************************************/
23static char *info[] = {
24 "Rename the specified TAC(s) inside a TAC file.",
25 " ",
26 "Usage: @P [options] file tac_id newname",
27 " ",
28 "Enter the number or (partial) name of the TAC to be renamed.",
29 "Set tac_id to 0, if all TAC names are to be changed.",
30 " ",
31 "For newname, use '_' to separate for example hemisphere or other position",
32 "from the target name. Character '#' is replaced by sequential number.",
33 "Character '@' specifies that previous partial name is to be kept.",
34 " ",
35 "Note that not all TAC file formats can store TAC names.",
36 "At least PMOD and DFT formats support TAC names.",
37 " ",
38 "Options:",
39 " -dry",
40 " Nothing is actually renamed, application only lists which TAC(s) would",
41 " be renamed and how.",
42 " -add=<field_nr>",
43 " New field name is added to given position; enter large number to add",
44 " it to the end.",
45 " -stdoptions", // List standard options like --help, -v, etc
46 " ",
47 "Example 1: Rename TAC number 3 to 'str_dx'",
48 " @P a123.tac 3 str_dx",
49 " ",
50 "Example 2: Rename all TACs to TACx where x is the number of the TAC",
51 " @P a234.tac 0 TAC#",
52 " ",
53 "Example 3: Rename name field 'sn' to 'sin'",
54 " @P a345.tac sn @_sin_@",
55 " ",
56 "Example 4: Add TAC nr as the first name field, and keep the next fields intact",
57 " @P -add=1 a456.tac 0 #_@_@_@",
58 " ",
59 "See also: taclist, tacnames, tacadd, tacformat, tacsort, tacunit, tacdel",
60 " ",
61 "Keywords: TAC, tool, rename, simulation",
62 0};
63/*****************************************************************************/
64
65/*****************************************************************************/
66/* Turn on the globbing of the command line, since it is disabled by default in
67 mingw-w64 (_dowildcard=0); in MinGW32 define _CRT_glob instead, if necessary;
68 In Unix&Linux wildcard command line processing is enabled by default. */
69/*
70#undef _CRT_glob
71#define _CRT_glob -1
72*/
73int _dowildcard = -1;
74/*****************************************************************************/
75
76/*****************************************************************************/
80int main(int argc, char **argv)
81{
82 int ai, help=0, version=0, verbose=1;
83 int ret, dryMode=0, addField=0;
84 char *cptr, tacfile[FILENAME_MAX], tacid[256], tacname[256];
85 TAC tac;
86 unsigned int n;
87
88
89 /*
90 * Get arguments
91 */
92 if(argc==1) {tpcPrintUsage(argv[0], info, stderr); return(1);}
93 tacInit(&tac);
94 tacfile[0]=tacid[0]=tacname[0]=(char)0;
95 /* Options */
96 for(ai=1; ai<argc; ai++) if(*argv[ai]=='-') {
97 if(tpcProcessStdOptions(argv[ai], &help, &version, &verbose)==0) continue;
98 cptr=argv[ai]+1; if(*cptr=='-') cptr++; if(!*cptr) continue;
99 if(strcasecmp(cptr, "DRY")==0) {
100 dryMode=1; continue;
101 } else if(strncasecmp(cptr, "ADD=", 4)==0) {
102 addField=atoi(cptr+4); if(addField>0) continue;
103 }
104 fprintf(stderr, "Error: invalid option '%s'\n", argv[ai]);
105 return(1);
106 } else break; // tac name argument may start with '-'
107
108 TPCSTATUS status; statusInit(&status);
109 statusSet(&status, __func__, __FILE__, __LINE__, TPCERROR_OK);
110 if(verbose>1) status.verbose=verbose-1;
111
112 /* Print help or version? */
113 if(help==2) {tpcHtmlUsage(argv[0], info, ""); return(0);}
114 if(help) {tpcPrintUsage(argv[0], info, stdout); return(0);}
115 if(version) {tpcPrintBuild(argv[0], stdout); return(0);}
116
117 /* The first argument (non-option) is the file name */
118 if(ai<argc) {
119 strlcpy(tacfile, argv[ai], FILENAME_MAX); ai++;
120 } else {
121 fprintf(stderr, "Error: missing filename.\n");
122 return(1);
123 }
124 /* Then user should have given the TAC id */
125 if(ai<argc) {
126 strlcpy(tacid, argv[ai], 256); ai++;
127 } else {
128 fprintf(stderr, "Error: missing TAC name or number.\n");
129 return(1);
130 }
131 /* And the rest should be the new name */
132 if(ai>=argc && addField==0) {
133 fprintf(stderr, "Error: missing new name for TAC(s).\n");
134 return(1);
135 }
136 n=0;
137 for(; ai<argc; ai++) {
138 if( (1+strlen(argv[ai])+strlen(tacname)) >= 255 ) {
139 fprintf(stderr, "Error: new name for TAC(s) is too long.\n");
140 return(1);
141 }
142 if(n>0) strncat(tacname, "_", 255-strlen(tacname));
143 strncat(tacname, argv[ai], 255-strlen(tacname));
144 n++;
145 }
146
147
148 /* In verbose mode print arguments and options */
149 if(verbose>1) {
150 printf("tacfile := %s\n", tacfile);
151 printf("dryMode := %d\n", dryMode);
152 printf("addField := %d\n", addField);
153 printf("tac_id := '%s'\n", tacid);
154 printf("new_tacname := '%s'\n", tacname);
155 fflush(stdout);
156 }
157
158
159 /* Check that new name contains only accepted characters */
160 /* And check if it contains # or @ characters */
161 int toNum=0, toKeep=0;
162 for(int unsigned i=0; i<strlen(tacname); i++) {
163 if(tacname[i]=='#') {toNum++; continue;}
164 if(tacname[i]=='@') {toKeep++; continue;}
165 if(tacname[i]=='_') continue;
166 if(tacname[i]=='-') continue;
167 if(isalnum(tacname[i])) continue;
168 fprintf(stderr, "Error: invalid character '%c' in new tacname.\n", tacname[i]);
169 return(1);
170 }
171 if(verbose>1) {
172 printf("edited_new_tacname := %s\n", tacname);
173 printf("toNum := %d\n", toNum);
174 printf("toKeep := %d\n", toKeep);
175 fflush(stdout);
176 }
177 if(toNum>1) {
178 fprintf(stderr, "Error: do not use '#' more than once.\n");
179 return(1);
180 }
181 /* Check that we have *_@_* or @_* or *_@ */
182 if(toKeep>0) {
183 ret=0;
184 for(int unsigned i=1; i<strlen(tacname)-1; i++) {
185 if(tacname[i]!='@') continue;
186 if(tacname[i-1]!='_' || tacname[i+1]!='_') ret++;
187 }
188 if(ret) {
189 fprintf(stderr, "Error: '@' must be separated by '_'.\n");
190 return(1);
191 }
192 }
193
194 /*
195 * Read the file
196 */
197 if(verbose>1) printf("reading %s\n", tacfile);
198 ret=tacRead(&tac, tacfile, &status);
199 if(ret!=TPCERROR_OK) {
200 fprintf(stderr, "Error: %s\n", errorMsg(status.error));
201 tacFree(&tac); return(2);
202 }
203 if(verbose>2) {
204 printf("fileformat := %s\n", tacFormattxt(tac.format));
205 printf("tacNr := %d\n", tac.tacNr);
206 printf("sampleNr := %d\n", tac.sampleNr);
207 fflush(stdout);
208 }
209 if(tac.tacNr<1) {
210 fprintf(stderr, "Error: no TACs in %s\n", tacfile);
211 tacFree(&tac); return(2);
212 }
213
214 /* Select the regions */
215 if(strcmp(tacid, "0")==0) {
216 for(int j=0; j<tac.tacNr; j++) tac.c[j].sw=1;
217 n=tac.tacNr;
218 if(verbose>1) printf("All %d tac(s) selected.\n", n);
219 } else {
220 n=tacSelectTACs(&tac, tacid, 1, &status);
221 if(n<1) {
222 fprintf(stderr, "Error: specified TACs not found in %s.\n", tacfile);
223 tacFree(&tac); return(3);
224 } else if(verbose>1)
225 printf("%d tac(s) match tac_id '%s'\n", n, tacid);
226 }
227
228
229 /*
230 * Rename the selected TACs
231 */
232 char oldname[MAX_TACNAME_LEN+1], newname[MAX_TACNAME_LEN+1];
233 char tmp[1024];
234 for(int j=0; j<tac.tacNr; j++) if(tac.c[j].sw) {
235 if(verbose>1) printf("\nold_name := '%s'\n", tac.c[j].name);
236 /* Get the current TAC name, without extra spaces or quotation marks */
237 strncpyClean(oldname, tac.c[j].name, MAX_TACNAME_LEN);
238 /* '.' means that name is actually empty */
239 if(strcmp(oldname, ".")==0) strcpy(oldname, "");
240 /* Add TAC name field, if required */
241 if(addField>0) {
242 if(!roinameAddField(oldname, "", addField-1, MAX_TACNAME_LEN)) {
243 fprintf(stderr, "Error: cannot add name field.\n");
244 tacFree(&tac); return(4);
245 }
246 }
247 /* Pre-process the template into tmp */
248 if(strlen(tacname)==0) {
249 /* Empty template can be given, if user wants to delete ROI name, or
250 if user just wants to add a name field */
251 if(addField>0) strcpy(tmp, oldname); else strcpy(tmp, "");
252 } else {
253 /* Replace the template # with TAC number */
254 strcpy(tmp, tacname);
255 if(toNum) {
256 unsigned int i;
257 if(verbose>10) printf("j+1=%d tmp := '%s'\n", j+1, tmp);
258 i=strcspn(tacname, "#"); tmp[i]=(char)0;
259 if(verbose>10) printf("tmp := '%s' i=%d\n", tmp, i);
260 strncatIntZ(tmp, 1+j, tac.tacNr, 1024-strlen(tmp)-1);
261 if(verbose>10) printf("tmp := '%s'\n", tmp);
262 strncat(tmp, tacname+i+1, 1024-strlen(tmp)-1);
263 if(verbose>10) printf("tmp := '%s'\n", tmp);
264 if(strlen(tmp)>MAX_TACNAME_LEN) {
265 fprintf(stderr, "Error: too long TAC name '%s'\n", tmp);
266 tacFree(&tac); return(5);
267 }
268 }
269 }
270 /* Set the new name based on the template */
271 if(!roinameEditByTemplate(tmp, oldname, newname, MAX_TACNAME_LEN+1)) {
272 fprintf(stderr, "Error: invalid TAC name '%s'\n", tmp);
273 tacFree(&tac); return(6);
274 }
275
276 /* Tell user what we are doing */
277 if(verbose>0 || dryMode) {printf("%s -> %s\n", tac.c[j].name, newname); fflush(stdout);}
278
279
280 /* Replace old name with the new name */
281 if(strlen(newname)>MAX_TACNAME_LEN) {
282 fprintf(stderr, "Error: too long TAC name '%s'\n", newname);
283 tacFree(&tac); return(7);
284 }
285 strcpy(tac.c[j].name, newname);
286
287 /* Do not let data to be saved in simple format if there is at least one TAC name */
288 if(tac.format==TAC_FORMAT_SIMPLE && strlen(newname)>0) tac.format=TAC_FORMAT_DFT;
289
290 } // next TAC
291
292
293 if(dryMode) {
294 tacFree(&tac); return(0);
295 }
296
297 /*
298 * Save data
299 */
300 if(verbose>1) printf("writing %s\n", tacfile);
301 FILE *fp; fp=fopen(tacfile, "w");
302 if(fp==NULL) {
303 fprintf(stderr, "Error: cannot open file for writing (%s)\n", tacfile);
304 tacFree(&tac); return(11);
305 }
306 if(verbose>2) printf("format := %s\n", tacFormattxt(tac.format));
307 ret=tacWrite(&tac, fp, TAC_FORMAT_UNKNOWN, 1, &status);
308 fclose(fp); tacFree(&tac);
309 if(ret!=TPCERROR_OK) {
310 fprintf(stderr, "Error (%d): %s\n", ret, errorMsg(status.error));
311 return(12);
312 }
313
314 return(0);
315}
316/*****************************************************************************/
317
318/*****************************************************************************/
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
char * roinameAddField(char *roiname, const char *field, const unsigned int in, const unsigned int count)
Definition roiname.c:106
char * roinameEditByTemplate(const char *template, const char *currname, char *newname, const unsigned int count)
Definition roiname.c:65
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
char * strncatIntZ(char *str1, const int n, const int maxn, size_t count)
Definition stringext.c:539
size_t strlcpy(char *dst, const char *src, size_t dstsize)
Definition stringext.c:632
int strncpyClean(char *s1, const char *s2, int maxlen)
Definition stringext.c:321
char sw
Definition tpctac.h:77
char name[MAX_TACNAME_LEN+1]
Definition tpctac.h:81
Definition tpctac.h:87
tacformat format
Definition tpctac.h:93
int sampleNr
Definition tpctac.h:89
TACC * c
Definition tpctac.h:117
int tacNr
Definition tpctac.h:91
int verbose
Verbose level, used by statusPrint() etc.
tpcerror error
Error code.
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
int tacWrite(TAC *tac, FILE *fp, tacformat format, int extra, TPCSTATUS *status)
Definition tacio.c:332
int tacSelectTACs(TAC *d, const char *region_name, int reset, TPCSTATUS *status)
Definition tacselect.c:24
Header file for library libtpcextensions.
#define MAX_TACNAME_LEN
Max length of TAC ID name (not including trailing zero).
@ TPCERROR_OK
No error.
Header file for library libtpcift.
Header file for library libtpctac.
@ TAC_FORMAT_UNKNOWN
Unknown format.
Definition tpctac.h:28
@ TAC_FORMAT_SIMPLE
x and y's with space delimiters
Definition tpctac.h:29
@ TAC_FORMAT_DFT
Data format of Turku PET Centre.
Definition tpctac.h:30