Insert types for args of some function pointers to improve type checking.
[mmh] / sbr / utils.c
1
2 /*
3  * utils.c -- various utility routines
4  *
5  * $Id$
6  *
7  * This code is Copyright (c) 2006, by the authors of nmh.  See the
8  * COPYRIGHT file in the root directory of the nmh distribution for
9  * complete copyright information.
10  */
11
12 #include <h/mh.h>
13 #include <h/utils.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16 #include <errno.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(NULL, "Tried to malloc 0 bytes");
34
35     memory = malloc(size);
36     if (!memory)
37         adios(NULL, "Malloc failed");
38
39     return memory;
40 }
41
42 /*
43  * Safely call realloc
44  */
45 void *
46 mh_xrealloc(void *ptr, size_t size)
47 {
48     void *memory;
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 (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  * folder_exists
125  *      Check to see if a folder exists.
126  */
127 int folder_exists(char *folder)
128 {
129     struct stat st;
130     int exists = 0;
131
132     if (stat (folder, &st) == -1) {
133         /* The folder either doesn't exist, or we hit an error.  Either way
134          * return a failure.
135          */
136         exists = 0;
137     } else {
138         /* We can see a folder with the right name */
139         exists = 1;
140     }
141
142     return exists;
143 }
144
145
146 /*
147  * create_folder
148  *      Check to see if a folder exists, if not, prompt the user to create
149  *      it.
150  */
151 void create_folder(char *folder, int autocreate, void (*done_callback)(int))
152 {
153     struct stat st;
154     extern int errno;
155     char *cp;
156
157     if (stat (folder, &st) == -1) {
158         if (errno != ENOENT)
159             adios (folder, "error on folder");
160         if (autocreate == 0) {
161             /* ask before creating folder */
162             cp = concat ("Create folder \"", folder, "\"? ", NULL);
163             if (!getanswer (cp))
164                 done_callback (1);
165             free (cp);
166         } else if (autocreate == -1) {
167             /* do not create, so exit */
168             done_callback (1);
169         }
170         if (!makedir (folder))
171             adios (NULL, "unable to create folder %s", folder);
172     }
173 }
174
175 /*
176  * num_digits
177  *      Return the number of digits in a nonnegative integer.
178  */
179 int
180 num_digits (int n)
181 {
182     int ndigits = 0;
183
184     /* Sanity check */
185     if (n < 0)
186         adios (NULL, "oops, num_digits called with negative value");
187
188     if (n == 0)
189         return 1;
190
191     while (n) {
192         n /= 10;
193         ndigits++;
194     }
195
196     return ndigits;
197 }
198
199 /*
200  * Append a message arg to an array of them, resizing it if necessary.
201  * The function is written to suit the arg parsing code it was extracted
202  * from, and will probably be changed when the other code is cleaned up.
203  */
204 void
205 app_msgarg(struct msgs_array *msgs, char *cp)
206 {
207         if(msgs->size >= msgs->max)
208                 msgs->msgs = mh_xrealloc(msgs->msgs, (msgs->max+=MAXMSGS)*sizeof(*msgs->msgs));
209         msgs->msgs[msgs->size++] = cp;
210 }
211
212 /* Open a form or components file */
213 int
214 open_form(char **form, char *def)
215 {
216         int in;
217         if (*form) {
218                 if ((in = open (etcpath (*form), O_RDONLY)) == NOTOK)
219                         adios (*form, "unable to open form file");
220         } else {
221                 if ((in = open (etcpath (def), O_RDONLY)) == NOTOK)
222                         adios (def, "unable to open default components file");
223                 *form = def;
224         }
225         return in;
226 }