]> diplodocus.org Git - nmh/blob - sbr/utils.c
Removed a bunch of unreachable break statements found by
[nmh] / sbr / utils.c
1
2 /*
3 * utils.c -- various utility routines
4 *
5 * This code is Copyright (c) 2006, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
8 */
9
10 #include <h/mh.h>
11 #include <h/utils.h>
12 #include <fcntl.h>
13
14 /*
15 * We allocate space for messages (msgs array)
16 * this number of elements at a time.
17 */
18 #define MAXMSGS 256
19
20 /*
21 * Safely call malloc
22 */
23 void *
24 mh_xmalloc(size_t size)
25 {
26 void *memory;
27
28 if (size == 0)
29 adios(NULL, "Tried to malloc 0 bytes");
30
31 memory = malloc(size);
32 if (!memory)
33 adios(NULL, "Malloc failed");
34
35 return memory;
36 }
37
38 /*
39 * Safely call realloc
40 */
41 void *
42 mh_xrealloc(void *ptr, size_t size)
43 {
44 void *memory;
45
46 /* Some non-POSIX realloc()s don't cope with realloc(NULL,sz) */
47 if (!ptr)
48 return mh_xmalloc(size);
49
50 if (size == 0)
51 adios(NULL, "Tried to realloc 0bytes");
52
53 memory = realloc(ptr, size);
54 if (!memory)
55 adios(NULL, "Realloc failed");
56
57 return memory;
58 }
59
60 /*
61 * Return the present working directory, if the current directory does not
62 * exist, or is too long, make / the pwd.
63 */
64 char *
65 pwd(void)
66 {
67 register char *cp;
68 static char curwd[PATH_MAX];
69
70 if (!getcwd (curwd, PATH_MAX)) {
71 admonish (NULL, "unable to determine working directory");
72 if (!mypath || !*mypath
73 || (strcpy (curwd, mypath), chdir (curwd)) == -1) {
74 strcpy (curwd, "/");
75 chdir (curwd);
76 }
77 return curwd;
78 }
79
80 if ((cp = curwd + strlen (curwd) - 1) > curwd && *cp == '/')
81 *cp = '\0';
82
83 return curwd;
84 }
85
86 /*
87 * add -- If "s1" is NULL, this routine just creates a
88 * -- copy of "s2" into newly malloc'ed memory.
89 * --
90 * -- If "s1" is not NULL, then copy the concatenation
91 * -- of "s1" and "s2" (note the order) into newly
92 * -- malloc'ed memory. Then free "s1".
93 */
94 char *
95 add (const char *s2, char *s1)
96 {
97 char *cp;
98 size_t len1 = 0, len2 = 0;
99
100 if (s1)
101 len1 = strlen (s1);
102 if (s2)
103 len2 = strlen (s2);
104
105 cp = mh_xmalloc (len1 + len2 + 1);
106
107 /* Copy s1 and free it */
108 if (s1) {
109 memcpy (cp, s1, len1);
110 free (s1);
111 }
112
113 /* Copy s2 */
114 if (s2)
115 memcpy (cp + len1, s2, len2);
116
117 /* Now NULL terminate the string */
118 cp[len1 + len2] = '\0';
119
120 return cp;
121 }
122
123 /*
124 * addlist
125 * Append an item to a comma separated list
126 */
127 char *
128 addlist (char *list, const char *item)
129 {
130 if (list)
131 list = add (", ", list);
132
133 return add (item, list);
134 }
135
136 /*
137 * folder_exists
138 * Check to see if a folder exists.
139 */
140 int folder_exists(const char *folder)
141 {
142 struct stat st;
143 int exists = 0;
144
145 if (stat (folder, &st) == -1) {
146 /* The folder either doesn't exist, or we hit an error. Either way
147 * return a failure.
148 */
149 exists = 0;
150 } else {
151 /* We can see a folder with the right name */
152 exists = 1;
153 }
154
155 return exists;
156 }
157
158
159 /*
160 * create_folder
161 * Check to see if a folder exists, if not, prompt the user to create
162 * it.
163 */
164 void create_folder(char *folder, int autocreate, void (*done_callback)(int))
165 {
166 struct stat st;
167 extern int errno;
168 char *cp;
169
170 if (stat (folder, &st) == -1) {
171 if (errno != ENOENT)
172 adios (folder, "error on folder");
173 if (autocreate == 0) {
174 /* ask before creating folder */
175 cp = concat ("Create folder \"", folder, "\"? ", NULL);
176 if (!getanswer (cp))
177 done_callback (1);
178 free (cp);
179 } else if (autocreate == -1) {
180 /* do not create, so exit */
181 done_callback (1);
182 }
183 if (!makedir (folder))
184 adios (NULL, "unable to create folder %s", folder);
185 }
186 }
187
188 /*
189 * num_digits
190 * Return the number of digits in a nonnegative integer.
191 */
192 int
193 num_digits (int n)
194 {
195 int ndigits = 0;
196
197 /* Sanity check */
198 if (n < 0)
199 adios (NULL, "oops, num_digits called with negative value");
200
201 if (n == 0)
202 return 1;
203
204 while (n) {
205 n /= 10;
206 ndigits++;
207 }
208
209 return ndigits;
210 }
211
212 /*
213 * Append a message arg to an array of them, resizing it if necessary.
214 * Really a simple vector-of-(char *) maintenance routine.
215 */
216 void
217 app_msgarg(struct msgs_array *msgs, char *cp)
218 {
219 if(msgs->size >= msgs->max) {
220 msgs->max += MAXMSGS;
221 msgs->msgs = mh_xrealloc(msgs->msgs,
222 msgs->max * sizeof(*msgs->msgs));
223 }
224 msgs->msgs[msgs->size++] = cp;
225 }
226
227 /*
228 * Append a message number to an array of them, resizing it if necessary.
229 * Like app_msgarg, but with a vector-of-ints instead.
230 */
231
232 void
233 app_msgnum(struct msgnum_array *msgs, int msgnum)
234 {
235 if (msgs->size >= msgs->max) {
236 msgs->max += MAXMSGS;
237 msgs->msgnums = mh_xrealloc(msgs->msgnums,
238 msgs->max * sizeof(*msgs->msgnums));
239 }
240 msgs->msgnums[msgs->size++] = msgnum;
241 }
242
243 /* Open a form or components file */
244 int
245 open_form(char **form, char *def)
246 {
247 int in;
248 if (*form) {
249 if ((in = open (etcpath (*form), O_RDONLY)) == NOTOK)
250 adios (*form, "unable to open form file");
251 } else {
252 if ((in = open (etcpath (def), O_RDONLY)) == NOTOK)
253 adios (def, "unable to open default components file");
254 *form = def;
255 }
256 return in;
257 }
258
259
260 /*
261 * Finds first occurrence of str in buf. buf is not a C string but a
262 * byte array of length buflen. str is a null-terminated C string.
263 * find_str() does not modify buf but passes back a non-const char *
264 * pointer so that the caller can modify it.
265 */
266 char *
267 find_str (const char buf[], size_t buflen, const char *str) {
268 const size_t len = strlen (str);
269 size_t i;
270
271 for (i = 0; i + len <= buflen; ++i, ++buf) {
272 if (! memcmp (buf, str, len)) return (char *) buf;
273 }
274
275 return NULL;
276 }
277
278
279 /*
280 * Finds last occurrence of str in buf. buf is not a C string but a
281 * byte array of length buflen. str is a null-terminated C string.
282 * find_str() does not modify buf but passes back a non-const char *
283 * pointer so that the caller can modify it.
284 */
285 char *
286 rfind_str (const char buf[], size_t buflen, const char *str) {
287 const size_t len = strlen (str);
288 size_t i;
289
290 for (i = 0, buf += buflen - len; i + len <= buflen; ++i, --buf) {
291 if (! memcmp (buf, str, len)) return (char *) buf;
292 }
293
294 return NULL;
295 }
296
297
298 /* POSIX doesn't have strcasestr() so emulate it. */
299 char *
300 nmh_strcasestr (const char *s1, const char *s2) {
301 const size_t len = strlen (s2);
302
303 if (isupper ((unsigned char) s2[0]) || islower ((unsigned char)s2[0])) {
304 char first[3];
305 first[0] = (char) toupper ((unsigned char) s2[0]);
306 first[1] = (char) tolower ((unsigned char) s2[0]);
307 first[2] = '\0';
308
309 for (s1 = strpbrk (s1, first); s1; s1 = strpbrk (++s1, first)) {
310 if (! strncasecmp (s1, s2, len)) return (char *) s1;
311 }
312 } else {
313 for (s1 = strchr (s1, s2[0]); s1; s1 = strchr (++s1, s2[0])) {
314 if (! strncasecmp (s1, s2, len)) return (char *) s1;
315 }
316 }
317
318 return NULL;
319 }