Commit | Line | Data |
---|---|---|
6e403221 | 1 | /* -*-c-*- |
2 | * | |
6e403221 | 3 | * Various useful utilities, stolen from mLib |
4 | * | |
5 | * (c) 2001 Mark Wooding | |
6 | */ | |
7 | ||
0279756e | 8 | /*----- Licensing notice --------------------------------------------------* |
6e403221 | 9 | * |
10 | * This file is part of Anag: a simple wordgame helper. | |
11 | * | |
12 | * Anag is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or | |
15 | * (at your option) any later version. | |
0279756e | 16 | * |
6e403221 | 17 | * Anag is distributed in the hope that it will be useful, |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
0279756e | 21 | * |
6e403221 | 22 | * You should have received a copy of the GNU General Public License |
23 | * along with Anag; if not, write to the Free Software Foundation, | |
24 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
25 | */ | |
26 | ||
6e403221 | 27 | /*----- Header files ------------------------------------------------------*/ |
28 | ||
29 | #include "anag.h" | |
30 | ||
31 | /*----- Static variables --------------------------------------------------*/ | |
32 | ||
33 | static const char *quis = "<unset>"; | |
34 | ||
35 | /*----- Error reporting ---------------------------------------------------*/ | |
36 | ||
37 | /* --- @ego@ --- * | |
38 | * | |
39 | * Arguments: @const char *p@ = pointer to program name | |
40 | * | |
41 | * Returns: --- | |
42 | * | |
43 | * Use: Stores what the program's name is. | |
44 | */ | |
45 | ||
46 | #ifndef PATHSEP | |
47 | # if defined(__riscos) | |
48 | # define PATHSEP '.' | |
49 | # elif defined(__unix) || defined(unix) | |
50 | # define PATHSEP '/' | |
51 | # else | |
52 | # define PATHSEP '\\' | |
53 | # endif | |
54 | #endif | |
55 | ||
56 | void ego(const char *p) | |
57 | { | |
58 | const char *q = p; | |
904ac13a MW |
59 | while (*q) |
60 | if (*q++ == PATHSEP) p = q; | |
61 | if (*p == '-') p++; | |
6e403221 | 62 | quis = p; |
63 | } | |
64 | ||
65 | #undef PATHSEP | |
66 | ||
67 | /* --- @pquis@ --- * | |
68 | * | |
69 | * Arguments: @FILE *fp@ = output stream to write on | |
70 | * @const char *p@ = pointer to string to write | |
71 | * | |
72 | * Returns: Zero if everything worked, EOF if not. | |
73 | * | |
74 | * Use: Writes the string @p@ to the output stream @fp@. Occurrences | |
75 | * of the character `$' in @p@ are replaced by the program name | |
76 | * as reported by @quis@. A `$$' is replaced by a single `$' | |
77 | * sign. | |
78 | */ | |
79 | ||
80 | int pquis(FILE *fp, const char *p) | |
81 | { | |
82 | size_t sz; | |
83 | ||
84 | while (*p) { | |
85 | sz = strcspn(p, "$"); | |
86 | if (sz) { | |
904ac13a | 87 | if (fwrite(p, 1, sz, fp) < sz) return (EOF); |
6e403221 | 88 | p += sz; |
89 | } | |
90 | if (*p == '$') { | |
91 | p++; | |
92 | if (*p == '$') { | |
904ac13a | 93 | if (fputc('$', fp) == EOF) return (EOF); |
6e403221 | 94 | p++; |
904ac13a MW |
95 | } else if (fputs(quis, fp) == EOF) |
96 | return (EOF); | |
6e403221 | 97 | } |
98 | } | |
99 | return (0); | |
100 | } | |
101 | ||
102 | /* --- @die@ --- * | |
103 | * | |
104 | * Arguments: @const char *f@ = a @printf@-style format string | |
105 | * @...@ = other arguments | |
106 | * | |
107 | * Returns: Never. | |
108 | * | |
109 | * Use: Reports an error and exits. | |
110 | */ | |
111 | ||
112 | void die(const char *f, ...) | |
113 | { | |
114 | va_list ap; | |
115 | va_start(ap, f); | |
116 | fprintf(stderr, "%s: ", quis); | |
117 | vfprintf(stderr, f, ap); | |
118 | va_end(ap); | |
119 | putc('\n', stderr); | |
94ed9b30 | 120 | exit(EX_FAIL); |
6e403221 | 121 | } |
122 | ||
123 | /*----- Memory allocation -------------------------------------------------*/ | |
124 | ||
125 | /* --- @xmalloc@ --- * | |
126 | * | |
127 | * Arguments: @size_t sz@ = size of block to allocate | |
128 | * | |
129 | * Returns: Pointer to allocated block. | |
130 | * | |
131 | * Use: Allocates memory. If there's not enough memory, the | |
132 | * program exits. | |
133 | */ | |
134 | ||
135 | void *xmalloc(size_t sz) | |
136 | { | |
137 | void *p = malloc(sz); | |
904ac13a | 138 | if (!p) die("not enough memory"); |
6e403221 | 139 | return (p); |
140 | } | |
141 | ||
142 | /* --- @xrealloc@ --- * | |
143 | * | |
144 | * Arguments: @void *p@ = a pointer to allocated memory | |
145 | * @size_t sz@ = new size of block wanted | |
146 | * | |
147 | * Returns: Pointer to resized block. | |
148 | * | |
149 | * Use: Resizes an allocated block. If there's not enough memory, | |
150 | * the program exits. | |
151 | */ | |
152 | ||
153 | void *xrealloc(void *p, size_t sz) | |
154 | { | |
155 | p = realloc(p, sz); | |
904ac13a | 156 | if (!p) die("not enough memory"); |
6e403221 | 157 | return (p); |
158 | } | |
159 | ||
160 | /*----- Dynamic string handling -------------------------------------------*/ | |
161 | ||
162 | #define DSTR_INITSZ 64 | |
163 | ||
164 | /* --- @dstr_destroy@ --- * | |
165 | * | |
166 | * Arguments: @dstr *d@ = pointer to a dynamic string block | |
167 | * | |
168 | * Returns: --- | |
169 | * | |
170 | * Use: Reclaims the space used by a dynamic string. | |
171 | */ | |
172 | ||
173 | void dstr_destroy(dstr *d) { free(d->buf); d->len = 0; d->sz = 0; } | |
174 | ||
175 | /* --- @dstr_reset@ --- * | |
176 | * | |
177 | * Arguments: @dstr *d@ = pointer to a dynamic string block | |
178 | * | |
179 | * Returns: --- | |
180 | * | |
181 | * Use: Resets a string so that new data gets put at the beginning. | |
182 | */ | |
183 | ||
184 | void dstr_reset(dstr *d) { d->len = 0; } | |
185 | ||
186 | /* --- @dstr_ensure@ --- * | |
187 | * | |
188 | * Arguments: @dstr *d@ = pointer to a dynamic string block | |
189 | * @size_t sz@ = amount of free space to ensure | |
190 | * | |
191 | * Returns: --- | |
192 | * | |
193 | * Use: Ensures that at least @sz@ bytes are available in the | |
194 | * given string. | |
195 | */ | |
196 | ||
197 | void dstr_ensure(dstr *d, size_t sz) | |
198 | { | |
199 | size_t rq = d->len + sz; | |
200 | size_t nsz; | |
201 | ||
904ac13a MW |
202 | /* If we have enough space, just leave it. */ |
203 | if (rq <= d->sz) return; | |
6e403221 | 204 | |
904ac13a | 205 | /* Grow the buffer. */ |
6e403221 | 206 | nsz = d->sz; |
904ac13a | 207 | if (nsz == 0) nsz = (DSTR_INITSZ >> 1); |
6e403221 | 208 | do nsz <<= 1; while (nsz < rq); |
904ac13a MW |
209 | if (d->buf) d->buf = xrealloc(d->buf, nsz); |
210 | else d->buf = xmalloc(nsz); | |
6e403221 | 211 | d->sz = nsz; |
212 | } | |
213 | ||
214 | /* --- @dstr_putline@ --- * | |
215 | * | |
216 | * Arguments: @dstr *d@ = pointer to a dynamic string block | |
217 | * @FILE *fp@ = a stream to read from | |
218 | * | |
219 | * Returns: The number of characters read into the buffer, or @EOF@ if | |
220 | * end-of-file was reached before any characters were read. | |
221 | * | |
222 | * Use: Appends the next line from the given input stream to the | |
223 | * string. A trailing newline is not added; a trailing null | |
224 | * byte is appended, as for @dstr_putz@. | |
225 | */ | |
226 | ||
227 | int dstr_putline(dstr *d, FILE *fp) | |
228 | { | |
229 | size_t left = d->sz - d->len; | |
230 | size_t off = d->len; | |
231 | int rd = 0; | |
232 | int ch; | |
233 | ||
234 | for (;;) { | |
235 | ||
904ac13a | 236 | /* Read the next byte. */ |
6e403221 | 237 | ch = getc(fp); |
238 | ||
904ac13a MW |
239 | /* End-of-file when no characters read is special. */ |
240 | if (ch == EOF && !rd) return (EOF); | |
6e403221 | 241 | |
904ac13a | 242 | /* Make sure there's some buffer space. */ |
6e403221 | 243 | if (!left) { |
244 | d->len = off; | |
245 | dstr_ensure(d, 1); | |
246 | left = d->sz - off; | |
247 | } | |
248 | ||
904ac13a | 249 | /* End-of-file or newline ends the loop. */ |
6e403221 | 250 | if (ch == EOF || ch == '\n') { |
251 | d->buf[off] = 0; | |
252 | d->len = off; | |
253 | return rd; | |
254 | } | |
255 | ||
904ac13a | 256 | /* Append the character and continue. */ |
6e403221 | 257 | d->buf[off++] = ch; |
258 | left--; rd++; | |
259 | } | |
260 | } | |
261 | ||
262 | /*----- That's all, folks -------------------------------------------------*/ |