OSDN Git Service

* decl.c (init_decl_processing): Remove duplicate decl of
[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 #endif
48 #endif
49 #endif
50
51 static
52 void
53 GetSetAttributes( Association_Mode* the_assoc )
54 {
55   struct stat statbuf;
56   int retco;
57
58   if( (retco = stat( the_assoc->pathname, &statbuf )) )
59     return;
60
61   if( S_ISREG(statbuf.st_mode) )
62     {
63       SET_FLAG( the_assoc, IO_EXISTING );
64       if( !TEST_FLAG( the_assoc, IO_VARIABLE ) )
65         SET_FLAG( the_assoc, IO_INDEXABLE );
66     }
67   else
68     if( S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode) )
69       {
70         SET_FLAG( the_assoc, IO_EXISTING );
71         CLR_FLAG( the_assoc, IO_INDEXABLE );
72       }
73   SET_FLAG( the_assoc, IO_SEQUENCIBLE );
74
75   /* FIXME: File size and computation of number of records for outoffile ? */
76
77   if( !access( the_assoc->pathname, R_OK ) )
78     SET_FLAG( the_assoc, IO_READABLE );
79   if( !access( the_assoc->pathname, W_OK ) )
80     SET_FLAG( the_assoc, IO_WRITEABLE );
81 }
82
83 static
84 void 
85 makeName( Association_Mode* the_assoc, char* the_path, int the_path_len,
86          char* file, int line)
87 {
88   int namlen;
89   if( ! the_assoc->pathname && 
90       ! (the_assoc->pathname = (char*)malloc( PATH_MAX )) )
91     CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
92
93   if( the_path[0] != DIRSEP )
94     {
95       if( !getcwd( the_assoc->pathname, PATH_MAX ) )
96         {
97           the_assoc->syserrno = errno;
98           CHILLEXCEPTION( file, line, ASSOCIATEFAIL, GETCWD_FAILS );
99         }
100       namlen = strlen( the_assoc->pathname );
101       the_assoc->pathname[namlen++] = DIRSEP;  
102     }
103   else
104     namlen = 0;
105
106   strncpy( the_assoc->pathname + namlen, the_path, the_path_len );
107   the_assoc->pathname[namlen+the_path_len] = '\0';
108 }
109
110 /*
111  * ASSOCIATE
112  */
113 /* Caution: returns an Association mode location (!) */
114 Association_Mode*
115 __associate( Association_Mode* the_assoc,
116              char*             the_path,
117              int               the_path_len,
118              char*             the_mode,
119              int               the_mode_len,
120              char*             file,
121              int               line )
122 {
123   if( !the_assoc )
124     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
125
126   if( TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
127     CHILLEXCEPTION( file, line, ASSOCIATEFAIL, IS_ASSOCIATED );
128
129   /* clear all flags */
130   the_assoc->flags = 0;
131
132   if( ! the_path_len )
133     CHILLEXCEPTION( file, line, ASSOCIATEFAIL, NO_PATH_NAME );
134
135   makeName( the_assoc, the_path, the_path_len, file, line );
136   GetSetAttributes( the_assoc );
137
138   CLR_FLAG( the_assoc, IO_VARIABLE );
139   if ( the_mode )
140     {
141       if( !strncmp( the_mode, "VARIABLE", 8 ) )
142         {
143           SET_FLAG( the_assoc, IO_VARIABLE );
144           CLR_FLAG( the_assoc, IO_INDEXABLE );
145         }
146       else
147         if( strlen( the_mode ) )
148           CHILLEXCEPTION( file, line, ASSOCIATEFAIL, INVALID_ASSOCIATION_MODE );
149     }
150
151   SET_FLAG( the_assoc, IO_ISASSOCIATED );
152   return the_assoc;
153 }
154
155 /*
156  *  DISSOCIATE
157  */
158 void
159 __dissociate( Association_Mode* the_assoc, char* file, int line )
160 {
161   if( !the_assoc )
162     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
163
164   if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
165     CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
166
167   if( the_assoc->access )
168     __disconnect( the_assoc->access, file, line );
169
170   the_assoc->access = NULL;
171   CLR_FLAG( the_assoc, IO_ISASSOCIATED );
172
173   /* free allocated memory */
174   if (the_assoc->pathname)
175     {
176       free (the_assoc->pathname);
177       the_assoc->pathname = 0;
178     }
179   if (the_assoc->bufptr)
180     {
181       free (the_assoc->bufptr);
182       the_assoc->bufptr = 0;
183     }
184 }
185
186 /*
187  * CREATE
188  */
189 void __create( Association_Mode* the_assoc, char* file, int line )
190 {
191   if( !the_assoc )
192     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
193
194   if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
195     CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
196
197   if( TEST_FLAG( the_assoc, IO_EXISTING ) )
198     CHILLEXCEPTION( file, line, CREATEFAIL, FILE_EXISTING );
199
200   if( (the_assoc->handle = open( the_assoc->pathname, O_CREAT+O_TRUNC+O_WRONLY, 0666 ))
201       == -1 )
202       CHILLEXCEPTION( file, line, CREATEFAIL, CREATE_FAILS );
203
204   the_assoc->usage = ReadWrite;
205   GetSetAttributes( the_assoc );
206
207   close( the_assoc->handle );
208 }
209
210 /*
211  * MODIFY
212  */
213 void
214 __modify( Association_Mode* the_assoc,
215           char*             the_path,
216           int               the_path_len,
217           char*             the_mode,
218           int               the_mode_len,
219           char*             file,
220           int               line )
221 {
222   if( !the_assoc )
223     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
224
225   if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
226     CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
227
228   if( the_path_len )
229     {
230       char* oldname;
231
232       if( ! (oldname = (char*)malloc( PATH_MAX )) )
233         CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
234       strcpy( oldname, the_assoc->pathname );
235
236       makeName( the_assoc, the_path, the_path_len, file, line );
237
238       if( rename( oldname, the_assoc->pathname ) )
239         {
240           free( oldname );
241           CHILLEXCEPTION( file, line, MODIFYFAIL, RENAME_FAILS );
242         }
243       free( oldname );
244     }
245   else
246     {
247       /* FIXME: other options? */
248     }
249 }
250
251 static
252 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
253 int DirMode[] = { O_RDONLY, O_RDWR, O_RDWR };
254
255 static
256 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
257 int SeqMode[] = { O_RDONLY, O_RDWR, O_RDWR };
258
259 /*
260  * CONNECT
261  */
262 void
263 __connect( void*             the_transfer,
264            Association_Mode* the_assoc,
265            Usage_Mode        the_usage,
266            Where_Mode        the_where,
267            Boolean           with_index,
268            signed long       the_index,
269            char*             file,
270            int               line )
271 {
272   Access_Mode*  the_access;
273   off_t         filepos;
274   off_t         savepos;
275   char          dummy;
276   unsigned long nbytes;
277   int           oflag;
278
279   if( !the_transfer )
280     CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
281   if( !the_assoc )
282     CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
283
284   if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
285     {
286       if( ! ((Text_Mode*)the_transfer)->access_sub )
287         CHILLEXCEPTION( file, line, EMPTY, NO_ACCESS_SUBLOCATION );
288       the_access = ((Text_Mode*)the_transfer)->access_sub;
289       SET_FLAG( the_access, IO_TEXTIO );
290     }
291   else
292     {
293       the_access = (Access_Mode*)the_transfer;
294       CLR_FLAG( the_access, IO_TEXTIO );
295     }
296
297   /* FIXME: This should be an (implementation-dependent) static check
298      if( with_index && the_access->rectype > Fixed )
299      CHILLEXCEPTION( file, line, CONNECTFAIL, IMPL_RESTRICTION );
300      */
301
302   if( ! TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
303     CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
304
305   if( ! TEST_FLAG( the_assoc, IO_EXISTING ) )
306     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_EXISTING );
307
308   if( ! TEST_FLAG( the_assoc, IO_READABLE ) &&
309       ( the_usage = ReadOnly || the_usage == ReadWrite ) )    
310     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_READABLE );
311
312   if( ! TEST_FLAG( the_assoc, IO_WRITEABLE ) &&
313       ( the_usage = WriteOnly || the_usage == ReadWrite ) )    
314     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_WRITEABLE );
315
316   if( ! TEST_FLAG( the_assoc, IO_INDEXABLE ) 
317       && TEST_FLAG( the_access, IO_INDEXED ) )
318     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXABLE );
319
320   if( ! TEST_FLAG( the_assoc, IO_SEQUENCIBLE ) 
321       && ! TEST_FLAG( the_access, IO_INDEXED ) )
322     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_SEQUENCIBLE );
323
324   if( the_where == Same && the_assoc->access == NULL )
325     CHILLEXCEPTION( file, line, CONNECTFAIL, NO_CURRENT_POS );
326
327   /* This dynamic condition is not checked for text connections. */
328   if( ! TEST_FLAG( the_access, IO_TEXTIO ) )
329     if( ! TEST_FLAG( the_assoc, IO_VARIABLE ) 
330         && the_access->rectype > Fixed 
331         && ( the_usage == WriteOnly || the_usage == ReadWrite ) )
332       CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_VARIABLE );
333  
334   if( TEST_FLAG( the_assoc, IO_VARIABLE )
335       && the_access->rectype == Fixed 
336       && ( the_usage == ReadOnly || the_usage == ReadWrite ) )
337     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_FIXED );
338  
339   if( ! TEST_FLAG( the_access, IO_INDEXED ) && the_usage == ReadWrite )
340     CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXED );
341
342   /* Access location may be connected to a different association. */
343   if( the_access->association && the_access->association != the_assoc )
344     __disconnect( the_access, file, line );
345
346   /* Is the association location already connected? */
347   if( the_assoc->access )
348     {
349       /* save position just in case we need it for the_where == Same */
350       if( (savepos = lseek( the_assoc->handle, 0L, SEEK_CUR )) == -1L )
351         CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
352
353       /* text: read correction, flush buffer */
354       if( the_assoc->bufptr ){
355         savepos -= the_assoc->bufptr->len - the_assoc->bufptr->cur;
356         the_assoc->bufptr->len = the_assoc->bufptr->cur = 0;
357       }
358
359       /* implicit disconnect */
360       __disconnect( the_assoc->access, file, line );
361     }
362
363   the_assoc->usage = the_usage;
364   CLR_FLAG( the_access, IO_OUTOFFILE );
365  
366   if( TEST_FLAG( the_access, IO_INDEXED ) )
367     {
368       if( (the_assoc->handle = open( the_assoc->pathname, DirMode[the_usage] )) == -1 )
369         CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
370
371       /* Set base index. */
372       switch( the_where )
373         {
374         case First: 
375           filepos = 0;
376           break;
377         case Same: 
378           filepos = savepos;
379           break;
380         case Last: 
381           if( lseek( the_assoc->handle, 0L, SEEK_END ) == -1L )
382             CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
383           filepos = lseek( the_assoc->handle, 0L, SEEK_CUR );
384           break;
385         }
386
387       /* Set current index */
388       if( with_index )
389         {
390           if( the_index < the_access->lowindex
391               || the_access->highindex < the_index )
392             CHILLEXCEPTION( file, line, RANGEFAIL, BAD_INDEX );
393           filepos += (the_index - the_access->lowindex) * the_access->reclength;
394         }
395       if( lseek( the_assoc->handle, filepos, SEEK_SET ) == -1L )
396         CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
397       the_access->base = filepos;
398     }
399   else
400     {
401       /* for association to text for reading: allocate buffer */
402       if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ) &&
403           the_usage == ReadOnly &&
404           !the_assoc->bufptr )
405         {
406           if( ! (the_assoc->bufptr = (readbuf_t*)malloc( sizeof(readbuf_t) )) )
407             CHILLEXCEPTION( file, line, CONNECTFAIL, BUFFER_ALLOC ); 
408           memset (the_assoc->bufptr, 0, sizeof (readbuf_t));
409         }
410       if( (the_assoc->handle = open( the_assoc->pathname, SeqMode[the_usage] )) == -1 )
411         CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
412
413       /* Set base index. */
414       switch( the_where )
415         {
416         case First: 
417           filepos = 0;
418           break;
419         case Same: 
420           filepos = savepos;
421           break;
422         case Last:
423           if( lseek( the_assoc->handle, 0L, SEEK_END ) == -1L )
424             CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
425           filepos = lseek( the_assoc->handle, 0L, SEEK_CUR );
426           break;
427         }
428
429       /* file truncation for sequential, Write Only */
430       /***************************** FIXME: cannot truncate at Same
431         if( the_usage == WriteOnly )
432         {
433         if( fseek( the_assoc->file_ptr, filepos, SEEK_SET ) == -1L )
434         CHILLEXCEPTION( file, line, CONNECTFAIL, FSEEK_FAILS );
435         fclose( the_assoc->file_ptr );
436         if( !(the_assoc->file_ptr = fopen( the_assoc->pathname, "ab" )) )
437         CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
438         }
439         else
440         ***************************/
441       if( (filepos = lseek( the_assoc->handle, filepos, SEEK_SET )) == -1L )
442         CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
443     }
444
445   the_access->association = the_assoc;
446   the_assoc->access = the_access;
447   /* for text: set carriage control default */
448   if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ) ){
449     the_assoc->ctl_pre  = '\0';
450     the_assoc->ctl_post = '\n';
451   }
452 }
453
454 void
455 __disconnect( void* the_transfer, char* file, int line )
456 {
457   Access_Mode* the_access;
458
459   if( !the_transfer )
460     CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
461
462   if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
463     {
464       the_access = ((Text_Mode*)the_transfer)->access_sub;
465       CLR_FLAG( the_access, IO_TEXTIO );
466     }
467   else
468     the_access = (Access_Mode*)the_transfer;
469
470   if( !the_access->association )
471     CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
472
473   close( the_access->association->handle );
474   /* FIXME: check result */
475
476   if( the_access->store_loc )
477     free( the_access->store_loc );
478   the_access->store_loc           = NULL;
479   the_access->association->access = NULL;
480   the_access->association         = NULL;
481 }