Delete trailing whitespace.
[freeradius.git] / src / lib / print.c
1 /*
2  * print.c      Routines to print stuff.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include        <freeradius-devel/libradius.h>
27
28 #include        <ctype.h>
29
30 /*
31  *      Convert a string to something printable.
32  *      The output string has to be _at least_ 4x the size
33  *      of the input string!
34  */
35 void librad_safeprint(char *in, int inlen, char *out, int outlen)
36 {
37         unsigned char   *str = (unsigned char *)in;
38         int             done = 0;
39         int             sp = 0;
40
41         if (inlen < 0) inlen = strlen(in);
42
43         while (inlen-- > 0 && (done + 3) < outlen) {
44                 /*
45                  *      Hack: never print trailing zero.
46                  *      Some clients send strings with an off-by-one
47                  *      length (confused with strings in C).
48                  */
49                 if (inlen == 0 && *str == 0)
50                         break;
51
52                 sp = 0;
53
54                 switch (*str) {
55                         case '\\':
56                                 sp = '\\';
57                                 break;
58                         case '\r':
59                                 sp = 'r';
60                                 break;
61                         case '\n':
62                                 sp = 'n';
63                                 break;
64                         case '\t':
65                                 sp = 't';
66                                 break;
67                         case '"':
68                                 sp = '"';
69                                 break;
70                         default:
71                           if (*str < 32 || (*str >= 128)){
72                                         snprintf(out, outlen, "\\%03o", *str);
73                                         done += 4;
74                                         out  += 4;
75                                         outlen -= 4;
76                                 } else {
77                                         *out++ = *str;
78                                         outlen--;
79                                         done++;
80                                 }
81                 }
82                 if (sp) {
83                         *out++ = '\\';
84                         *out++ = sp;
85                         outlen -= 2;
86                         done += 2;
87                 }
88                 str++;
89         }
90         *out = 0;
91 }
92
93
94 /*
95  *  Print one value into a string.
96  *  delimitst will define if strings and dates will be delimited by '"'
97  */
98 int vp_prints_value(char * out, int outlen, VALUE_PAIR *vp, int delimitst)
99 {
100         DICT_VALUE  *v;
101         char        buf[1024];
102         const char  *a = NULL;
103         size_t      len;
104         time_t      t;
105         struct tm   s_tm;
106
107         out[0] = '\0';
108         if (!vp) return 0;
109
110         switch (vp->type) {
111                 case PW_TYPE_STRING:
112                         if ((delimitst == 1) && vp->flags.has_tag) {
113                                 /* Tagged attribute: print delimter and ignore tag */
114                                 buf[0] = '"';
115                                 librad_safeprint((char *)(vp->vp_strvalue),
116                                                  vp->length, buf + 1, sizeof(buf) - 2);
117                                 strcat(buf, "\"");
118                         } else if (delimitst == 1) {
119                                 /* Non-tagged attribute: print delimter */
120                                 buf[0] = '"';
121                                 librad_safeprint((char *)vp->vp_strvalue,
122                                                  vp->length, buf + 1, sizeof(buf) - 2);
123                                 strcat(buf, "\"");
124
125                         } else if (delimitst < 0) {
126                                 strlcpy(out, vp->vp_strvalue, outlen);
127                                 return strlen(out);
128
129                         } else {
130                                 /* Non-tagged attribute: no delimiter */
131                                 librad_safeprint((char *)vp->vp_strvalue,
132                                                  vp->length, buf, sizeof(buf));
133                         }
134                         a = buf;
135                         break;
136                 case PW_TYPE_INTEGER:
137                         if ( vp->flags.has_tag ) {
138                                 /* Attribute value has a tag, need to ignore it */
139                                 if ((v = dict_valbyattr(vp->attribute, (vp->vp_integer & 0xffffff)))
140                                     != NULL)
141                                         a = v->name;
142                                 else {
143                                         snprintf(buf, sizeof(buf), "%u", (vp->vp_integer & 0xffffff));
144                                         a = buf;
145                                 }
146                         } else {
147                         case PW_TYPE_BYTE:
148                         case PW_TYPE_SHORT:
149                                 /* Normal, non-tagged attribute */
150                                 if ((v = dict_valbyattr(vp->attribute, vp->vp_integer))
151                                     != NULL)
152                                         a = v->name;
153                                 else {
154                                         snprintf(buf, sizeof(buf), "%u", vp->vp_integer);
155                                         a = buf;
156                                 }
157                         }
158                         break;
159                 case PW_TYPE_DATE:
160                         t = vp->vp_date;
161                         if (delimitst) {
162                           len = strftime(buf, sizeof(buf), "\"%b %e %Y %H:%M:%S %Z\"",
163                                          localtime_r(&t, &s_tm));
164                         } else {
165                           len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z",
166                                          localtime_r(&t, &s_tm));
167                         }
168                         if (len > 0) a = buf;
169                         break;
170                 case PW_TYPE_IPADDR:
171                         a = inet_ntop(AF_INET, &(vp->vp_ipaddr),
172                                       buf, sizeof(buf));
173                         break;
174                 case PW_TYPE_ABINARY:
175 #ifdef ASCEND_BINARY
176                         a = buf;
177                         print_abinary(vp, buf, sizeof(buf));
178                         break;
179 #else
180                   /* FALL THROUGH */
181 #endif
182                 case PW_TYPE_OCTETS:
183                         if (outlen <= (2 * (vp->length + 1))) return 0;
184
185                         strcpy(buf, "0x");
186
187                         lrad_bin2hex(vp->vp_octets, buf + 2, vp->length);
188                         a = buf;
189                   break;
190
191                 case PW_TYPE_IFID:
192                         a = ifid_ntoa(buf, sizeof(buf), vp->vp_octets);
193                         break;
194
195                 case PW_TYPE_IPV6ADDR:
196                         a = inet_ntop(AF_INET6,
197                                       (const struct in6_addr *) vp->vp_strvalue,
198                                       buf, sizeof(buf));
199                         break;
200
201                 case PW_TYPE_IPV6PREFIX:
202                 {
203                         struct in6_addr addr;
204
205                         /*
206                          *      Alignment issues.
207                          */
208                         memcpy(&addr, vp->vp_strvalue + 2, sizeof(addr));
209
210                         a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
211                         if (a) {
212                                 char *p = buf + strlen(buf);
213                                 sprintf(p, "/%u", (unsigned int) vp->vp_strvalue[1]);
214                         }
215                 }
216                         break;
217
218                 default:
219                         a = "UNKNOWN-TYPE";
220                         break;
221         }
222
223         if (a != NULL) strlcpy(out, a, outlen);
224
225         return strlen(out);
226 }
227
228 /*
229  *  This is a hack, and has to be kept in sync with tokens.h
230  */
231 static const char *vp_tokens[] = {
232   "?",                          /* T_OP_INVALID */
233   "EOL",                        /* T_EOL */
234   "{",
235   "}",
236   "(",
237   ")",
238   ",",
239   ";",
240   "+=",
241   "-=",
242   ":=",
243   "=",
244   "!=",
245   ">=",
246   ">",
247   "<=",
248   "<",
249   "=~",
250   "!~",
251   "=*",
252   "!*",
253   "==",
254   "#",
255   "<BARE-WORD>",
256   "<\"STRING\">",
257   "<'STRING'>",
258   "<`STRING`>"
259 };
260
261
262 /*
263  *      Print one attribute and value into a string.
264  */
265 int vp_prints(char *out, int outlen, VALUE_PAIR *vp)
266 {
267         int             len;
268         const char      *token = NULL;
269         const char      *name;
270
271         out[0] = 0;
272         if (!vp) return 0;
273         name = vp->name;
274
275         if (!*name) {
276                 DICT_ATTR *da = dict_attrbyvalue(vp->attribute);
277                 if (!da) return 0;
278
279                 name = da->name;
280         }
281
282         if (strlen(name) + 3 > (size_t)outlen) {
283                 return 0;
284         }
285
286         if ((vp->operator > T_OP_INVALID) &&
287             (vp->operator < T_TOKEN_LAST)) {
288                 token = vp_tokens[vp->operator];
289         } else {
290                 token = "<INVALID-TOKEN>";
291         }
292
293         if( vp->flags.has_tag ) {
294
295                 snprintf(out, outlen, "%s:%d %s ", name, vp->flags.tag,
296                          token);
297
298                 len = strlen(out);
299                 vp_prints_value(out + len, outlen - len, vp, 1);
300
301         } else {
302
303                 snprintf(out, outlen, "%s %s ", name, token);
304                 len = strlen(out);
305                 vp_prints_value(out + len, outlen - len, vp, 1);
306
307         }
308
309         return strlen(out);
310 }
311
312
313 /*
314  *      Print one attribute and value.
315  */
316 void vp_print(FILE *fp, VALUE_PAIR *vp)
317 {
318         char    buf[1024];
319
320         vp_prints(buf, sizeof(buf), vp);
321         fputs(buf, fp);
322 }
323
324
325 /*
326  *      Print a whole list of attributes, indented by a TAB
327  *      and with a newline at the end.
328  */
329 void vp_printlist(FILE *fp, VALUE_PAIR *vp)
330 {
331         for (; vp; vp = vp->next) {
332                 fprintf(fp, "\t");
333                 vp_print(fp, vp);
334                 fprintf(fp, "\n");
335         }
336 }
337