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.
8 * Copyright (c) 1980, 1993
9 * The Regents of the University of California. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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 the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its 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 THE REGENTS 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 THE REGENTS 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
44 * Mail -- a mail program
46 * Variable handling stuff.
49 static char *canonify(const char *vn
);
50 static void vfree(char *cp
);
51 static struct var
*lookup(const char *name
, int h
);
52 static void remove_grouplist(struct grouphead
*gh
);
55 * If a variable name begins with a lowercase-character and contains at
56 * least one '@', it is converted to all-lowercase. This is necessary
57 * for lookups of names based on email addresses.
59 * Following the standard, only the part following the last '@' should
60 * be lower-cased, but practice has established otherwise here.
63 canonify(const char *vn
)
69 for (vp
= vn
; *vp
&& *vp
!= '@'; vp
++)
71 return ((*vp
== '@') ? i_strdup(vn
) : (char*)vn
);
75 * Assign a value to a variable.
78 assign(const char *name
, const char *value
)
83 name
= canonify(name
);
88 vp
= (struct var
*)scalloc(1, sizeof *vp
);
89 vp
->v_name
= vcopy(name
);
90 vp
->v_link
= variables
[h
];
95 vp
->v_value
= vcopy(value
);
99 * Free up a variable string. We do not bother to allocate
100 * strings whose value is "" since they are expected to be frequent.
101 * Thus, we cannot free same!
111 * Copy a variable value into permanent (ie, not collected after each
112 * command) space. Do not bother to alloc space for ""
116 vcopy(const char *str
)
123 len
= strlen(str
) + 1;
125 memcpy(news
, str
, (int)len
);
130 * Get the value of a variable and return it.
131 * Look in the environment if its not available locally.
135 value(const char *name
)
140 name
= canonify(name
);
141 if ((vp
= lookup(name
, -1)) == NULL
) {
142 if ((vs
= getenv(name
)) != NULL
&& *vs
)
146 return (vp
->v_value
);
150 * Locate a variable and return its variable node.
153 lookup(const char *name
, int h
)
155 struct var
**vap
, *lvp
, *vp
;
157 vap
= variables
+ ((h
>= 0) ? h
: hash(name
));
159 for (lvp
= NULL
, vp
= *vap
; vp
!= NULL
; lvp
= vp
, vp
= vp
->v_link
)
160 if (*vp
->v_name
== *name
&& strcmp(vp
->v_name
, name
) == 0) {
161 /* Relink as head, hope it "sorts on usage" over time */
163 lvp
->v_link
= vp
->v_link
;
173 * Locate a group name and return it.
177 findgroup(char *name
)
179 struct grouphead
*gh
;
181 for (gh
= groups
[hash(name
)]; gh
!= NULL
; gh
= gh
->g_link
)
182 if (*gh
->g_name
== *name
&& strcmp(gh
->g_name
, name
) == 0)
188 * Print a group out on stdout
191 printgroup(char *name
)
193 struct grouphead
*gh
;
196 if ((gh
= findgroup(name
)) == NULL
) {
197 printf(catgets(catd
, CATSET
, 202, "\"%s\": not a group\n"),
201 printf("%s\t", gh
->g_name
);
202 for (gp
= gh
->g_list
; gp
!= NULL
; gp
= gp
->ge_link
)
203 printf(" %s", gp
->ge_name
);
208 * Hash the passed string and return an index into
209 * the variable or group hash table.
210 * Use Chris Torek's hash algorithm.
213 hash(const char *name
)
221 if (h
< 0 && (h
= -h
) < 0)
223 return (h
% HSHSIZE
);
227 unset_internal(const char *name
)
232 name
= canonify(name
);
235 if ((vp
= lookup(name
, h
)) == NULL
) {
236 if (! sourcing
&& ! unset_allow_undefined
) {
237 printf(tr(203, "\"%s\": undefined variable\n"), name
);
243 /* Always listhead after lookup() */
244 variables
[h
] = variables
[h
]->v_link
;
252 remove_grouplist(struct grouphead
*gh
)
254 struct group
*gp
, *gq
;
256 if ((gp
= gh
->g_list
) != NULL
) {
257 for (; gp
; gp
= gq
) {
266 remove_group(const char *name
)
268 struct grouphead
*gh
, *gp
= NULL
;
271 for (gh
= groups
[h
]; gh
!= NULL
; gh
= gh
->g_link
) {
272 if (*gh
->g_name
== *name
&& strcmp(gh
->g_name
, name
) == 0) {
273 remove_grouplist(gh
);
276 gp
->g_link
= gh
->g_link
;