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