main.c: set -S twice! And about command line processing..
[s-mailx.git] / macro.c
blob5ac1e39d7180cc101a53c74fb0fa9d7cf23ee0f2
1 /*
2 * S-nail - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
6 */
7 /*
8 * Copyright (c) 2004
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
40 #include "config.h"
42 #include "rcv.h"
43 #include "extern.h"
46 * Mail -- a mail program
48 * Macros.
51 #define MAPRIME 29
53 struct line {
54 struct line *l_next;
55 char *l_line;
56 size_t l_linesize;
59 struct macro {
60 struct macro *ma_next;
61 char *ma_name;
62 struct line *ma_contents;
63 enum maflags {
64 MA_NOFLAGS,
65 MA_ACCOUNT
66 } ma_flags;
69 static struct macro *macros[MAPRIME];
70 static struct macro *accounts[MAPRIME];
72 #define mahash(cp) (pjw(cp) % MAPRIME)
73 static void undef1(const char *name, struct macro **table);
74 static int maexec(struct macro *mp);
75 static int closingangle(const char *cp);
76 static struct macro *malook(const char *name, struct macro *data,
77 struct macro **table);
78 static void freelines(struct line *lp);
79 static void list0(FILE *fp, struct line *lp);
80 static int list1(FILE *fp, struct macro **table);
82 int
83 cdefine(void *v)
85 char **args = v;
87 if (args[0] == NULL) {
88 fprintf(stderr, "Missing macro name to define.\n");
89 return 1;
91 if (args[1] == NULL || strcmp(args[1], "{") || args[2] != NULL) {
92 fprintf(stderr, "Syntax is: define <name> {\n");
93 return 1;
95 return define1(args[0], 0);
98 int
99 define1(const char *name, int account)
101 struct macro *mp;
102 struct line *lp, *lst = NULL, *lnd = NULL;
103 char *linebuf = NULL;
104 size_t linesize = 0;
105 int n;
106 mp = scalloc(1, sizeof *mp);
107 mp->ma_name = sstrdup(name);
108 if (account)
109 mp->ma_flags |= MA_ACCOUNT;
110 for (;;) {
111 n = 0;
112 for (;;) {
113 n = readline_restart(input, &linebuf, &linesize, n);
114 if (n < 0)
115 break;
116 if (n == 0 || linebuf[n-1] != '\\')
117 break;
118 linebuf[n-1] = '\n';
120 if (n < 0) {
121 fprintf(stderr, "Unterminated %s definition: \"%s\".\n",
122 account ? "account" : "macro",
123 mp->ma_name);
124 if (sourcing)
125 unstack();
126 free(mp->ma_name);
127 free(mp);
128 return 1;
130 if (closingangle(linebuf))
131 break;
132 lp = scalloc(1, sizeof *lp);
133 lp->l_linesize = n+1;
134 lp->l_line = smalloc(lp->l_linesize);
135 memcpy(lp->l_line, linebuf, lp->l_linesize);
136 lp->l_line[n] = '\0';
137 if (lst && lnd) {
138 lnd->l_next = lp;
139 lnd = lp;
140 } else
141 lst = lnd = lp;
143 mp->ma_contents = lst;
144 if (malook(mp->ma_name, mp, account ? accounts : macros) != NULL) {
145 if (!account) {
146 fprintf(stderr,
147 "A macro named \"%s\" already exists.\n",
148 mp->ma_name);
149 freelines(mp->ma_contents);
150 free(mp->ma_name);
151 free(mp);
152 return 1;
154 undef1(mp->ma_name, accounts);
155 malook(mp->ma_name, mp, accounts);
157 return 0;
160 int
161 cundef(void *v)
163 char **args = v;
165 if (*args == NULL) {
166 fprintf(stderr, "Missing macro name to undef.\n");
167 return 1;
170 undef1(*args, macros);
171 while (*++args);
172 return 0;
175 static void
176 undef1(const char *name, struct macro **table)
178 struct macro *mp;
180 if ((mp = malook(name, NULL, table)) != NULL) {
181 freelines(mp->ma_contents);
182 free(mp->ma_name);
183 mp->ma_name = NULL;
187 int
188 ccall(void *v)
190 char **args = v;
191 struct macro *mp;
193 if (args[0] == NULL || (args[1] != NULL && args[2] != NULL)) {
194 fprintf(stderr, "Syntax is: call <name>\n");
195 return 1;
197 if ((mp = malook(*args, NULL, macros)) == NULL) {
198 fprintf(stderr, "Undefined macro called: \"%s\"\n", *args);
199 return 1;
201 return maexec(mp);
204 int
205 callaccount(const char *name)
207 struct macro *mp;
209 if ((mp = malook(name, NULL, accounts)) == NULL)
210 return CBAD;
211 return maexec(mp);
214 int
215 callhook(const char *name, int newmail)
217 struct macro *mp;
218 char *var, *cp;
219 int len, r;
221 var = ac_alloc(len = strlen(name) + 13);
222 snprintf(var, len, "folder-hook-%s", name);
223 if ((cp = value(var)) == NULL && (cp = value("folder-hook")) == NULL)
224 return 0;
225 if ((mp = malook(cp, NULL, macros)) == NULL) {
226 fprintf(stderr, "Cannot call hook for folder \"%s\": "
227 "Macro \"%s\" does not exist.\n",
228 name, cp);
229 return 1;
231 inhook = newmail ? 3 : 1;
232 r = maexec(mp);
233 inhook = 0;
234 return r;
237 static int
238 maexec(struct macro *mp)
240 struct line *lp;
241 const char *sp;
242 char *copy, *cp;
243 int r = 0;
245 unset_allow_undefined = 1;
246 for (lp = mp->ma_contents; lp; lp = lp->l_next) {
247 sp = lp->l_line;
248 while (sp < &lp->l_line[lp->l_linesize] &&
249 (blankchar(*sp&0377) || *sp == '\n' ||
250 *sp == '\0'))
251 sp++;
252 if (sp == &lp->l_line[lp->l_linesize])
253 continue;
254 cp = copy = smalloc(lp->l_linesize + (lp->l_line - sp));
256 *cp++ = *sp != '\n' ? *sp : ' ';
257 while (++sp < &lp->l_line[lp->l_linesize]);
258 r = execute(copy, 0, lp->l_linesize);
259 free(copy);
261 unset_allow_undefined = 0;
262 return r;
265 static int
266 closingangle(const char *cp)
268 while (spacechar(*cp&0377))
269 cp++;
270 if (*cp++ != '}')
271 return 0;
272 while (spacechar(*cp&0377))
273 cp++;
274 return *cp == '\0';
277 static struct macro *
278 malook(const char *name, struct macro *data, struct macro **table)
280 struct macro *mp;
281 unsigned h;
283 mp = table[h = mahash(name)];
284 while (mp != NULL) {
285 if (mp->ma_name && strcmp(mp->ma_name, name) == 0)
286 break;
287 mp = mp->ma_next;
289 if (data) {
290 if (mp != NULL)
291 return mp;
292 data->ma_next = table[h];
293 table[h] = data;
295 return mp;
298 static void
299 freelines(struct line *lp)
301 struct line *lq = NULL;
303 while (lp) {
304 free(lp->l_line);
305 free(lq);
306 lq = lp;
307 lp = lp->l_next;
309 free(lq);
313 listaccounts(FILE *fp)
315 return list1(fp, accounts);
318 static void
319 list0(FILE *fp, struct line *lp)
321 const char *sp;
322 int c;
324 for (sp = lp->l_line; sp < &lp->l_line[lp->l_linesize]; sp++) {
325 if ((c = *sp&0377) != '\0') {
326 if ((c = *sp&0377) == '\n')
327 putc('\\', fp);
328 putc(c, fp);
331 putc('\n', fp);
334 static int
335 list1(FILE *fp, struct macro **table)
337 struct macro **mp, *mq;
338 struct line *lp;
339 int mc = 0;
341 for (mp = table; mp < &table[MAPRIME]; mp++)
342 for (mq = *mp; mq; mq = mq->ma_next)
343 if (mq->ma_name) {
344 if (mc++)
345 fputc('\n', fp);
346 fprintf(fp, "%s %s {\n",
347 table == accounts ?
348 "account" : "define",
349 mq->ma_name);
350 for (lp = mq->ma_contents; lp; lp = lp->l_next)
351 list0(fp, lp);
352 fputs("}\n", fp);
354 return mc;
357 /*ARGSUSED*/
358 int
359 cdefines(void *v)
361 FILE *fp;
362 char *cp;
363 int mc;
364 (void)v;
366 if ((fp = Ftemp(&cp, "Ra", "w+", 0600, 1)) == NULL) {
367 perror("tmpfile");
368 return 1;
370 rm(cp);
371 Ftfree(&cp);
372 mc = list1(fp, macros);
373 if (mc)
374 try_pager(fp);
375 Fclose(fp);
376 return 0;
379 void
380 delaccount(const char *name)
382 undef1(name, accounts);