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
53 GetSetAttributes( Association_Mode
* the_assoc
)
58 if( (retco
= stat( the_assoc
->pathname
, &statbuf
)) )
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
);
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
);
85 makeName( Association_Mode
* the_assoc
, char* the_path
, int the_path_len
,
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
;
106 strncpy( the_assoc
->pathname
+ namlen
, the_path
, the_path_len
);
107 the_assoc
->pathname
[namlen
+the_path_len
] = '\0';
113 /* Caution: returns an Association mode location (!) */
115 __associate( Association_Mode
* 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;
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
);
141 if( !strncmp( the_mode
, "VARIABLE", 8 ) )
143 SET_FLAG( the_assoc
, IO_VARIABLE
);
144 CLR_FLAG( the_assoc
, IO_INDEXABLE
);
147 if( strlen( the_mode
) )
148 CHILLEXCEPTION( file
, line
, ASSOCIATEFAIL
, INVALID_ASSOCIATION_MODE
);
151 SET_FLAG( the_assoc
, IO_ISASSOCIATED
);
159 __dissociate( Association_Mode
* the_assoc
, char* file
, int line
)
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;
189 void __create( Association_Mode
* the_assoc
, char* file
, int line
)
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 ))
202 CHILLEXCEPTION( file
, line
, CREATEFAIL
, CREATE_FAILS
);
204 the_assoc
->usage
= ReadWrite
;
205 GetSetAttributes( the_assoc
);
207 close( the_assoc
->handle
);
214 __modify( Association_Mode
* 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
);
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
) )
241 CHILLEXCEPTION( file
, line
, MODIFYFAIL
, RENAME_FAILS
);
247 /* FIXME: other options? */
252 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
253 int DirMode
[] = { O_RDONLY
, O_RDWR
, O_RDWR
};
256 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
257 int SeqMode
[] = { O_RDONLY
, O_RDWR
, O_RDWR
};
263 __connect( void* the_transfer
,
264 Association_Mode
* the_assoc
,
265 Usage_Mode the_usage
,
266 Where_Mode the_where
,
268 signed long the_index
,
272 Access_Mode
* the_access
;
276 unsigned long nbytes
;
280 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ACCESS
);
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
);
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. */
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
);
387 /* Set current 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
;
401 /* for association to text for reading: allocate buffer */
402 if( TEST_FLAG((Text_Mode
*)the_transfer
, IO_TEXTLOCATION
) &&
403 the_usage
== ReadOnly
&&
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. */
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
);
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 );
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';
455 __disconnect( void* the_transfer
, char* file
, int line
)
457 Access_Mode
* the_access
;
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
);
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
;