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