1 /* ----------------------------- MNI Header -----------------------------------
2 @NAME : project_file.c
3 @DESCRIPTION: Code to do manipulate the project files (files containing
4 info on what to do with files for each project).
5 @METHOD :
6 @GLOBALS :
7 @CALLS :
8 @CREATED : February 14, 1995 (Peter Neelin)
9 @MODIFIED :
10 * $Log: project_file.c,v $
11 * Revision 6.8 2001-04-21 13:29:06 neelin
12 * Added PROJECT_CAPTURE file type and support for .default project file.
13 *
14 * Revision 6.7 2001/04/09 23:02:50 neelin
15 * Modified copyright notice, removing permission statement since copying,
16 * etc. is probably not permitted by our non-disclosure agreement with
17 * Philips.
18 *
19 * Revision 6.6 2001/02/19 22:03:13 neelin
20 * Port to linux.
21 *
22 * Revision 6.5 2000/06/14 18:24:08 neelin
23 * Added UseSafeOrientations keyword to project files to allow forcing of
24 * direction cosines to standard (safe) ones, and modified convert_to_dicom
25 * so that this is no longer the default behaviour.
26 *
27 * Revision 6.4 2000/02/21 23:48:14 neelin
28 * More changes to improve dicom conformance for MNH PACS system.
29 * Allow UID prefix to be defined in project file. Define SOP instance UID in
30 * addition to study and series instance UIDs and frame-of-reference UID and
31 * make sure that these are all the constant for the same image data.
32 * Set series number from acquisition number.
33 * Set study description from part of comment field.
34 *
35 * Revision 6.3 2000/01/31 13:57:38 neelin
36 * Added keyword to project file to allow definition of the local AEtitle.
37 * A simple syntax allows insertion of the host name into the AEtitle.
38 *
39 * Revision 6.2 1999/10/29 17:52:04 neelin
40 * Fixed Log keyword
41 *
42 * Revision 6.1 1997/09/12 23:13:28 neelin
43 * Added ability to convert gyrocom images to dicom images.
44 *
45 * Revision 6.0 1997/09/12 13:23:50 neelin
46 * Release of minc version 0.6
47 *
48 * Revision 5.1 1997/09/11 13:09:40 neelin
49 * Added more complicated syntax for project files so that different things
50 * can be done to the data. The old syntax is still supported.
51 *
52 * Revision 5.0 1997/08/21 13:24:50 neelin
53 * Release of minc version 0.5
54 *
55 * Revision 4.0 1997/05/07 20:01:07 neelin
56 * Release of minc version 0.4
57 *
58 * Revision 3.0 1995/05/15 19:31:44 neelin
59 * Release of minc version 0.3
60 *
61 * Revision 1.1 1995/02/14 18:12:26 neelin
62 * Initial revision
63 *
64 @COPYRIGHT :
65 Copyright 1995 Peter Neelin, McConnell Brain Imaging Centre,
66 Montreal Neurological Institute, McGill University.
67 ---------------------------------------------------------------------------- */
68
69 #include <sys/types.h>
70 #include <unistd.h>
71 #include <dirent.h>
72 #include <ctype.h>
73 #include <string.h>
74 #include <gcomserver.h>
75
76 /* Macros */
77 #define STREQ(s1, s2) (strcmp(s1, s2) == 0)
78 #define STRCOPY(s1, s2, maxlen) \
79 { (void) strncpy(s1, s2, (maxlen)-1); s1[(maxlen)-1] = '\0'; }
80
81 /* ----------------------------- MNI Header -----------------------------------
82 @NAME : read_project_file
83 @INPUT : project_name - name to use for project file
84 @OUTPUT : project_info - information about the project returned in
85 a user-allocated structure. If NULL, then no data is
86 returned.
87 @RETURNS : TRUE if an error occurs, FALSE otherwise.
88 @DESCRIPTION: Routine to read in information for a given project.
89 @METHOD :
90 @GLOBALS :
91 @CALLS :
92 @CREATED : February 14, 1995 (Peter Neelin)
93 @MODIFIED : September 9, 1997 (P.N.)
94 ---------------------------------------------------------------------------- */
read_project_file(char * project_name,Project_File_Info * project_info)95 public int read_project_file(char *project_name,
96 Project_File_Info *project_info)
97 {
98 Project_File_Info temp_project_info;
99 char project_string[256];
100 char output_default_file[256];
101 int ichar, ochar;
102 int length;
103 FILE *fp;
104 char string[512];
105 int project_name_given;
106 char *keyword, *value, *ptr, *error;
107 int oldformat;
108 int iline;
109
110 /* Check that the user actually wants return values */
111 if (project_info == NULL) {
112 project_info = &temp_project_info;
113 }
114
115 /* Set some default values */
116 project_info->type = PROJECT_DIRECTORY;
117 project_info->info.directory.file_prefix[0] = '\0';
118 project_info->info.directory.command_line[0] = '\0';
119 project_info->info.directory.output_uid = INT_MIN;
120 project_info->info.directory.output_gid = INT_MIN;
121
122 /* Copy the project name, removing spaces */
123 if (project_name != NULL)
124 length = strlen(project_name);
125 else
126 length = 0;
127 for (ichar=0, ochar=0;
128 (ichar < length) && (ochar < sizeof(project_string)-1);
129 ichar++) {
130 if (isprint((int) project_name[ichar]) &&
131 !isspace((int) project_name[ichar])) {
132 project_string[ochar] = (char) toupper((int) project_name[ichar]);
133 ochar++;
134 }
135 }
136 project_string[ochar] = '\0';
137
138 /* Get the host name if there is no project string */
139 project_name_given = (strlen(project_string) > (size_t) 0);
140 if (!project_name_given)
141 (void) gethostname(project_string, sizeof(project_string) - 1);
142 (void) sprintf(output_default_file, "%s/%s%s",
143 OUTPUT_DEFAULT_FILE_DIR, OUTPUT_DEFAULT_FILE_PREFIX,
144 project_string);
145
146 /* Open and read the defaults file. If it is not there and no project
147 name was given, then try the ".default" extension. Return TRUE (error)
148 only if a project name was given */
149 if ((fp=fopen(output_default_file, "r")) == NULL) {
150 if (project_name_given) {
151 return TRUE;
152 }
153 else {
154 (void) sprintf(output_default_file, "%s/%s%s",
155 OUTPUT_DEFAULT_FILE_DIR, OUTPUT_DEFAULT_FILE_PREFIX,
156 OUTPUT_DEFAULT_FILE_SUFFIX);
157 if ((fp=fopen(output_default_file, "r")) == NULL) {
158 return FALSE;
159 }
160 }
161 }
162
163 /* Loop over lines of the file */
164 iline = 0;
165 project_info->type = PROJECT_UNKNOWN;
166 while (fgets(string, (int) sizeof(string), fp) != NULL) {
167
168 /* Remove the newline, or read in the rest of the line
169 if it is too long */
170 if (string[strlen(string) - 1] == '\n') {
171 string[strlen(string) - 1] = '\0';
172 }
173 else {
174 while ((getc(fp) != (int) '\n') && !feof(fp)) {}
175 }
176
177 /* Ignore comments and blank lines (don't even count them as lines) */
178 if (string[0] == '#') continue;
179 for (ptr=string; (*ptr != '\0') && isspace((int) *ptr); ptr++) {}
180 if (*ptr == '\0') continue;
181
182 /* If this is the first line, figure out whether we have an old
183 or new format file (look for the "=") */
184 ptr = strchr(string, (int) '=');
185 if (iline == 0) {
186 oldformat = (ptr == NULL);
187 }
188
189 /* Read old format file */
190 if (oldformat) {
191 switch (iline) {
192 case 0:
193 project_info->type = PROJECT_DIRECTORY;
194 if (sscanf(string, "%s %d %d",
195 project_info->info.directory.file_prefix,
196 &project_info->info.directory.output_uid,
197 &project_info->info.directory.output_gid) != 3) {
198 (void) fclose(fp);
199 return TRUE;
200 }
201 break;
202 case 1:
203 (void) strcpy(project_info->info.directory.command_line, string);
204 break;
205 default:
206 (void) fprintf(stderr,
207 "Old format project file (%s) contains extra lines\n",
208 project_string);
209 (void) fclose(fp);
210 return TRUE;
211 }
212 }
213
214 /* Read new format file */
215 else { /* New format */
216
217 /* Check for missing '=' */
218 if (ptr == NULL) {
219 (void) fprintf(stderr, "Project file error (%s): syntax error\n",
220 project_string);
221 (void) fclose(fp);
222 return TRUE;
223 }
224
225 /* Get keyword and value (remove leading and trailing whitespace) */
226 for (keyword=string; isspace((int) *keyword); keyword++) {}
227 if (*keyword == '=') keyword--;
228 for (value = ptr+1; isspace((int) *value); value++) {}
229 for (ptr--; (ptr > keyword) && isspace((int) *ptr); ptr--) {}
230 ptr++;
231 *ptr = '\0';
232 for (ptr=&value[strlen(value)-1];
233 (ptr > value) && isspace((int) *ptr); ptr--) {}
234 ptr++;
235 *ptr = '\0';
236
237 /* Downcase the keyword */
238 for (ichar=0; (size_t) ichar < strlen(keyword); ichar++) {
239 keyword[ichar] = tolower((int) keyword[ichar]);
240 }
241
242 /* Set up error string */
243 error = NULL;
244
245 /* Look for the project type on the first line */
246 if (iline == 0) {
247 for (ichar=0; (size_t) ichar < strlen(value); ichar++) {
248 value[ichar] = tolower((int) value[ichar]);
249 }
250 if (STREQ(keyword, "type")) {
251 if (STREQ(value, "directory")) {
252 project_info->type = PROJECT_DIRECTORY;
253 }
254 else if (STREQ(value, "dicom")) {
255 project_info->type = PROJECT_DICOM;
256 project_info->info.dicom.hostname[0] = '\0';
257 project_info->info.dicom.port[0] = '\0';
258 project_info->info.dicom.AEtitle[0] = '\0';
259 project_info->info.dicom.LocalAEtitle[0] = '\0';
260 project_info->info.dicom.UIDprefix[0] = '\0';
261 project_info->info.dicom.use_safe_orientations = FALSE;
262 project_info->info.dicom.afpin = NULL;
263 project_info->info.dicom.afpout = NULL;
264 }
265 else if (STREQ(value, "capture")) {
266 project_info->type = PROJECT_CAPTURE;
267 }
268 else {
269 error = "Unknown project type";
270 }
271 }
272 else {
273 error = "Type must be given on first line";
274 }
275 }
276
277 /* Get other keywords */
278 else { /* Subsequent lines */
279
280 /* Check that project type is defined */
281 if (project_info->type == PROJECT_UNKNOWN) {
282 error = "Type must be given on first line";
283 }
284
285 /* Keywords for directory type */
286 else if ((project_info->type == PROJECT_DIRECTORY) ||
287 (project_info->type == PROJECT_CAPTURE)) {
288 if (STREQ("prefix", keyword)) {
289 STRCOPY(project_info->info.directory.file_prefix,
290 value, LONG_LINE);
291 }
292 else if (STREQ("uid", keyword)) {
293 project_info->info.directory.output_uid = atoi(value);
294 }
295 else if (STREQ("gid", keyword)) {
296 project_info->info.directory.output_gid = atoi(value);
297 }
298 else if (STREQ("command", keyword)) {
299 STRCOPY(project_info->info.directory.command_line,
300 value, LONG_LINE);
301 }
302 else {
303 error = "Unrecognized keyword for given type";
304 }
305 }
306
307 /* Keywords for dicom type */
308 else if (project_info->type == PROJECT_DICOM) {
309 if (STREQ("host", keyword)) {
310 STRCOPY(project_info->info.dicom.hostname,
311 value, SHORT_LINE);
312 }
313 else if (STREQ("port", keyword)) {
314 STRCOPY(project_info->info.dicom.port,
315 value, SHORT_LINE);
316 }
317 else if (STREQ("aetitle", keyword)) {
318 STRCOPY(project_info->info.dicom.AEtitle,
319 value, SHORT_LINE);
320 }
321 else if (STREQ("localaetitle", keyword)) {
322 STRCOPY(project_info->info.dicom.LocalAEtitle,
323 value, SHORT_LINE);
324 }
325 else if (STREQ("uidprefix", keyword)) {
326 STRCOPY(project_info->info.dicom.UIDprefix,
327 value, SHORT_LINE);
328 }
329 else if (STREQ("usesafeorientations", keyword)) {
330 for (ichar=0; (size_t) ichar < strlen(value); ichar++) {
331 value[ichar] = tolower((int) value[ichar]);
332 }
333 if (STREQ(value, "true") || STREQ(value, "yes")) {
334 project_info->info.dicom.use_safe_orientations =
335 TRUE;
336 }
337 else if (STREQ(value, "false") || STREQ(value, "no")) {
338 project_info->info.dicom.use_safe_orientations =
339 FALSE;
340 }
341 else {
342 error = "Unrecognized boolean value";
343 }
344 }
345 else {
346 error = "Unrecognized keyword for given type";
347 }
348 }
349
350 } /* Subsequent lines */
351
352 /* Check for error */
353 if (error != NULL) {
354 (void) fprintf(stderr, "Project file error (%s), keyword %s: %s\n",
355 project_string, keyword, error);
356 (void) fclose(fp);
357 return TRUE;
358 }
359
360 } /* New format */
361
362 /* Increment the line counter */
363 iline++;
364 }
365
366 /* Close the file */
367 (void) fclose(fp);
368
369 /* Check that something was found */
370 if (project_info->type == PROJECT_UNKNOWN) {
371 return TRUE;
372 }
373
374 /* Check that minimal set of keywords was found */
375 if (project_info->type == PROJECT_DICOM) {
376 if ((project_info->info.dicom.hostname[0] == '\0') ||
377 (project_info->info.dicom.port[0] == '\0') ||
378 (project_info->info.dicom.AEtitle[0] == '\0')) {
379 (void) fprintf(stderr, "Project file (%s) missing options\n",
380 project_string);
381 return TRUE;
382 }
383 }
384
385 return FALSE;
386 }
387
388 /* ----------------------------- MNI Header -----------------------------------
389 @NAME : get_project_option_string
390 @INPUT : (none)
391 @OUTPUT : project_option_string - string containing list of options
392 for project name
393 maxlen_project_option - maximum length for the string (including
394 '\0' at end)
395 @RETURNS : (nothing)
396 @DESCRIPTION: Routine to get a list of possibilities for the project name
397 (looking for appropriately named files).
398 @METHOD :
399 @GLOBALS :
400 @CALLS :
401 @CREATED : February 14, 1995 (Peter Neelin)
402 @MODIFIED :
403 ---------------------------------------------------------------------------- */
get_project_option_string(char * project_option_string,int maxlen_project_option)404 public void get_project_option_string(char *project_option_string,
405 int maxlen_project_option)
406 {
407 DIR *dirp;
408 struct dirent *dp;
409 int length;
410 char *name, *filler;
411 int compare_length;
412
413 /* Set up the string */
414 if (maxlen_project_option > 0) {
415 project_option_string[0] = '\0';
416 length = 1;
417 }
418
419 /* Open directory */
420 if ((dirp = opendir(OUTPUT_DEFAULT_FILE_DIR)) == NULL)
421 return;
422
423 /* Loop through directory entries */
424 compare_length = strlen(OUTPUT_DEFAULT_FILE_PREFIX);
425 while ((dp = readdir(dirp)) != NULL) {
426
427 /* Check for an entry with the right prefix */
428 if (strncmp(OUTPUT_DEFAULT_FILE_PREFIX,
429 dp->d_name, compare_length) == 0) {
430
431 /* Check for an uppercase letter */
432 if ((strlen(dp->d_name) > (size_t) compare_length) &&
433 (isupper(dp->d_name[compare_length]))) {
434 name = &dp->d_name[compare_length];
435
436 /* Check that we can read the project file */
437 if (!read_project_file(name, NULL)) {
438 if (length > 1)
439 filler = ", ";
440 else
441 filler = "";
442 if ((strlen(name) + length + strlen(filler))
443 < (size_t) maxlen_project_option) {
444 (void) strcat(strcat(project_option_string, filler), name);
445 length += strlen(filler) + strlen(name);
446 }
447 } /* We can read the project file */
448
449 } /* Found uppercase letter */
450
451 } /* Found file matching prefix */
452
453 } /* Loop over files */
454 }
455