Include tm_p.h in ggc files
[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 #endif
48 #endif
49 #endif
50
51 static
52 void
53 GetSetAttributes( Association_Mode* the_assoc )
54 {
55 struct stat statbuf;
56 int retco;
57
58 if( (retco = stat( the_assoc->pathname, &statbuf )) )
59 return;
60
61 if( S_ISREG(statbuf.st_mode) )
62 {
63 SET_FLAG( the_assoc, IO_EXISTING );
64 if( !TEST_FLAG( the_assoc, IO_VARIABLE ) )
65 SET_FLAG( the_assoc, IO_INDEXABLE );
66 }
67 else
68 if( S_ISCHR(statbuf.st_mode) || S_ISFIFO(statbuf.st_mode) )
69 {
70 SET_FLAG( the_assoc, IO_EXISTING );
71 CLR_FLAG( the_assoc, IO_INDEXABLE );
72 }
73 SET_FLAG( the_assoc, IO_SEQUENCIBLE );
74
75 /* FIXME: File size and computation of number of records for outoffile ? */
76
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 );
81 }
82
83 static
84 void
85 makeName( Association_Mode* the_assoc, char* the_path, int the_path_len,
86 char* file, int line)
87 {
88 int namlen;
89 if( ! the_assoc->pathname &&
90 ! (the_assoc->pathname = (char*)malloc( PATH_MAX )) )
91 CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
92
93 if( the_path[0] != DIRSEP )
94 {
95 if( !getcwd( the_assoc->pathname, PATH_MAX ) )
96 {
97 the_assoc->syserrno = errno;
98 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, GETCWD_FAILS );
99 }
100 namlen = strlen( the_assoc->pathname );
101 the_assoc->pathname[namlen++] = DIRSEP;
102 }
103 else
104 namlen = 0;
105
106 strncpy( the_assoc->pathname + namlen, the_path, the_path_len );
107 the_assoc->pathname[namlen+the_path_len] = '\0';
108 }
109
110 /*
111 * ASSOCIATE
112 */
113 /* Caution: returns an Association mode location (!) */
114 Association_Mode*
115 __associate( Association_Mode* the_assoc,
116 char* the_path,
117 int the_path_len,
118 char* the_mode,
119 int the_mode_len,
120 char* file,
121 int line )
122 {
123 if( !the_assoc )
124 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
125
126 if( TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
127 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, IS_ASSOCIATED );
128
129 /* clear all flags */
130 the_assoc->flags = 0;
131
132 if( ! the_path_len )
133 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, NO_PATH_NAME );
134
135 makeName( the_assoc, the_path, the_path_len, file, line );
136 GetSetAttributes( the_assoc );
137
138 CLR_FLAG( the_assoc, IO_VARIABLE );
139 if ( the_mode )
140 {
141 if( !strncmp( the_mode, "VARIABLE", 8 ) )
142 {
143 SET_FLAG( the_assoc, IO_VARIABLE );
144 CLR_FLAG( the_assoc, IO_INDEXABLE );
145 }
146 else
147 if( strlen( the_mode ) )
148 CHILLEXCEPTION( file, line, ASSOCIATEFAIL, INVALID_ASSOCIATION_MODE );
149 }
150
151 SET_FLAG( the_assoc, IO_ISASSOCIATED );
152 return the_assoc;
153 }
154
155 /*
156 * DISSOCIATE
157 */
158 void
159 __dissociate( Association_Mode* the_assoc, char* file, int line )
160 {
161 if( !the_assoc )
162 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
163
164 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
165 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
166
167 if( the_assoc->access )
168 __disconnect( the_assoc->access, file, line );
169
170 the_assoc->access = NULL;
171 CLR_FLAG( the_assoc, IO_ISASSOCIATED );
172
173 /* free allocated memory */
174 if (the_assoc->pathname)
175 {
176 free (the_assoc->pathname);
177 the_assoc->pathname = 0;
178 }
179 if (the_assoc->bufptr)
180 {
181 free (the_assoc->bufptr);
182 the_assoc->bufptr = 0;
183 }
184 }
185
186 /*
187 * CREATE
188 */
189 void __create( Association_Mode* the_assoc, char* file, int line )
190 {
191 if( !the_assoc )
192 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
193
194 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
195 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
196
197 if( TEST_FLAG( the_assoc, IO_EXISTING ) )
198 CHILLEXCEPTION( file, line, CREATEFAIL, FILE_EXISTING );
199
200 if( (the_assoc->handle = open( the_assoc->pathname, O_CREAT+O_TRUNC+O_WRONLY, 0666 ))
201 == -1 )
202 CHILLEXCEPTION( file, line, CREATEFAIL, CREATE_FAILS );
203
204 the_assoc->usage = ReadWrite;
205 GetSetAttributes( the_assoc );
206
207 close( the_assoc->handle );
208 }
209
210 /*
211 * MODIFY
212 */
213 void
214 __modify( Association_Mode* the_assoc,
215 char* the_path,
216 int the_path_len,
217 char* the_mode,
218 int the_mode_len,
219 char* file,
220 int line )
221 {
222 if( !the_assoc )
223 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
224
225 if( !TEST_FLAG( the_assoc, IO_ISASSOCIATED ) )
226 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
227
228 if( the_path_len )
229 {
230 char* oldname;
231
232 if( ! (oldname = (char*)malloc( PATH_MAX )) )
233 CHILLEXCEPTION( file, line, SPACEFAIL, PATHNAME_ALLOC );
234 strcpy( oldname, the_assoc->pathname );
235
236 makeName( the_assoc, the_path, the_path_len, file, line );
237
238 if( rename( oldname, the_assoc->pathname ) )
239 {
240 free( oldname );
241 CHILLEXCEPTION( file, line, MODIFYFAIL, RENAME_FAILS );
242 }
243 free( oldname );
244 }
245 else
246 {
247 /* FIXME: other options? */
248 }
249 }
250
251 static
252 /*** char* DirMode[] = { "rb", "r+b", "r+b" }; ***/
253 int DirMode[] = { O_RDONLY, O_RDWR, O_RDWR };
254
255 static
256 /*** char* SeqMode [] = { "rb", "r+b", "r+b" }; ***/
257 int SeqMode[] = { O_RDONLY, O_RDWR, O_RDWR };
258
259 /*
260 * CONNECT
261 */
262 void
263 __connect( void* the_transfer,
264 Association_Mode* the_assoc,
265 Usage_Mode the_usage,
266 Where_Mode the_where,
267 Boolean with_index,
268 signed long the_index,
269 char* file,
270 int line )
271 {
272 Access_Mode* the_access;
273 off_t filepos;
274 off_t savepos;
275 char dummy;
276 unsigned long nbytes;
277 int oflag;
278
279 if( !the_transfer )
280 CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
281 if( !the_assoc )
282 CHILLEXCEPTION( file, line, EMPTY, NULL_ASSOCIATION );
283
284 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
285 {
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 );
290 }
291 else
292 {
293 the_access = (Access_Mode*)the_transfer;
294 CLR_FLAG( the_access, IO_TEXTIO );
295 }
296
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 );
300 */
301
302 if( ! TEST_FLAG(the_assoc, IO_ISASSOCIATED) )
303 CHILLEXCEPTION( file, line, NOTASSOCIATED, IS_NOT_ASSOCIATED );
304
305 if( ! TEST_FLAG( the_assoc, IO_EXISTING ) )
306 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_EXISTING );
307
308 if( ! TEST_FLAG( the_assoc, IO_READABLE ) &&
309 ( the_usage = ReadOnly || the_usage == ReadWrite ) )
310 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_READABLE );
311
312 if( ! TEST_FLAG( the_assoc, IO_WRITEABLE ) &&
313 ( the_usage = WriteOnly || the_usage == ReadWrite ) )
314 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_WRITEABLE );
315
316 if( ! TEST_FLAG( the_assoc, IO_INDEXABLE )
317 && TEST_FLAG( the_access, IO_INDEXED ) )
318 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXABLE );
319
320 if( ! TEST_FLAG( the_assoc, IO_SEQUENCIBLE )
321 && ! TEST_FLAG( the_access, IO_INDEXED ) )
322 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_SEQUENCIBLE );
323
324 if( the_where == Same && the_assoc->access == NULL )
325 CHILLEXCEPTION( file, line, CONNECTFAIL, NO_CURRENT_POS );
326
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 );
333
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 );
338
339 if( ! TEST_FLAG( the_access, IO_INDEXED ) && the_usage == ReadWrite )
340 CHILLEXCEPTION( file, line, CONNECTFAIL, NOT_INDEXED );
341
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 );
345
346 /* Is the association location already connected? */
347 if( the_assoc->access )
348 {
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 );
352
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;
357 }
358
359 /* implicit disconnect */
360 __disconnect( the_assoc->access, file, line );
361 }
362
363 the_assoc->usage = the_usage;
364 CLR_FLAG( the_access, IO_OUTOFFILE );
365
366 if( TEST_FLAG( the_access, IO_INDEXED ) )
367 {
368 if( (the_assoc->handle = open( the_assoc->pathname, DirMode[the_usage] )) == -1 )
369 CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
370
371 /* Set base index. */
372 switch( the_where )
373 {
374 case First:
375 filepos = 0;
376 break;
377 case Same:
378 filepos = savepos;
379 break;
380 case Last:
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 );
384 break;
385 }
386
387 /* Set current index */
388 if( with_index )
389 {
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;
394 }
395 if( lseek( the_assoc->handle, filepos, SEEK_SET ) == -1L )
396 CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
397 the_access->base = filepos;
398 }
399 else
400 {
401 /* for association to text for reading: allocate buffer */
402 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ) &&
403 the_usage == ReadOnly &&
404 !the_assoc->bufptr )
405 {
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));
409 }
410 if( (the_assoc->handle = open( the_assoc->pathname, SeqMode[the_usage] )) == -1 )
411 CHILLEXCEPTION( file, line, CONNECTFAIL, OPEN_FAILS );
412
413 /* Set base index. */
414 switch( the_where )
415 {
416 case First:
417 filepos = 0;
418 break;
419 case Same:
420 filepos = savepos;
421 break;
422 case Last:
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 );
426 break;
427 }
428
429 /* file truncation for sequential, Write Only */
430 /***************************** FIXME: cannot truncate at Same
431 if( the_usage == WriteOnly )
432 {
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 );
438 }
439 else
440 ***************************/
441 if( (filepos = lseek( the_assoc->handle, filepos, SEEK_SET )) == -1L )
442 CHILLEXCEPTION( file, line, CONNECTFAIL, LSEEK_FAILS );
443 }
444
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';
451 }
452 }
453
454 void
455 __disconnect( void* the_transfer, char* file, int line )
456 {
457 Access_Mode* the_access;
458
459 if( !the_transfer )
460 CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
461
462 if( TEST_FLAG((Text_Mode*)the_transfer, IO_TEXTLOCATION ))
463 {
464 the_access = ((Text_Mode*)the_transfer)->access_sub;
465 CLR_FLAG( the_access, IO_TEXTIO );
466 }
467 else
468 the_access = (Access_Mode*)the_transfer;
469
470 if( !the_access->association )
471 CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
472
473 close( the_access->association->handle );
474 /* FIXME: check result */
475
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;
481 }