* decl2.c (start_static_storage_duration_function): Push the
[official-gcc.git] / libchill / basicio.c
blob7ff71d9f52455f8d9d8ffdfb928e68eff9b19ddd
1 /* Implement Input/Output runtime actions for CHILL.
2 Copyright (C) 1992,1993 Free Software Foundation, Inc.
3 Author: Wilfried Moser, et al
5 This file is part of GNU CC.
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.
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.
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. */
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. */
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>
36 #include <string.h>
37 #include <stdlib.h>
39 #include "fileio.h"
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
51 static
52 void
53 GetSetAttributes( Association_Mode* the_assoc )
55 struct stat statbuf;
56 int retco;
58 if( (retco = stat( the_assoc->pathname, &statbuf )) )
59 return;
61 if( S_ISREG(statbuf.st_mode) )
63 SET_FLAG( the_assoc, IO_EXISTING );
64 if( !TEST_FLAG( the_assoc, IO_VARIABLE ) )
65 SET_FLAG( the_assoc, IO_INDEXABLE );
67 else
68 if( S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode) )
70 SET_FLAG( the_assoc, IO_EXISTING );
71 CLR_FLAG( the_assoc, IO_INDEXABLE );
73 SET_FLAG( the_assoc, IO_SEQUENCIBLE );
75 /* FIXME: File size and computation of number of records for outoffile ? */
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 );
83 static
84 void
85 makeName( Association_Mode* the_assoc, char* the_path, int the_path_len,
86 char* file, int line)
88 int namlen;
89 if( ! the_assoc->pathname &&
90 ! (the_assoc->pathname = (char*)malloc( PATH_MAX )) )
91 CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
93 if( the_path[0] != DIRSEP )
95 if( !getcwd( the_assoc->pathname, PATH_MAX ) )
97 the_assoc->syserrno = errno;
98 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, GETCWD_FAILS );
100 namlen = strlen( the_assoc->pathname );
101 the_assoc->pathname[namlen++] = DIRSEP;
103 else
104 namlen = 0;
106 strncpy( the_assoc->pathname + namlen, the_path, the_path_len );
107 the_assoc->pathname[namlen+the_path_len] = '\0';
111 * ASSOCIATE
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 )
123 if( !the_assoc )
124 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
126 if( TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
127 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, IS_ASSOCIATED );
129 /* clear all flags */
130 the_assoc->flags = 0;
132 if( ! the_path_len )
133 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, NO_PATH_NAME );
135 makeName( the_assoc, the_path, the_path_len, file, line );
136 GetSetAttributes( the_assoc );
138 CLR_FLAG( the_assoc, IO_VARIABLE );
139 if ( the_mode )
141 if( !strncmp( the_mode, "VARIABLE", 8 ) )
143 SET_FLAG( the_assoc, IO_VARIABLE );
144 CLR_FLAG( the_assoc, IO_INDEXABLE );
146 else
147 if( strlen( the_mode ) )
148 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, INVALID_ASSOCIATION_MODE );
151 SET_FLAG( the_assoc, IO_ISASSOCIATED );
152 return the_assoc;
156 * DISSOCIATE
158 void
159 __dissociate( Association_Mode* the_assoc, char* file, int line )
161 if( !the_assoc )
162 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
164 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
165 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
167 if( the_assoc->access )
168 __disconnect( the_assoc->access, file, line );
170 the_assoc->access = NULL;
171 CLR_FLAG( the_assoc, IO_ISASSOCIATED );
173 /* free allocated memory */
174 if (the_assoc->pathname)
176 free (the_assoc->pathname);
177 the_assoc->pathname = 0;
179 if (the_assoc->bufptr)
181 free (the_assoc->bufptr);
182 the_assoc->bufptr = 0;
187 * CREATE
189 void __create( Association_Mode* the_assoc, char* file, int line )
191 if( !the_assoc )
192 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
194 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
195 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
197 if( TEST_FLAG( the_assoc, IO_EXISTING ) )
198 CHILLEXCEPTION( file, line, CREATEFAIL, FILE_EXISTING );
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 );
204 the_assoc->usage = ReadWrite;
205 GetSetAttributes( the_assoc );
207 close( the_assoc->handle );
211 * MODIFY
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 )
222 if( !the_assoc )
223 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
225 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
226 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
228 if( the_path_len )
230 char* oldname;
232 if( ! (oldname = (char*)malloc( PATH_MAX )) )
233 CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
234 strcpy( oldname, the_assoc->pathname );
236 makeName( the_assoc, the_path, the_path_len, file, line );
238 if( rename( oldname, the_assoc->pathname ) )
240 free( oldname );
241 CHILLEXCEPTION( file, line, MODIFYFAIL, RENAME_FAILS );
243 free( oldname );
245 else
247 /* FIXME: other options? */
251 static
252 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
253 int DirMode[] = { O_RDONLY, O_RDWR, O_RDWR };
255 static
256 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
257 int SeqMode[] = { O_RDONLY, O_RDWR, O_RDWR };
260 * CONNECT
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 )
272 Access_Mode* the_access;
273 off_t filepos;
274 off_t savepos;
275 char dummy;
276 unsigned long nbytes;
277 int oflag;
279 if( !the_transfer )
280 CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
281 if( !the_assoc )
282 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
284 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
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 );
291 else
293 the_access = (Access_Mode*)the_transfer;
294 CLR_FLAG( the_access, IO_TEXTIO );
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 );
302 if( ! TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
303 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
305 if( ! TEST_FLAG( the_assoc, IO_EXISTING ) )
306 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_EXISTING );
308 if( ! TEST_FLAG( the_assoc, IO_READABLE ) &&
309 ( the_usage = ReadOnly || the_usage == ReadWrite ) )
310 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_READABLE );
312 if( ! TEST_FLAG( the_assoc, IO_WRITEABLE ) &&
313 ( the_usage = WriteOnly || the_usage == ReadWrite ) )
314 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_WRITEABLE );
316 if( ! TEST_FLAG( the_assoc, IO_INDEXABLE )
317 && TEST_FLAG( the_access, IO_INDEXED ) )
318 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXABLE );
320 if( ! TEST_FLAG( the_assoc, IO_SEQUENCIBLE )
321 && ! TEST_FLAG( the_access, IO_INDEXED ) )
322 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_SEQUENCIBLE );
324 if( the_where == Same && the_assoc->access == NULL )
325 CHILLEXCEPTION( file, line, CONNECTFAIL, NO_CURRENT_POS );
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 );
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 );
339 if( ! TEST_FLAG( the_access, IO_INDEXED ) && the_usage == ReadWrite )
340 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXED );
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 );
346 /* Is the association location already connected? */
347 if( the_assoc->access )
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 );
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;
359 /* implicit disconnect */
360 __disconnect( the_assoc->access, file, line );
363 the_assoc->usage = the_usage;
364 CLR_FLAG( the_access, IO_OUTOFFILE );
366 if( TEST_FLAG( the_access, IO_INDEXED ) )
368 if( (the_assoc->handle = open( the_assoc->pathname, DirMode[the_usage] )) == -1 )
369 CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
371 /* Set base index. */
372 switch( the_where )
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;
387 /* Set current index */
388 if( with_index )
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;
395 if( lseek( the_assoc->handle, filepos, SEEK_SET ) == -1L )
396 CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
397 the_access->base = filepos;
399 else
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 )
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));
410 if( (the_assoc->handle = open( the_assoc->pathname, SeqMode[the_usage] )) == -1 )
411 CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
413 /* Set base index. */
414 switch( the_where )
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;
429 /* file truncation for sequential, Write Only */
430 /***************************** FIXME: cannot truncate at Same
431 if( the_usage == WriteOnly )
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 );
439 else
440 ***************************/
441 if( (filepos = lseek( the_assoc->handle, filepos, SEEK_SET )) == -1L )
442 CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
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';
454 void
455 __disconnect( void* the_transfer, char* file, int line )
457 Access_Mode* the_access;
459 if( !the_transfer )
460 CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
462 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
464 the_access = ((Text_Mode*)the_transfer)->access_sub;
465 CLR_FLAG( the_access, IO_TEXTIO );
467 else
468 the_access = (Access_Mode*)the_transfer;
470 if( !the_access->association )
471 CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
473 close( the_access->association->handle );
474 /* FIXME: check result */
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;