1 /*
2  * Copyright (c) 2003, 2007-14 Matteo Frigo
3  * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20 
21 
22 #include "kernel/ifftw.h"
23 #include <stddef.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 
27 #define BSZ 64
28 
myputs(printer * p,const char * s)29 static void myputs(printer *p, const char *s)
30 {
31      char c;
32      while ((c = *s++))
33           p->putchr(p, c);
34 }
35 
newline(printer * p)36 static void newline(printer *p)
37 {
38      int i;
39 
40      p->putchr(p, '\n');
41      for (i = 0; i < p->indent; ++i)
42 	  p->putchr(p, ' ');
43 }
44 
45 static const char *digits = "0123456789abcdef";
46 
putint(printer * p,INT i)47 static void putint(printer *p, INT i)
48 {
49      char buf[BSZ];
50      char *f = buf;
51 
52      if (i < 0) {
53 	  p->putchr(p, '-');
54 	  i = -i;
55      }
56 
57      do {
58 	  *f++ = digits[i % 10];
59 	  i /= 10;
60      } while (i);
61 
62      do {
63 	  p->putchr(p, *--f);
64      } while (f != buf);
65 }
66 
putulong(printer * p,unsigned long i,unsigned base,int width)67 static void putulong(printer *p, unsigned long i, unsigned base, int width)
68 {
69      char buf[BSZ];
70      char *f = buf;
71 
72      do {
73 	  *f++ = digits[i % base];
74 	  i /= base;
75      } while (i);
76 
77      while (width > f - buf) {
78 	  p->putchr(p, '0');
79 	  --width;
80      }
81 
82      do {
83 	  p->putchr(p, *--f);
84      } while (f != buf);
85 }
86 
vprint(printer * p,const char * format,va_list ap)87 static void vprint(printer *p, const char *format, va_list ap)
88 {
89      const char *s = format;
90      char c;
91      INT ival;
92 
93      while ((c = *s++)) {
94           switch (c) {
95 	      case '%':
96 		   switch ((c = *s++)) {
97 		       case 'M': {
98 			    /* md5 value */
99 			    md5uint x = va_arg(ap, md5uint);
100 			    putulong(p, (unsigned long)(0xffffffffUL & x),
101 				     16u, 8);
102 			    break;
103 		       }
104 		       case 'c': {
105 			    int x = va_arg(ap, int);
106 			    p->putchr(p, (char)x);
107 			    break;
108 		       }
109 		       case 's': {
110 			    char *x = va_arg(ap, char *);
111 			    if (x)
112 				 myputs(p, x);
113 			    else
114 				 goto putnull;
115 			    break;
116 		       }
117 		       case 'd': {
118 			    int x = va_arg(ap, int);
119 			    ival = (INT)x;
120 			    goto putival;
121 		       }
122 		       case 'D': {
123 			    ival = va_arg(ap, INT);
124 			    goto putival;
125 		       }
126 		       case 'v': {
127 			    /* print optional vector length */
128 			    ival = va_arg(ap, INT);
129 			    if (ival > 1) {
130 				 myputs(p, "-x");
131 				 goto putival;
132 			    }
133 			    break;
134 		       }
135 		       case 'o': {
136 			    /* integer option.  Usage: %oNAME= */
137 			    ival = va_arg(ap, INT);
138 			    if (ival)
139 				 p->putchr(p, '/');
140 			    while ((c = *s++) != '=')
141 				 if (ival)
142 				      p->putchr(p, c);
143 			    if (ival) {
144 				 p->putchr(p, '=');
145 				 goto putival;
146 			    }
147 			    break;
148 		       }
149 		       case 'u': {
150 			    unsigned x = va_arg(ap, unsigned);
151 			    putulong(p, (unsigned long)x, 10u, 0);
152 			    break;
153 		       }
154 		       case 'x': {
155 			    unsigned x = va_arg(ap, unsigned);
156 			    putulong(p, (unsigned long)x, 16u, 0);
157 			    break;
158 		       }
159 		       case '(': {
160 			    /* newline, augment indent level */
161 			    p->indent += p->indent_incr;
162 			    newline(p);
163 			    break;
164 		       }
165 		       case ')': {
166 			    /* decrement indent level */
167 			    p->indent -= p->indent_incr;
168 			    break;
169 		       }
170 		       case 'p': {  /* note difference from C's %p */
171 			    /* print plan */
172 			    plan *x = va_arg(ap, plan *);
173 			    if (x)
174 				 x->adt->print(x, p);
175 			    else
176 				 goto putnull;
177 			    break;
178 		       }
179 		       case 'P': {
180 			    /* print problem */
181 			    problem *x = va_arg(ap, problem *);
182 			    if (x)
183 				 x->adt->print(x, p);
184 			    else
185 				 goto putnull;
186 			    break;
187 		       }
188 		       case 'T': {
189 			    /* print tensor */
190 			    tensor *x = va_arg(ap, tensor *);
191 			    if (x)
192 				 X(tensor_print)(x, p);
193 			    else
194 				 goto putnull;
195 			    break;
196 		       }
197 		       default:
198 			    A(0 /* unknown format */);
199 			    break;
200 
201 		   putnull:
202 			    myputs(p, "(null)");
203 			    break;
204 
205 		   putival:
206 			    putint(p, ival);
207 			    break;
208 		   }
209 		   break;
210 	      default:
211 		   p->putchr(p, c);
212 		   break;
213           }
214      }
215 }
216 
print(printer * p,const char * format,...)217 static void print(printer *p, const char *format, ...)
218 {
219      va_list ap;
220      va_start(ap, format);
221      vprint(p, format, ap);
222      va_end(ap);
223 }
224 
X(mkprinter)225 printer *X(mkprinter)(size_t size,
226 		      void (*putchr)(printer *p, char c),
227 		      void (*cleanup)(printer *p))
228 {
229      printer *s = (printer *)MALLOC(size, OTHER);
230      s->print = print;
231      s->vprint = vprint;
232      s->putchr = putchr;
233      s->cleanup = cleanup;
234      s->indent = 0;
235      s->indent_incr = 2;
236      return s;
237 }
238 
X(printer_destroy)239 void X(printer_destroy)(printer *p)
240 {
241      if (p->cleanup)
242 	  p->cleanup(p);
243      X(ifree)(p);
244 }
245