OSDN Git Service

Merge branch 'master' of git://github.com/monaka/binutils
[pf3gnuchains/pf3gnuchains3x.git] / newlib / libc / stdio / fgets.c
1 /*
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17
18 /*
19 FUNCTION
20 <<fgets>>---get character string from a file or stream
21
22 INDEX
23         fgets
24 INDEX
25         _fgets_r
26
27 ANSI_SYNOPSIS
28         #include <stdio.h>
29         char *fgets(char *<[buf]>, int <[n]>, FILE *<[fp]>);
30
31         #include <stdio.h>
32         char *_fgets_r(struct _reent *<[ptr]>, char *<[buf]>, int <[n]>, FILE *<[fp]>);
33
34 TRAD_SYNOPSIS
35         #include <stdio.h>
36         char *fgets(<[buf]>,<[n]>,<[fp]>)
37         char *<[buf]>;
38         int <[n]>;
39         FILE *<[fp]>;
40
41         #include <stdio.h>
42         char *_fgets_r(<[ptr]>, <[buf]>,<[n]>,<[fp]>)
43         struct _reent *<[ptr]>;
44         char *<[buf]>;
45         int <[n]>;
46         FILE *<[fp]>;
47
48 DESCRIPTION
49         Reads at most <[n-1]> characters from <[fp]> until a newline
50         is found. The characters including to the newline are stored
51         in <[buf]>. The buffer is terminated with a 0.
52
53         The <<_fgets_r>> function is simply the reentrant version of
54         <<fgets>> and is passed an additional reentrancy structure
55         pointer: <[ptr]>.
56
57 RETURNS
58         <<fgets>> returns the buffer passed to it, with the data
59         filled in. If end of file occurs with some data already
60         accumulated, the data is returned with no other indication. If
61         no data are read, NULL is returned instead.
62
63 PORTABILITY
64         <<fgets>> should replace all uses of <<gets>>. Note however
65         that <<fgets>> returns all of the data, while <<gets>> removes
66         the trailing newline (with no indication that it has done so.)
67
68 Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
69 <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
70 */
71
72 #include <_ansi.h>
73 #include <stdio.h>
74 #include <string.h>
75 #include "local.h"
76
77 /*
78  * Read at most n-1 characters from the given file.
79  * Stop when a newline has been read, or the count runs out.
80  * Return first argument, or NULL if no characters were read.
81  */
82
83 char *
84 _DEFUN(_fgets_r, (ptr, buf, n, fp),
85        struct _reent * ptr _AND
86        char *buf _AND
87        int n     _AND
88        FILE * fp)
89 {
90   size_t len;
91   char *s;
92   unsigned char *p, *t;
93
94   if (n < 2)                    /* sanity check */
95     return 0;
96
97   s = buf;
98
99   CHECK_INIT(ptr, fp);
100
101   __sfp_lock_acquire ();
102   _flockfile (fp);
103 #ifdef __SCLE
104   if (fp->_flags & __SCLE)
105     {
106       int c;
107       /* Sorry, have to do it the slow way */
108       while (--n > 0 && (c = __sgetc_r (ptr, fp)) != EOF)
109         {
110           *s++ = c;
111           if (c == '\n')
112             break;
113         }
114       if (c == EOF && s == buf)
115         {
116           _funlockfile (fp);
117           __sfp_lock_release ();
118           return NULL;
119         }
120       *s = 0;
121       _funlockfile (fp);
122       __sfp_lock_release ();
123       return buf;
124     }
125 #endif
126
127   n--;                          /* leave space for NUL */
128   do
129     {
130       /*
131        * If the buffer is empty, refill it.
132        */
133       if ((len = fp->_r) <= 0)
134         {
135           if (__srefill_r (ptr, fp))
136             {
137               /* EOF: stop with partial or no line */
138               if (s == buf)
139                 {
140                   _funlockfile (fp);
141                   __sfp_lock_release ();
142                   return 0;
143                 }
144               break;
145             }
146           len = fp->_r;
147         }
148       p = fp->_p;
149
150       /*
151        * Scan through at most n bytes of the current buffer,
152        * looking for '\n'.  If found, copy up to and including
153        * newline, and stop.  Otherwise, copy entire chunk
154        * and loop.
155        */
156       if (len > n)
157         len = n;
158       t = (unsigned char *) memchr ((_PTR) p, '\n', len);
159       if (t != 0)
160         {
161           len = ++t - p;
162           fp->_r -= len;
163           fp->_p = t;
164           _CAST_VOID memcpy ((_PTR) s, (_PTR) p, len);
165           s[len] = 0;
166           _funlockfile (fp);
167           __sfp_lock_release ();
168           return (buf);
169         }
170       fp->_r -= len;
171       fp->_p += len;
172       _CAST_VOID memcpy ((_PTR) s, (_PTR) p, len);
173       s += len;
174     }
175   while ((n -= len) != 0);
176   *s = 0;
177   _funlockfile (fp);
178   __sfp_lock_release ();
179   return buf;
180 }
181
182 #ifndef _REENT_ONLY
183
184 char *
185 _DEFUN(fgets, (buf, n, fp),
186        char *buf _AND
187        int n     _AND
188        FILE * fp)
189 {
190   return _fgets_r (_REENT, buf, n, fp);
191 }
192
193 #endif /* !_REENT_ONLY */