Use gmtime_r by default, so that we're thread-safe.
[freeradius.git] / src / lib / print.c
1 /*
2  * print.c      Routines to print stuff.
3  *
4  * Version:     $Id$
5  *
6  */
7
8 static const char rcsid[] = "$Id$";
9
10 #include        "autoconf.h"
11
12 #include        <stdio.h>
13 #include        <stdlib.h>
14 #include        <sys/types.h>
15 #include        <ctype.h>
16 #include        <string.h>
17
18 #include        "libradius.h"
19
20 /*
21  *      Convert a string to something printable.
22  *      The output string has to be _at least_ 4x the size
23  *      of the input string!
24  */
25 void librad_safeprint(char *in, int inlen, char *out, int outlen)
26 {
27         unsigned char   *str = (unsigned char *)in;
28         int             done = 0;
29         int             sp = 0;
30
31         if (inlen < 0) inlen = strlen(in);
32
33         while (inlen-- > 0 && (done + 3) < outlen) {
34                 /*
35                  *      Hack: never print trailing zero.
36                  *      Some clients send strings with an off-by-one
37                  *      length (confused with strings in C).
38                  */
39                 if (inlen == 0 && *str == 0)
40                         break;
41
42                 sp = 0;
43
44                 switch (*str) {
45                         case '\\':
46                                 sp = '\\';
47                                 break;
48                         case '\r':
49                                 sp = 'r';
50                                 break;
51                         case '\n':
52                                 sp = 'n';
53                                 break;
54                         case '\t':
55                                 sp = 't';
56                                 break;
57                         default:
58                                 if (*str < 32 || (*str >= 128)){
59                                         snprintf(out, outlen, "\\%03o", *str);
60                                         done += 4;
61                                         out  += 4;
62                                         outlen -= 4;
63                                 } else {
64                                         *out++ = *str;
65                                         outlen--;
66                                         done++;
67                                 }
68                 }
69                 if (sp) {
70                         *out++ = '\\';
71                         *out++ = sp;
72                         outlen -= 2;
73                         done += 2;
74                 }
75                 str++;
76         }
77         *out = 0;
78 }
79
80
81 /*
82  *  Print one value into a string.
83  *  delimitst will define if strings and dates will be delimited by '"'
84  */
85 int vp_prints_value(char * out, int outlen, VALUE_PAIR *vp, int delimitst)
86 {
87         DICT_VALUE  *v;
88         char        buf[1024];
89         char        *a;
90         time_t      t;
91         struct tm   s_tm;
92
93         out[0] = 0;
94         if (!vp) return 0;
95
96         switch (vp->type) {
97                 case PW_TYPE_STRING:
98                         if (vp->attribute == PW_NAS_PORT_ID)
99                                 a = (char *)vp->strvalue;
100                         else {
101                                 if (delimitst && vp->flags.has_tag) {
102                                         /* Tagged attribute: print delimter and ignore tag */
103                                         buf[0] = '"';
104                                         librad_safeprint((char *)(vp->strvalue),
105                                                          vp->length, buf + 1, sizeof(buf) - 2);
106                                         strcat(buf, "\"");
107                                 } else if (delimitst) {
108                                         /* Non-tagged attribute: print delimter */
109                                         buf[0] = '"';
110                                         librad_safeprint((char *)vp->strvalue,
111                                                          vp->length, buf + 1, sizeof(buf) - 2);
112                                         strcat(buf, "\"");
113                                 } else {
114                                         /* Non-tagged attribute: no delimiter */
115                                         librad_safeprint((char *)vp->strvalue,
116                                                          vp->length, buf, sizeof(buf));
117                                 }
118                                 a = buf;
119                         }
120                         break;
121                 case PW_TYPE_INTEGER:
122                         if ( vp->flags.has_tag ) {
123                                 /* Attribute value has a tag, need to ignore it */
124                                 if ((v = dict_valbyattr(vp->attribute, (vp->lvalue & 0xffffff)))
125                                     != NULL)
126                                         a = v->name;
127                                 else {
128                                         snprintf(buf, sizeof(buf), "%u", (vp->lvalue & 0xffffff));
129                                         a = buf;
130                                 }
131                         } else {
132                                 /* Normal, non-tagged attribute */
133                                 if ((v = dict_valbyattr(vp->attribute, vp->lvalue))
134                                     != NULL)
135                                         a = v->name;
136                                 else {
137                                         snprintf(buf, sizeof(buf), "%u", vp->lvalue);
138                                         a = buf;
139                                 }
140                         }
141                         break;
142                 case PW_TYPE_DATE:
143                         t = vp->lvalue;
144                         if (delimitst) {
145                           strftime(buf, sizeof(buf), "\"%b %e %Y\"", gmtime_r(&t, &s_tm));
146                         } else {
147                           strftime(buf, sizeof(buf), "%b %e %Y", gmtime_r(&t, &s_tm));
148                         }
149                         a = buf;
150                         break;
151                 case PW_TYPE_IPADDR:
152                         if (vp->strvalue[0])
153                                 a = (char *)vp->strvalue;
154                         else
155                                 a = ip_hostname((char *)vp->strvalue,
156                                                 sizeof(vp->strvalue),
157                                                 vp->lvalue);
158                         break;
159                 case PW_TYPE_ABINARY:
160 #ifdef ASCEND_BINARY
161                   a = buf;
162                   print_abinary(vp, (unsigned char *)buf, sizeof(buf));
163                   break;
164 #else
165                   /* FALL THROUGH */
166 #endif
167                 case PW_TYPE_OCTETS:
168                   strcpy(buf, "0x");
169                   a = buf + 2;
170                   for (t = 0; t < vp->length; t++) {
171                         sprintf(a, "%02x", vp->strvalue[t]);
172                         a += 2;
173                   }
174                   a = buf;
175                   break;
176
177                 default:
178                         a = 0;
179                         break;
180         }
181         strNcpy(out, a?a:"UNKNOWN-TYPE", outlen);
182         
183         return strlen(out);
184 }
185
186
187 /*
188  *      Print one attribute and value into a string.
189  */
190 int vp_prints(char *out, int outlen, VALUE_PAIR *vp)
191 {
192         int             len;
193
194         out[0] = 0;
195         if (!vp) return 0;
196
197         if (strlen(vp->name) + 3 > (size_t)outlen) {
198                 return 0;
199         }
200
201         if( vp->flags.has_tag ) {
202
203                 snprintf(out, outlen, "%s:%d = ", vp->name, vp->flags.tag);
204                 
205                 len = strlen(out);
206                 vp_prints_value(out + len, outlen - len, vp, 1);
207
208         } else {
209
210                 snprintf(out, outlen, "%s = ", vp->name);
211                 len = strlen(out);
212                 vp_prints_value(out + len, outlen - len, vp, 1);
213
214         }         
215
216         return strlen(out);
217 }
218
219
220 /*
221  *      Print one attribute and value.
222  */
223 void vp_print(FILE *fp, VALUE_PAIR *vp)
224 {
225         char    buf[1024];
226
227         vp_prints(buf, sizeof(buf), vp);
228         fputs(buf, fp);
229 }
230
231
232 /*
233  *      Print a whole list of attributes, indented by a TAB
234  *      and with a newline at the end.
235  */
236 void vp_printlist(FILE *fp, VALUE_PAIR *vp)
237 {
238         for (; vp; vp = vp->next) {
239                 fprintf(fp, "\t");
240                 vp_print(fp, vp);
241                 fprintf(fp, "\n");
242         }
243 }
244