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