| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | /* zgetline - read a line of input from a specified file descriptor and return
 | 
					
						
							|  |  |  | 	      a pointer to a newly-allocated buffer containing the data. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Copyright (C) 2008,2009 Free Software Foundation, Inc.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    This file is part of GNU Bash, the Bourne Again SHell. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Bash is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |    it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |    the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |    (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Bash is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |    GNU General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <config.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if defined (HAVE_UNISTD_H)
 | 
					
						
							|  |  |  | #  include <unistd.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include "xmalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined (errno)
 | 
					
						
							|  |  |  | extern int errno; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extern ssize_t zread __P((int, char *, size_t)); | 
					
						
							|  |  |  | extern ssize_t zreadc __P((int, char *)); | 
					
						
							| 
									
										
										
										
											2009-02-19 22:21:29 +00:00
										 |  |  | extern ssize_t zreadintr __P((int, char *, size_t)); | 
					
						
							|  |  |  | extern ssize_t zreadcintr __P((int, char *)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef ssize_t breadfunc_t __P((int, char *, size_t)); | 
					
						
							|  |  |  | typedef ssize_t creadfunc_t __P((int, char *)); | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Initial memory allocation for automatic growing buffer in zreadlinec */ | 
					
						
							|  |  |  | #define GET_LINE_INITIAL_ALLOCATION 16
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Derived from GNU libc's getline.
 | 
					
						
							|  |  |  |    The behavior is almost the same as getline. See man getline. | 
					
						
							|  |  |  |    The differences are | 
					
						
							|  |  |  |    	(1) using file descriptor instead of FILE *, | 
					
						
							|  |  |  | 	(2) the order of arguments; the file descriptor comes the first, and | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | 	(3) the addition of third argument, UNBUFFERED_READ; this argument | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	    controls whether get_line uses buffering or not to get a byte data | 
					
						
							|  |  |  | 	    from FD. get_line uses zreadc if UNBUFFERED_READ is zero; and | 
					
						
							|  |  |  | 	    uses zread if UNBUFFERED_READ is non-zero. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    Returns number of bytes read or -1 on error. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ssize_t | 
					
						
							|  |  |  | zgetline (fd, lineptr, n, unbuffered_read) | 
					
						
							|  |  |  |      int fd; | 
					
						
							|  |  |  |      char **lineptr; | 
					
						
							|  |  |  |      size_t *n; | 
					
						
							|  |  |  |      int unbuffered_read; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   int nr, retval; | 
					
						
							|  |  |  |   char *line, c; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (lineptr == 0 || n == 0 || (*lineptr == 0 && *n != 0)) | 
					
						
							|  |  |  |     return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   nr = 0; | 
					
						
							|  |  |  |   line = *lineptr; | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   while (1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       retval = unbuffered_read ? zread (fd, &c, 1) : zreadc(fd, &c); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (retval <= 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-02-19 22:21:29 +00:00
										 |  |  | 	  if (line && nr > 0) | 
					
						
							|  |  |  | 	    line[nr] = '\0'; | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	  break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (nr + 2 >= *n) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2009-02-19 22:21:29 +00:00
										 |  |  | 	  size_t new_size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  new_size = (*n == 0) ? GET_LINE_INITIAL_ALLOCATION : *n * 2; | 
					
						
							|  |  |  | 	  line = (*n >= new_size) ? NULL : xrealloc (*lineptr, new_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  if (line) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      *lineptr = line; | 
					
						
							|  |  |  | 	      *n = new_size; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	  else | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 	      if (*n > 0) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		  (*lineptr)[*n - 1] = '\0'; | 
					
						
							|  |  |  | 		  nr = *n - 2; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	      break; | 
					
						
							|  |  |  | 	    } | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       line[nr] = c; | 
					
						
							|  |  |  |       nr++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (c == '\n') | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  line[nr] = '\0'; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return nr - 1; | 
					
						
							|  |  |  | } |