1 2 /** 3 * \file file.c 4 * 5 * Handle options that have file names for arguments. 6 * 7 * @addtogroup autoopts 8 * @{ 9 */ 10 /* 11 * This file is part of AutoOpts, a companion to AutoGen. 12 * AutoOpts is free software. 13 * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved 14 * 15 * AutoOpts is available under any one of two licenses. The license 16 * in use must be one of these two and the choice is under the control 17 * of the user of the license. 18 * 19 * The GNU Lesser General Public License, version 3 or later 20 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 21 * 22 * The Modified Berkeley Software Distribution License 23 * See the file "COPYING.mbsd" 24 * 25 * These files have the following sha256 sums: 26 * 27 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 28 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 29 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 30 */ 31 32 /** 33 * Make sure the directory containing the subject file exists and that 34 * the file exists or does not exist, per the option requirements. 35 * 36 * @param ftype file existence type flags 37 * @param pOpts program option descriptor 38 * @param pOD the option descriptor 39 */ 40 static void 41 check_existence(teOptFileType ftype, tOptions * pOpts, tOptDesc * pOD) 42 { 43 char const * fname = pOD->optArg.argString; 44 struct stat sb; 45 46 errno = 0; 47 48 switch (ftype & FTYPE_MODE_EXIST_MASK) { 49 case FTYPE_MODE_MUST_NOT_EXIST: 50 if ((stat(fname, &sb) == 0) || (errno != ENOENT)) { 51 if (errno == 0) 52 errno = EINVAL; 53 fserr_exit(pOpts->pzProgName, "stat", fname); 54 /* NOTREACHED */ 55 } 56 /* FALLTHROUGH */ 57 58 default: 59 case FTYPE_MODE_MAY_EXIST: 60 { 61 char * p = strrchr(fname, DIRCH); 62 size_t l; 63 64 if (p == NULL) 65 /* 66 * The file may or may not exist and its directory is ".". 67 * Assume that "." exists. 68 */ 69 break; 70 71 l = (size_t)(p - fname); 72 p = AGALOC(l + 1, "fname"); 73 memcpy(p, fname, l); 74 p[l] = NUL; 75 76 if ((stat(p, &sb) != 0) || (errno = EINVAL, ! S_ISDIR(sb.st_mode))) 77 fserr_exit(pOpts->pzProgName, "stat", p); 78 /* NOTREACHED */ 79 80 AGFREE(p); 81 break; 82 } 83 84 case FTYPE_MODE_MUST_EXIST: 85 if ( (stat(fname, &sb) != 0) 86 || (errno = EINVAL, ! S_ISREG(sb.st_mode)) ) 87 fserr_exit(pOpts->pzProgName, "stat", fname); 88 /* NOTREACHED */ 89 90 break; 91 } 92 } 93 94 /** 95 * Open the specified file with open(2) and save the FD. 96 * 97 * @param pOpts program option descriptor 98 * @param pOD the option descriptor 99 * @param mode the open mode (uses int flags value) 100 */ 101 static void 102 open_file_fd(tOptions * pOpts, tOptDesc * pOD, tuFileMode mode) 103 { 104 int fd = open(pOD->optArg.argString, mode.file_flags); 105 if (fd < 0) 106 fserr_exit(pOpts->pzProgName, "open", pOD->optArg.argString); 107 /* NOTREACHED */ 108 109 if ((pOD->fOptState & OPTST_ALLOC_ARG) != 0) 110 pOD->optCookie = VOIDP(pOD->optArg.argString); 111 else 112 AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name"); 113 114 pOD->optArg.argFd = fd; 115 pOD->fOptState &= ~OPTST_ALLOC_ARG; 116 } 117 118 /** 119 * Open the specified file with open(2) and save the FD. 120 * 121 * @param pOpts program option descriptor 122 * @param pOD the option descriptor 123 * @param mode the open mode (uses "char *" mode value) 124 */ 125 static void 126 fopen_file_fp(tOptions * pOpts, tOptDesc * pOD, tuFileMode mode) 127 { 128 FILE * fp = fopen(pOD->optArg.argString, mode.file_mode); 129 if (fp == NULL) 130 fserr_exit(pOpts->pzProgName, "fopen", pOD->optArg.argString); 131 /* NOTREACHED */ 132 133 if ((pOD->fOptState & OPTST_ALLOC_ARG) != 0) 134 pOD->optCookie = VOIDP(pOD->optArg.argString); 135 else 136 AGDUPSTR(pOD->optCookie, pOD->optArg.argString, "file name"); 137 138 pOD->optArg.argFp = fp; 139 pOD->fOptState &= ~OPTST_ALLOC_ARG; 140 } 141 142 /*=export_func optionFileCheck 143 * private: 144 * 145 * what: Decipher a boolean value 146 * arg: + tOptions * + pOpts + program options descriptor + 147 * arg: + tOptDesc * + pOptDesc + the descriptor for this arg + 148 * arg: + teOptFileType + ftype + File handling type + 149 * arg: + tuFileMode + mode + file open mode (if needed) + 150 * 151 * doc: 152 * Make sure the named file conforms with the file type mode. 153 * The mode specifies if the file must exist, must not exist or may 154 * (or may not) exist. The mode may also specify opening the 155 * file: don't, open just the descriptor (fd), or open as a stream 156 * (FILE * pointer). 157 =*/ 158 void 159 optionFileCheck(tOptions * pOpts, tOptDesc * pOD, 160 teOptFileType ftype, tuFileMode mode) 161 { 162 if (pOpts <= OPTPROC_EMIT_LIMIT) { 163 if (pOpts != OPTPROC_EMIT_USAGE) 164 return; 165 166 switch (ftype & FTYPE_MODE_EXIST_MASK) { 167 case FTYPE_MODE_MUST_NOT_EXIST: 168 fputs(zFileCannotExist + tab_skip_ct, option_usage_fp); 169 break; 170 171 case FTYPE_MODE_MUST_EXIST: 172 fputs(zFileMustExist + tab_skip_ct, option_usage_fp); 173 break; 174 } 175 return; 176 } 177 178 if ((pOD->fOptState & OPTST_RESET) != 0) { 179 if (pOD->optCookie != NULL) 180 AGFREE(pOD->optCookie); 181 return; 182 } 183 184 check_existence(ftype, pOpts, pOD); 185 186 switch (ftype & FTYPE_MODE_OPEN_MASK) { 187 default: 188 case FTYPE_MODE_NO_OPEN: break; 189 case FTYPE_MODE_OPEN_FD: open_file_fd( pOpts, pOD, mode); break; 190 case FTYPE_MODE_FOPEN_FP: fopen_file_fp(pOpts, pOD, mode); break; 191 } 192 } 193 194 /** @} 195 * 196 * Local Variables: 197 * mode: C 198 * c-file-style: "stroustrup" 199 * indent-tabs-mode: nil 200 * End: 201 * end of autoopts/file.c */ 202