Initialize all vcores in SCP mode
[akaros.git] / user / parlib / printf-ext.c
1 /* Copyright (c) 2013-14 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Common printf format extensions.  For now, %r is installed by default
6  * (in early init code), and the others need to be requested.
7  *
8  * To register, for example %i for ipaddr, call:
9  *              register_printf_specifier('i', printf_ipaddr, printf_ipaddr_info);
10  *
11  * __printf_ipaddr, printf_ipmask, and printf_ethaddr adapted from Inferno's
12  * eipconvtest.c.  Their copyright:
13  *
14  * Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
15  * Portions Copyright © 1997-1999 Vita Nuova Limited
16  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
17  *                                (www.vitanuova.com)
18  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining a copy
21  * of this software and associated documentation files (the "Software"), to deal
22  * in the Software without restriction, including without limitation the rights
23  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24  * copies of the Software, and to permit persons to whom the Software is
25  * furnished to do so, subject to the following conditions:
26  *
27  * The above copyright notice and this permission notice shall be included in
28  * all copies or substantial portions of the Software.
29  *
30  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
33  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36  * SOFTWARE. */
37
38 #include <parlib/printf-ext.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <errno.h>
42
43 static bool is_ipv4(uint8_t *ipaddr)
44 {
45         uint8_t v4prefix[] = {
46                 0, 0, 0, 0,
47                 0, 0, 0, 0,
48                 0, 0, 0xff, 0xff
49         };
50         return memcmp(ipaddr, v4prefix, sizeof(v4prefix)) == 0;
51 }
52
53 /* Helper, prints a formatted ipaddr to stream. */
54 static int __printf_ipaddr(FILE *stream, uint8_t *ipaddr)
55 {
56         int i, j, eln, eli;
57         int ret = 0;
58         uint16_t s;
59
60         if (is_ipv4(ipaddr))
61                 return fprintf(stream, "%d.%d.%d.%d", ipaddr[12], ipaddr[13],
62                                ipaddr[14], ipaddr[15]);
63         /* find longest elision */
64         eln = eli = -1;
65         for (i = 0; i < 16; i += 2) {
66                 for (j = i; j < 16; j += 2)
67                         if (ipaddr[j] != 0 || ipaddr[j + 1] != 0)
68                                 break;
69                 if (j > i && j - i > eln) {
70                         eli = i;
71                         eln = j - i;
72                 }
73         }
74         /* print with possible elision */
75         for (i = 0; i < 16; i += 2) {
76                 if (i == eli) {
77                         ret += fprintf(stream, "::");
78                         i += eln;
79                         if (i >= 16)
80                                 break;
81                 } else if (i != 0)
82                         ret += fprintf(stream, ":");
83                 s = (ipaddr[i] << 8) + ipaddr[i + 1];
84                 ret += fprintf(stream, "%x", s);
85         }
86         return ret;
87 }
88
89 int printf_ipaddr(FILE *stream, const struct printf_info *info,
90                   const void *const *args)
91 {
92         /* args is an array of pointers, each of which points to an arg.
93          * to extract: TYPE x = *(TYPE*)args[n]. */
94         uint8_t *ipaddr = *(uint8_t**)args[0];
95         return __printf_ipaddr(stream, ipaddr);
96 }
97
98 int printf_ipaddr_info(const struct printf_info* info, size_t n, int *argtypes,
99                        int *size)
100 {
101         /* seems like this is how many va_args we will use, and how big each was
102          * we're supposed to fill up to n, i think.  we're only doing one */
103         if (n > 0) {
104                 argtypes[0] = PA_POINTER;
105                 size[0] = sizeof(uint8_t*);
106         }
107         /* returns the nr of args required by the format string, no matter what */
108         return 1;
109 }
110
111 int printf_ipmask(FILE *stream, const struct printf_info *info,
112                   const void *const *args)
113 {
114         enum {
115                 Isprefix = 16,
116         };
117         static uint8_t prefixvals[256] = {
118                 [0x00] 0 | Isprefix,
119                 [0x80] 1 | Isprefix,
120                 [0xC0] 2 | Isprefix,
121                 [0xE0] 3 | Isprefix,
122                 [0xF0] 4 | Isprefix,
123                 [0xF8] 5 | Isprefix,
124                 [0xFC] 6 | Isprefix,
125                 [0xFE] 7 | Isprefix,
126                 [0xFF] 8 | Isprefix,
127         };
128
129         uint8_t *ipmask = *(uint8_t**)args[0];
130         int i, j, n;
131         /* look for a prefix mask */
132         for (i = 0; i < 16; i++)
133                 if (ipmask[i] != 0xff)
134                         break;
135         if (i < 16) {
136                 if ((prefixvals[ipmask[i]] & Isprefix) == 0)
137                         return __printf_ipaddr(stream, ipmask);
138                 for (j = i + 1; j < 16; j++)
139                         if (ipmask[j] != 0)
140                                 return __printf_ipaddr(stream, ipmask);
141                 n = 8 * i + (prefixvals[ipmask[i]] & ~Isprefix);
142         } else
143                 n = 8 * 16;
144         /* got one, use /xx format */
145         return fprintf(stream, "/%d", n);
146 }
147
148 int printf_ipmask_info(const struct printf_info* info, size_t n, int *argtypes,
149                        int *size)
150 {
151         if (n > 0) {
152                 argtypes[0] = PA_POINTER;
153                 size[0] = sizeof(uint8_t*);
154         }
155         return 1;
156 }
157
158 int printf_ethaddr(FILE *stream, const struct printf_info *info,
159                    const void *const *args)
160 {
161         uint8_t *e = *(uint8_t**)args[0];
162         if (!e)
163                 e = "\0\0\0\0\0\0";
164         return fprintf(stream, "%02x:%02x:%02x:%02x:%02x:%02x", e[0], e[1], e[2],
165                        e[3], e[4], e[5]);
166 }
167
168 int printf_ethaddr_info(const struct printf_info* info, size_t n, int *argtypes,
169                         int *size)
170 {
171         if (n > 0) {
172                 argtypes[0] = PA_POINTER;
173                 size[0] = sizeof(uint8_t*);
174         }
175         return 1;
176 }
177
178 int printf_errstr(FILE *stream, const struct printf_info *info,
179                   const void *const *args)
180 {
181         return fprintf(stream, "%s", errstr());
182 }
183
184 int printf_errstr_info(const struct printf_info* info, size_t n, int *argtypes,
185                        int *size)
186 {
187         /* errstr consumes no arguments */
188         return 0;
189 }