Changes for nameservice. Use RPC client for NS functionality.
[barrelfish] / lib / dist2 / parser / read.c
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, Haldeneggsteig 4, 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 <dist2/getset.h>
22 #include <dist2/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  * TODO: more detailed docs!
28  *
29  * \param record Record to read.
30  * \param format What you want to read.
31  * \param ... Values read are stored in the provided arguments.
32  *
33  * \retval SYS_ERR_OK
34  * \retval DIST2_ERR_ATTRIBUTE_NOT_FOUND
35  * \retval DIST2_ERR_TYPE_MISMATCH
36  * \retval DIST2_ERR_RECORD_NAME_MISMATCH
37  * \retval DIST2_ERR_ATTRIBUTE_MISMATCH
38  */
39 errval_t dist_read(const char* record, const char* format, ...)
40 {
41         errval_t err = SYS_ERR_OK;
42         va_list args;
43         va_start(args, format);
44
45         char** s = NULL;
46         int64_t* i = NULL;
47         double* d = NULL;
48
49         // Parse record and format strings
50         struct ast_object* ast = NULL;
51         struct ast_object* format_ast = NULL;
52
53         err = generate_ast(record, &ast);
54         if(err_is_fail(err)) {
55                 goto out;
56         }
57         err = generate_ast(format, &format_ast);
58         if(err_is_fail(err)) {
59                 goto out;
60         }
61
62         // Scan Name
63         struct ast_object* format_name = format_ast->u.on.name;
64         switch(format_name->type) {
65         case nodeType_Scan:
66                 if(format_name->u.scn.c != 's') {
67                         err = DIST2_ERR_INVALID_FORMAT;
68                         goto out;
69                 }
70                 s = va_arg(args, char**);
71                 *s = ast->u.on.name->u.in.str;
72                 // Remove from AST so client has to free it
73                 ast->u.on.name->u.in.str = NULL;
74                 break;
75
76         case nodeType_Variable:
77                 // Just ignore record name
78                 break;
79
80         default:
81                 err = DIST2_ERR_INVALID_FORMAT;
82                 goto out;
83                 break;
84         }
85
86         // Scan Attributes
87         struct ast_object* attr = format_ast->u.on.attrs;
88         for(; attr != NULL; attr = attr->u.an.next) {
89
90                 struct ast_object* format_attr = attr->u.an.attr;
91
92                 // Enforced by Parser
93                 assert(format_attr->type == nodeType_Pair);
94                 assert(format_attr->u.pn.left->type == nodeType_Ident);
95                 if(format_attr->u.pn.right->type != nodeType_Scan) {
96                         err = DIST2_ERR_INVALID_FORMAT;
97                         goto out;
98                 }
99
100                 // Try to find attribute in record AST
101                 struct ast_object* record_attr = ast_find_attribute(ast,
102                         format_attr->u.pn.left->u.in.str);
103                 if(record_attr == NULL) {
104                         err = DIST2_ERR_UNKNOWN_ATTRIBUTE;
105                         goto out;
106                 }
107                 struct ast_object* value = record_attr->u.pn.right;
108
109                 switch(format_attr->u.pn.right->u.scn.c) {
110                 case 's':
111                         s = va_arg(args, char**);
112                         if(value->type == nodeType_Ident) {
113                                 *s = value->u.in.str;
114                                 value->u.in.str = NULL;
115                         }
116                         else if(value->type == nodeType_String) {
117                                 *s = value->u.sn.str;
118                                 value->u.sn.str = NULL;
119                         }
120                         else {
121                                 err = DIST2_ERR_INVALID_FORMAT;
122                                 goto out;
123                         }
124                         break;
125
126                 case 'd':
127                         i = va_arg(args, int64_t*);
128                         if(value->type == nodeType_Constant) {
129                                 *i = value->u.cn.value;
130                         }
131                         else {
132                                 *i = 0;
133                                 err = DIST2_ERR_INVALID_FORMAT;
134                                 goto out;
135                         }
136                         break;
137
138                 case 'f':
139                         d = va_arg(args, double*);
140                         if(value->type == nodeType_Float) {
141                                 *d = value->u.fn.value;
142                         }
143                         else {
144                                 *d = 0.0;
145                                 err = DIST2_ERR_INVALID_FORMAT;
146                                 goto out;
147                         }
148                         break;
149
150                 default:
151                         err = DIST2_ERR_INVALID_FORMAT;
152                         goto out;
153                         break;
154                 }
155         }
156         va_end(args);
157
158         out:
159         free_ast(ast);
160         free_ast(format_ast);
161         return err;
162 }