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