Adjust coding style from nmh to mmh
[mmh] / sbr / utils.c
1 /*
2 ** utils.c -- various utility routines
3 **
4 ** This code is Copyright (c) 2006, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/utils.h>
11 #include <stdlib.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #include <unistd.h>
15 #include <sys/stat.h>
16 #include <sysexits.h>
17
18 /*
19 ** We allocate space for messages (msgs array)
20 ** this number of elements at a time.
21 */
22 #define MAXMSGS 256
23
24 /*
25 ** Safely call malloc
26 */
27 void *
28 mh_xmalloc(size_t size)
29 {
30         void *memory;
31
32         if (size == 0) {
33                 adios(EX_SOFTWARE, NULL, "Tried to malloc 0 bytes");
34         }
35
36         memory = malloc(size);
37         if (!memory) {
38                 adios(EX_OSERR, NULL, "Malloc failed");
39         }
40
41         return memory;
42 }
43
44 /*
45 ** Safely call realloc
46 */
47 void *
48 mh_xrealloc(void *ptr, size_t size)
49 {
50         void *memory;
51
52         /* Some non-POSIX realloc()s don't cope with realloc(NULL,sz) */
53         if (!ptr) {
54                 return mh_xcalloc((size_t) 1, size);
55         }
56         if (size == 0) {
57                 adios(EX_SOFTWARE, NULL, "Tried to realloc 0 bytes");
58         }
59
60         memory = realloc(ptr, size);
61         if (!memory) {
62                 adios(EX_OSERR, NULL, "Realloc failed");
63         }
64
65         return memory;
66 }
67
68 /*
69 ** Safely call calloc
70 */
71 void *
72 mh_xcalloc(size_t nmemb, size_t size)
73 {
74         void *memory;
75
76         if (nmemb == 0  ||  size == 0) {
77                 adios(EX_SOFTWARE, NULL, "Tried to calloc 0 bytes");
78         }
79
80         if ((memory = calloc(nmemb, size))) {
81                 return memory;
82         } else {
83                 adios(EX_OSERR, NULL, "calloc failed");
84         }
85 }
86
87 /*
88 ** Return the present working directory, if the current directory does not
89 ** exist, or is too long, make / the pwd.
90 */
91 char *
92 pwd(void)
93 {
94         char *cp;
95         static char curwd[PATH_MAX];
96
97         if (!getcwd(curwd, PATH_MAX)) {
98                 admonish(NULL, "unable to determine working directory");
99                 if (!mypath || !*mypath ||
100                                 (strcpy(curwd, mypath), chdir(curwd)) == -1) {
101                         strcpy(curwd, "/");
102                         chdir(curwd);
103                 }
104                 return curwd;
105         }
106
107         if ((cp = curwd + strlen(curwd) - 1) > curwd && *cp == '/') {
108                 /* strip trailing slash */
109                 *cp = '\0';
110         }
111
112         return curwd;
113 }
114
115 /*
116 ** add   -- If "s1" is NULL, this routine just creates a
117 **       -- copy of "s2" into newly malloc'ed memory.
118 **       -- (use getcpy() instead in this case)
119 **       --
120 **       -- If "s1" is not NULL, then copy the concatenation
121 **       -- of "s1" and "s2" (note the order) into newly
122 **       -- malloc'ed memory.  Then free "s1".
123 */
124 char *
125 add(char *s2, char *s1)
126 {
127         char *cp;
128         size_t len1 = 0, len2 = 0;
129
130         if (s1) {
131                 len1 = strlen(s1);
132         }
133         if (s2) {
134                 len2 = strlen(s2);
135         }
136
137         cp = mh_xmalloc(len1 + len2 + 1);
138
139         /* Copy s1 and free it */
140         if (s1) {
141                 memcpy(cp, s1, len1);
142                 free(s1);
143         }
144
145         /* Copy s2 */
146         if (s2) {
147                 memcpy(cp + len1, s2, len2);
148         }
149
150         /* Now NULL terminate the string */
151         cp[len1 + len2] = '\0';
152
153         return cp;
154 }
155
156
157 /*
158 ** create_folder
159 **     Check to see if a folder exists, if not, prompt the user to create it.
160 */
161 void
162 create_folder(char *folder, int autocreate, void (*done_callback)(int))
163 {
164         struct stat st;
165         extern int errno;
166         char *cp;
167
168         if (stat(folder, &st) == -1) {
169                 if (errno != ENOENT) {
170                         adios(EX_IOERR, folder, "error on folder");
171                 }
172                 if (autocreate == 0) {
173                         /* ask before creating folder */
174                         cp = concat("Create folder \"", folder, "\"? ", NULL);
175                         if (!getanswer(cp)) {
176                                 done_callback(EX_CANTCREAT);
177                         }
178                         free(cp);
179                 } else if (autocreate == -1) {
180                         /* do not create, so exit */
181                         done_callback(EX_CANTCREAT);
182                 }
183                 if (!makedir(folder)) {
184                         adios(EX_CANTCREAT, NULL, "unable to create folder %s", folder);
185                 }
186         }
187 }
188
189 /*
190 ** num_digits
191 **     Return the number of digits in a nonnegative integer.
192 */
193 int
194 num_digits(int n)
195 {
196         int ndigits = 0;
197
198         /* Sanity check */
199         if (n < 0) {
200                 adios(EX_SOFTWARE, NULL, "oops, num_digits called with negative value");
201         }
202
203         if (n == 0) {
204                 return 1;
205         }
206
207         while (n) {
208                 n /= 10;
209                 ndigits++;
210         }
211
212         return ndigits;
213 }
214
215 /*
216 ** Append a message arg to an array of them, resizing it if necessary.
217 ** The function is written to suit the arg parsing code it was extracted
218 ** from, and will probably be changed when the other code is cleaned up.
219 */
220 void
221 app_msgarg(struct msgs_array *msgs, char *cp)
222 {
223         if(msgs->size >= msgs->max) {
224                 msgs->msgs = mh_xrealloc(msgs->msgs,
225                                 (msgs->max+=MAXMSGS)*sizeof(*msgs->msgs));
226         }
227         msgs->msgs[msgs->size++] = cp;
228 }