OSDN Git Service

tweak
[pf3gnuchains/gcc-fork.git] / libchill / readrecord.c
1 /* Implement Input/Output runtime actions for CHILL.
2    Copyright (C) 1992, 1993, 1998 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 <setjmp.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34
35 #include "fileio.h"
36
37 #ifdef EOF
38 #undef EOF
39 #endif
40 #define EOF -1
41
42 static
43 Boolean
44 doRead( Access_Mode* the_access, void* buf, size_t nbyte )
45 {
46   size_t nread;
47
48   nread = read( the_access->association->handle, buf, nbyte );
49   if( nread == nbyte )
50   {
51     CLR_FLAG( the_access, IO_OUTOFFILE );
52     return True;
53   }
54   if( nread == 0 )
55   {
56     SET_FLAG( the_access, IO_OUTOFFILE );
57     return False;
58   }
59   the_access->association->syserrno = errno;
60   RWEXCEPTION( READFAIL, OS_IO_ERROR );
61   /* no return */
62 }
63
64 static
65 int bgetc( int handle, readbuf_t* rbptr )
66 {
67   if( rbptr->cur >= rbptr->len )
68     {
69       rbptr->len = read( handle, rbptr->buf, READBUFLEN );
70       if( rbptr->len == 0 )
71         return EOF;
72       rbptr->cur = 0;
73     }
74   return rbptr->buf[rbptr->cur++];
75 }
76
77 static
78 void bungetc( readbuf_t* rbptr, int c )
79 {
80   rbptr->buf[--rbptr->cur] = c;
81 }
82
83 void*
84 __readrecord( Access_Mode*  the_access,
85               signed long   the_index,
86               char*         the_buf_addr,
87               char*         file,
88               int           line )
89 {
90   unsigned long  info;
91   char*          actaddr;
92   unsigned short actlen;
93   off_t          filepos;
94   unsigned short reclen;
95   unsigned long  readlen;
96
97   if( !the_access )
98     CHILLEXCEPTION( file, line, EMPTY, NULL_ACCESS );
99
100   if( !the_access->association )
101     CHILLEXCEPTION( file, line, NOTCONNECTED, IS_NOT_CONNECTED );
102
103   /* Usage must not be WriteOnly */
104   if( the_access->association->usage == WriteOnly )
105     CHILLEXCEPTION( file, line, READFAIL, BAD_USAGE );
106
107   /* OUTOFFILE must not be True when connected for sequential read */
108   if( !TEST_FLAG( the_access, IO_INDEXED )
109       && TEST_FLAG( the_access, IO_OUTOFFILE ) )
110     CHILLEXCEPTION( file, line, READFAIL, OUT_OF_FILE );
111
112   /*
113    *  Positioning
114    */
115   if( TEST_FLAG( the_access, IO_INDEXED ) )
116   {
117     /* index expression must be within bounds of index mode */
118     if( the_index < the_access->lowindex
119         || the_access->highindex < the_index ) 
120       CHILLEXCEPTION( file, line, RANGEFAIL, BAD_INDEX );
121
122     filepos = the_access->base + 
123               (the_index - the_access->lowindex) * the_access->reclength;
124
125     if( lseek( the_access->association->handle, filepos, SEEK_SET ) == -1L )
126       CHILLEXCEPTION( file, line, READFAIL, LSEEK_FAILS );
127   }
128
129   /* establish store loc */
130   if( !(actaddr = the_buf_addr ))
131   {
132     /* if not yet allocated, do it now */
133     if (!the_access->store_loc)
134       if( !(the_access->store_loc = (char*)malloc( the_access->reclength ) ) )
135         CHILLEXCEPTION( file, line, SPACEFAIL, STORE_LOC_ALLOC );
136     actaddr = the_access->store_loc;
137   }
138   actlen  = the_access->reclength;
139
140   if( (info = setjmp( __rw_exception )) )
141     CHILLEXCEPTION( file, line, info>>16, info & 0xffff );
142
143   if( TEST_FLAG( the_access, IO_TEXTIO ) )
144   {
145     readlen = actlen - 2;
146     if( TEST_FLAG( the_access, IO_INDEXED ) )
147     {
148       if( ! doRead( the_access, &reclen, sizeof(reclen) ) )
149         return NULL;
150       if( reclen > readlen )
151         CHILLEXCEPTION( file, line, RANGEFAIL, RECORD_TOO_LONG );
152       if( ! doRead( the_access, actaddr + 2, reclen ) )
153         CHILLEXCEPTION( file, line, READFAIL, RECORD_TOO_SHORT );
154     }
155     else
156     { 
157       Association_Mode *assoc = the_access->association;
158       int              handle = assoc->handle;
159       readbuf_t*       rbuf   = assoc->bufptr;
160       char* cptr = actaddr+2;
161       int   curr;
162
163       reclen = 0;
164       while( readlen-- )
165       {
166         curr = bgetc( handle, rbuf );
167         if( curr == '\n' )
168           goto end_of_line;
169         if( curr == EOF )
170         {
171           if( !reclen )
172             SET_FLAG( the_access, IO_OUTOFFILE );
173           goto end_of_line;
174         }
175         *cptr++ = curr;
176         reclen++;
177       }
178       if( (curr = bgetc( handle, rbuf )) != '\n' )
179         {
180           bungetc( rbuf, curr );
181           CHILLEXCEPTION( file, line, RANGEFAIL, RECORD_TOO_LONG );
182         }
183 end_of_line: ;
184     }
185     MOV2(actaddr,&reclen);
186   }
187   else
188   {
189     switch( the_access->rectype )
190     {
191     case Fixed:
192       if( ! doRead( the_access, actaddr, actlen ) )
193         return NULL;
194       break;
195     case VaryingChars:
196       if( TEST_FLAG( the_access->association, IO_VARIABLE ) )
197       {
198         if( ! doRead( the_access, &reclen, sizeof(reclen) ) )
199           return NULL;
200         if( reclen > actlen - 2 )
201           CHILLEXCEPTION( file, line, RANGEFAIL, RECORD_TOO_LONG );
202         readlen = TEST_FLAG( the_access, IO_INDEXED ) ? actlen - 2 : reclen;
203         if( ! doRead( the_access, actaddr + 2, readlen ) )
204           CHILLEXCEPTION( file, line, READFAIL, RECORD_TOO_SHORT );
205       }
206       else
207       {
208         if( ! doRead( the_access, actaddr + 2, reclen = actlen - 2 ) )
209           CHILLEXCEPTION( file, line, READFAIL, RECORD_TOO_SHORT );
210       }
211       MOV2(actaddr,&reclen);
212       break;
213     }
214   }
215
216   return actaddr;
217 }