util.c revision 238742
1204433Sraj/*
2238742Simp * Copyright 2011 The Chromium Authors, All Rights Reserved.
3204433Sraj * Copyright 2008 Jon Loeliger, Freescale Semiconductor, Inc.
4204433Sraj *
5238742Simp * util_is_printable_string contributed by
6238742Simp *	Pantelis Antoniou <pantelis.antoniou AT gmail.com>
7238742Simp *
8204433Sraj * This program is free software; you can redistribute it and/or
9204433Sraj * modify it under the terms of the GNU General Public License as
10204433Sraj * published by the Free Software Foundation; either version 2 of the
11204433Sraj * License, or (at your option) any later version.
12204433Sraj *
13204433Sraj *  This program is distributed in the hope that it will be useful,
14204433Sraj *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15204433Sraj *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16204433Sraj *  General Public License for more details.
17204433Sraj *
18204433Sraj *  You should have received a copy of the GNU General Public License
19204433Sraj *  along with this program; if not, write to the Free Software
20204433Sraj *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
21204433Sraj *                                                                   USA
22204433Sraj */
23204433Sraj
24238742Simp#include <ctype.h>
25238742Simp#include <stdio.h>
26238742Simp#include <stdlib.h>
27238742Simp#include <stdarg.h>
28238742Simp#include <string.h>
29238742Simp#include <assert.h>
30204433Sraj
31238742Simp#include <errno.h>
32238742Simp#include <fcntl.h>
33238742Simp#include <unistd.h>
34238742Simp
35238742Simp#include "libfdt.h"
36238742Simp#include "util.h"
37238742Simp
38204433Srajchar *xstrdup(const char *s)
39204433Sraj{
40204433Sraj	int len = strlen(s) + 1;
41204433Sraj	char *dup = xmalloc(len);
42204433Sraj
43204433Sraj	memcpy(dup, s, len);
44204433Sraj
45204433Sraj	return dup;
46204433Sraj}
47238742Simp
48238742Simpchar *join_path(const char *path, const char *name)
49238742Simp{
50238742Simp	int lenp = strlen(path);
51238742Simp	int lenn = strlen(name);
52238742Simp	int len;
53238742Simp	int needslash = 1;
54238742Simp	char *str;
55238742Simp
56238742Simp	len = lenp + lenn + 2;
57238742Simp	if ((lenp > 0) && (path[lenp-1] == '/')) {
58238742Simp		needslash = 0;
59238742Simp		len--;
60238742Simp	}
61238742Simp
62238742Simp	str = xmalloc(len);
63238742Simp	memcpy(str, path, lenp);
64238742Simp	if (needslash) {
65238742Simp		str[lenp] = '/';
66238742Simp		lenp++;
67238742Simp	}
68238742Simp	memcpy(str+lenp, name, lenn+1);
69238742Simp	return str;
70238742Simp}
71238742Simp
72238742Simpint util_is_printable_string(const void *data, int len)
73238742Simp{
74238742Simp	const char *s = data;
75238742Simp	const char *ss;
76238742Simp
77238742Simp	/* zero length is not */
78238742Simp	if (len == 0)
79238742Simp		return 0;
80238742Simp
81238742Simp	/* must terminate with zero */
82238742Simp	if (s[len - 1] != '\0')
83238742Simp		return 0;
84238742Simp
85238742Simp	ss = s;
86238742Simp	while (*s && isprint(*s))
87238742Simp		s++;
88238742Simp
89238742Simp	/* not zero, or not done yet */
90238742Simp	if (*s != '\0' || (s + 1 - ss) < len)
91238742Simp		return 0;
92238742Simp
93238742Simp	return 1;
94238742Simp}
95238742Simp
96238742Simp/*
97238742Simp * Parse a octal encoded character starting at index i in string s.  The
98238742Simp * resulting character will be returned and the index i will be updated to
99238742Simp * point at the character directly after the end of the encoding, this may be
100238742Simp * the '\0' terminator of the string.
101238742Simp */
102238742Simpstatic char get_oct_char(const char *s, int *i)
103238742Simp{
104238742Simp	char x[4];
105238742Simp	char *endx;
106238742Simp	long val;
107238742Simp
108238742Simp	x[3] = '\0';
109238742Simp	strncpy(x, s + *i, 3);
110238742Simp
111238742Simp	val = strtol(x, &endx, 8);
112238742Simp
113238742Simp	assert(endx > x);
114238742Simp
115238742Simp	(*i) += endx - x;
116238742Simp	return val;
117238742Simp}
118238742Simp
119238742Simp/*
120238742Simp * Parse a hexadecimal encoded character starting at index i in string s.  The
121238742Simp * resulting character will be returned and the index i will be updated to
122238742Simp * point at the character directly after the end of the encoding, this may be
123238742Simp * the '\0' terminator of the string.
124238742Simp */
125238742Simpstatic char get_hex_char(const char *s, int *i)
126238742Simp{
127238742Simp	char x[3];
128238742Simp	char *endx;
129238742Simp	long val;
130238742Simp
131238742Simp	x[2] = '\0';
132238742Simp	strncpy(x, s + *i, 2);
133238742Simp
134238742Simp	val = strtol(x, &endx, 16);
135238742Simp	if (!(endx  > x))
136238742Simp		die("\\x used with no following hex digits\n");
137238742Simp
138238742Simp	(*i) += endx - x;
139238742Simp	return val;
140238742Simp}
141238742Simp
142238742Simpchar get_escape_char(const char *s, int *i)
143238742Simp{
144238742Simp	char	c = s[*i];
145238742Simp	int	j = *i + 1;
146238742Simp	char	val;
147238742Simp
148238742Simp	assert(c);
149238742Simp	switch (c) {
150238742Simp	case 'a':
151238742Simp		val = '\a';
152238742Simp		break;
153238742Simp	case 'b':
154238742Simp		val = '\b';
155238742Simp		break;
156238742Simp	case 't':
157238742Simp		val = '\t';
158238742Simp		break;
159238742Simp	case 'n':
160238742Simp		val = '\n';
161238742Simp		break;
162238742Simp	case 'v':
163238742Simp		val = '\v';
164238742Simp		break;
165238742Simp	case 'f':
166238742Simp		val = '\f';
167238742Simp		break;
168238742Simp	case 'r':
169238742Simp		val = '\r';
170238742Simp		break;
171238742Simp	case '0':
172238742Simp	case '1':
173238742Simp	case '2':
174238742Simp	case '3':
175238742Simp	case '4':
176238742Simp	case '5':
177238742Simp	case '6':
178238742Simp	case '7':
179238742Simp		j--; /* need to re-read the first digit as
180238742Simp		      * part of the octal value */
181238742Simp		val = get_oct_char(s, &j);
182238742Simp		break;
183238742Simp	case 'x':
184238742Simp		val = get_hex_char(s, &j);
185238742Simp		break;
186238742Simp	default:
187238742Simp		val = c;
188238742Simp	}
189238742Simp
190238742Simp	(*i) = j;
191238742Simp	return val;
192238742Simp}
193238742Simp
194238742Simpint utilfdt_read_err(const char *filename, char **buffp)
195238742Simp{
196238742Simp	int fd = 0;	/* assume stdin */
197238742Simp	char *buf = NULL;
198238742Simp	off_t bufsize = 1024, offset = 0;
199238742Simp	int ret = 0;
200238742Simp
201238742Simp	*buffp = NULL;
202238742Simp	if (strcmp(filename, "-") != 0) {
203238742Simp		fd = open(filename, O_RDONLY);
204238742Simp		if (fd < 0)
205238742Simp			return errno;
206238742Simp	}
207238742Simp
208238742Simp	/* Loop until we have read everything */
209238742Simp	buf = malloc(bufsize);
210238742Simp	do {
211238742Simp		/* Expand the buffer to hold the next chunk */
212238742Simp		if (offset == bufsize) {
213238742Simp			bufsize *= 2;
214238742Simp			buf = realloc(buf, bufsize);
215238742Simp			if (!buf) {
216238742Simp				ret = ENOMEM;
217238742Simp				break;
218238742Simp			}
219238742Simp		}
220238742Simp
221238742Simp		ret = read(fd, &buf[offset], bufsize - offset);
222238742Simp		if (ret < 0) {
223238742Simp			ret = errno;
224238742Simp			break;
225238742Simp		}
226238742Simp		offset += ret;
227238742Simp	} while (ret != 0);
228238742Simp
229238742Simp	/* Clean up, including closing stdin; return errno on error */
230238742Simp	close(fd);
231238742Simp	if (ret)
232238742Simp		free(buf);
233238742Simp	else
234238742Simp		*buffp = buf;
235238742Simp	return ret;
236238742Simp}
237238742Simp
238238742Simpchar *utilfdt_read(const char *filename)
239238742Simp{
240238742Simp	char *buff;
241238742Simp	int ret = utilfdt_read_err(filename, &buff);
242238742Simp
243238742Simp	if (ret) {
244238742Simp		fprintf(stderr, "Couldn't open blob from '%s': %s\n", filename,
245238742Simp			strerror(ret));
246238742Simp		return NULL;
247238742Simp	}
248238742Simp	/* Successful read */
249238742Simp	return buff;
250238742Simp}
251238742Simp
252238742Simpint utilfdt_write_err(const char *filename, const void *blob)
253238742Simp{
254238742Simp	int fd = 1;	/* assume stdout */
255238742Simp	int totalsize;
256238742Simp	int offset;
257238742Simp	int ret = 0;
258238742Simp	const char *ptr = blob;
259238742Simp
260238742Simp	if (strcmp(filename, "-") != 0) {
261238742Simp		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
262238742Simp		if (fd < 0)
263238742Simp			return errno;
264238742Simp	}
265238742Simp
266238742Simp	totalsize = fdt_totalsize(blob);
267238742Simp	offset = 0;
268238742Simp
269238742Simp	while (offset < totalsize) {
270238742Simp		ret = write(fd, ptr + offset, totalsize - offset);
271238742Simp		if (ret < 0) {
272238742Simp			ret = -errno;
273238742Simp			break;
274238742Simp		}
275238742Simp		offset += ret;
276238742Simp	}
277238742Simp	/* Close the file/stdin; return errno on error */
278238742Simp	if (fd != 1)
279238742Simp		close(fd);
280238742Simp	return ret < 0 ? -ret : 0;
281238742Simp}
282238742Simp
283238742Simp
284238742Simpint utilfdt_write(const char *filename, const void *blob)
285238742Simp{
286238742Simp	int ret = utilfdt_write_err(filename, blob);
287238742Simp
288238742Simp	if (ret) {
289238742Simp		fprintf(stderr, "Couldn't write blob to '%s': %s\n", filename,
290238742Simp			strerror(ret));
291238742Simp	}
292238742Simp	return ret ? -1 : 0;
293238742Simp}
294238742Simp
295238742Simpint utilfdt_decode_type(const char *fmt, int *type, int *size)
296238742Simp{
297238742Simp	int qualifier = 0;
298238742Simp
299238742Simp	if (!*fmt)
300238742Simp		return -1;
301238742Simp
302238742Simp	/* get the conversion qualifier */
303238742Simp	*size = -1;
304238742Simp	if (strchr("hlLb", *fmt)) {
305238742Simp		qualifier = *fmt++;
306238742Simp		if (qualifier == *fmt) {
307238742Simp			switch (*fmt++) {
308238742Simp/* TODO:		case 'l': qualifier = 'L'; break;*/
309238742Simp			case 'h':
310238742Simp				qualifier = 'b';
311238742Simp				break;
312238742Simp			}
313238742Simp		}
314238742Simp	}
315238742Simp
316238742Simp	/* we should now have a type */
317238742Simp	if ((*fmt == '\0') || !strchr("iuxs", *fmt))
318238742Simp		return -1;
319238742Simp
320238742Simp	/* convert qualifier (bhL) to byte size */
321238742Simp	if (*fmt != 's')
322238742Simp		*size = qualifier == 'b' ? 1 :
323238742Simp				qualifier == 'h' ? 2 :
324238742Simp				qualifier == 'l' ? 4 : -1;
325238742Simp	*type = *fmt++;
326238742Simp
327238742Simp	/* that should be it! */
328238742Simp	if (*fmt)
329238742Simp		return -1;
330238742Simp	return 0;
331238742Simp}
332