1/**
2 * \file
3 * \brief Helper functions to read record contents.
4 */
5
6/*
7 * Copyright (c) 2011, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <stdarg.h>
18
19#include <barrelfish/barrelfish.h>
20
21#include <octopus/getset.h>
22#include <octopus/parser/ast.h>
23
24/**
25 * \brief Reads the content of a record string based on the provided format.
26 * Currently supported %d (int64_t*), %f (double*?), %s (char**).
27 *
28 * ATTENTION: Currently we only parse 64-bit numbers (with %d).
29 * This function tends to behave badly when calling it with
30 * 32bit pointers (i.e., oct_read(rec, "_ {iref: 1}", (iref_t) iref);)
31 * Don't do it!
32 *
33 * \TODO: docs && support proper scan types from (inttypes.h)
34 *
35 * \param record Record to read.
36 * \param format What you want to read.
37 * \param ... Values read are stored in the provided arguments.
38 *
39 * \retval SYS_ERR_OK
40 * \retval OCT_ERR_ATTRIBUTE_NOT_FOUND
41 * \retval OCT_ERR_TYPE_MISMATCH
42 * \retval OCT_ERR_RECORD_NAME_MISMATCH
43 * \retval OCT_ERR_ATTRIBUTE_MISMATCH
44 */
45errval_t oct_read(const char* record, const char* format, ...)
46{
47	errval_t err = SYS_ERR_OK;
48	va_list args;
49	va_start(args, format);
50
51	char** s = NULL;
52	int64_t* i = NULL;
53	double* d = NULL;
54
55	// Parse record and format strings
56	struct ast_object* ast = NULL;
57	struct ast_object* format_ast = NULL;
58
59	err = generate_ast(record, &ast);
60	if(err_is_fail(err)) {
61		goto out;
62	}
63	err = generate_ast(format, &format_ast);
64	if(err_is_fail(err)) {
65		goto out;
66	}
67
68	// Scan Name
69	struct ast_object* format_name = format_ast->u.on.name;
70	switch(format_name->type) {
71	case nodeType_Scan:
72		if(format_name->u.scn.c != 's') {
73			err = OCT_ERR_INVALID_FORMAT;
74			goto out;
75		}
76		s = va_arg(args, char**);
77		*s = ast->u.on.name->u.in.str;
78		// Remove from AST so client has to free it
79		ast->u.on.name->u.in.str = NULL;
80		break;
81
82	case nodeType_Variable:
83		// Just ignore record name
84		break;
85
86	default:
87		err = OCT_ERR_INVALID_FORMAT;
88		goto out;
89		break;
90	}
91
92	// Scan Attributes
93	struct ast_object* attr = format_ast->u.on.attrs;
94	for(; attr != NULL; attr = attr->u.an.next) {
95
96		struct ast_object* format_attr = attr->u.an.attr;
97
98		// Enforced by Parser
99		assert(format_attr->type == nodeType_Pair);
100		assert(format_attr->u.pn.left->type == nodeType_Ident);
101		if(format_attr->u.pn.right->type != nodeType_Scan) {
102			err = OCT_ERR_INVALID_FORMAT;
103			goto out;
104		}
105
106		// Try to find attribute in record AST
107		struct ast_object* record_attr = ast_find_attribute(ast,
108		        format_attr->u.pn.left->u.in.str);
109		if(record_attr == NULL) {
110			err = OCT_ERR_UNKNOWN_ATTRIBUTE;
111			goto out;
112		}
113		struct ast_object* value = record_attr->u.pn.right;
114
115		switch(format_attr->u.pn.right->u.scn.c) {
116		case 's':
117			s = va_arg(args, char**);
118			if(value->type == nodeType_Ident) {
119				*s = value->u.in.str;
120				value->u.in.str = NULL;
121			}
122			else if(value->type == nodeType_String) {
123				*s = value->u.sn.str;
124				value->u.sn.str = NULL;
125			}
126			else {
127				err = OCT_ERR_INVALID_FORMAT;
128				goto out;
129			}
130			break;
131
132		case 'd':
133			i = va_arg(args, int64_t*);
134			if(value->type == nodeType_Constant) {
135				*i = value->u.cn.value;
136			}
137			else {
138				*i = 0;
139				err = OCT_ERR_INVALID_FORMAT;
140				goto out;
141			}
142			break;
143
144		case 'f':
145			d = va_arg(args, double*);
146			if(value->type == nodeType_Float) {
147				*d = value->u.fn.value;
148			}
149			else {
150				*d = 0.0;
151				err = OCT_ERR_INVALID_FORMAT;
152				goto out;
153			}
154			break;
155
156		default:
157			err = OCT_ERR_INVALID_FORMAT;
158			goto out;
159			break;
160		}
161	}
162	va_end(args);
163
164	out:
165	free_ast(ast);
166	free_ast(format_ast);
167	return err;
168}
169