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, 675 Mass Ave, Cambridge, MA 02139, USA. */
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. */
28 #include <sys/types.h>
41 #define PATH_MAX _POSIX_PATH_MAX
46 GetSetAttributes( Association_Mode
* the_assoc
)
51 if( (retco
= stat( the_assoc
->pathname
, &statbuf
)) )
54 if( S_ISREG(statbuf
.st_mode
) )
56 SET_FLAG( the_assoc
, IO_EXISTING
);
57 if( !TEST_FLAG( the_assoc
, IO_VARIABLE
) )
58 SET_FLAG( the_assoc
, IO_INDEXABLE
);
61 if( S_ISCHR(statbuf
.st_mode
) || S_ISFIFO(statbuf
.st_mode
) )
63 SET_FLAG( the_assoc
, IO_EXISTING
);
64 CLR_FLAG( the_assoc
, IO_INDEXABLE
);
66 SET_FLAG( the_assoc
, IO_SEQUENCIBLE
);
68 /* FIXME: File size and computation of number of records for outoffile ? */
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
);
78 makeName( Association_Mode
* the_assoc
, char* the_path
, int the_path_len
,
82 if( ! the_assoc
->pathname
&&
83 ! (the_assoc
->pathname
= (char*)malloc( PATH_MAX
)) )
84 CHILLEXCEPTION( file
, line
, SPACEFAIL
, PATHNAME_ALLOC
);
86 if( the_path
[0] != DIRSEP
)
88 if( !getcwd( the_assoc
->pathname
, PATH_MAX
) )
90 the_assoc
->syserrno
= errno
;
91 CHILLEXCEPTION( file
, line
, ASSOCIATEFAIL
, GETCWD_FAILS
);
93 namlen
= strlen( the_assoc
->pathname
);
94 the_assoc
->pathname
[namlen
++] = DIRSEP
;
99 strncpy( the_assoc
->pathname
+ namlen
, the_path
, the_path_len
);
100 the_assoc
->pathname
[namlen
+the_path_len
] = '\0';
106 /* Caution: returns an Association mode location (!) */
108 __associate( Association_Mode
* the_assoc
,
117 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ASSOCIATION
);
119 if( TEST_FLAG(the_assoc
, IO_ISASSOCIATED
) )
120 CHILLEXCEPTION( file
, line
, ASSOCIATEFAIL
, IS_ASSOCIATED
);
122 /* clear all flags */
123 the_assoc
->flags
= 0;
126 CHILLEXCEPTION( file
, line
, ASSOCIATEFAIL
, NO_PATH_NAME
);
128 makeName( the_assoc
, the_path
, the_path_len
, file
, line
);
129 GetSetAttributes( the_assoc
);
131 CLR_FLAG( the_assoc
, IO_VARIABLE
);
134 if( !strncmp( the_mode
, "VARIABLE", 8 ) )
136 SET_FLAG( the_assoc
, IO_VARIABLE
);
137 CLR_FLAG( the_assoc
, IO_INDEXABLE
);
140 if( strlen( the_mode
) )
141 CHILLEXCEPTION( file
, line
, ASSOCIATEFAIL
, INVALID_ASSOCIATION_MODE
);
144 SET_FLAG( the_assoc
, IO_ISASSOCIATED
);
152 __dissociate( Association_Mode
* the_assoc
, char* file
, int line
)
155 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ASSOCIATION
);
157 if( !TEST_FLAG( the_assoc
, IO_ISASSOCIATED
) )
158 CHILLEXCEPTION( file
, line
, NOTASSOCIATED
, IS_NOT_ASSOCIATED
);
160 if( the_assoc
->access
)
161 __disconnect( the_assoc
->access
, file
, line
);
163 the_assoc
->access
= NULL
;
164 CLR_FLAG( the_assoc
, IO_ISASSOCIATED
);
166 /* free allocated memory */
167 if (the_assoc
->pathname
)
169 free (the_assoc
->pathname
);
170 the_assoc
->pathname
= 0;
172 if (the_assoc
->bufptr
)
174 free (the_assoc
->bufptr
);
175 the_assoc
->bufptr
= 0;
182 void __create( Association_Mode
* the_assoc
, char* file
, int line
)
185 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ASSOCIATION
);
187 if( !TEST_FLAG( the_assoc
, IO_ISASSOCIATED
) )
188 CHILLEXCEPTION( file
, line
, NOTASSOCIATED
, IS_NOT_ASSOCIATED
);
190 if( TEST_FLAG( the_assoc
, IO_EXISTING
) )
191 CHILLEXCEPTION( file
, line
, CREATEFAIL
, FILE_EXISTING
);
193 if( (the_assoc
->handle
= open( the_assoc
->pathname
, O_CREAT
+O_TRUNC
+O_WRONLY
, 0666 ))
195 CHILLEXCEPTION( file
, line
, CREATEFAIL
, CREATE_FAILS
);
197 the_assoc
->usage
= ReadWrite
;
198 GetSetAttributes( the_assoc
);
200 close( the_assoc
->handle
);
207 __modify( Association_Mode
* the_assoc
,
216 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ASSOCIATION
);
218 if( !TEST_FLAG( the_assoc
, IO_ISASSOCIATED
) )
219 CHILLEXCEPTION( file
, line
, NOTASSOCIATED
, IS_NOT_ASSOCIATED
);
225 if( ! (oldname
= (char*)malloc( PATH_MAX
)) )
226 CHILLEXCEPTION( file
, line
, SPACEFAIL
, PATHNAME_ALLOC
);
227 strcpy( oldname
, the_assoc
->pathname
);
229 makeName( the_assoc
, the_path
, the_path_len
, file
, line
);
231 if( rename( oldname
, the_assoc
->pathname
) )
234 CHILLEXCEPTION( file
, line
, MODIFYFAIL
, RENAME_FAILS
);
240 /* FIXME: other options? */
245 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
246 int DirMode
[] = { O_RDONLY
, O_RDWR
, O_RDWR
};
249 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
250 int SeqMode
[] = { O_RDONLY
, O_RDWR
, O_RDWR
};
256 __connect( void* the_transfer
,
257 Association_Mode
* the_assoc
,
258 Usage_Mode the_usage
,
259 Where_Mode the_where
,
261 signed long the_index
,
265 Access_Mode
* the_access
;
269 unsigned long nbytes
;
273 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ACCESS
);
275 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ASSOCIATION
);
277 if( TEST_FLAG((Text_Mode
*)the_transfer
, IO_TEXTLOCATION
))
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
);
286 the_access
= (Access_Mode
*)the_transfer
;
287 CLR_FLAG( the_access
, IO_TEXTIO
);
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 );
295 if( ! TEST_FLAG(the_assoc
, IO_ISASSOCIATED
) )
296 CHILLEXCEPTION( file
, line
, NOTASSOCIATED
, IS_NOT_ASSOCIATED
);
298 if( ! TEST_FLAG( the_assoc
, IO_EXISTING
) )
299 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, NOT_EXISTING
);
301 if( ! TEST_FLAG( the_assoc
, IO_READABLE
) &&
302 ( the_usage
= ReadOnly
|| the_usage
== ReadWrite
) )
303 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, NOT_READABLE
);
305 if( ! TEST_FLAG( the_assoc
, IO_WRITEABLE
) &&
306 ( the_usage
= WriteOnly
|| the_usage
== ReadWrite
) )
307 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, NOT_WRITEABLE
);
309 if( ! TEST_FLAG( the_assoc
, IO_INDEXABLE
)
310 && TEST_FLAG( the_access
, IO_INDEXED
) )
311 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, NOT_INDEXABLE
);
313 if( ! TEST_FLAG( the_assoc
, IO_SEQUENCIBLE
)
314 && ! TEST_FLAG( the_access
, IO_INDEXED
) )
315 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, NOT_SEQUENCIBLE
);
317 if( the_where
== Same
&& the_assoc
->access
== NULL
)
318 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, NO_CURRENT_POS
);
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
);
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
);
332 if( ! TEST_FLAG( the_access
, IO_INDEXED
) && the_usage
== ReadWrite
)
333 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, NOT_INDEXED
);
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
);
339 /* Is the association location already connected? */
340 if( the_assoc
->access
)
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
);
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;
352 /* implicit disconnect */
353 __disconnect( the_assoc
->access
, file
, line
);
356 the_assoc
->usage
= the_usage
;
357 CLR_FLAG( the_access
, IO_OUTOFFILE
);
359 if( TEST_FLAG( the_access
, IO_INDEXED
) )
361 if( (the_assoc
->handle
= open( the_assoc
->pathname
, DirMode
[the_usage
] )) == -1 )
362 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, OPEN_FAILS
);
364 /* Set base index. */
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
);
380 /* Set current index */
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
;
388 if( lseek( the_assoc
->handle
, filepos
, SEEK_SET
) == -1L )
389 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, LSEEK_FAILS
);
390 the_access
->base
= filepos
;
394 /* for association to text for reading: allocate buffer */
395 if( TEST_FLAG((Text_Mode
*)the_transfer
, IO_TEXTLOCATION
) &&
396 the_usage
== ReadOnly
&&
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
));
403 if( (the_assoc
->handle
= open( the_assoc
->pathname
, SeqMode
[the_usage
] )) == -1 )
404 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, OPEN_FAILS
);
406 /* Set base index. */
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
);
422 /* file truncation for sequential, Write Only */
423 /***************************** FIXME: cannot truncate at Same
424 if( the_usage == WriteOnly )
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 );
433 ***************************/
434 if( (filepos
= lseek( the_assoc
->handle
, filepos
, SEEK_SET
)) == -1L )
435 CHILLEXCEPTION( file
, line
, CONNECTFAIL
, LSEEK_FAILS
);
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';
448 __disconnect( void* the_transfer
, char* file
, int line
)
450 Access_Mode
* the_access
;
453 CHILLEXCEPTION( file
, line
, EMPTY
, NULL_ACCESS
);
455 if( TEST_FLAG((Text_Mode
*)the_transfer
, IO_TEXTLOCATION
))
457 the_access
= ((Text_Mode
*)the_transfer
)->access_sub
;
458 CLR_FLAG( the_access
, IO_TEXTIO
);
461 the_access
= (Access_Mode
*)the_transfer
;
463 if( !the_access
->association
)
464 CHILLEXCEPTION( file
, line
, NOTCONNECTED
, IS_NOT_CONNECTED
);
466 close( the_access
->association
->handle
);
467 /* FIXME: check result */
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
;