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