1 /* Copyright 2007,2008,2010 ENSEIRB, INRIA & CNRS
2 **
3 ** This file is part of the Scotch software package for static mapping,
4 ** graph partitioning and sparse matrix ordering.
5 **
6 ** This software is governed by the CeCILL-C license under French law
7 ** and abiding by the rules of distribution of free software. You can
8 ** use, modify and/or redistribute the software under the terms of the
9 ** CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
10 ** URL: "http://www.cecill.info".
11 **
12 ** As a counterpart to the access to the source code and rights to copy,
13 ** modify and redistribute granted by the license, users are provided
14 ** only with a limited warranty and the software's author, the holder of
15 ** the economic rights, and the successive licensors have only limited
16 ** liability.
17 **
18 ** In this respect, the user's attention is drawn to the risks associated
19 ** with loading, using, modifying and/or developing or reproducing the
20 ** software by the user in light of its specific status of free software,
21 ** that may mean that it is complicated to manipulate, and that also
22 ** therefore means that it is reserved for developers and experienced
23 ** professionals having in-depth computer knowledge. Users are therefore
24 ** encouraged to load and test the software's suitability as regards
25 ** their requirements in conditions enabling the security of their
26 ** systems and/or data to be ensured and, more generally, to use and
27 ** operate it in the same conditions as regards security.
28 **
29 ** The fact that you are presently reading this means that you have had
30 ** knowledge of the CeCILL-C license and that you accept its terms.
31 */
32 /************************************************************/
33 /** **/
34 /** NAME : common_file.c **/
35 /** **/
36 /** AUTHOR : Francois PELLEGRINI **/
37 /** **/
38 /** FUNCTION : This module handles files and file **/
39 /** names. **/
40 /** **/
41 /** DATES : # Version 5.0 : from : 21 may 2007 **/
42 /** to : 16 mar 2008 **/
43 /** # Version 5.1 : from : 27 jun 2010 **/
44 /** to 27 jun 2010 **/
45 /** # Version 6.0 : from : 10 nov 2014 **/
46 /** to 12 nov 2014 **/
47 /** **/
48 /************************************************************/
49
50 /*
51 ** The defines and includes.
52 */
53
54 #define COMMON_FILE
55
56 #ifndef COMMON_NOMODULE
57 #include "module.h"
58 #endif /* COMMON_NOMODULE */
59 #include "common.h"
60 #include "common_file.h"
61
62 /*********************************/
63 /* */
64 /* Basic routines for filenames. */
65 /* */
66 /*********************************/
67
68 /* This routine expands distributed filenames
69 ** according to process numbers and the root
70 ** process number.
71 ** It returns:
72 ** - 0 : on success.
73 ** - !0 : on error.
74 */
75
76 int
fileNameDistExpand(char ** const nameptr,const int procnbr,const int procnum,const int protnum)77 fileNameDistExpand (
78 char ** const nameptr, /*+ Pointer to name string pointer +*/
79 const int procnbr, /*+ Number of processes +*/
80 const int procnum, /*+ Number of current process +*/
81 const int protnum) /*+ Root process number +*/
82 {
83 int namemax;
84 int namenum;
85 char * naexptr;
86 int naexmax;
87 int naexnum;
88 int flagval; /* Flag set if expansion took place */
89
90 namemax = strlen (*nameptr);
91 naexmax = namemax + FILENAMEDISTEXPANDNBR * 2;
92
93 if ((naexptr = memAlloc ((naexmax + 1) * sizeof (char))) == NULL) /* "+ 1" for terminating character */
94 return (1);
95
96 #ifdef COMMON_DEBUG
97 sprintf (naexptr, FILENAMEDISTEXPANDSTR, procnbr); /* TRICK: Test if FILENAMEDISTEXPANDNBR is a size large enough */
98 if (atoi (naexptr) != procnbr) {
99 errorPrint ("fileNameDistExpand: undersized integer string size");
100 memFree (naexptr);
101 return (1);
102 }
103 #endif /* COMMON_DEBUG */
104
105 for (namenum = naexnum = flagval = 0; namenum < namemax; ) {
106 char charval;
107 int dataval = 0;
108 int datasiz;
109
110 charval = (*nameptr)[namenum ++]; /* Get current characted */
111 datasiz = 1; /* Assume individual expanded character */
112 if (charval == '%') {
113 char chnxval; /* Value of next char */
114
115 switch (chnxval = (*nameptr)[namenum ++]) {
116 case 'p' : /* "%p" translates into number of processes */
117 flagval = 1;
118 datasiz = FILENAMEDISTEXPANDNBR;
119 dataval = procnbr;
120 break;
121 case 'r' : /* "%r" translates into process rank */
122 flagval = 1;
123 datasiz = FILENAMEDISTEXPANDNBR;
124 dataval = procnum;
125 break;
126 case '-' : /* "%-" translates into nothing but indicates distributed file */
127 datasiz = 0;
128 flagval = 1;
129 break;
130 case '%' : /* "%%" translates into '%' */
131 break;
132 default :
133 charval = chnxval; /* Unrecognized character */
134 }
135 }
136 if (datasiz > 0) {
137 if ((naexnum + datasiz) > naexmax) {
138 char * nanwptr;
139
140 naexmax += datasiz + FILENAMEDISTEXPANDNBR;
141 if ((nanwptr = memRealloc (naexptr, (naexmax + 1) * sizeof (char))) == NULL) { /* "+ 1" for terminating character */
142 memFree (naexptr);
143 return (1);
144 }
145 naexptr = nanwptr;
146 }
147 if (datasiz == 1)
148 naexptr[naexnum ++] = charval;
149 else {
150 sprintf (&naexptr[naexnum], FILENAMEDISTEXPANDSTR, dataval); /* TRICK: Change format string if FILENAMEDISTEXPANDNBR changes */
151 naexptr[naexnum + FILENAMEDISTEXPANDNBR] = ' ';
152 naexnum = strchr (&naexptr[naexnum], ' ') - naexptr;
153 }
154 }
155 }
156 naexptr[naexnum] = '\0'; /* Set terminating character as there is always room for it */
157
158 if ((flagval != 0) || (procnum == protnum)) /* If file name is a distributed one or we are the root process */
159 *nameptr = naexptr; /* Replace new string by old one */
160 else {
161 memFree (naexptr); /* No need for the expanded string */
162 *nameptr = NULL;
163 }
164
165 return (0);
166 }
167
168 /* This routine initializes a block of
169 ** file descriptor structures.
170 ** It returns:
171 ** - void : in all cases.
172 */
173
174 void
fileBlockInit(File * const filetab,const int filenbr)175 fileBlockInit (
176 File * const filetab,
177 const int filenbr)
178 {
179 int i;
180
181 for (i = 0; i < filenbr; i ++) { /* For all file names */
182 filetab[i].nameptr = "-"; /* Assume standard stream */
183 filetab[i].fileptr = (filetab[i].modeptr[0] == 'r') ? stdin : stdout;
184 filetab[i].dataptr = NULL; /* Assume nothing to free */
185 }
186 }
187
188 /* This routine opens a block of file
189 ** descriptor structures.
190 ** It returns:
191 ** - 0 : on success.
192 ** - !0 : on error.
193 */
194
195 int
fileBlockOpen(File * const filetab,const int filenbr)196 fileBlockOpen (
197 File * const filetab,
198 const int filenbr)
199 {
200 int i, j;
201
202 for (i = 0; i < filenbr; i ++) { /* For all file names */
203 if (filetab[i].fileptr == NULL) /* If unwanted stream, do nothing */
204 continue;
205
206 for (j = 0; j < i; j ++) {
207 if ((filetab[i].modeptr[0] == filetab[j].modeptr[0]) && /* If very same name with same opening mode */
208 (filetab[j].nameptr != NULL) &&
209 (strcmp (filetab[i].nameptr, filetab[j].nameptr) == 0)) {
210 filetab[i].fileptr = filetab[j].fileptr; /* Share pointer to already processed stream */
211 filetab[i].nameptr = NULL; /* Do not close this stream multiple times */
212 break;
213 }
214 }
215 if (j == i) { /* If original stream */
216 int compval; /* Compression type */
217 FILE * compptr; /* Processed ((un)compressed) stream */
218
219 if (filetab[i].nameptr[0] != '-') { /* If not standard stream, open it */
220 if ((filetab[i].fileptr = fopen (filetab[i].nameptr, filetab[i].modeptr)) == NULL) { /* Open the file */
221 errorPrint ("fileBlockOpen: cannot open file (%d)", i);
222 return (1);
223 }
224 }
225 compval = (filetab[i].modeptr[0] == 'r') ? fileUncompressType (filetab[i].nameptr) : fileCompressType (filetab[i].nameptr);
226 if (compval < 0) {
227 errorPrint ("fileBlockOpen: (un)compression type not implemented");
228 return (1);
229 }
230 compptr = (filetab[i].modeptr[0] == 'r') ? fileUncompress (filetab[i].fileptr, compval) : fileCompress (filetab[i].fileptr, compval);
231 if (compptr == NULL) {
232 errorPrint ("fileBlockOpen: cannot create (un)compression subprocess");
233 return (1);
234 }
235 filetab[i].fileptr = compptr; /* Use processed stream instead of original stream */
236 }
237 }
238
239 return (0);
240 }
241
242 /* This routine opens a block of eventually
243 ** distributed file descriptor structures.
244 ** It returns:
245 ** - 0 : on success.
246 ** - !0 : on error.
247 */
248
249 int
fileBlockOpenDist(File * const filetab,const int filenbr,const int procglbnbr,const int proclocnum,const int protglbnum)250 fileBlockOpenDist (
251 File * const filetab,
252 const int filenbr,
253 const int procglbnbr,
254 const int proclocnum,
255 const int protglbnum)
256 {
257 int i, j;
258
259 for (i = 0; i < filenbr; i ++) { /* For all file names */
260 if (filetab[i].fileptr == NULL) { /* If unwanted stream, do nothing */
261 filetab[i].nameptr = NULL; /* Do nothing on closing, too */
262 continue;
263 }
264
265 if (fileNameDistExpand (&filetab[i].nameptr, procglbnbr, proclocnum, protglbnum) != 0) { /* If cannot allocate new name */
266 errorPrint ("fileBlockOpenDist: cannot create file name (%d)", i);
267 return (1);
268 }
269 if (filetab[i].nameptr == NULL) { /* If inexisting stream because not root process and centralized stream */
270 filetab[i].fileptr = NULL;
271 continue;
272 }
273 filetab[i].dataptr = filetab[i].nameptr; /* From now on, we will have to free it anyway */
274
275 for (j = 0; j < i; j ++) {
276 if ((filetab[i].modeptr[0] == filetab[j].modeptr[0]) && /* If very same name with same opening mode */
277 (filetab[j].nameptr != NULL) &&
278 (strcmp (filetab[i].nameptr, filetab[j].nameptr) == 0)) {
279 filetab[i].fileptr = filetab[j].fileptr; /* Share pointer to already processed stream */
280 filetab[i].nameptr = NULL; /* Do not close this stream multiple times */
281 break;
282 }
283 }
284 if (j == i) { /* If original stream */
285 int compval; /* Compression type */
286 FILE * compptr; /* Processed ((un)compressed) stream */
287
288 if (filetab[i].nameptr[0] != '-') { /* If not standard stream, open it */
289 if ((filetab[i].fileptr = fopen (filetab[i].nameptr, filetab[i].modeptr)) == NULL) { /* Open the file */
290 errorPrint ("fileBlockOpenDist: cannot open file (%d)", i);
291 return (1);
292 }
293 }
294 compval = (filetab[i].modeptr[0] == 'r') ? fileUncompressType (filetab[i].nameptr) : fileCompressType (filetab[i].nameptr);
295 if (compval < 0) {
296 errorPrint ("fileBlockOpenDist: (un)compression type not implemented");
297 return (1);
298 }
299 compptr = (filetab[i].modeptr[0] == 'r') ? fileUncompress (filetab[i].fileptr, compval) : fileCompress (filetab[i].fileptr, compval);
300 if (compptr == NULL) {
301 errorPrint ("fileBlockOpenDist: cannot create (un)compression subprocess");
302 return (1);
303 }
304 filetab[i].fileptr = compptr; /* Use processed stream instead of original stream */
305 }
306 }
307
308 return (0);
309 }
310
311 /* This routine opens a block of file
312 ** descriptor structures.
313 ** It returns:
314 ** - 0 : on success.
315 ** - !0 : on error.
316 */
317
318 void
fileBlockClose(File * const filetab,const int filenbr)319 fileBlockClose (
320 File * const filetab,
321 const int filenbr)
322 {
323 int i;
324
325 for (i = 0; i < filenbr; i ++) { /* For all file names */
326 if ((filetab[i].fileptr != NULL) && /* If stream exists */
327 (filetab[i].nameptr != NULL) && /* And it has a name */
328 (filetab[i].nameptr[0] != '-')) /* Which is not default */
329 fclose (filetab[i].fileptr); /* Close the stream */
330
331 if (filetab[i].dataptr != NULL) /* If file name data to free */
332 memFree (filetab[i].dataptr);
333 }
334 }
335