Merge from vendor branch GCC:
[dragonfly.git] / contrib / dhcp-3.0 / common / print.c
1 /* print.c
2
3    Turn data structures into printable text. */
4
5 /*
6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1995-2003 by Internet Software Consortium
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   http://www.isc.org/
26  *
27  * This software has been written for Internet Systems Consortium
28  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29  * To learn more about Internet Systems Consortium, see
30  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
31  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
32  * ``http://www.nominum.com''.
33  */
34
35 #ifndef lint
36 static char copyright[] =
37 "$Id: print.c,v 1.53.2.11 2004/06/17 20:54:39 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #include "dhcpd.h"
41
42 char *quotify_string (const char *s, const char *file, int line)
43 {
44         unsigned len = 0;
45         const char *sp;
46         char *buf, *nsp;
47
48         for (sp = s; sp && *sp; sp++) {
49                 if (*sp == ' ')
50                         len++;
51                 else if (!isascii (*sp) || !isprint (*sp))
52                         len += 4;
53                 else if (*sp == '"' || *sp == '\\')
54                         len += 2;
55                 else
56                         len++;
57         }
58
59         buf = dmalloc (len + 1, file, line);
60         if (buf) {
61                 nsp = buf;
62                 for (sp = s; sp && *sp; sp++) {
63                         if (*sp == ' ')
64                                 *nsp++ = ' ';
65                         else if (!isascii (*sp) || !isprint (*sp)) {
66                                 sprintf (nsp, "\\%03o",
67                                          *(const unsigned char *)sp);
68                                 nsp += 4;
69                         } else if (*sp == '"' || *sp == '\\') {
70                                 *nsp++ = '\\';
71                                 *nsp++ = *sp;
72                         } else
73                                 *nsp++ = *sp;
74                 }
75                 *nsp++ = 0;
76         }
77         return buf;
78 }
79
80 char *quotify_buf (const unsigned char *s, unsigned len,
81                    const char *file, int line)
82 {
83         unsigned nulen = 0;
84         char *buf, *nsp;
85         int i;
86
87         for (i = 0; i < len; i++) {
88                 if (s [i] == ' ')
89                         nulen++;
90                 else if (!isascii (s [i]) || !isprint (s [i]))
91                         nulen += 4;
92                 else if (s [i] == '"' || s [i] == '\\')
93                         nulen += 2;
94                 else
95                         nulen++;
96         }
97
98         buf = dmalloc (nulen + 1, MDL);
99         if (buf) {
100                 nsp = buf;
101                 for (i = 0; i < len; i++) {
102                         if (s [i] == ' ')
103                                 *nsp++ = ' ';
104                         else if (!isascii (s [i]) || !isprint (s [i])) {
105                                 sprintf (nsp, "\\%03o", s [i]);
106                                 nsp += 4;
107                         } else if (s [i] == '"' || s [i] == '\\') {
108                                 *nsp++ = '\\';
109                                 *nsp++ = s [i];
110                         } else
111                                 *nsp++ = s [i];
112                 }
113                 *nsp++ = 0;
114         }
115         return buf;
116 }
117
118 char *print_base64 (const unsigned char *buf, unsigned len,
119                     const char *file, int line)
120 {
121         char *s, *b;
122         unsigned bl;
123         int i;
124         unsigned val, extra;
125         static char to64 [] =
126            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
127
128         bl = ((len * 4 + 2) / 3) + 1;
129         b = dmalloc (bl + 1, file, line);
130         if (!b)
131                 return (char *)0;
132         
133         i = 0;
134         s = b;
135         while (i != len) {
136                 val = buf [i++];
137                 extra = val & 3;
138                 val = val >> 2;
139                 *s++ = to64 [val];
140                 if (i == len) {
141                         *s++ = to64 [extra << 4];
142                         *s++ = '=';
143                         break;
144                 }
145                 val = (extra << 8) + buf [i++];
146                 extra = val & 15;
147                 val = val >> 4;
148                 *s++ = to64 [val];
149                 if (i == len) {
150                         *s++ = to64 [extra << 2];
151                         *s++ = '=';
152                         break;
153                 }
154                 val = (extra << 8) + buf [i++];
155                 extra = val & 0x3f;
156                 val = val >> 6;
157                 *s++ = to64 [val];
158                 *s++ = to64 [extra];
159         }
160         if (!len)
161                 *s++ = '=';
162         *s++ = 0;
163         if (s > b + bl + 1)
164                 abort ();
165         return b;
166 }
167
168 char *print_hw_addr (htype, hlen, data)
169         int htype;
170         int hlen;
171         unsigned char *data;
172 {
173         static char habuf [49];
174         char *s;
175         int i;
176
177         if (hlen <= 0)
178                 habuf [0] = 0;
179         else {
180                 s = habuf;
181                 for (i = 0; i < hlen; i++) {
182                         sprintf (s, "%02x", data [i]);
183                         s += strlen (s);
184                         *s++ = ':';
185                 }
186                 *--s = 0;
187         }
188         return habuf;
189 }
190
191 void print_lease (lease)
192         struct lease *lease;
193 {
194         struct tm *t;
195         char tbuf [32];
196
197         log_debug ("  Lease %s",
198                piaddr (lease -> ip_addr));
199         
200         t = gmtime (&lease -> starts);
201         strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
202         log_debug ("  start %s", tbuf);
203         
204         t = gmtime (&lease -> ends);
205         strftime (tbuf, sizeof tbuf, "%Y/%m/%d %H:%M:%S", t);
206         log_debug ("  end %s", tbuf);
207         
208         if (lease -> hardware_addr.hlen)
209                 log_debug ("    hardware addr = %s",
210                            print_hw_addr (lease -> hardware_addr.hbuf [0],
211                                           lease -> hardware_addr.hlen - 1,
212                                           &lease -> hardware_addr.hbuf [1]));
213         log_debug ("  host %s  ",
214                lease -> host ? lease -> host -> name : "<none>");
215 }       
216
217 #if defined (DEBUG_PACKET)
218 void dump_packet_option (struct option_cache *oc,
219                          struct packet *packet,
220                          struct lease *lease,
221                          struct client_state *client,
222                          struct option_state *in_options,
223                          struct option_state *cfg_options,
224                          struct binding_scope **scope,
225                          struct universe *u, void *foo)
226 {
227         const char *name, *dot;
228         struct data_string ds;
229         memset (&ds, 0, sizeof ds);
230
231         if (u != &dhcp_universe) {
232                 name = u -> name;
233                 dot = ".";
234         } else {
235                 name = "";
236                 dot = "";
237         }
238         if (evaluate_option_cache (&ds, packet, lease, client,
239                                    in_options, cfg_options, scope, oc, MDL)) {
240                 log_debug ("  option %s%s%s %s;\n",
241                            name, dot, oc -> option -> name,
242                            pretty_print_option (oc -> option,
243                                                 ds.data, ds.len, 1, 1));
244                 data_string_forget (&ds, MDL);
245         }
246 }
247
248 void dump_packet (tp)
249         struct packet *tp;
250 {
251         struct dhcp_packet *tdp = tp -> raw;
252
253         log_debug ("packet length %d", tp -> packet_length);
254         log_debug ("op = %d  htype = %d  hlen = %d  hops = %d",
255                tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops);
256         log_debug ("xid = %x  secs = %ld  flags = %x",
257                tdp -> xid, (unsigned long)tdp -> secs, tdp -> flags);
258         log_debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr));
259         log_debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr));
260         log_debug ("siaddr = %s", inet_ntoa (tdp -> siaddr));
261         log_debug ("giaddr = %s", inet_ntoa (tdp -> giaddr));
262         log_debug ("chaddr = %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
263                ((unsigned char *)(tdp -> chaddr)) [0],
264                ((unsigned char *)(tdp -> chaddr)) [1],
265                ((unsigned char *)(tdp -> chaddr)) [2],
266                ((unsigned char *)(tdp -> chaddr)) [3],
267                ((unsigned char *)(tdp -> chaddr)) [4],
268                ((unsigned char *)(tdp -> chaddr)) [5]);
269         log_debug ("filename = %s", tdp -> file);
270         log_debug ("server_name = %s", tdp -> sname);
271         if (tp -> options_valid) {
272                 int i;
273
274                 for (i = 0; i < tp -> options -> universe_count; i++) {
275                         if (tp -> options -> universes [i]) {
276                                 option_space_foreach (tp, (struct lease *)0,
277                                                       (struct client_state *)0,
278                                                       (struct option_state *)0,
279                                                       tp -> options,
280                                                       &global_scope,
281                                                       universes [i], 0,
282                                                       dump_packet_option);
283                         }
284                 }
285         }
286         log_debug ("%s", "");
287 }
288 #endif
289
290 void dump_raw (buf, len)
291         const unsigned char *buf;
292         unsigned len;
293 {
294         int i;
295         char lbuf [80];
296         int lbix = 0;
297
298 /*
299           1         2         3         4         5         6         7
300 01234567890123456789012345678901234567890123456789012345678901234567890123
301 280: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   .................  
302 */
303
304         memset(lbuf, ' ', 79);
305         lbuf [79] = 0;
306
307         for (i = 0; i < len; i++) {
308                 if ((i & 15) == 0) {
309                   if (lbix) {
310                         lbuf[53]=' ';
311                         lbuf[54]=' ';
312                         lbuf[55]=' ';
313                         lbuf[73]='\0';
314                         log_info (lbuf);
315                   }
316                   memset(lbuf, ' ', 79);
317                   lbuf [79] = 0;
318                   sprintf (lbuf, "%03x:", i);
319                   lbix = 4;
320                 } else if ((i & 7) == 0)
321                         lbuf [lbix++] = ' ';
322
323                 if(isprint(buf[i])) {
324                   lbuf[56+(i%16)]=buf[i];
325                 } else {
326                   lbuf[56+(i%16)]='.';
327                 }
328
329                 sprintf (&lbuf [lbix], " %02x", buf [i]);
330                 lbix += 3;
331                 lbuf[lbix]=' ';
332
333         }
334         lbuf[53]=' ';
335         lbuf[54]=' ';
336         lbuf[55]=' ';
337         lbuf[73]='\0';
338         log_info (lbuf);
339 }
340
341 void hash_dump (table)
342         struct hash_table *table;
343 {
344         int i;
345         struct hash_bucket *bp;
346
347         if (!table)
348                 return;
349
350         for (i = 0; i < table -> hash_count; i++) {
351                 if (!table -> buckets [i])
352                         continue;
353                 log_info ("hash bucket %d:", i);
354                 for (bp = table -> buckets [i]; bp; bp = bp -> next) {
355                         if (bp -> len)
356                                 dump_raw (bp -> name, bp -> len);
357                         else
358                                 log_info ("%s", (const char *)bp -> name);
359                 }
360         }
361 }
362
363 #define HBLEN 60
364
365 #define DECLARE_HEX_PRINTER(x)                                                \
366 char *print_hex##x (len, data, limit)                                         \
367         unsigned len;                                                         \
368         const u_int8_t *data;                                                 \
369         unsigned limit;                                                       \
370 {                                                                             \
371                                                                               \
372         static char hex_buf##x [HBLEN + 1];                                   \
373         unsigned i;                                                           \
374                                                                               \
375         if (limit > HBLEN)                                                    \
376                 limit = HBLEN;                                                \
377                                                                               \
378         for (i = 0; i < (limit - 2) && i < len; i++) {                        \
379                 if (!isascii (data [i]) || !isprint (data [i])) {             \
380                         for (i = 0; i < limit / 3 && i < len; i++) {          \
381                                 sprintf (&hex_buf##x [i * 3],                 \
382                                          "%02x:", data [i]);                  \
383                         }                                                     \
384                         hex_buf##x [i * 3 - 1] = 0;                           \
385                         return hex_buf##x;                                    \
386                 }                                                             \
387         }                                                                     \
388         hex_buf##x [0] = '"';                                                 \
389         i = len;                                                              \
390         if (i > limit - 2)                                                    \
391                 i = limit - 2;                                                \
392         memcpy (&hex_buf##x [1], data, i);                                    \
393         hex_buf##x [i + 1] = '"';                                             \
394         hex_buf##x [i + 2] = 0;                                               \
395         return hex_buf##x;                                                    \
396 }
397
398 DECLARE_HEX_PRINTER (_1)
399 DECLARE_HEX_PRINTER (_2)
400 DECLARE_HEX_PRINTER (_3)
401
402 #define DQLEN   80
403
404 char *print_dotted_quads (len, data)
405         unsigned len;
406         const u_int8_t *data;
407 {
408         static char dq_buf [DQLEN + 1];
409         int i;
410         char *s, *last;
411
412         s = &dq_buf [0];
413         last = s;
414         
415         i = 0;
416
417         /* %Audit% Loop bounds checks to 21 bytes. %2004.06.17,Safe%
418          * The sprintf can't exceed 18 bytes, and since the loop enforces
419          * 21 bytes of space per iteration at no time can we exit the
420          * loop without at least 3 bytes spare.
421          */
422         do {
423                 sprintf (s, "%u.%u.%u.%u, ",
424                          data [i], data [i + 1], data [i + 2], data [i + 3]);
425                 s += strlen (s);
426                 i += 4;
427         } while ((s - &dq_buf [0] > DQLEN - 21) &&
428                  i + 3 < len);
429         if (i == len)
430                 s [-2] = 0;
431         else
432                 strcpy (s, "...");
433         return dq_buf;
434 }
435
436 char *print_dec_1 (val)
437         unsigned long val;
438 {
439         static char vbuf [32];
440         sprintf (vbuf, "%lu", val);
441         return vbuf;
442 }
443
444 char *print_dec_2 (val)
445         unsigned long val;
446 {
447         static char vbuf [32];
448         sprintf (vbuf, "%lu", val);
449         return vbuf;
450 }
451
452 static unsigned print_subexpression PROTO ((struct expression *,
453                                             char *, unsigned));
454
455 static unsigned print_subexpression (expr, buf, len)
456         struct expression *expr;
457         char *buf;
458         unsigned len;
459 {
460         unsigned rv, left;
461         const char *s;
462         
463         switch (expr -> op) {
464               case expr_none:
465                 if (len > 3) {
466                         strcpy (buf, "nil");
467                         return 3;
468                 }
469                 break;
470                   
471               case expr_match:
472                 if (len > 7) {
473                         strcpy (buf, "(match)");
474                         return 7;
475                 }
476                 break;
477
478               case expr_check:
479                 rv = 10 + strlen (expr -> data.check -> name);
480                 if (len > rv) {
481                         sprintf (buf, "(check %s)",
482                                  expr -> data.check -> name);
483                         return rv;
484                 }
485                 break;
486
487               case expr_equal:
488                 if (len > 6) {
489                         rv = 4;
490                         strcpy (buf, "(eq ");
491                         rv += print_subexpression (expr -> data.equal [0],
492                                                    buf + rv, len - rv - 2);
493                         buf [rv++] = ' ';
494                         rv += print_subexpression (expr -> data.equal [1],
495                                                    buf + rv, len - rv - 1);
496                         buf [rv++] = ')';
497                         buf [rv] = 0;
498                         return rv;
499                 }
500                 break;
501
502               case expr_not_equal:
503                 if (len > 7) {
504                         rv = 5;
505                         strcpy (buf, "(neq ");
506                         rv += print_subexpression (expr -> data.equal [0],
507                                                    buf + rv, len - rv - 2);
508                         buf [rv++] = ' ';
509                         rv += print_subexpression (expr -> data.equal [1],
510                                                    buf + rv, len - rv - 1);
511                         buf [rv++] = ')';
512                         buf [rv] = 0;
513                         return rv;
514                 }
515                 break;
516
517               case expr_substring:
518                 if (len > 11) {
519                         rv = 8;
520                         strcpy (buf, "(substr ");
521                         rv += print_subexpression (expr -> data.substring.expr,
522                                                    buf + rv, len - rv - 3);
523                         buf [rv++] = ' ';
524                         rv += print_subexpression
525                                 (expr -> data.substring.offset,
526                                  buf + rv, len - rv - 2);
527                         buf [rv++] = ' ';
528                         rv += print_subexpression (expr -> data.substring.len,
529                                                    buf + rv, len - rv - 1);
530                         buf [rv++] = ')';
531                         buf [rv] = 0;
532                         return rv;
533                 }
534                 break;
535
536               case expr_suffix:
537                 if (len > 10) {
538                         rv = 8;
539                         strcpy (buf, "(suffix ");
540                         rv += print_subexpression (expr -> data.suffix.expr,
541                                                    buf + rv, len - rv - 2);
542                         if (len > rv)
543                                 buf [rv++] = ' ';
544                         rv += print_subexpression (expr -> data.suffix.len,
545                                                    buf + rv, len - rv - 1);
546                         if (len > rv)
547                                 buf [rv++] = ')';
548                         buf [rv] = 0;
549                         return rv;
550                 }
551                 break;
552
553               case expr_concat:
554                 if (len > 10) {
555                         rv = 8;
556                         strcpy (buf, "(concat ");
557                         rv += print_subexpression (expr -> data.concat [0],
558                                                    buf + rv, len - rv - 2);
559                         buf [rv++] = ' ';
560                         rv += print_subexpression (expr -> data.concat [1],
561                                                    buf + rv, len - rv - 1);
562                         buf [rv++] = ')';
563                         buf [rv] = 0;
564                         return rv;
565                 }
566                 break;
567
568               case expr_pick_first_value:
569                 if (len > 8) {
570                         rv = 6;
571                         strcpy (buf, "(pick1st ");
572                         rv += print_subexpression
573                                 (expr -> data.pick_first_value.car,
574                                  buf + rv, len - rv - 2);
575                         buf [rv++] = ' ';
576                         rv += print_subexpression
577                                 (expr -> data.pick_first_value.cdr,
578                                  buf + rv, len - rv - 1);
579                         buf [rv++] = ')';
580                         buf [rv] = 0;
581                         return rv;
582                 }
583                 break;
584
585               case expr_host_lookup:
586                 rv = 15 + strlen (expr -> data.host_lookup -> hostname);
587                 if (len > rv) {
588                         sprintf (buf, "(dns-lookup %s)",
589                                  expr -> data.host_lookup -> hostname);
590                         return rv;
591                 }
592                 break;
593
594               case expr_and:
595                 s = "and";
596               binop:
597                 rv = strlen (s);
598                 if (len > rv + 4) {
599                         buf [0] = '(';
600                         strcpy (&buf [1], s);
601                         rv += 1;
602                         buf [rv++] = ' ';
603                         rv += print_subexpression (expr -> data.and [0],
604                                                 buf + rv, len - rv - 2);
605                         buf [rv++] = ' ';
606                         rv += print_subexpression (expr -> data.and [1],
607                                                    buf + rv, len - rv - 1);
608                         buf [rv++] = ')';
609                         buf [rv] = 0;
610                         return rv;
611                 }
612                 break;
613
614               case expr_or:
615                 s = "or";
616                 goto binop;
617
618               case expr_add:
619                 s = "+";
620                 goto binop;
621
622               case expr_subtract:
623                 s = "-";
624                 goto binop;
625
626               case expr_multiply:
627                 s = "*";
628                 goto binop;
629
630               case expr_divide:
631                 s = "/";
632                 goto binop;
633
634               case expr_remainder:
635                 s = "%";
636                 goto binop;
637
638               case expr_binary_and:
639                 s = "&";
640                 goto binop;
641
642               case expr_binary_or:
643                 s = "|";
644                 goto binop;
645
646               case expr_binary_xor:
647                 s = "^";
648                 goto binop;
649                 
650               case expr_not:
651                 if (len > 6) {
652                         rv = 5;
653                         strcpy (buf, "(not ");
654                         rv += print_subexpression (expr -> data.not,
655                                                    buf + rv, len - rv - 1);
656                         buf [rv++] = ')';
657                         buf [rv] = 0;
658                         return rv;
659                 }
660                 break;
661
662               case expr_config_option:
663                 s = "cfg-option";
664                 goto dooption;
665
666               case expr_option:
667                 s = "option";
668               dooption:
669                 rv = strlen (s) + 2 + (strlen (expr -> data.option -> name) +
670                            strlen (expr -> data.option -> universe -> name));
671                 if (len > rv) {
672                         sprintf (buf, "(option %s.%s)",
673                                  expr -> data.option -> universe -> name,
674                                  expr -> data.option -> name);
675                         return rv;
676                 }
677                 break;
678
679               case expr_hardware:
680                 if (len > 10) {
681                         strcpy (buf, "(hardware)");
682                         return 10;
683                 }
684                 break;
685
686               case expr_packet:
687                 if (len > 10) {
688                         rv = 8;
689                         strcpy (buf, "(substr ");
690                         rv += print_subexpression (expr -> data.packet.offset,
691                                                    buf + rv, len - rv - 2);
692                         buf [rv++] = ' ';
693                         rv += print_subexpression (expr -> data.packet.len,
694                                                    buf + rv, len - rv - 1);
695                         buf [rv++] = ')';
696                         buf [rv] = 0;
697                         return rv;
698                 }
699                 break;
700
701               case expr_const_data:
702                 s = print_hex_1 (expr -> data.const_data.len,
703                                  expr -> data.const_data.data, len);
704                 rv = strlen (s);
705                 if (rv >= len)
706                         rv = len - 1;
707                 strncpy (buf, s, rv);
708                 buf [rv] = 0;
709                 return rv;
710
711               case expr_encapsulate:
712                 rv = 13;
713                 strcpy (buf, "(encapsulate ");
714                 rv += expr -> data.encapsulate.len;
715                 if (rv + 2 > len)
716                         rv = len - 2;
717                 strncpy (buf,
718                          (const char *)expr -> data.encapsulate.data, rv - 13);
719                 buf [rv++] = ')';
720                 buf [rv++] = 0;
721                 break;
722
723               case expr_extract_int8:
724                 if (len > 7) {
725                         rv = 6;
726                         strcpy (buf, "(int8 ");
727                         rv += print_subexpression (expr -> data.extract_int,
728                                                    buf + rv, len - rv - 1);
729                         buf [rv++] = ')';
730                         buf [rv] = 0;
731                         return rv;
732                 }
733                 break;
734
735               case expr_extract_int16:
736                 if (len > 8) {
737                         rv = 7;
738                         strcpy (buf, "(int16 ");
739                         rv += print_subexpression (expr -> data.extract_int,
740                                                    buf + rv, len - rv - 1);
741                         buf [rv++] = ')';
742                         buf [rv] = 0;
743                         return rv;
744                 }
745                 break;
746
747               case expr_extract_int32:
748                 if (len > 8) {
749                         rv = 7;
750                         strcpy (buf, "(int32 ");
751                         rv += print_subexpression (expr -> data.extract_int,
752                                                    buf + rv, len - rv - 1);
753                         buf [rv++] = ')';
754                         buf [rv] = 0;
755                         return rv;
756                 }
757                 break;
758
759               case expr_encode_int8:
760                 if (len > 7) {
761                         rv = 6;
762                         strcpy (buf, "(to-int8 ");
763                         rv += print_subexpression (expr -> data.encode_int,
764                                                    buf + rv, len - rv - 1);
765                         buf [rv++] = ')';
766                         buf [rv] = 0;
767                         return rv;
768                 }
769                 break;
770
771               case expr_encode_int16:
772                 if (len > 8) {
773                         rv = 7;
774                         strcpy (buf, "(to-int16 ");
775                         rv += print_subexpression (expr -> data.encode_int,
776                                                    buf + rv, len - rv - 1);
777                         buf [rv++] = ')';
778                         buf [rv] = 0;
779                         return rv;
780                 }
781                 break;
782
783               case expr_encode_int32:
784                 if (len > 8) {
785                         rv = 7;
786                         strcpy (buf, "(to-int32 ");
787                         rv += print_subexpression (expr -> data.encode_int,
788                                                    buf + rv, len - rv - 1);
789                         buf [rv++] = ')';
790                         buf [rv] = 0;
791                         return rv;
792                 }
793                 break;
794
795               case expr_const_int:
796                 s = print_dec_1 (expr -> data.const_int);
797                 rv = strlen (s);
798                 if (len > rv) {
799                         strcpy (buf, s);
800                         return rv;
801                 }
802                 break;
803
804               case expr_exists:
805                 rv = 10 + (strlen (expr -> data.option -> name) +
806                            strlen (expr -> data.option -> universe -> name));
807                 if (len > rv) {
808                         sprintf (buf, "(exists %s.%s)",
809                                  expr -> data.option -> universe -> name,
810                                  expr -> data.option -> name);
811                         return rv;
812                 }
813                 break;
814
815               case expr_variable_exists:
816                 rv = 10 + strlen (expr -> data.variable);
817                 if (len > rv) {
818                         sprintf (buf, "(defined %s)", expr -> data.variable);
819                         return rv;
820                 }
821                 break;
822
823               case expr_variable_reference:
824                 rv = strlen (expr -> data.variable);
825                 if (len > rv) {
826                         sprintf (buf, "%s", expr -> data.variable);
827                         return rv;
828                 }
829                 break;
830
831               case expr_known:
832                 s = "known";
833               astring:
834                 rv = strlen (s);
835                 if (len > rv) {
836                         strcpy (buf, s);
837                         return rv;
838                 }
839                 break;
840
841               case expr_leased_address:
842                 s = "leased-address";
843                 goto astring;
844
845               case expr_client_state:
846                 s = "client-state";
847                 goto astring;
848
849               case expr_host_decl_name:
850                 s = "host-decl-name";
851                 goto astring;
852
853               case expr_lease_time:
854                 s = "lease-time";
855                 goto astring;
856
857               case expr_static:
858                 s = "static";
859                 goto astring;
860
861               case expr_filename:
862                 s = "filename";
863                 goto astring;
864
865               case expr_sname:
866                 s = "server-name";
867                 goto astring;
868
869               case expr_reverse:
870                 if (len > 11) {
871                         rv = 13;
872                         strcpy (buf, "(reverse ");
873                         rv += print_subexpression (expr -> data.reverse.width,
874                                                    buf + rv, len - rv - 2);
875                         buf [rv++] = ' ';
876                         rv += print_subexpression (expr -> data.reverse.buffer,
877                                                    buf + rv, len - rv - 1);
878                         buf [rv++] = ')';
879                         buf [rv] = 0;
880                         return rv;
881                 }
882                 break;
883
884               case expr_binary_to_ascii:
885                 if (len > 5) {
886                         rv = 9;
887                         strcpy (buf, "(b2a ");
888                         rv += print_subexpression (expr -> data.b2a.base,
889                                                    buf + rv, len - rv - 4);
890                         buf [rv++] = ' ';
891                         rv += print_subexpression (expr -> data.b2a.width,
892                                                    buf + rv, len - rv - 3);
893                         buf [rv++] = ' ';
894                         rv += print_subexpression (expr -> data.b2a.seperator,
895                                                    buf + rv, len - rv - 2);
896                         buf [rv++] = ' ';
897                         rv += print_subexpression (expr -> data.b2a.buffer,
898                                                    buf + rv, len - rv - 1);
899                         buf [rv++] = ')';
900                         buf [rv] = 0;
901                         return rv;
902                 }
903                 break;
904
905               case expr_dns_transaction:
906                 rv = 10;
907                 if (len < rv + 2) {
908                         buf [0] = '(';
909                         strcpy (&buf [1], "ns-update ");
910                         while (len < rv + 2) {
911                                 rv += print_subexpression
912                                         (expr -> data.dns_transaction.car,
913                                          buf + rv, len - rv - 2);
914                                 buf [rv++] = ' ';
915                                 expr = expr -> data.dns_transaction.cdr;
916                         }
917                         buf [rv - 1] = ')';
918                         buf [rv] = 0;
919                         return rv;
920                 }
921                 return 0;
922
923               case expr_ns_delete:
924                 s = "delete";
925                 left = 4;
926                 goto dodnsupd;
927               case expr_ns_exists:
928                 s = "exists";
929                 left = 4;
930                 goto dodnsupd;
931               case expr_ns_not_exists:
932                 s = "not_exists";
933                 left = 4;
934                 goto dodnsupd;
935               case expr_ns_add:
936                 s = "update";
937                 left = 5;
938               dodnsupd:
939                 rv = strlen (s);
940                 if (len > strlen (s) + 1) {
941                         buf [0] = '(';
942                         strcpy (buf + 1, s);
943                         rv++;
944                         buf [rv++] = ' ';
945                         s = print_dec_1 (expr -> data.ns_add.rrclass);
946                         if (len > rv + strlen (s) + left) {
947                                 strcpy (&buf [rv], s);
948                                 rv += strlen (&buf [rv]);
949                         }
950                         buf [rv++] = ' ';
951                         left--;
952                         s = print_dec_1 (expr -> data.ns_add.rrtype);
953                         if (len > rv + strlen (s) + left) {
954                                 strcpy (&buf [rv], s);
955                                 rv += strlen (&buf [rv]);
956                         }
957                         buf [rv++] = ' ';
958                         left--;
959                         rv += print_subexpression
960                                 (expr -> data.ns_add.rrname,
961                                  buf + rv, len - rv - left);
962                         buf [rv++] = ' ';
963                         left--;
964                         rv += print_subexpression
965                                 (expr -> data.ns_add.rrdata,
966                                  buf + rv, len - rv - left);
967                         buf [rv++] = ' ';
968                         left--;
969                         rv += print_subexpression
970                                 (expr -> data.ns_add.ttl,
971                                  buf + rv, len - rv - left);
972                         buf [rv++] = ')';
973                         buf [rv] = 0;
974                         return rv;
975                 }
976                 break;
977
978               case expr_null:
979                 if (len > 6) {
980                         strcpy (buf, "(null)");
981                         return 6;
982                 }
983                 break;
984               case expr_funcall:
985                 rv = 12 + strlen (expr -> data.funcall.name);
986                 if (len > rv + 1) {
987                         strcpy (buf, "(funcall  ");
988                         strcpy (buf + 9, expr -> data.funcall.name);
989                         buf [rv++] = ' ';
990                         rv += print_subexpression
991                                 (expr -> data.funcall.arglist, buf + rv,
992                                  len - rv - 1);
993                         buf [rv++] = ')';
994                         buf [rv] = 0;
995                         return rv;
996                 }
997                 break;
998
999               case expr_arg:
1000                 rv = print_subexpression (expr -> data.arg.val, buf, len);
1001                 if (expr -> data.arg.next && rv + 2 < len) {
1002                         buf [rv++] = ' ';
1003                         rv += print_subexpression (expr -> data.arg.next,
1004                                                    buf, len);
1005                         if (rv + 1 < len)
1006                                 buf [rv++] = 0;
1007                         return rv;
1008                 }
1009                 break;
1010               case expr_function:
1011                 rv = 9;
1012                 if (len > rv + 1) {
1013                         struct string_list *foo;
1014                         strcpy (buf, "(function");
1015                         for (foo = expr -> data.func -> args;
1016                              foo; foo = foo -> next) {
1017                                 if (len > rv + 2 + strlen (foo -> string)) {
1018                                         buf [rv - 1] = ' ';
1019                                         strcpy (&buf [rv], foo -> string);
1020                                         rv += strlen (foo -> string);
1021                                 }
1022                         }
1023                         buf [rv] = ')';
1024                         buf [rv++] = 0;
1025                         return rv;
1026                 }
1027         }
1028         return 0;
1029 }
1030
1031 void print_expression (name, expr)
1032         const char *name;
1033         struct expression *expr;
1034 {
1035         char buf [1024];
1036
1037         print_subexpression (expr, buf, sizeof buf);
1038         log_info ("%s: %s", name, buf);
1039 }
1040
1041 int token_print_indent_concat (FILE *file, int col,  int indent,
1042                                const char *prefix, 
1043                                const char *suffix, ...)
1044 {
1045         va_list list;
1046         char *buf;
1047         unsigned len;
1048         char *s, *t, *u;
1049
1050         va_start (list, suffix);
1051         s = va_arg (list, char *);
1052         len = 0;
1053         while (s) {
1054                 len += strlen (s);
1055                 s = va_arg (list, char *);
1056         }
1057         va_end (list);
1058
1059         t = dmalloc (len + 1, MDL);
1060         if (!t)
1061                 log_fatal ("token_print_indent: no memory for copy buffer");
1062
1063         va_start (list, suffix);
1064         s = va_arg (list, char *);
1065         u = t;
1066         while (s) {
1067                 len = strlen (s);
1068                 strcpy (u, s);
1069                 u += len;
1070         }
1071         va_end (list);
1072         
1073         len = token_print_indent (file, col, indent,
1074                                   prefix, suffix, t);
1075         dfree (t, MDL);
1076         return col;
1077 }
1078
1079 int token_indent_data_string (FILE *file, int col, int indent,
1080                               const char *prefix, const char *suffix,
1081                               struct data_string *data)
1082 {
1083         int i;
1084         char *buf;
1085         char obuf [3];
1086
1087         /* See if this is just ASCII. */
1088         for (i = 0; i < data -> len; i++)
1089                 if (!isascii (data -> data [i]) ||
1090                     !isprint (data -> data [i]))
1091                         break;
1092
1093         /* If we have a purely ASCII string, output it as text. */
1094         if (i == data -> len) {
1095                 char *buf = dmalloc (data -> len + 3, MDL);
1096                 if (buf) {
1097                         buf [0] = '"';
1098                         memcpy (buf + 1, data -> data, data -> len);
1099                         buf [data -> len + 1] = '"';
1100                         buf [data -> len + 2] = 0;
1101                         i = token_print_indent (file, col, indent,
1102                                                 prefix, suffix, buf);
1103                         dfree (buf, MDL);
1104                         return i;
1105                 }
1106         }
1107
1108         for (i = 0; i < data -> len; i++) {
1109                 sprintf (obuf, "%2.2x", data -> data [i]);
1110                 col = token_print_indent (file, col, indent,
1111                                           i == 0 ? prefix : "",
1112                                           (i + 1 == data -> len
1113                                            ? suffix
1114                                            : ""), obuf);
1115                 if (i + 1 != data -> len)
1116                         col = token_print_indent (file, col, indent,
1117                                                   prefix, suffix, ":");
1118         }
1119         return col;
1120 }
1121
1122 int token_print_indent (FILE *file, int col, int indent,
1123                         const char *prefix,
1124                         const char *suffix, const char *buf)
1125 {
1126         int len = strlen (buf) + strlen (prefix);
1127         if (col + len > 79) {
1128                 if (indent + len < 79) {
1129                         indent_spaces (file, indent);
1130                         col = indent;
1131                 } else {
1132                         indent_spaces (file, col);
1133                         col = len > 79 ? 0 : 79 - len - 1;
1134                 }
1135         } else if (prefix && *prefix) {
1136                 fputs (prefix, file);
1137                 col += strlen (prefix);
1138         }
1139         fputs (buf, file);
1140         col += len;
1141         if (suffix && *suffix) {
1142                 if (col + strlen (suffix) > 79) {
1143                         indent_spaces (file, indent);
1144                         col = indent;
1145                 } else {
1146                         fputs (suffix, file);
1147                         col += strlen (suffix);
1148                 }
1149         }
1150         return col;
1151 }
1152
1153 void indent_spaces (FILE *file, int indent)
1154 {
1155         int i;
1156         fputc ('\n', file);
1157         for (i = 0; i < indent; i++)
1158                 fputc (' ', file);
1159 }
1160
1161 #if defined (NSUPDATE)
1162 void print_dns_status (int status, ns_updque *uq)
1163 {
1164         char obuf [1024];
1165         char *s = &obuf [0], *end = &obuf [1022];
1166         ns_updrec *u;
1167         int position;
1168         int ttlp;
1169         const char *predicate = "if", *en, *op;
1170         int errorp;
1171
1172         for (u = ISC_LIST_HEAD (*uq); u; u = ISC_LIST_NEXT (u, r_link)) {
1173                 ttlp = 0;
1174
1175                 switch (u -> r_opcode)
1176                 {
1177                       case NXRRSET:
1178                         op = "rrset doesn't exist";
1179                         position = 1;
1180                         break;
1181                       case YXRRSET:
1182                         op = "rrset exists";
1183                         position = 1;
1184                         break;
1185                       case NXDOMAIN:
1186                         op = "domain doesn't exist";
1187                         position = 1;
1188                         break;
1189                       case YXDOMAIN:
1190                         op = "domain exists";
1191                         position = 1;
1192                         break;
1193                       case ADD:
1194                         op = "add";
1195                         position = 0;
1196                         ttlp = 1;
1197                         break;
1198                       case DELETE:
1199                         op = "delete";
1200                         position = 0;
1201                         break;
1202                       default:
1203                         op = "unknown";
1204                         position = 0;
1205                         break;
1206                 }
1207                 if (!position) {
1208                         if (s != &obuf [0] && s + 1 < end)
1209                                 *s++ = ' ';
1210                         if (s + strlen (op) < end) {
1211                                 strcpy (s, op);
1212                                 s += strlen (s);
1213                         }
1214                 } else {
1215                         if (s != &obuf [0] && s + 1 < end)
1216                                 *s++ = ' ';
1217                         if (s + strlen (predicate) < end) {
1218                                 strcpy (s, predicate);
1219                                 s += strlen (s);
1220                         }
1221                         predicate = "and";
1222                 }
1223                 if (u -> r_dname) {
1224                         if (s + 1 < end)
1225                                 *s++ = ' ';
1226                         if (s + strlen (u -> r_dname) < end) {
1227                                 strcpy (s, u -> r_dname);
1228                                 s += strlen (s);
1229                         }
1230                 }
1231                 if (ttlp) {
1232                         if (s + 1 < end)
1233                                 *s++ = ' ';
1234                         /* 27 is as big as a ttl can get. */
1235                         if (s + 27 < end) {
1236                                 sprintf (s, "%lu",
1237                                          (unsigned long)(u -> r_ttl));
1238                                 s += strlen (s);
1239                         }
1240                 }
1241                 switch (u -> r_class) {
1242                       case C_IN:
1243                         en = "IN";
1244                         break;
1245                       case C_CHAOS:
1246                         en = "CHAOS";
1247                         break;
1248                       case C_HS:
1249                         en = "HS";
1250                         break;
1251                       default:
1252                         en = "UNKNOWN";
1253                         break;
1254                 }
1255                 if (s + strlen (en) < end) {
1256                         if (s + 1 < end)
1257                                 *s++ = ' ';
1258                         strcpy (s, en);
1259                         s += strlen (en);
1260                 }
1261                 switch (u -> r_type) {
1262                       case T_A:
1263                         en = "A";
1264                         break;
1265                       case T_PTR:
1266                         en = "PTR";
1267                         break;
1268                       case T_MX:
1269                         en = "MX";
1270                         break;
1271                       case T_TXT:
1272                         en = "TXT";
1273                         break;
1274                       case T_KEY:
1275                         en = "KEY";
1276                         break;
1277                       case T_CNAME:
1278                         en = "CNAME";
1279                         break;
1280                       default:
1281                         en = "UNKNOWN";
1282                         break;
1283                 }
1284                 if (s + strlen (en) < end) {
1285                         if (s + 1 < end)
1286                                 *s++ = ' ';
1287                         strcpy (s, en);
1288                         s += strlen (en);
1289                 }
1290                 if (u -> r_data) {
1291                         if (s + 1 < end)
1292                                 *s++ = ' ';
1293                         if (u -> r_type == T_TXT) {
1294                                 if (s + 1 < end)
1295                                         *s++ = '"';
1296                         }
1297                         if(u->r_type == T_KEY) {
1298                           strcat(s, "<keydata>");
1299                           s+=strlen("<keydata>");
1300                         }
1301                         else {  
1302                           if (s + u -> r_size < end) {
1303                             memcpy (s, u -> r_data, u -> r_size);
1304                             s += u -> r_size;
1305                             if (u -> r_type == T_TXT) {
1306                               if (s + 1 < end)
1307                                 *s++ = '"';
1308                             }
1309                           }
1310                         }
1311                 }
1312                 if (position) {
1313                         if (s + 1 < end)
1314                                 *s++ = ' ';
1315                         if (s + strlen (op) < end) {
1316                                 strcpy (s, op);
1317                                 s += strlen (s);
1318                         }
1319                 }
1320                 if (u == ISC_LIST_TAIL (*uq))
1321                         break;
1322         }
1323         if (s == &obuf [0]) {
1324                 strcpy (s, "empty update");
1325                 s += strlen (s);
1326         }
1327         if (status == NOERROR)
1328                 errorp = 0;
1329         else
1330                 errorp = 1;
1331         en = isc_result_totext (status);
1332 #if 0
1333         switch (status) {
1334               case -1:
1335                 en = "resolver failed";
1336                 break;
1337
1338               case FORMERR:
1339                 en = "format error";
1340                 break;
1341
1342               case NOERROR:
1343                 en = "succeeded";
1344                 errorp = 0;
1345                 break;
1346
1347               case NOTAUTH:
1348                 en = "not authorized";
1349                 break;
1350
1351               case NOTIMP:
1352                 en = "not implemented";
1353                 break;
1354
1355               case NOTZONE:
1356                 en = "not a single valid zone";
1357                 break;
1358
1359               case NXDOMAIN:
1360                 en = "no such domain";
1361                 break;
1362
1363               case NXRRSET:
1364                 en = "no such record";
1365                 break;
1366
1367               case REFUSED:
1368                 en = "refused";
1369                 break;
1370
1371               case SERVFAIL:
1372                 en = "server failed";
1373                 break;
1374
1375               case YXDOMAIN:
1376                 en = "domain exists";
1377                 break;
1378
1379               case YXRRSET:
1380                 en = "record exists";
1381                 break;
1382
1383               default:
1384                 en = "unknown error";
1385                 break;
1386         }
1387 #endif
1388
1389         if (s + 2 < end) {
1390                 *s++ = ':';
1391                 *s++ = ' ';
1392         }
1393         if (s + strlen (en) < end) {
1394                 strcpy (s, en);
1395                 s += strlen (en);
1396         }
1397         if (s + 1 < end)
1398                 *s++ = '.';
1399         *s++ = 0;
1400         if (errorp)
1401                 log_error ("%s", obuf);
1402         else
1403                 log_info ("%s", obuf);
1404 }
1405 #endif /* NSUPDATE */