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