]> diplodocus.org Git - nmh/blob - sbr/readconfig.c
5a850b04b53d349f6cfd5f6868eb3081b557805d
[nmh] / sbr / readconfig.c
1 /* readconfig.c -- base routine to read nmh configuration files
2 * -- such as nmh profile, context file, or mhn.defaults.
3 *
4 * This code is Copyright (c) 2002, 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 "error.h"
11 #include "h/utils.h"
12
13 struct procstr {
14 char *procname;
15 char **procnaddr;
16 };
17
18 static struct procstr procs[] = {
19 { "context", &context },
20 { "mh-sequences", &mh_seq },
21 { "buildmimeproc", &buildmimeproc },
22 { "fileproc", &fileproc },
23 { "formatproc", &formatproc },
24 { "incproc", &incproc },
25 { "lproc", &lproc },
26 { "mailproc", &mailproc },
27 { "mhlproc", &mhlproc },
28 { "moreproc", &moreproc },
29 { "packproc", &packproc },
30 { "postproc", &postproc },
31 { "rmmproc", &rmmproc },
32 { "sendproc", &sendproc },
33 { "showmimeproc", &showmimeproc },
34 { "showproc", &showproc },
35 { "whatnowproc", &whatnowproc },
36 { "whomproc", &whomproc },
37 { NULL, NULL }
38 };
39
40 static struct node **opp = NULL;
41
42
43 void
44 readconfig (struct node **npp, FILE *ib, const char *file, int ctx)
45 {
46 int state;
47 char *cp;
48 char name[NAMESZ], field[NMH_BUFSIZ];
49 struct node *np;
50 struct procstr *ps;
51 m_getfld_state_t gstate;
52
53 if (npp == NULL && (npp = opp) == NULL) {
54 inform("bug: readconfig called but pump not primed, continuing...");
55 return;
56 }
57
58 gstate = m_getfld_state_init(ib);
59 for (;;) {
60 int fieldsz = sizeof field;
61 switch (state = m_getfld2(&gstate, name, field, &fieldsz)) {
62 case FLD:
63 case FLDPLUS:
64 NEW(np);
65 *npp = np;
66 *(npp = &np->n_next) = NULL;
67 np->n_name = mh_xstrdup(name);
68 if (state == FLDPLUS) {
69 cp = mh_xstrdup(field);
70 while (state == FLDPLUS) {
71 fieldsz = sizeof field;
72 state = m_getfld2(&gstate, name, field, &fieldsz);
73 cp = add (field, cp);
74 }
75 np->n_field = trimcpy (cp);
76 free (cp);
77 } else {
78 np->n_field = trimcpy (field);
79 }
80 np->n_context = ctx;
81
82 /*
83 * Now scan the list of `procs' and link in the
84 * field value to the global variable.
85 */
86 for (ps = procs; ps->procname; ps++)
87 if (strcmp (np->n_name, ps->procname) == 0) {
88 *ps->procnaddr = np->n_field;
89 break;
90 }
91 continue;
92
93 case BODY:
94 die("no blank lines are permitted in %s", file);
95
96 case FILEEOF:
97 break;
98
99 default:
100 die("%s is poorly formatted", file);
101 }
102 break;
103 }
104 m_getfld_state_destroy (&gstate);
105
106 /*
107 * Special handling for the pager processes: lproc and moreproc.
108 *
109 * If they are not set by the profile, use the callers $PAGER if
110 * available, otherwise set them to DEFAULT_PAGER.
111 */
112 if (lproc == NULL) {
113 lproc = getenv("PAGER");
114 if (lproc == NULL || lproc[0] == '\0')
115 lproc = DEFAULT_PAGER;
116 }
117 if (moreproc == NULL) {
118 moreproc = getenv("PAGER");
119 if (moreproc == NULL || moreproc[0] == '\0')
120 moreproc = DEFAULT_PAGER;
121 }
122
123 if (opp == NULL) {
124 /* Check for duplicated non-null profile entries. Except
125 allow multiple profile entries named "#", because that's
126 what mh-profile(5) suggests using for comments.
127
128 Only do this check on the very first call from
129 context_read(), when opp is NULL. That way, entries in
130 mhn.defaults can be overridden without triggering
131 warnings.
132
133 Note that mhn.defaults, $MHN, $MHBUILD, $MHSHOW, and
134 $MHSTORE all put their entries into just one list, m_defs,
135 the same list that the profile uses. */
136
137 struct node *np;
138 for (np = m_defs; np; np = np->n_next) {
139 /* Yes, this is O(N^2). The profile should be small enough so
140 that's not a performance problem. */
141 if (*np->n_name && strcmp("#", np->n_name)) {
142 struct node *np2;
143 for (np2 = np->n_next; np2; np2 = np2->n_next) {
144 if (! strcasecmp (np->n_name, np2->n_name)) {
145 inform("multiple \"%s\" profile components in %s, "
146 "ignoring \"%s\", continuing...",
147 np->n_name, defpath, np2->n_field);
148 }
149 }
150 }
151 }
152 }
153
154 opp = npp;
155 }
156
157
158 void
159 add_profile_entry (const char *key, const char *value)
160 {
161 struct node *newnode;
162
163 /* This inserts the new node at the beginning of m_defs because
164 that doesn't require traversing it or checking to see if it's
165 empty. */
166 NEW(newnode);
167 newnode->n_name = getcpy (key);
168 newnode->n_field = getcpy (value);
169 newnode->n_context = 0;
170 newnode->n_next = m_defs;
171 m_defs = newnode;
172 }