97f4271e5edf7037aab5c1f3962436566546420b
[mmh] / sbr / fmt_addr.c
1
2 /*
3  * fmt_addr.c -- format an address field (from fmt_scan)
4  *
5  * $Id$
6  *
7  * This code is Copyright (c) 2002, by the authors of nmh.  See the
8  * COPYRIGHT file in the root directory of the nmh distribution for
9  * complete copyright information.
10  */
11
12 #include <h/mh.h>
13 #include <h/addrsbr.h>
14 #include <h/fmt_scan.h>
15 #include <h/utils.h>
16
17 static char *buf;               /* our current working buffer  */
18 static char *bufend;            /* end of working buffer       */
19 static char *last_dst;          /* buf ptr at end of last call */
20 static unsigned int bufsiz;     /* current size of buf         */
21
22 #define BUFINCR 512             /* how much to expand buf when if fills */
23
24 #define CPY(s) { cp = (s); while ((*dst++ = *cp++)) ; --dst; }
25
26 /* check if there's enough room in buf for str.  add more mem if needed */
27 #define CHECKMEM(str) \
28             if ((len = strlen (str)) >= bufend - dst) {\
29                 int i = dst - buf;\
30                 int n = last_dst - buf;\
31                 bufsiz += ((dst + len - bufend) / BUFINCR + 1) * BUFINCR;\
32                 buf = realloc (buf, bufsiz);\
33                 dst = buf + i;\
34                 last_dst = buf + n;\
35                 if (! buf)\
36                     adios (NULL, "formataddr: couldn't get buffer space");\
37                 bufend = buf + bufsiz;\
38             }
39
40
41 /* fmt_scan will call this routine if the user includes the function
42  * "(formataddr {component})" in a format string.  "orig" is the
43  * original contents of the string register.  "str" is the address
44  * string to be formatted and concatenated onto orig.  This routine
45  * returns a pointer to the concatenated address string.
46  *
47  * We try to not do a lot of malloc/copy/free's (which is why we
48  * don't call "getcpy") but still place no upper limit on the
49  * length of the result string.
50  *
51  * This routine is placed in a separate library so it can be
52  * overridden by particular programs (e.g., "replsbr").
53  */
54
55 char *
56 formataddr (char *orig, char *str)
57 {
58     register int len;
59     register int isgroup;
60     register char *dst;
61     register char *cp;
62     register char *sp;
63     register struct mailname *mp = NULL;
64
65     /* if we don't have a buffer yet, get one */
66     if (bufsiz == 0) {
67         buf = mh_xmalloc (BUFINCR);
68         last_dst = buf;         /* XXX */
69         bufsiz = BUFINCR - 6;  /* leave some slop */
70         bufend = buf + bufsiz;
71     }
72     /*
73      * If "orig" points to our buffer we can just pick up where we
74      * left off.  Otherwise we have to copy orig into our buffer.
75      */
76     if (orig == buf)
77         dst = last_dst;
78     else if (!orig || !*orig) {
79         dst = buf;
80         *dst = '\0';
81     } else {
82         dst = last_dst;         /* XXX */
83         CHECKMEM (orig);
84         CPY (orig);
85     }
86
87     /* concatenate all the new addresses onto 'buf' */
88     for (isgroup = 0; (cp = getname (str)); ) {
89         if ((mp = getm (cp, NULL, 0, fmt_norm, NULL)) == NULL)
90             continue;
91
92         if (isgroup && (mp->m_gname || !mp->m_ingrp)) {
93             *dst++ = ';';
94             isgroup = 0;
95         }
96         /* if we get here we're going to add an address */
97         if (dst != buf) {
98             *dst++ = ',';
99             *dst++ = ' ';
100         }
101         if (mp->m_gname) {
102             CHECKMEM (mp->m_gname);
103             CPY (mp->m_gname);
104             isgroup++;
105         }
106         sp = adrformat (mp);
107         CHECKMEM (sp);
108         CPY (sp);
109         mnfree (mp);
110     }
111
112     if (isgroup)
113         *dst++ = ';';
114
115     *dst = '\0';
116     last_dst = dst;
117     return (buf);
118 }