readline.c
1 /* 2 * Copyright (c) 2003-2004,2006-2010,2013-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 * 23 * readline.c 24 */ 25 26 #include "readline.h" 27 28 #include <errno.h> 29 #include <fcntl.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 /* Inspects a file's existence and size. Returns a file handle or -1 on failure */ 36 int inspect_file_and_size(const char* name, off_t *out_off_end) { 37 38 int fd, result; 39 off_t off_end; 40 41 do { 42 fd = open(name, O_RDONLY, 0); 43 } while (fd == -1 && errno == EINTR); 44 45 if (fd == -1) 46 { 47 fprintf(stderr, "open %s: %s", name, strerror(errno)); 48 result = -1; 49 goto loser; 50 } 51 52 off_end = lseek(fd, 0, SEEK_END); 53 if (off_end == -1) 54 { 55 fprintf(stderr, "lseek %s, SEEK_END: %s", name, strerror(errno)); 56 result = -1; 57 goto loser; 58 } 59 60 if (off_end > (unsigned)SIZE_MAX) { 61 fprintf(stderr, "file %s too large %llu bytes", name, off_end); 62 result = -1; 63 goto loser; 64 } 65 66 if (out_off_end) { 67 *out_off_end = off_end; 68 } 69 70 return fd; 71 72 loser: 73 return result; 74 } 75 76 77 /* Read a line from stdin into buffer as a null terminated string. If buffer is 78 non NULL use at most buffer_size bytes and return a pointer to buffer. Otherwise 79 return a newly malloced buffer. 80 if EOF is read this function returns NULL. */ 81 char * 82 readline(char *buffer, int buffer_size) 83 { 84 int ix = 0, bytes_malloced = 0; 85 86 if (!buffer) 87 { 88 bytes_malloced = 64; 89 buffer = (char *)malloc(bytes_malloced); 90 buffer_size = bytes_malloced; 91 } 92 93 for (;;++ix) 94 { 95 int ch; 96 97 if (ix == buffer_size - 1) 98 { 99 if (!bytes_malloced) 100 break; 101 bytes_malloced += bytes_malloced; 102 buffer = (char *)realloc(buffer, bytes_malloced); 103 buffer_size = bytes_malloced; 104 } 105 106 ch = getchar(); 107 if (ch == EOF) 108 { 109 if (bytes_malloced) 110 free(buffer); 111 return NULL; 112 } 113 if (ch == '\n') 114 break; 115 buffer[ix] = ch; 116 } 117 118 /* 0 terminate buffer. */ 119 buffer[ix] = '\0'; 120 121 return buffer; 122 } 123 124 /* Read the file name into buffer. On return buffer contains a newly 125 malloced buffer or length buffer_size. Return 0 on success and -1 on failure. */ 126 int 127 read_file(const char *name, uint8_t **outData, size_t *outLength) 128 { 129 int fd, result; 130 char *buffer = NULL; 131 off_t off_end; 132 ssize_t bytes_read; 133 size_t length; 134 135 if( (fd = inspect_file_and_size(name, &off_end)) == -1 ){ 136 result = -1; 137 goto loser; 138 } 139 140 length = (size_t)off_end; 141 buffer = malloc(length); 142 if (buffer == NULL) { 143 result = -1; 144 goto loser; 145 } 146 147 do { 148 bytes_read = pread(fd, buffer, length, 0); 149 } while (bytes_read == -1 && errno == EINTR); 150 151 if (bytes_read == -1) 152 { 153 fprintf(stderr, "pread %s: %s", name, strerror(errno)); 154 result = -1; 155 goto loser; 156 } 157 if (bytes_read != (ssize_t)length) 158 { 159 fprintf(stderr, "read %s: only read %zu of %zu bytes", name, bytes_read, length); 160 result = -1; 161 goto loser; 162 } 163 164 do { 165 result = close(fd); 166 } while (result == -1 && errno == EINTR); 167 168 if (result == -1) 169 { 170 fprintf(stderr, "close %s: %s", name, strerror(errno)); 171 goto loser; 172 } 173 174 *outData = (uint8_t *)buffer; 175 *outLength = length; 176 177 return result; 178 179 loser: 180 if (buffer) 181 free(buffer); 182 183 return result; 184 } 185 186 CFDataRef copyFileContents(const char *path) { 187 CFMutableDataRef data = NULL; 188 int fd = open(path, O_RDONLY, 0666); 189 if (fd == -1) { 190 fprintf(stderr, "open %s: %s", path, strerror(errno)); 191 goto badFile; 192 } 193 194 off_t fsize = lseek(fd, 0, SEEK_END); 195 if (fsize == (off_t)-1) { 196 fprintf(stderr, "lseek %s, 0, SEEK_END: %s", path, strerror(errno)); 197 goto badFile; 198 } 199 200 if (fsize > (off_t)INT32_MAX) { 201 fprintf(stderr, "file %s too large %llu bytes", path, fsize); 202 goto badFile; 203 } 204 205 data = CFDataCreateMutable(kCFAllocatorDefault, (CFIndex)fsize); 206 CFDataSetLength(data, (CFIndex)fsize); 207 void *buf = CFDataGetMutableBytePtr(data); 208 off_t total_read = 0; 209 while (total_read < fsize) { 210 ssize_t bytes_read; 211 212 bytes_read = pread(fd, buf, (size_t)(fsize - total_read), total_read); 213 if (bytes_read == -1) { 214 fprintf(stderr, "read %s: %s", path, strerror(errno)); 215 goto badFile; 216 } 217 if (bytes_read == 0) { 218 fprintf(stderr, "read %s: unexpected end of file", path); 219 goto badFile; 220 } 221 total_read += bytes_read; 222 } 223 224 if (close(fd) == -1) { 225 fprintf(stderr, "close %s: %s", path, strerror(errno)); 226 /* Failure to close the file isn't fatal. */ 227 } 228 229 return data; 230 badFile: 231 if (fd != -1) { 232 if (close(fd) == -1) { 233 fprintf(stderr, "close %s: %s", path, strerror(errno)); 234 } 235 } 236 if (data) 237 CFRelease(data); 238 return NULL; 239 } 240 241 242 bool writeFileContents(const char *path, CFDataRef data) { 243 int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); 244 if (fd == -1) { 245 fprintf(stderr, "open %s: %s", path, strerror(errno)); 246 goto badFile; 247 } 248 249 const void *buf = CFDataGetBytePtr(data); 250 off_t fsize = CFDataGetLength(data); 251 252 off_t total_write = 0; 253 while (total_write < fsize) { 254 ssize_t bytes_write; 255 256 bytes_write = pwrite(fd, buf, (size_t)(fsize - total_write), total_write); 257 if (bytes_write == -1) { 258 fprintf(stderr, "write %s: %s", path, strerror(errno)); 259 goto badFile; 260 } 261 if (bytes_write == 0) { 262 fprintf(stderr, "write %s: unexpected end of file", path); 263 goto badFile; 264 } 265 total_write += bytes_write; 266 } 267 268 if (close(fd) == -1) { 269 fprintf(stderr, "close %s: %s", path, strerror(errno)); 270 /* Failure to close the file isn't fatal. */ 271 } 272 273 return true; 274 badFile: 275 if (fd != -1) { 276 if (close(fd) == -1) { 277 fprintf(stderr, "close %s: %s", path, strerror(errno)); 278 } 279 } 280 if (data) 281 CFRelease(data); 282 return false; 283 }