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)
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>
42 # ifdef _POSIX_PATH_MAX
43 # define PATH_MAX _POSIX_PATH_MAX
46 # define PATH_MAX MAXPATHLEN
48 # define PATH_MAX 1024
55 GetSetAttributes( Association_Mode
* the_assoc
)
60 if( (retco
= stat( the_assoc
->pathname
, &statbuf
)) )
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
);
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
);
87 makeName( Association_Mode
* the_assoc
, char* the_path
, int the_path_len
,
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
;
108 strncpy( the_assoc
->pathname
+ namlen
, the_path
, the_path_len
);
109 the_assoc
->pathname
[namlen
+the_path_len
] = '\0';
115 /* Caution: returns an Association mode location (!) */
117 __associate( Association_Mode
* 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;
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
);
143 if( !strncmp( the_mode
, "VARIABLE", 8 ) )
145 SET_FLAG( the_assoc
, IO_VARIABLE
);
146 CLR_FLAG( the_assoc
, IO_INDEXABLE
);
149 if( strlen( the_mode
) )
150 CHILLEXCEPTION( file
, line
, ASSOCIATEFAIL
, INVALID_ASSOCIATION_MODE
);
153 SET_FLAG( the_assoc
, IO_ISASSOCIATED
);
161 __dissociate( Association_Mode
* the_assoc
, char* file
, int line
)
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;
191 void __create( Association_Mode
* the_assoc
, char* file
, int line
)
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 ))
204 CHILLEXCEPTION( file
, line
, CREATEFAIL
, CREATE_FAILS
);
206 the_assoc
->usage
= ReadWrite
;
207 GetSetAttributes( the_assoc
);
209 close( the_assoc
->handle
);
216 __modify( Association_Mode
* 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
);
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
) )
243 CHILLEXCEPTION( file
, line
, MODIFYFAIL
, RENAME_FAILS
);
249 /* FIXME: other options? */
254 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
255 int DirMode
[] = { O_RDONLY
, O_RDWR
, O_RDWR
};
258 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
259 int SeqMode
[] = { O_RDONLY
, O_RDWR
, O_RDWR
};
265 __connect( void* the_transfer
,
266 Association_Mode
* the_assoc
,
267 Usage_Mode the_usage
,
268 Where_Mode the_where
,
270 signed long the_index
,
274 Access_Mode
* the_access
;
278 unsigned long nbytes
;
282 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ACCESS
);
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
);
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. */
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
);
389 /* Set current 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
;
403 /* for association to text for reading: allocate buffer */
404 if( TEST_FLAG((Text_Mode
*)the_transfer
, IO_TEXTLOCATION
) &&
405 the_usage
== ReadOnly
&&
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. */
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
);
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 );
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';
457 __disconnect( void* the_transfer
, char* file
, int line
)
459 Access_Mode
* the_access
;
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
);
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
;