1af0dd31fSDavid Chisnall /*- 2af0dd31fSDavid Chisnall * Copyright (c) 2013 David Chisnall 3af0dd31fSDavid Chisnall * All rights reserved. 4af0dd31fSDavid Chisnall * 5af0dd31fSDavid Chisnall * This software was developed by SRI International and the University of 6af0dd31fSDavid Chisnall * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7af0dd31fSDavid Chisnall * ("CTSRD"), as part of the DARPA CRASH research programme. 8af0dd31fSDavid Chisnall * 9af0dd31fSDavid Chisnall * Redistribution and use in source and binary forms, with or without 10af0dd31fSDavid Chisnall * modification, are permitted provided that the following conditions 11af0dd31fSDavid Chisnall * are met: 12af0dd31fSDavid Chisnall * 1. Redistributions of source code must retain the above copyright 13af0dd31fSDavid Chisnall * notice, this list of conditions and the following disclaimer. 14af0dd31fSDavid Chisnall * 2. Redistributions in binary form must reproduce the above copyright 15af0dd31fSDavid Chisnall * notice, this list of conditions and the following disclaimer in the 16af0dd31fSDavid Chisnall * documentation and/or other materials provided with the distribution. 17af0dd31fSDavid Chisnall * 18af0dd31fSDavid Chisnall * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19af0dd31fSDavid Chisnall * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20af0dd31fSDavid Chisnall * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21af0dd31fSDavid Chisnall * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22af0dd31fSDavid Chisnall * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23af0dd31fSDavid Chisnall * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24af0dd31fSDavid Chisnall * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25af0dd31fSDavid Chisnall * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26af0dd31fSDavid Chisnall * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27af0dd31fSDavid Chisnall * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28af0dd31fSDavid Chisnall * SUCH DAMAGE. 29af0dd31fSDavid Chisnall * 30af0dd31fSDavid Chisnall * $FreeBSD$ 31af0dd31fSDavid Chisnall */ 32af0dd31fSDavid Chisnall 33af0dd31fSDavid Chisnall #include "string.hh" 34*009f7b42SDavid Chisnall #include <ctype.h> 35*009f7b42SDavid Chisnall #include <stdio.h> 36af0dd31fSDavid Chisnall 37af0dd31fSDavid Chisnall namespace 38af0dd31fSDavid Chisnall { 39af0dd31fSDavid Chisnall /** 40af0dd31fSDavid Chisnall * The source files are ASCII, so we provide a non-locale-aware version of 41af0dd31fSDavid Chisnall * isalpha. This is a class so that it can be used with a template function 42af0dd31fSDavid Chisnall * for parsing strings. 43af0dd31fSDavid Chisnall */ 44af0dd31fSDavid Chisnall struct is_alpha 45af0dd31fSDavid Chisnall { 46af0dd31fSDavid Chisnall static inline bool check(const char c) 47af0dd31fSDavid Chisnall { 48af0dd31fSDavid Chisnall return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && 49af0dd31fSDavid Chisnall (c <= 'Z')); 50af0dd31fSDavid Chisnall } 51af0dd31fSDavid Chisnall }; 52af0dd31fSDavid Chisnall /** 53af0dd31fSDavid Chisnall * Check whether a character is in the set allowed for node names. This is a 54af0dd31fSDavid Chisnall * class so that it can be used with a template function for parsing strings. 55af0dd31fSDavid Chisnall */ 56af0dd31fSDavid Chisnall struct is_node_name_character 57af0dd31fSDavid Chisnall { 58af0dd31fSDavid Chisnall static inline bool check(const char c) 59af0dd31fSDavid Chisnall { 60af0dd31fSDavid Chisnall switch(c) 61af0dd31fSDavid Chisnall { 62af0dd31fSDavid Chisnall default: 63af0dd31fSDavid Chisnall return false; 64af0dd31fSDavid Chisnall case 'a'...'z': case 'A'...'Z': case '0'...'9': 65af0dd31fSDavid Chisnall case ',': case '.': case '+': case '-': 66af0dd31fSDavid Chisnall case '_': 67af0dd31fSDavid Chisnall return true; 68af0dd31fSDavid Chisnall } 69af0dd31fSDavid Chisnall } 70af0dd31fSDavid Chisnall }; 71af0dd31fSDavid Chisnall /** 72af0dd31fSDavid Chisnall * Check whether a character is in the set allowed for property names. This is 73af0dd31fSDavid Chisnall * a class so that it can be used with a template function for parsing strings. 74af0dd31fSDavid Chisnall */ 75af0dd31fSDavid Chisnall struct is_property_name_character 76af0dd31fSDavid Chisnall { 77af0dd31fSDavid Chisnall static inline bool check(const char c) 78af0dd31fSDavid Chisnall { 79af0dd31fSDavid Chisnall switch(c) 80af0dd31fSDavid Chisnall { 81af0dd31fSDavid Chisnall default: 82af0dd31fSDavid Chisnall return false; 83af0dd31fSDavid Chisnall case 'a'...'z': case 'A'...'Z': case '0'...'9': 84af0dd31fSDavid Chisnall case ',': case '.': case '+': case '-': 85af0dd31fSDavid Chisnall case '_': case '#': 86af0dd31fSDavid Chisnall return true; 87af0dd31fSDavid Chisnall } 88af0dd31fSDavid Chisnall } 89af0dd31fSDavid Chisnall }; 90af0dd31fSDavid Chisnall 91af0dd31fSDavid Chisnall } 92af0dd31fSDavid Chisnall 93af0dd31fSDavid Chisnall namespace dtc 94af0dd31fSDavid Chisnall { 95af0dd31fSDavid Chisnall 96af0dd31fSDavid Chisnall template<class T> string 97af0dd31fSDavid Chisnall string::parse(input_buffer &s) 98af0dd31fSDavid Chisnall { 99af0dd31fSDavid Chisnall const char *start = s; 100af0dd31fSDavid Chisnall int l=0; 101af0dd31fSDavid Chisnall while (T::check(*s)) { l++; ++s; } 102af0dd31fSDavid Chisnall return string(start, l); 103af0dd31fSDavid Chisnall } 104af0dd31fSDavid Chisnall 105af0dd31fSDavid Chisnall string::string(input_buffer &s) : start((const char*)s), length(0) 106af0dd31fSDavid Chisnall { 107af0dd31fSDavid Chisnall while(s[length] != '\0') 108af0dd31fSDavid Chisnall { 109af0dd31fSDavid Chisnall length++; 110af0dd31fSDavid Chisnall } 111af0dd31fSDavid Chisnall } 112af0dd31fSDavid Chisnall 113af0dd31fSDavid Chisnall string 114af0dd31fSDavid Chisnall string::parse_node_name(input_buffer &s) 115af0dd31fSDavid Chisnall { 116af0dd31fSDavid Chisnall return parse<is_node_name_character>(s); 117af0dd31fSDavid Chisnall } 118af0dd31fSDavid Chisnall 119af0dd31fSDavid Chisnall string 120af0dd31fSDavid Chisnall string::parse_property_name(input_buffer &s) 121af0dd31fSDavid Chisnall { 122af0dd31fSDavid Chisnall return parse<is_property_name_character>(s); 123af0dd31fSDavid Chisnall } 124af0dd31fSDavid Chisnall string 125af0dd31fSDavid Chisnall string::parse_node_or_property_name(input_buffer &s, bool &is_property) 126af0dd31fSDavid Chisnall { 127af0dd31fSDavid Chisnall if (is_property) 128af0dd31fSDavid Chisnall { 129af0dd31fSDavid Chisnall return parse_property_name(s); 130af0dd31fSDavid Chisnall } 131af0dd31fSDavid Chisnall const char *start = s; 132af0dd31fSDavid Chisnall int l=0; 133af0dd31fSDavid Chisnall while (is_node_name_character::check(*s)) 134af0dd31fSDavid Chisnall { 135af0dd31fSDavid Chisnall l++; 136af0dd31fSDavid Chisnall ++s; 137af0dd31fSDavid Chisnall } 138af0dd31fSDavid Chisnall while (is_property_name_character::check(*s)) 139af0dd31fSDavid Chisnall { 140af0dd31fSDavid Chisnall l++; 141af0dd31fSDavid Chisnall ++s; 142af0dd31fSDavid Chisnall is_property = true; 143af0dd31fSDavid Chisnall } 144af0dd31fSDavid Chisnall return string(start, l); 145af0dd31fSDavid Chisnall } 146af0dd31fSDavid Chisnall 147af0dd31fSDavid Chisnall bool 148af0dd31fSDavid Chisnall string::operator==(const string& other) const 149af0dd31fSDavid Chisnall { 150af0dd31fSDavid Chisnall return (length == other.length) && 151af0dd31fSDavid Chisnall (memcmp(start, other.start, length) == 0); 152af0dd31fSDavid Chisnall } 153af0dd31fSDavid Chisnall 154af0dd31fSDavid Chisnall bool 155af0dd31fSDavid Chisnall string::operator==(const char *other) const 156af0dd31fSDavid Chisnall { 157af0dd31fSDavid Chisnall return strncmp(other, start, length) == 0; 158af0dd31fSDavid Chisnall } 159af0dd31fSDavid Chisnall 160af0dd31fSDavid Chisnall bool 161af0dd31fSDavid Chisnall string::operator<(const string& other) const 162af0dd31fSDavid Chisnall { 163af0dd31fSDavid Chisnall if (length < other.length) { return true; } 164af0dd31fSDavid Chisnall if (length > other.length) { return false; } 165af0dd31fSDavid Chisnall return memcmp(start, other.start, length) < 0; 166af0dd31fSDavid Chisnall } 167af0dd31fSDavid Chisnall 168af0dd31fSDavid Chisnall void 169af0dd31fSDavid Chisnall string::push_to_buffer(byte_buffer &buffer, bool escapes) 170af0dd31fSDavid Chisnall { 171af0dd31fSDavid Chisnall for (int i=0 ; i<length ; ++i) 172af0dd31fSDavid Chisnall { 173af0dd31fSDavid Chisnall uint8_t c = start[i]; 174af0dd31fSDavid Chisnall if (escapes && c == '\\' && i+1 < length) 175af0dd31fSDavid Chisnall { 176af0dd31fSDavid Chisnall c = start[++i]; 177af0dd31fSDavid Chisnall switch (c) 178af0dd31fSDavid Chisnall { 179af0dd31fSDavid Chisnall // For now, we just ignore invalid escape sequences. 180af0dd31fSDavid Chisnall default: 181af0dd31fSDavid Chisnall case '"': 182af0dd31fSDavid Chisnall case '\'': 183af0dd31fSDavid Chisnall case '\\': 184af0dd31fSDavid Chisnall break; 185af0dd31fSDavid Chisnall case 'a': 186af0dd31fSDavid Chisnall c = '\a'; 187af0dd31fSDavid Chisnall break; 188af0dd31fSDavid Chisnall case 'b': 189af0dd31fSDavid Chisnall c = '\b'; 190af0dd31fSDavid Chisnall break; 191af0dd31fSDavid Chisnall case 't': 192af0dd31fSDavid Chisnall c = '\t'; 193af0dd31fSDavid Chisnall break; 194af0dd31fSDavid Chisnall case 'n': 195af0dd31fSDavid Chisnall c = '\n'; 196af0dd31fSDavid Chisnall break; 197af0dd31fSDavid Chisnall case 'v': 198af0dd31fSDavid Chisnall c = '\v'; 199af0dd31fSDavid Chisnall break; 200af0dd31fSDavid Chisnall case 'f': 201af0dd31fSDavid Chisnall c = '\f'; 202af0dd31fSDavid Chisnall break; 203af0dd31fSDavid Chisnall case 'r': 204af0dd31fSDavid Chisnall c = '\r'; 205af0dd31fSDavid Chisnall break; 206af0dd31fSDavid Chisnall case '0'...'7': 207af0dd31fSDavid Chisnall { 208af0dd31fSDavid Chisnall int v = digittoint(c); 209af0dd31fSDavid Chisnall if (i+1 < length && start[i+1] <= '7' && start[i+1] >= '0') 210af0dd31fSDavid Chisnall { 211af0dd31fSDavid Chisnall v <<= 3; 212af0dd31fSDavid Chisnall v |= digittoint(start[i+1]); 213af0dd31fSDavid Chisnall i++; 214af0dd31fSDavid Chisnall if (i+1 < length && start[i+1] <= '7' && start[i+1] >= '0') 215af0dd31fSDavid Chisnall { 216af0dd31fSDavid Chisnall v <<= 3; 217af0dd31fSDavid Chisnall v |= digittoint(start[i+1]); 218af0dd31fSDavid Chisnall } 219af0dd31fSDavid Chisnall } 220af0dd31fSDavid Chisnall c = (uint8_t)v; 221af0dd31fSDavid Chisnall break; 222af0dd31fSDavid Chisnall } 223af0dd31fSDavid Chisnall case 'x': 224af0dd31fSDavid Chisnall { 225af0dd31fSDavid Chisnall ++i; 226af0dd31fSDavid Chisnall if (i >= length) 227af0dd31fSDavid Chisnall { 228af0dd31fSDavid Chisnall break; 229af0dd31fSDavid Chisnall } 230af0dd31fSDavid Chisnall int v = digittoint(start[i]); 231af0dd31fSDavid Chisnall if (i+1 < length && ishexdigit(start[i+1])) 232af0dd31fSDavid Chisnall { 233af0dd31fSDavid Chisnall v <<= 4; 234af0dd31fSDavid Chisnall v |= digittoint(start[++i]); 235af0dd31fSDavid Chisnall } 236af0dd31fSDavid Chisnall c = (uint8_t)v; 237af0dd31fSDavid Chisnall break; 238af0dd31fSDavid Chisnall } 239af0dd31fSDavid Chisnall } 240af0dd31fSDavid Chisnall } 241af0dd31fSDavid Chisnall buffer.push_back(c); 242af0dd31fSDavid Chisnall } 243af0dd31fSDavid Chisnall } 244af0dd31fSDavid Chisnall 245af0dd31fSDavid Chisnall void 246af0dd31fSDavid Chisnall string::print(FILE *file) 247af0dd31fSDavid Chisnall { 248af0dd31fSDavid Chisnall fwrite(start, length, 1, file); 249af0dd31fSDavid Chisnall } 250af0dd31fSDavid Chisnall 251af0dd31fSDavid Chisnall void 252af0dd31fSDavid Chisnall string::dump() 253af0dd31fSDavid Chisnall { 254af0dd31fSDavid Chisnall print(stderr); 255af0dd31fSDavid Chisnall } 256af0dd31fSDavid Chisnall 257af0dd31fSDavid Chisnall } // namespace dtc 258af0dd31fSDavid Chisnall 259