/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include #include #include #include #include #include // contains strncasecmp for msvc #include "sch_legacy_plugin_helpers.h" // Token delimiters. const char* delims = " \t\r\n"; bool is_eol( char c ) { // The default file eol character used internally by KiCad. // | // | Possible eol if someone edited the file by hand on certain platforms. // | | // | | May have gone past eol with strtok(). // | | | if( c == '\n' || c == '\r' || c == 0 ) return true; return false; } bool strCompare( const char* aString, const char* aLine, const char** aOutput ) { size_t len = strlen( aString ); bool retv = ( strncasecmp( aLine, aString, len ) == 0 ) && ( isspace( aLine[ len ] ) || aLine[ len ] == 0 ); if( retv && aOutput ) { const char* tmp = aLine; // Move past the end of the token. tmp += len; // Move to the beginning of the next token. while( *tmp && isspace( *tmp ) ) tmp++; *aOutput = tmp; } return retv; } int parseInt( LINE_READER& aReader, const char* aLine, const char** aOutput ) { if( !*aLine ) SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine ); // Clear errno before calling strtol() in case some other crt call set it. errno = 0; long retv = strtol( aLine, (char**) aOutput, 10 ); // Make sure no error occurred when calling strtol(). if( errno == ERANGE ) SCH_PARSE_ERROR( "invalid integer value", aReader, aLine ); // strtol does not strip off whitespace before the next token. if( aOutput ) { const char* next = *aOutput; while( *next && isspace( *next ) ) next++; *aOutput = next; } return (int) retv; } uint32_t parseHex( LINE_READER& aReader, const char* aLine, const char** aOutput ) { if( !*aLine ) SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine ); // Due to some issues between some files created by a 64 bits version and those // created by a 32 bits version, we use here a temporary at least 64 bits storage: unsigned long long retv; // Clear errno before calling strtoull() in case some other crt call set it. errno = 0; retv = strtoull( aLine, (char**) aOutput, 16 ); // Make sure no error occurred when calling strtoull(). if( errno == ERANGE ) SCH_PARSE_ERROR( "invalid hexadecimal number", aReader, aLine ); // Strip off whitespace before the next token. if( aOutput ) { const char* next = *aOutput; while( *next && isspace( *next ) ) next++; *aOutput = next; } return (uint32_t)retv; } double parseDouble( LINE_READER& aReader, const char* aLine, const char** aOutput ) { if( !*aLine ) SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aLine ); // Clear errno before calling strtod() in case some other crt call set it. errno = 0; double retv = strtod( aLine, (char**) aOutput ); // Make sure no error occurred when calling strtod(). if( errno == ERANGE ) SCH_PARSE_ERROR( "invalid floating point number", aReader, aLine ); // strtod does not strip off whitespace before the next token. if( aOutput ) { const char* next = *aOutput; while( *next && isspace( *next ) ) next++; *aOutput = next; } return retv; } char parseChar( LINE_READER& aReader, const char* aCurrentToken, const char** aNextToken ) { while( *aCurrentToken && isspace( *aCurrentToken ) ) aCurrentToken++; if( !*aCurrentToken ) SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken ); if( !isspace( *( aCurrentToken + 1 ) ) ) SCH_PARSE_ERROR( "expected single character token", aReader, aCurrentToken ); if( aNextToken ) { const char* next = aCurrentToken + 2; while( *next && isspace( *next ) ) next++; *aNextToken = next; } return *aCurrentToken; } void parseUnquotedString( wxString& aString, LINE_READER& aReader, const char* aCurrentToken, const char** aNextToken, bool aCanBeEmpty ) { if( !*aCurrentToken ) { if( aCanBeEmpty ) return; else SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken ); } const char* tmp = aCurrentToken; while( *tmp && isspace( *tmp ) ) tmp++; if( !*tmp ) { if( aCanBeEmpty ) return; else SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken ); } std::string utf8; while( *tmp && !isspace( *tmp ) ) utf8 += *tmp++; aString = FROM_UTF8( utf8.c_str() ); if( aString.IsEmpty() && !aCanBeEmpty ) SCH_PARSE_ERROR( _( "expected unquoted string" ), aReader, aCurrentToken ); if( aNextToken ) { const char* next = tmp; while( *next && isspace( *next ) ) next++; *aNextToken = next; } } void parseQuotedString( wxString& aString, LINE_READER& aReader, const char* aCurrentToken, const char** aNextToken, bool aCanBeEmpty ) { if( !*aCurrentToken ) { if( aCanBeEmpty ) return; else SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken ); } const char* tmp = aCurrentToken; while( *tmp && isspace( *tmp ) ) tmp++; if( !*tmp ) { if( aCanBeEmpty ) return; else SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken ); } // Verify opening quote. if( *tmp != '"' ) SCH_PARSE_ERROR( "expecting opening quote", aReader, aCurrentToken ); tmp++; std::string utf8; // utf8 without escapes and quotes. // Fetch everything up to closing quote. while( *tmp ) { if( *tmp == '\\' ) { tmp++; if( !*tmp ) SCH_PARSE_ERROR( _( "unexpected end of line" ), aReader, aCurrentToken ); // Do not copy the escape byte if it is followed by \ or " if( *tmp != '"' && *tmp != '\\' ) utf8 += '\\'; utf8 += *tmp; } else if( *tmp == '"' ) // Closing double quote. { break; } else { utf8 += *tmp; } tmp++; } aString = FROM_UTF8( utf8.c_str() ); if( aString.IsEmpty() && !aCanBeEmpty ) SCH_PARSE_ERROR( "expected quoted string", aReader, aCurrentToken ); if( *tmp && *tmp != '"' ) SCH_PARSE_ERROR( "no closing quote for string found", aReader, tmp ); // Move past the closing quote. tmp++; if( aNextToken ) { const char* next = tmp; while( *next == ' ' ) next++; *aNextToken = next; } }