libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008, 2009, 2013 Peter Miller 00004 * Written by Peter Miller <pmiller@opensource.org.au> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as 00008 * published by the Free Software Foundation; either version 3 of the 00009 * License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <libexplain/ac/fcntl.h> 00021 00022 #include <libexplain/string_buffer.h> 00023 #include <libexplain/string_flags.h> 00024 00025 00026 void 00027 explain_string_flags_init(explain_string_flags_t *sf, const char *flags) 00028 { 00029 int acc_mode; 00030 int options; 00031 const char *cp; 00032 explain_string_buffer_t yuck_buf; 00033 int plus_seen; 00034 00035 explain_string_buffer_init(&yuck_buf, sf->invalid, sizeof(sf->invalid)); 00036 00037 /* 00038 * Parse the flags string. 00039 * 00040 * (It turns out glibc is more generous than this, when it comes to 00041 * validity, but we only complain for EINVAL. Different systems 00042 * will see validity differently.) 00043 */ 00044 sf->rwa_seen = 0; 00045 acc_mode = O_RDONLY; 00046 options = 0; 00047 #ifdef O_LARGEFILE 00048 options |= O_LARGEFILE; 00049 #endif 00050 #ifdef O_LARGEFILE_HIDDEN 00051 options |= O_LARGEFILE_HIDDEN; 00052 #endif 00053 sf->flags_string_valid = 1; 00054 cp = flags; 00055 plus_seen = 0; 00056 for (;;) 00057 { 00058 unsigned char c; 00059 00060 c = *cp++; 00061 switch (c) 00062 { 00063 case '\0': 00064 /* end of string */ 00065 if (!sf->rwa_seen) 00066 sf->flags_string_valid = 0; 00067 sf->flags = acc_mode | options; 00068 return; 00069 00070 case '+': 00071 /* 00072 * "r+" Open for reading and writing. The stream is 00073 * positioned at the beginning of the file. 00074 * 00075 * "w+" Open for reading and writing. The file is created 00076 * if it does not exist, otherwise it is truncated. 00077 * The stream is positioned at the beginning of the 00078 * file. 00079 * 00080 * "a+" Open for reading and appending (writing at end of 00081 * file). The file is created if it does not exist. 00082 * The initial file position for reading is at the 00083 * beginning of the file, but output is always appended 00084 * to the end of the file. 00085 */ 00086 if (!sf->rwa_seen || plus_seen) 00087 goto duplicate; 00088 acc_mode = O_RDWR; 00089 plus_seen = 1; 00090 break; 00091 00092 case 'a': 00093 /* 00094 * Open for appending (writing at end of file). The file is 00095 * created if it does not exist. The stream is positioned 00096 * at the end of the file. 00097 */ 00098 if (sf->rwa_seen && (options & O_APPEND)) 00099 goto duplicate; 00100 acc_mode = O_WRONLY; 00101 options |= O_CREAT | O_APPEND; 00102 sf->rwa_seen = 1; 00103 break; 00104 00105 case 'b': 00106 /* 00107 * The mode string can also include the letter 'b' either 00108 * as a last character or as a character between the 00109 * characters in any of the two-character strings 00110 * described above. This is strictly for compatibility with 00111 * C89 and has no effect; the 'b' is ignored on all POSIX 00112 * conforming systems, including Linux. (Other systems 00113 * may treat text files and binary files differently, and 00114 * adding the 'b' may be a good idea if you do I/O to a 00115 * binary file and expect that your program may be ported to 00116 * non-UNIX environments.) 00117 */ 00118 options |= O_BINARY; 00119 break; 00120 00121 case 'c': 00122 /* 00123 * GNU extension 00124 * not a thread cancellation point 00125 */ 00126 break; 00127 00128 case 'e': 00129 /* GNU extension */ 00130 options |= O_CLOEXEC; 00131 break; 00132 00133 case 'm': 00134 /* 00135 * GNU extension 00136 * try to use mmap 00137 */ 00138 break; 00139 00140 case 'r': 00141 /* 00142 * Open text file for reading. The stream is positioned at 00143 * the beginning of the file. 00144 */ 00145 if (sf->rwa_seen && acc_mode == O_RDONLY) 00146 goto duplicate; 00147 acc_mode = O_RDONLY; 00148 sf->rwa_seen = 1; 00149 break; 00150 00151 case 't': 00152 /* GNU extension */ 00153 options |= O_TEXT; 00154 break; 00155 00156 case 'w': 00157 /* 00158 * Truncate file to zero length or create text file for 00159 * writing. The stream is positioned at the beginning of 00160 * the file. 00161 */ 00162 if (sf->rwa_seen && acc_mode == O_WRONLY) 00163 goto duplicate; 00164 acc_mode = O_WRONLY; 00165 options |= O_CREAT | O_TRUNC; 00166 sf->rwa_seen = 1; 00167 break; 00168 00169 case 'x': 00170 /* GNU extension */ 00171 options |= O_EXCL; 00172 break; 00173 00174 default: 00175 duplicate: 00176 sf->flags_string_valid = 0; 00177 explain_string_buffer_putc(&yuck_buf, c); 00178 break; 00179 } 00180 } 00181 } 00182 00183 /* vim: set ts=8 sw=4 et : */