* cpp.texi (-Wtraditional): Update description.
[official-gcc.git] / libchill / basicio.c
blob79fd9cbfa93f6112ab072372355d99ad0335ea82
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 # else
48 # define PATH_MAX 1024
49 # endif
50 # endif
51 #endif
53 static
54 void
55 GetSetAttributes( Association_Mode* the_assoc )
57 struct stat statbuf;
58 int retco;
60 if( (retco = stat( the_assoc->pathname, &statbuf )) )
61 return;
63 if( S_ISREG(statbuf.st_mode) )
65 SET_FLAG( the_assoc, IO_EXISTING );
66 if( !TEST_FLAG( the_assoc, IO_VARIABLE ) )
67 SET_FLAG( the_assoc, IO_INDEXABLE );
69 else
70 if( S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode) )
72 SET_FLAG( the_assoc, IO_EXISTING );
73 CLR_FLAG( the_assoc, IO_INDEXABLE );
75 SET_FLAG( the_assoc, IO_SEQUENCIBLE );
77 /* FIXME: File size and computation of number of records for outoffile ? */
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 );
85 static
86 void
87 makeName( Association_Mode* the_assoc, char* the_path, int the_path_len,
88 char* file, int line)
90 int namlen;
91 if( ! the_assoc->pathname &&
92 ! (the_assoc->pathname = (char*)malloc( PATH_MAX )) )
93 CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
95 if( the_path[0] != DIRSEP )
97 if( !getcwd( the_assoc->pathname, PATH_MAX ) )
99 the_assoc->syserrno = errno;
100 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, GETCWD_FAILS );
102 namlen = strlen( the_assoc->pathname );
103 the_assoc->pathname[namlen++] = DIRSEP;
105 else
106 namlen = 0;
108 strncpy( the_assoc->pathname + namlen, the_path, the_path_len );
109 the_assoc->pathname[namlen+the_path_len] = '\0';
113 * ASSOCIATE
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 )
125 if( !the_assoc )
126 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
128 if( TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
129 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, IS_ASSOCIATED );
131 /* clear all flags */
132 the_assoc->flags = 0;
134 if( ! the_path_len )
135 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, NO_PATH_NAME );
137 makeName( the_assoc, the_path, the_path_len, file, line );
138 GetSetAttributes( the_assoc );
140 CLR_FLAG( the_assoc, IO_VARIABLE );
141 if ( the_mode )
143 if( !strncmp( the_mode, "VARIABLE", 8 ) )
145 SET_FLAG( the_assoc, IO_VARIABLE );
146 CLR_FLAG( the_assoc, IO_INDEXABLE );
148 else
149 if( strlen( the_mode ) )
150 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, INVALID_ASSOCIATION_MODE );
153 SET_FLAG( the_assoc, IO_ISASSOCIATED );
154 return the_assoc;
158 * DISSOCIATE
160 void
161 __dissociate( Association_Mode* the_assoc, char* file, int line )
163 if( !the_assoc )
164 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
166 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
167 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
169 if( the_assoc->access )
170 __disconnect( the_assoc->access, file, line );
172 the_assoc->access = NULL;
173 CLR_FLAG( the_assoc, IO_ISASSOCIATED );
175 /* free allocated memory */
176 if (the_assoc->pathname)
178 free (the_assoc->pathname);
179 the_assoc->pathname = 0;
181 if (the_assoc->bufptr)
183 free (the_assoc->bufptr);
184 the_assoc->bufptr = 0;
189 * CREATE
191 void __create( Association_Mode* the_assoc, char* file, int line )
193 if( !the_assoc )
194 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
196 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
197 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
199 if( TEST_FLAG( the_assoc, IO_EXISTING ) )
200 CHILLEXCEPTION( file, line, CREATEFAIL, FILE_EXISTING );
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 );
206 the_assoc->usage = ReadWrite;
207 GetSetAttributes( the_assoc );
209 close( the_assoc->handle );
213 * MODIFY
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 )
224 if( !the_assoc )
225 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
227 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
228 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
230 if( the_path_len )
232 char* oldname;
234 if( ! (oldname = (char*)malloc( PATH_MAX )) )
235 CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
236 strcpy( oldname, the_assoc->pathname );
238 makeName( the_assoc, the_path, the_path_len, file, line );
240 if( rename( oldname, the_assoc->pathname ) )
242 free( oldname );
243 CHILLEXCEPTION( file, line, MODIFYFAIL, RENAME_FAILS );
245 free( oldname );
247 else
249 /* FIXME: other options? */
253 static
254 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
255 int DirMode[] = { O_RDONLY, O_RDWR, O_RDWR };
257 static
258 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
259 int SeqMode[] = { O_RDONLY, O_RDWR, O_RDWR };
262 * CONNECT
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 )
274 Access_Mode* the_access;
275 off_t filepos;
276 off_t savepos;
277 char dummy;
278 unsigned long nbytes;
279 int oflag;
281 if( !the_transfer )
282 CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
283 if( !the_assoc )
284 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
286 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
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 );
293 else
295 the_access = (Access_Mode*)the_transfer;
296 CLR_FLAG( the_access, IO_TEXTIO );
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 );
304 if( ! TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
305 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
307 if( ! TEST_FLAG( the_assoc, IO_EXISTING ) )
308 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_EXISTING );
310 if( ! TEST_FLAG( the_assoc, IO_READABLE ) &&
311 ( the_usage = ReadOnly || the_usage == ReadWrite ) )
312 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_READABLE );
314 if( ! TEST_FLAG( the_assoc, IO_WRITEABLE ) &&
315 ( the_usage = WriteOnly || the_usage == ReadWrite ) )
316 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_WRITEABLE );
318 if( ! TEST_FLAG( the_assoc, IO_INDEXABLE )
319 && TEST_FLAG( the_access, IO_INDEXED ) )
320 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXABLE );
322 if( ! TEST_FLAG( the_assoc, IO_SEQUENCIBLE )
323 && ! TEST_FLAG( the_access, IO_INDEXED ) )
324 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_SEQUENCIBLE );
326 if( the_where == Same && the_assoc->access == NULL )
327 CHILLEXCEPTION( file, line, CONNECTFAIL, NO_CURRENT_POS );
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 );
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 );
341 if( ! TEST_FLAG( the_access, IO_INDEXED ) && the_usage == ReadWrite )
342 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXED );
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 );
348 /* Is the association location already connected? */
349 if( the_assoc->access )
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 );
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;
361 /* implicit disconnect */
362 __disconnect( the_assoc->access, file, line );
365 the_assoc->usage = the_usage;
366 CLR_FLAG( the_access, IO_OUTOFFILE );
368 if( TEST_FLAG( the_access, IO_INDEXED ) )
370 if( (the_assoc->handle = open( the_assoc->pathname, DirMode[the_usage] )) == -1 )
371 CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
373 /* Set base index. */
374 switch( the_where )
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;
389 /* Set current index */
390 if( with_index )
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;
397 if( lseek( the_assoc->handle, filepos, SEEK_SET ) == -1L )
398 CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
399 the_access->base = filepos;
401 else
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 )
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));
412 if( (the_assoc->handle = open( the_assoc->pathname, SeqMode[the_usage] )) == -1 )
413 CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
415 /* Set base index. */
416 switch( the_where )
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;
431 /* file truncation for sequential, Write Only */
432 /***************************** FIXME: cannot truncate at Same
433 if( the_usage == WriteOnly )
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 );
441 else
442 ***************************/
443 if( (filepos = lseek( the_assoc->handle, filepos, SEEK_SET )) == -1L )
444 CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
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';
456 void
457 __disconnect( void* the_transfer, char* file, int line )
459 Access_Mode* the_access;
461 if( !the_transfer )
462 CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
464 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
466 the_access = ((Text_Mode*)the_transfer)->access_sub;
467 CLR_FLAG( the_access, IO_TEXTIO );
469 else
470 the_access = (Access_Mode*)the_transfer;
472 if( !the_access->association )
473 CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
475 close( the_access->association->handle );
476 /* FIXME: check result */
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;