00001 /* 00002 Functions for User Buffering 00003 AUP2, Sec. 2.12.2 00004 00005 Copyright 2003 by Marc J. Rochkind. All rights reserved. 00006 May be copied only for purposes and under conditions described 00007 on the Web page www.basepath.com/aup/copyright.htm. 00008 00009 The Example Files are provided "as is," without any warranty; 00010 without even the implied warranty of merchantability or fitness 00011 for a particular purpose. The author and his publisher are not 00012 responsible for any damages, direct or incidental, resulting 00013 from the use or non-use of these Example Files. 00014 00015 The Example Files may contain defects, and some contain deliberate 00016 coding mistakes that were included for educational reasons. 00017 You are responsible for determining if and how the Example Files 00018 are to be used. 00019 */ 00020 #include "defs.h" 00021 #include "bufio.h" 00022 00023 static BUFIO *Bopen_internal(int fd, const char *path, const char *dir) 00024 { 00025 BUFIO *b = NULL; 00026 int flags; 00027 00028 switch (dir[0]) { 00029 case 'r': 00030 flags = O_RDONLY; 00031 break; 00032 case 'w': 00033 flags = O_WRONLY | O_CREAT | O_TRUNC; 00034 break; 00035 default: 00036 errno = EINVAL; 00037 EC_FAIL 00038 } 00039 ec_null( b = calloc(1, sizeof(BUFIO)) ) 00040 b->fdopen = path == NULL; 00041 if (b->fdopen) 00042 b->fd = fd; 00043 else 00044 b->fd = open(path, flags, PERM_FILE); 00045 ec_neg1( b->fd ) 00046 b->dir = dir[0]; 00047 return b; 00048 00049 EC_CLEANUP_BGN 00050 free(b); 00051 return NULL; 00052 EC_CLEANUP_END 00053 } 00054 00055 BUFIO *Bfdopen(int fd, const char *dir) 00056 { 00057 return Bopen_internal(fd, NULL, dir); 00058 } 00059 00060 /*[bufio.c]*/ 00061 #if 0 /* non-Bfdopen version, as appeared in Chap. 2 of book */ 00062 BUFIO *Bopen(const char *path, const char *dir) 00063 { 00064 BUFIO *b = NULL; 00065 int flags; 00066 00067 switch (dir[0]) { 00068 case 'r': 00069 flags = O_RDONLY; 00070 break; 00071 case 'w': 00072 flags = O_WRONLY | O_CREAT | O_TRUNC; 00073 break; 00074 default: 00075 errno = EINVAL; 00076 EC_FAIL 00077 } 00078 ec_null( b = calloc(1, sizeof(BUFIO)) ) 00079 ec_neg1( b->fd = open(path, flags, PERM_FILE) ) 00080 b->dir = dir[0]; 00081 return b; 00082 00083 EC_CLEANUP_BGN 00084 free(b); 00085 return NULL; 00086 EC_CLEANUP_END 00087 } 00088 #else 00089 BUFIO *Bopen(const char *path, const char *dir) 00090 { 00091 return Bopen_internal(-1, path, dir); 00092 } 00093 #endif 00094 00095 static bool readbuf(BUFIO *b) 00096 { 00097 if (b->timeout.tv_sec != 0 || b->timeout.tv_usec != 0) { 00098 fd_set set; 00099 00100 FD_ZERO(&set); 00101 FD_SET(b->fd, &set); 00102 ec_neg1( select(b->fd + 1, &set, NULL, NULL, &b->timeout) ) 00103 if (!FD_ISSET(b->fd, &set)) { 00104 errno = ETIMEDOUT; 00105 return false; 00106 } 00107 } 00108 ec_neg1( b->total = read(b->fd, b->buf, sizeof(b->buf)) ) 00109 if (b->total == 0) { 00110 errno = 0; 00111 return false; 00112 } 00113 b->next = 0; 00114 return true; 00115 00116 EC_CLEANUP_BGN 00117 return false; 00118 EC_CLEANUP_END 00119 } 00120 00121 static bool writebuf(BUFIO *b) /* flush buffer */ 00122 { 00123 ssize_t n, total; 00124 00125 total = 0; 00126 while (total < b->next) { 00127 ec_neg1( n = write(b->fd, &b->buf[total], b->next - total) ) 00128 total += n; 00129 } 00130 b->next = 0; 00131 return true; 00132 00133 EC_CLEANUP_BGN 00134 return false; 00135 EC_CLEANUP_END 00136 } 00137 00138 int Bgetc(BUFIO *b) 00139 { 00140 if (b->next >= b->total) 00141 if (!readbuf(b)) { 00142 if (errno == 0) 00143 return -1; 00144 EC_FAIL 00145 } 00146 return b->buf[b->next++]; 00147 00148 EC_CLEANUP_BGN 00149 return -1; 00150 EC_CLEANUP_END 00151 } 00152 00153 bool Bputc(BUFIO *b, int c) 00154 { 00155 b->buf[b->next++] = c; 00156 if (b->next >= sizeof(b->buf)) 00157 ec_false( writebuf(b) ) 00158 return true; 00159 00160 EC_CLEANUP_BGN 00161 return false; 00162 EC_CLEANUP_END 00163 } 00164 00165 bool Bclose(BUFIO *b) 00166 { 00167 if (b != NULL) { 00168 if (b->dir == 'w') 00169 ec_false( writebuf(b) ) 00170 if (!b->fdopen) /* this line not in book */ 00171 ec_neg1( close(b->fd) ) 00172 free(b); 00173 } 00174 return true; 00175 00176 EC_CLEANUP_BGN 00177 return false; 00178 EC_CLEANUP_END 00179 } 00180 /*[]*/ 00181 00182 /* 00183 Rest of functions not in book. 00184 */ 00185 bool Bgets(BUFIO *b, char *s, size_t smax) 00186 { 00187 int c, i; 00188 bool ok = true; 00189 00190 for (i = 0; i < smax - 1; i++) { 00191 switch (c = Bgetc(b)) { 00192 case '\n': 00193 break; 00194 case -1: 00195 ok = i > 0; 00196 break; 00197 default: 00198 s[i] = (char)c; 00199 continue; 00200 } 00201 break; 00202 } 00203 s[i] = '\0'; 00204 return ok; 00205 } 00206 00207 void Bsettimeout(BUFIO *b, struct timeval *timeout) 00208 { 00209 b->timeout = *timeout; 00210 }