OSDN Git Service

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