OSDN Git Service

Add - before rms to be more portable.
[pf3gnuchains/gcc-fork.git] / libchill / basicio.c
1 /* Implement Input/Output runtime actions for CHILL.
2    Copyright (C) 1992,1993 Free Software Foundation, Inc.
3    Author: Wilfried Moser, et al
4    
5    This file is part of GNU CC.
6    
7    GNU CC is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11    
12    GNU CC is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with GNU CC; see the file COPYING.  If not, write to
19    the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* As a special exception, if you link this library with other files,
23    some of which are compiled with GCC, to produce an executable,
24    this library does not by itself cause the resulting executable
25    to be covered by the GNU General Public License.
26    This exception does not however invalidate any other reasons why
27    the executable file might be covered by the GNU General Public License.  */
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <limits.h>
34 #include <errno.h>
35
36 #include <string.h>
37 #include <stdlib.h>
38
39 #include "fileio.h"
40
41 #ifndef PATH_MAX
42 #   ifdef _POSIX_PATH_MAX
43 #       define PATH_MAX _POSIX_PATH_MAX
44 #   else
45 #       ifdef MAXPATHLEN
46 #           define PATH_MAX MAXPATHLEN
47 #       else
48 #           define PATH_MAX 1024
49 #       endif
50 #   endif
51 #endif
52
53 static
54 void
55 GetSetAttributes( Association_Mode* the_assoc )
56 {
57   struct stat statbuf;
58   int retco;
59
60   if( (retco = stat( the_assoc->pathname, &statbuf )) )
61     return;
62
63   if( S_ISREG(statbuf.st_mode) )
64     {
65       SET_FLAG( the_assoc, IO_EXISTING );
66       if( !TEST_FLAG( the_assoc, IO_VARIABLE ) )
67         SET_FLAG( the_assoc, IO_INDEXABLE );
68     }
69   else
70     if( S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode) )
71       {
72         SET_FLAG( the_assoc, IO_EXISTING );
73         CLR_FLAG( the_assoc, IO_INDEXABLE );
74       }
75   SET_FLAG( the_assoc, IO_SEQUENCIBLE );
76
77   /* FIXME: File size and computation of number of records for outoffile ? */
78
79   if( !access( the_assoc->pathname, R_OK ) )
80     SET_FLAG( the_assoc, IO_READABLE );
81   if( !access( the_assoc->pathname, W_OK ) )
82     SET_FLAG( the_assoc, IO_WRITEABLE );
83 }
84
85 static
86 void 
87 makeName( Association_Mode* the_assoc, char* the_path, int the_path_len,
88          char* file, int line)
89 {
90   int namlen;
91   if( ! the_assoc->pathname && 
92       ! (the_assoc->pathname = (char*)malloc( PATH_MAX )) )
93     CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
94
95   if( the_path[0] != DIRSEP )
96     {
97       if( !getcwd( the_assoc->pathname, PATH_MAX ) )
98         {
99           the_assoc->syserrno = errno;
100           CHILLEXCEPTION( file, line, ASSOCIATEFAIL, GETCWD_FAILS );
101         }
102       namlen = strlen( the_assoc->pathname );
103       the_assoc->pathname[namlen++] = DIRSEP;  
104     }
105   else
106     namlen = 0;
107
108   strncpy( the_assoc->pathname + namlen, the_path, the_path_len );
109   the_assoc->pathname[namlen+the_path_len] = '\0';
110 }
111
112 /*
113  * ASSOCIATE
114  */
115 /* Caution: returns an Association mode location (!) */
116 Association_Mode*
117 __associate( Association_Mode* the_assoc,
118              char*             the_path,
119              int               the_path_len,
120              char*             the_mode,
121              int               the_mode_len,
122              char*             file,
123              int               line )
124 {
125   if( !the_assoc )
126     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
127
128   if( TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
129     CHILLEXCEPTION( file, line, ASSOCIATEFAIL, IS_ASSOCIATED );
130
131   /* clear all flags */
132   the_assoc->flags = 0;
133
134   if( ! the_path_len )
135     CHILLEXCEPTION( file, line, ASSOCIATEFAIL, NO_PATH_NAME );
136
137   makeName( the_assoc, the_path, the_path_len, file, line );
138   GetSetAttributes( the_assoc );
139
140   CLR_FLAG( the_assoc, IO_VARIABLE );
141   if ( the_mode )
142     {
143       if( !strncmp( the_mode, "VARIABLE", 8 ) )
144         {
145           SET_FLAG( the_assoc, IO_VARIABLE );
146           CLR_FLAG( the_assoc, IO_INDEXABLE );
147         }
148       else
149         if( strlen( the_mode ) )
150           CHILLEXCEPTION( file, line, ASSOCIATEFAIL, INVALID_ASSOCIATION_MODE );
151     }
152
153   SET_FLAG( the_assoc, IO_ISASSOCIATED );
154   return the_assoc;
155 }
156
157 /*
158  *  DISSOCIATE
159  */
160 void
161 __dissociate( Association_Mode* the_assoc, char* file, int line )
162 {
163   if( !the_assoc )
164     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
165
166   if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
167     CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
168
169   if( the_assoc->access )
170     __disconnect( the_assoc->access, file, line );
171
172   the_assoc->access = NULL;
173   CLR_FLAG( the_assoc, IO_ISASSOCIATED );
174
175   /* free allocated memory */
176   if (the_assoc->pathname)
177     {
178       free (the_assoc->pathname);
179       the_assoc->pathname = 0;
180     }
181   if (the_assoc->bufptr)
182     {
183       free (the_assoc->bufptr);
184       the_assoc->bufptr = 0;
185     }
186 }
187
188 /*
189  * CREATE
190  */
191 void __create( Association_Mode* the_assoc, char* file, int line )
192 {
193   if( !the_assoc )
194     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
195
196   if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
197     CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
198
199   if( TEST_FLAG( the_assoc, IO_EXISTING ) )
200     CHILLEXCEPTION( file, line, CREATEFAIL, FILE_EXISTING );
201
202   if( (the_assoc->handle = open( the_assoc->pathname, O_CREAT+O_TRUNC+O_WRONLY, 0666 ))
203       == -1 )
204       CHILLEXCEPTION( file, line, CREATEFAIL, CREATE_FAILS );
205
206   the_assoc->usage = ReadWrite;
207   GetSetAttributes( the_assoc );
208
209   close( the_assoc->handle );
210 }
211
212 /*
213  * MODIFY
214  */
215 void
216 __modify( Association_Mode* the_assoc,
217           char*             the_path,
218           int               the_path_len,
219           char*             the_mode,
220           int               the_mode_len,
221           char*             file,
222           int               line )
223 {
224   if( !the_assoc )
225     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
226
227   if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
228     CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
229
230   if( the_path_len )
231     {
232       char* oldname;
233
234       if( ! (oldname = (char*)malloc( PATH_MAX )) )
235         CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
236       strcpy( oldname, the_assoc->pathname );
237
238       makeName( the_assoc, the_path, the_path_len, file, line );
239
240       if( rename( oldname, the_assoc->pathname ) )
241         {
242           free( oldname );
243           CHILLEXCEPTION( file, line, MODIFYFAIL, RENAME_FAILS );
244         }
245       free( oldname );
246     }
247   else
248     {
249       /* FIXME: other options? */
250     }
251 }
252
253 static
254 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
255 int DirMode[] = { O_RDONLY, O_RDWR, O_RDWR };
256
257 static
258 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
259 int SeqMode[] = { O_RDONLY, O_RDWR, O_RDWR };
260
261 /*
262  * CONNECT
263  */
264 void
265 __connect( void*             the_transfer,
266            Association_Mode* the_assoc,
267            Usage_Mode        the_usage,
268            Where_Mode        the_where,
269            Boolean           with_index,
270            signed long       the_index,
271            char*             file,
272            int               line )
273 {
274   Access_Mode*  the_access;
275   off_t         filepos;
276   off_t         savepos;
277   char          dummy;
278   unsigned long nbytes;
279   int           oflag;
280
281   if( !the_transfer )
282     CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
283   if( !the_assoc )
284     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
285
286   if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
287     {
288       if( ! ((Text_Mode*)the_transfer)->access_sub )
289         CHILLEXCEPTION( file, line, EMPTY, NO_ACCESS_SUBLOCATION );
290       the_access = ((Text_Mode*)the_transfer)->access_sub;
291       SET_FLAG( the_access, IO_TEXTIO );
292     }
293   else
294     {
295       the_access = (Access_Mode*)the_transfer;
296       CLR_FLAG( the_access, IO_TEXTIO );
297     }
298
299   /* FIXME: This should be an (implementation-dependent) static check
300      if( with_index && the_access->rectype > Fixed )
301      CHILLEXCEPTION( file, line, CONNECTFAIL, IMPL_RESTRICTION );
302      */
303
304   if( ! TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
305     CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
306
307   if( ! TEST_FLAG( the_assoc, IO_EXISTING ) )
308     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_EXISTING );
309
310   if( ! TEST_FLAG( the_assoc, IO_READABLE ) &&
311       ( the_usage = ReadOnly || the_usage == ReadWrite ) )    
312     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_READABLE );
313
314   if( ! TEST_FLAG( the_assoc, IO_WRITEABLE ) &&
315       ( the_usage = WriteOnly || the_usage == ReadWrite ) )    
316     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_WRITEABLE );
317
318   if( ! TEST_FLAG( the_assoc, IO_INDEXABLE ) 
319       && TEST_FLAG( the_access, IO_INDEXED ) )
320     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXABLE );
321
322   if( ! TEST_FLAG( the_assoc, IO_SEQUENCIBLE ) 
323       && ! TEST_FLAG( the_access, IO_INDEXED ) )
324     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_SEQUENCIBLE );
325
326   if( the_where == Same && the_assoc->access == NULL )
327     CHILLEXCEPTION( file, line, CONNECTFAIL, NO_CURRENT_POS );
328
329   /* This dynamic condition is not checked for text connections. */
330   if( ! TEST_FLAG( the_access, IO_TEXTIO ) )
331     if( ! TEST_FLAG( the_assoc, IO_VARIABLE ) 
332         && the_access->rectype > Fixed 
333         && ( the_usage == WriteOnly || the_usage == ReadWrite ) )
334       CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_VARIABLE );
335  
336   if( TEST_FLAG( the_assoc, IO_VARIABLE )
337       && the_access->rectype == Fixed 
338       && ( the_usage == ReadOnly || the_usage == ReadWrite ) )
339     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_FIXED );
340  
341   if( ! TEST_FLAG( the_access, IO_INDEXED ) && the_usage == ReadWrite )
342     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXED );
343
344   /* Access location may be connected to a different association. */
345   if( the_access->association && the_access->association != the_assoc )
346     __disconnect( the_access, file, line );
347
348   /* Is the association location already connected? */
349   if( the_assoc->access )
350     {
351       /* save position just in case we need it for the_where == Same */
352       if( (savepos = lseek( the_assoc->handle, 0L, SEEK_CUR )) == -1L )
353         CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
354
355       /* text: read correction, flush buffer */
356       if( the_assoc->bufptr ){
357         savepos -= the_assoc->bufptr->len - the_assoc->bufptr->cur;
358         the_assoc->bufptr->len = the_assoc->bufptr->cur = 0;
359       }
360
361       /* implicit disconnect */
362       __disconnect( the_assoc->access, file, line );
363     }
364
365   the_assoc->usage = the_usage;
366   CLR_FLAG( the_access, IO_OUTOFFILE );
367  
368   if( TEST_FLAG( the_access, IO_INDEXED ) )
369     {
370       if( (the_assoc->handle = open( the_assoc->pathname, DirMode[the_usage] )) == -1 )
371         CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
372
373       /* Set base index. */
374       switch( the_where )
375         {
376         case First: 
377           filepos = 0;
378           break;
379         case Same: 
380           filepos = savepos;
381           break;
382         case Last: 
383           if( lseek( the_assoc->handle, 0L, SEEK_END ) == -1L )
384             CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
385           filepos = lseek( the_assoc->handle, 0L, SEEK_CUR );
386           break;
387         }
388
389       /* Set current index */
390       if( with_index )
391         {
392           if( the_index < the_access->lowindex
393               || the_access->highindex < the_index )
394             CHILLEXCEPTION( file, line, RANGEFAIL, BAD_INDEX );
395           filepos += (the_index - the_access->lowindex) * the_access->reclength;
396         }
397       if( lseek( the_assoc->handle, filepos, SEEK_SET ) == -1L )
398         CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
399       the_access->base = filepos;
400     }
401   else
402     {
403       /* for association to text for reading: allocate buffer */
404       if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ) &&
405           the_usage == ReadOnly &&
406           !the_assoc->bufptr )
407         {
408           if( ! (the_assoc->bufptr = (readbuf_t*)malloc( sizeof(readbuf_t) )) )
409             CHILLEXCEPTION( file, line, CONNECTFAIL, BUFFER_ALLOC ); 
410           memset (the_assoc->bufptr, 0, sizeof (readbuf_t));
411         }
412       if( (the_assoc->handle = open( the_assoc->pathname, SeqMode[the_usage] )) == -1 )
413         CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
414
415       /* Set base index. */
416       switch( the_where )
417         {
418         case First: 
419           filepos = 0;
420           break;
421         case Same: 
422           filepos = savepos;
423           break;
424         case Last:
425           if( lseek( the_assoc->handle, 0L, SEEK_END ) == -1L )
426             CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
427           filepos = lseek( the_assoc->handle, 0L, SEEK_CUR );
428           break;
429         }
430
431       /* file truncation for sequential, Write Only */
432       /***************************** FIXME: cannot truncate at Same
433         if( the_usage == WriteOnly )
434         {
435         if( fseek( the_assoc->file_ptr, filepos, SEEK_SET ) == -1L )
436         CHILLEXCEPTION( file, line, CONNECTFAIL, FSEEK_FAILS );
437         fclose( the_assoc->file_ptr );
438         if( !(the_assoc->file_ptr = fopen( the_assoc->pathname, "ab" )) )
439         CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
440         }
441         else
442         ***************************/
443       if( (filepos = lseek( the_assoc->handle, filepos, SEEK_SET )) == -1L )
444         CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
445     }
446
447   the_access->association = the_assoc;
448   the_assoc->access = the_access;
449   /* for text: set carriage control default */
450   if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ) ){
451     the_assoc->ctl_pre  = '\0';
452     the_assoc->ctl_post = '\n';
453   }
454 }
455
456 void
457 __disconnect( void* the_transfer, char* file, int line )
458 {
459   Access_Mode* the_access;
460
461   if( !the_transfer )
462     CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
463
464   if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
465     {
466       the_access = ((Text_Mode*)the_transfer)->access_sub;
467       CLR_FLAG( the_access, IO_TEXTIO );
468     }
469   else
470     the_access = (Access_Mode*)the_transfer;
471
472   if( !the_access->association )
473     CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
474
475   close( the_access->association->handle );
476   /* FIXME: check result */
477
478   if( the_access->store_loc )
479     free( the_access->store_loc );
480   the_access->store_loc           = NULL;
481   the_access->association->access = NULL;
482   the_access->association         = NULL;
483 }