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