s390.c: New.
[gcc.git] / libchill / basicio.c
1 /* Implement Input/Output runtime actions for CHILL.
2 Copyright (C) 1992,1993 Free Software Foundation, Inc.
3 Author: Wilfried Moser, et al
4
5 This file is part of GNU CC.
6
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.
11
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.
16
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. */
21
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. */
28
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>
35
36 #include <string.h>
37 #include <stdlib.h>
38
39 #include "fileio.h"
40
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
52
53 static
54 void
55 GetSetAttributes( Association_Mode* the_assoc )
56 {
57 struct stat statbuf;
58 int retco;
59
60 if( (retco = stat( the_assoc->pathname, &statbuf )) )
61 return;
62
63 if( S_ISREG(statbuf.st_mode) )
64 {
65 SET_FLAG( the_assoc, IO_EXISTING );
66 if( !TEST_FLAG( the_assoc, IO_VARIABLE ) )
67 SET_FLAG( the_assoc, IO_INDEXABLE );
68 }
69 else
70 if( S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode) )
71 {
72 SET_FLAG( the_assoc, IO_EXISTING );
73 CLR_FLAG( the_assoc, IO_INDEXABLE );
74 }
75 SET_FLAG( the_assoc, IO_SEQUENCIBLE );
76
77 /* FIXME: File size and computation of number of records for outoffile ? */
78
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 );
83 }
84
85 static
86 void
87 makeName( Association_Mode* the_assoc, char* the_path, int the_path_len,
88 char* file, int line)
89 {
90 int namlen;
91 if( ! the_assoc->pathname &&
92 ! (the_assoc->pathname = (char*)malloc( PATH_MAX )) )
93 CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
94
95 if( the_path[0] != DIRSEP )
96 {
97 if( !getcwd( the_assoc->pathname, PATH_MAX ) )
98 {
99 the_assoc->syserrno = errno;
100 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, GETCWD_FAILS );
101 }
102 namlen = strlen( the_assoc->pathname );
103 the_assoc->pathname[namlen++] = DIRSEP;
104 }
105 else
106 namlen = 0;
107
108 strncpy( the_assoc->pathname + namlen, the_path, the_path_len );
109 the_assoc->pathname[namlen+the_path_len] = '\0';
110 }
111
112 /*
113 * ASSOCIATE
114 */
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 )
124 {
125 if( !the_assoc )
126 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
127
128 if( TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
129 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, IS_ASSOCIATED );
130
131 /* clear all flags */
132 the_assoc->flags = 0;
133
134 if( ! the_path_len )
135 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, NO_PATH_NAME );
136
137 makeName( the_assoc, the_path, the_path_len, file, line );
138 GetSetAttributes( the_assoc );
139
140 CLR_FLAG( the_assoc, IO_VARIABLE );
141 if ( the_mode )
142 {
143 if( !strncmp( the_mode, "VARIABLE", 8 ) )
144 {
145 SET_FLAG( the_assoc, IO_VARIABLE );
146 CLR_FLAG( the_assoc, IO_INDEXABLE );
147 }
148 else
149 if( strlen( the_mode ) )
150 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, INVALID_ASSOCIATION_MODE );
151 }
152
153 SET_FLAG( the_assoc, IO_ISASSOCIATED );
154 return the_assoc;
155 }
156
157 /*
158 * DISSOCIATE
159 */
160 void
161 __dissociate( Association_Mode* the_assoc, char* file, int line )
162 {
163 if( !the_assoc )
164 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
165
166 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
167 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
168
169 if( the_assoc->access )
170 __disconnect( the_assoc->access, file, line );
171
172 the_assoc->access = NULL;
173 CLR_FLAG( the_assoc, IO_ISASSOCIATED );
174
175 /* free allocated memory */
176 if (the_assoc->pathname)
177 {
178 free (the_assoc->pathname);
179 the_assoc->pathname = 0;
180 }
181 if (the_assoc->bufptr)
182 {
183 free (the_assoc->bufptr);
184 the_assoc->bufptr = 0;
185 }
186 }
187
188 /*
189 * CREATE
190 */
191 void __create( Association_Mode* the_assoc, char* file, int line )
192 {
193 if( !the_assoc )
194 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
195
196 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
197 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
198
199 if( TEST_FLAG( the_assoc, IO_EXISTING ) )
200 CHILLEXCEPTION( file, line, CREATEFAIL, FILE_EXISTING );
201
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 );
205
206 the_assoc->usage = ReadWrite;
207 GetSetAttributes( the_assoc );
208
209 close( the_assoc->handle );
210 }
211
212 /*
213 * MODIFY
214 */
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 )
223 {
224 if( !the_assoc )
225 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
226
227 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
228 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
229
230 if( the_path_len )
231 {
232 char* oldname;
233
234 if( ! (oldname = (char*)malloc( PATH_MAX )) )
235 CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
236 strcpy( oldname, the_assoc->pathname );
237
238 makeName( the_assoc, the_path, the_path_len, file, line );
239
240 if( rename( oldname, the_assoc->pathname ) )
241 {
242 free( oldname );
243 CHILLEXCEPTION( file, line, MODIFYFAIL, RENAME_FAILS );
244 }
245 free( oldname );
246 }
247 else
248 {
249 /* FIXME: other options? */
250 }
251 }
252
253 static
254 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
255 int DirMode[] = { O_RDONLY, O_RDWR, O_RDWR };
256
257 static
258 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
259 int SeqMode[] = { O_RDONLY, O_RDWR, O_RDWR };
260
261 /*
262 * CONNECT
263 */
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 )
273 {
274 Access_Mode* the_access;
275 off_t filepos;
276 off_t savepos;
277 char dummy;
278 unsigned long nbytes;
279 int oflag;
280
281 if( !the_transfer )
282 CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
283 if( !the_assoc )
284 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
285
286 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
287 {
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 );
292 }
293 else
294 {
295 the_access = (Access_Mode*)the_transfer;
296 CLR_FLAG( the_access, IO_TEXTIO );
297 }
298
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 );
302 */
303
304 if( ! TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
305 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
306
307 if( ! TEST_FLAG( the_assoc, IO_EXISTING ) )
308 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_EXISTING );
309
310 if( ! TEST_FLAG( the_assoc, IO_READABLE ) &&
311 ( the_usage = ReadOnly || the_usage == ReadWrite ) )
312 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_READABLE );
313
314 if( ! TEST_FLAG( the_assoc, IO_WRITEABLE ) &&
315 ( the_usage = WriteOnly || the_usage == ReadWrite ) )
316 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_WRITEABLE );
317
318 if( ! TEST_FLAG( the_assoc, IO_INDEXABLE )
319 && TEST_FLAG( the_access, IO_INDEXED ) )
320 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXABLE );
321
322 if( ! TEST_FLAG( the_assoc, IO_SEQUENCIBLE )
323 && ! TEST_FLAG( the_access, IO_INDEXED ) )
324 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_SEQUENCIBLE );
325
326 if( the_where == Same && the_assoc->access == NULL )
327 CHILLEXCEPTION( file, line, CONNECTFAIL, NO_CURRENT_POS );
328
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 );
335
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 );
340
341 if( ! TEST_FLAG( the_access, IO_INDEXED ) && the_usage == ReadWrite )
342 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXED );
343
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 );
347
348 /* Is the association location already connected? */
349 if( the_assoc->access )
350 {
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 );
354
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;
359 }
360
361 /* implicit disconnect */
362 __disconnect( the_assoc->access, file, line );
363 }
364
365 the_assoc->usage = the_usage;
366 CLR_FLAG( the_access, IO_OUTOFFILE );
367
368 if( TEST_FLAG( the_access, IO_INDEXED ) )
369 {
370 if( (the_assoc->handle = open( the_assoc->pathname, DirMode[the_usage] )) == -1 )
371 CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
372
373 /* Set base index. */
374 switch( the_where )
375 {
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;
387 }
388
389 /* Set current index */
390 if( with_index )
391 {
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;
396 }
397 if( lseek( the_assoc->handle, filepos, SEEK_SET ) == -1L )
398 CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
399 the_access->base = filepos;
400 }
401 else
402 {
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 )
407 {
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));
411 }
412 if( (the_assoc->handle = open( the_assoc->pathname, SeqMode[the_usage] )) == -1 )
413 CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
414
415 /* Set base index. */
416 switch( the_where )
417 {
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;
429 }
430
431 /* file truncation for sequential, Write Only */
432 /***************************** FIXME: cannot truncate at Same
433 if( the_usage == WriteOnly )
434 {
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 );
440 }
441 else
442 ***************************/
443 if( (filepos = lseek( the_assoc->handle, filepos, SEEK_SET )) == -1L )
444 CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
445 }
446
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';
453 }
454 }
455
456 void
457 __disconnect( void* the_transfer, char* file, int line )
458 {
459 Access_Mode* the_access;
460
461 if( !the_transfer )
462 CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
463
464 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
465 {
466 the_access = ((Text_Mode*)the_transfer)->access_sub;
467 CLR_FLAG( the_access, IO_TEXTIO );
468 }
469 else
470 the_access = (Access_Mode*)the_transfer;
471
472 if( !the_access->association )
473 CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
474
475 close( the_access->association->handle );
476 /* FIXME: check result */
477
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;
483 }