b47d8fb5aac669188a01dc0907fe4bdc12e94f2b
[vpp.git] / vppinfra / vppinfra / std-formats.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #include <vppinfra/format.h>
39 #include <ctype.h>
40
41 /* Format vectors. */
42 u8 * format_vec32 (u8 * s, va_list * va)
43 {
44   u32 * v = va_arg (*va, u32 *);
45   char * fmt = va_arg (*va, char *);
46   uword i;
47   for (i = 0; i < vec_len (v); i++)
48     {
49       if (i > 0)
50         s = format (s, ", ");
51       s = format (s, fmt, v[i]);
52     }
53   return s;
54 }
55
56 u8 * format_vec_uword (u8 * s, va_list * va)
57 {
58   uword * v = va_arg (*va, uword *);
59   char * fmt = va_arg (*va, char *);
60   uword i;
61   for (i = 0; i < vec_len (v); i++)
62     {
63       if (i > 0)
64         s = format (s, ", ");
65       s = format (s, fmt, v[i]);
66     }
67   return s;
68 }
69
70 /* Ascii buffer and length. */
71 u8 * format_ascii_bytes (u8 * s, va_list * va)
72 {
73   u8 * v = va_arg (*va, u8 *);
74   uword n_bytes = va_arg (*va, uword);
75   vec_add (s, v, n_bytes);
76   return s;
77 }
78
79 /* Format hex dump. */
80 u8 * format_hex_bytes (u8 * s, va_list * va)
81 {
82   u8 * bytes = va_arg (*va, u8 *);
83   int n_bytes = va_arg (*va, int);
84   uword i;
85
86   /* Print short or long form depending on byte count. */
87   uword short_form = n_bytes <= 32;
88   uword indent = format_get_indent (s);
89
90   if (n_bytes == 0)
91     return s;
92
93   for (i = 0; i < n_bytes; i++)
94     {
95       if (! short_form && (i % 32) == 0)
96         s = format (s, "%08x: ", i);
97
98       s = format (s, "%02x", bytes[i]);
99
100       if (! short_form && ((i + 1) % 32) == 0 && (i + 1) < n_bytes)
101         s = format (s, "\n%U", format_white_space, indent);
102     }
103
104   return s;
105 }
106
107 /* Add variable number of spaces. */
108 u8 * format_white_space (u8 * s, va_list * va)
109 {
110   uword n = va_arg (*va, uword);
111   while (n-- > 0)
112     vec_add1 (s, ' ');
113   return s;
114 }
115
116 u8 * format_time_interval (u8 * s, va_list * args)
117 {
118   u8 * fmt = va_arg (*args, u8 *);
119   f64 t = va_arg (*args, f64);
120   u8 * f;
121
122   const f64 seconds_per_minute = 60;
123   const f64 seconds_per_hour = 60 * seconds_per_minute;
124   const f64 seconds_per_day = 24 * seconds_per_hour;
125   uword days, hours, minutes, secs, msecs, usecs;
126   
127   days = t / seconds_per_day;
128   t -= days * seconds_per_day;
129
130   hours = t / seconds_per_hour;
131   t -= hours * seconds_per_hour;
132
133   minutes = t / seconds_per_minute;
134   t -= minutes * seconds_per_minute;
135
136   secs = t;
137   t -= secs;
138
139   msecs = 1e3*t;
140   usecs = 1e6*t;
141
142   for (f = fmt; *f; f++)
143     {
144       uword what, c;
145       char * what_fmt = "%d";
146
147       switch (c = *f)
148         {
149         default:
150           vec_add1 (s, c);
151           continue;
152
153         case 'd':
154           what = days;
155           what_fmt = "%d";
156           break;
157         case 'h':
158           what = hours;
159           what_fmt = "%02d";
160           break;
161         case 'm':
162           what = minutes;
163           what_fmt = "%02d";
164           break;
165         case 's':
166           what = secs;
167           what_fmt = "%02d";
168           break;
169         case 'f':
170           what = msecs;
171           what_fmt = "%03d";
172           break;
173         case 'u':
174           what = usecs;
175           what_fmt = "%06d";
176           break;
177         }
178
179       s = format (s, what_fmt, what);
180     }
181
182   return s;
183 }
184
185 /* Unparse memory size e.g. 100, 100k, 100m, 100g. */
186 u8 * format_memory_size (u8 * s, va_list * va)
187 {
188   uword size = va_arg (*va, uword);
189   uword l, u, log_u;
190
191   l = size > 0 ? min_log2 (size) : 0;
192   if (l < 10)
193     log_u = 0;
194   else if (l < 20)
195     log_u = 10;
196   else if (l < 30)
197     log_u = 20;
198   else
199     log_u = 30;
200
201   u = (uword) 1 << log_u;
202   if (size & (u - 1))
203     s = format (s, "%.2f", (f64) size / (f64) u);
204   else
205     s = format (s, "%d", size >> log_u);
206
207   if (log_u != 0)
208     s = format (s, "%c", " kmg"[log_u / 10]);
209
210   return s;
211 }
212
213 /* Parse memory size e.g. 100, 100k, 100m, 100g. */
214 uword unformat_memory_size (unformat_input_t * input, va_list * va)
215 {
216   uword amount, shift, c;
217   uword * result = va_arg (*va, uword *);
218
219   if (! unformat (input, "%wd%_", &amount))
220     return 0;
221
222   c = unformat_get_input (input);
223   switch (c)
224     {
225     case 'k': case 'K': shift = 10; break;
226     case 'm': case 'M': shift = 20; break;
227     case 'g': case 'G': shift = 30; break;
228     default:
229       shift = 0;
230       unformat_put_input (input);
231       break;
232     }
233
234   *result = amount << shift;
235   return 1;
236 }
237
238 /* Format c identifier: e.g. a_name -> "a name".
239    Words for both vector names and null terminated c strings. */
240 u8 * format_c_identifier (u8 * s, va_list * va)
241 {
242   u8 * id = va_arg (*va, u8 *);
243   uword i, l;
244
245   l = ~0;
246   if (clib_mem_is_vec (id))
247     l = vec_len (id);
248
249   if (id)
250     for (i = 0; id[i] != 0 && i < l; i++)
251       {
252         u8 c = id[i];
253
254         if (c == '_')
255           c = ' ';
256         vec_add1 (s, c);
257       }
258
259   return s;
260 }
261
262 u8 *
263 format_hexdump (u8 * s, va_list * args)
264 {
265   u8 * data = va_arg (*args, u8 *);
266   uword len = va_arg (*args, uword);
267   int i, index =0;
268   const int line_len = 16;
269   u8 * line_hex = 0;
270   u8 * line_str = 0;
271   uword indent = format_get_indent (s);
272
273   if (!len)
274     return s;
275
276   for(i=0; i < len; i++)
277     {
278       line_hex = format (line_hex, "%02x ",  data[i]);
279       line_str = format (line_str, "%c", isprint (data[i]) ? data[i] : '.');
280       if (!( (i + 1) % line_len))
281         {
282           s = format (s, "%U%05x: %v[%v]",
283                       format_white_space, index ? indent : 0,
284                       index, line_hex, line_str);
285           if (i < len - 1)
286             s = format (s, "\n");
287           index = i + 1;
288           vec_reset_length(line_hex);
289           vec_reset_length(line_str);
290         }
291     }
292
293   while (i++ % line_len)
294     line_hex = format (line_hex, "   ");
295
296   if (vec_len(line_hex))
297     s = format (s, "%U%05x: %v[%v]",
298                 format_white_space, indent,
299                 index, line_hex, line_str);
300
301   vec_free(line_hex);
302   vec_free(line_str);
303
304   return s;
305 }