1/* Machine-independent I/O routines for gcov.
2   Copyright (C) 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
3   Contributed by Bob Manson <manson@cygnus.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING.  If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-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
28   License.  */
29
30#ifndef GCC_GCOV_IO_H
31#define GCC_GCOV_IO_H
32#include <stdio.h>
33#include <sys/types.h>
34
35static int __fetch_long	PARAMS ((long *, char *, size_t))
36	ATTRIBUTE_UNUSED;
37static int __read_long  PARAMS ((long *, FILE *, size_t))
38	ATTRIBUTE_UNUSED;
39static int __write_long PARAMS ((long, FILE *, size_t))
40	ATTRIBUTE_UNUSED;
41static int __fetch_gcov_type PARAMS ((gcov_type *, char *, size_t))
42	ATTRIBUTE_UNUSED;
43static int __store_gcov_type PARAMS ((gcov_type, char *, size_t))
44	ATTRIBUTE_UNUSED;
45static int __read_gcov_type  PARAMS ((gcov_type *, FILE *, size_t))
46	ATTRIBUTE_UNUSED;
47static int __write_gcov_type PARAMS ((gcov_type, FILE *, size_t))
48	ATTRIBUTE_UNUSED;
49static int __write_gcov_string PARAMS ((const char *, size_t, FILE*, long))
50	ATTRIBUTE_UNUSED;
51static int __read_gcov_string PARAMS ((char *, size_t, FILE*, long))
52	ATTRIBUTE_UNUSED;
53
54/* These routines only work for signed values.  */
55
56/* Store a portable representation of VALUE in DEST using BYTES*8-1 bits.
57   Return a nonzero value if VALUE requires more than BYTES*8-1 bits
58   to store.  */
59
60static int
61__store_gcov_type (value, dest, bytes)
62     gcov_type value;
63     char *dest;
64     size_t bytes;
65{
66  int upper_bit = (value < 0 ? 128 : 0);
67  size_t i;
68
69  if (value < 0)
70    {
71      gcov_type oldvalue = value;
72      value = -value;
73      if (oldvalue != -value)
74	return 1;
75    }
76
77  for(i = 0 ; i < (sizeof (value) < bytes ? sizeof (value) : bytes) ; i++) {
78    dest[i] = value & (i == (bytes - 1) ? 127 : 255);
79    value = value / 256;
80  }
81
82  if (value && value != -1)
83    return 1;
84
85  for(; i < bytes ; i++)
86    dest[i] = 0;
87  dest[bytes - 1] |= upper_bit;
88  return 0;
89}
90
91/* Retrieve a quantity containing BYTES*8-1 bits from SOURCE and store
92   the result in DEST. Returns a nonzero value if the value in SOURCE
93   will not fit in DEST.  */
94
95static int
96__fetch_gcov_type (dest, source, bytes)
97     gcov_type *dest;
98     char *source;
99     size_t bytes;
100{
101  gcov_type value = 0;
102  int i;
103
104  for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
105    if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
106      return 1;
107
108  for (; i >= 0; i--)
109    value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
110
111  if ((source[bytes - 1] & 128) && (value > 0))
112    value = - value;
113
114  *dest = value;
115  return 0;
116}
117
118static int
119__fetch_long (dest, source, bytes)
120     long *dest;
121     char *source;
122     size_t bytes;
123{
124  long value = 0;
125  int i;
126
127  for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
128    if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
129      return 1;
130
131  for (; i >= 0; i--)
132    value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
133
134  if ((source[bytes - 1] & 128) && (value > 0))
135    value = - value;
136
137  *dest = value;
138  return 0;
139}
140
141/* Write a BYTES*8-bit quantity to FILE, portably. Returns a nonzero
142   value if the write fails, or if VALUE can't be stored in BYTES*8
143   bits.
144
145   Note that VALUE may not actually be large enough to hold BYTES*8
146   bits, but BYTES characters will be written anyway.
147
148   BYTES may be a maximum of 10.  */
149
150static int
151__write_gcov_type (value, file, bytes)
152     gcov_type value;
153     FILE *file;
154     size_t bytes;
155{
156  char c[10];
157
158  if (bytes > 10 || __store_gcov_type (value, c, bytes))
159    return 1;
160  else
161    return fwrite(c, 1, bytes, file) != bytes;
162}
163
164static int
165__write_long (value, file, bytes)
166     long value;
167     FILE *file;
168     size_t bytes;
169{
170  char c[10];
171
172  if (bytes > 10 || __store_gcov_type ((gcov_type)value, c, bytes))
173    return 1;
174  else
175    return fwrite(c, 1, bytes, file) != bytes;
176}
177
178/* Read a quantity containing BYTES bytes from FILE, portably. Return
179   a nonzero value if the read fails or if the value will not fit
180   in DEST.
181
182   Note that DEST may not be large enough to hold all of the requested
183   data, but the function will read BYTES characters anyway.
184
185   BYTES may be a maximum of 10.  */
186
187static int
188__read_gcov_type (dest, file, bytes)
189     gcov_type *dest;
190     FILE *file;
191     size_t bytes;
192{
193  char c[10];
194
195  if (bytes > 10 || fread(c, 1, bytes, file) != bytes)
196    return 1;
197  else
198    return __fetch_gcov_type (dest, c, bytes);
199}
200
201static int
202__read_long (dest, file, bytes)
203     long *dest;
204     FILE *file;
205     size_t bytes;
206{
207  char c[10];
208
209  if (bytes > 10 || fread(c, 1, bytes, file) != bytes)
210    return 1;
211  else
212    return __fetch_long (dest, c, bytes);
213}
214
215
216/* Writes string in gcov format.  */
217
218static int
219__write_gcov_string (string, length, file, delim)
220     const char *string;
221     size_t length;
222     FILE *file;
223     long delim;
224{
225  size_t temp = length + 1;
226
227  /* delimiter */
228  if (__write_long (delim, file, 4) != 0)
229    return 1;
230
231  if (__write_long (length, file, 4) != 0)
232    return 1;
233
234  if (fwrite (string, temp, 1, file) != 1)
235    return 1;
236
237  temp &= 3;
238
239  if (temp)
240    {
241      char c[4];
242
243      c[0] = c[1] = c[2] = c[3] = 0;
244
245      if (fwrite (c, sizeof (char), 4 - temp, file) != 4 - temp)
246	return 1;
247    }
248
249  if (__write_long (delim, file, 4) != 0)
250    return 1;
251
252  return 0;
253}
254
255/* Reads string in gcov format.  */
256
257
258static int
259__read_gcov_string (string, max_length, file, delim)
260     char *string;
261     size_t max_length;
262     FILE *file;
263     long delim;
264{
265  long delim_from_file;
266  long length;
267  long read_length;
268  long tmp;
269
270  if (__read_long (&delim_from_file, file, 4) != 0)
271    return 1;
272
273  if (delim_from_file != delim)
274    return 1;
275
276  if (__read_long (&length, file, 4) != 0)
277    return 1;
278
279  if (length > (long) max_length)
280    read_length = max_length;
281  else
282    read_length = length;
283
284  tmp = (((length + 1) - 1) / 4 + 1) * 4;
285  /* This is the size occupied by the string in the file */
286
287  if (fread (string, read_length, 1, file) != 1)
288    return 1;
289
290  string[read_length] = 0;
291
292  if (fseek (file, tmp - read_length, SEEK_CUR) < 0)
293    return 1;
294
295  if (__read_long (&delim_from_file, file, 4) != 0)
296    return 1;
297
298  if (delim_from_file != delim)
299    return 1;
300
301  return 0;
302}
303
304
305#endif /* ! GCC_GCOV_IO_H */
306