@ -81,6 +81,10 @@ const char* const kUpperSegmentsList[] = {"url", "http", "https"};
hash_set < string > kUpperSegments =
MakeWordsMap ( kUpperSegmentsList , GOOGLE_ARRAYSIZE ( kUpperSegmentsList ) ) ;
bool ascii_isnewline ( char c ) {
return c = = ' \n ' | | c = = ' \r ' ;
}
// Internal helper for name handing.
// Do not expose this outside of helpers, stick to having functions for specific
// cases (ClassName(), FieldName()), so there is always consistent suffix rules.
@ -272,6 +276,16 @@ string StripProto(const string& filename) {
}
}
void StringPieceTrimWhitespace ( StringPiece * input ) {
while ( ! input - > empty ( ) & & ascii_isspace ( * input - > data ( ) ) ) {
input - > remove_prefix ( 1 ) ;
}
while ( ! input - > empty ( ) & & ascii_isspace ( ( * input ) [ input - > length ( ) - 1 ] ) ) {
input - > remove_suffix ( 1 ) ;
}
}
bool IsRetainedName ( const string & name ) {
// List of prefixes from
// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html
@ -871,65 +885,6 @@ bool IsProtobufLibraryBundledProtoFile(const FileDescriptor* file) {
return false ;
}
namespace {
// Internal helper class that parses the expected package to prefix mappings
// file.
class Parser {
public :
Parser ( map < string , string > * inout_package_to_prefix_map )
: prefix_map_ ( inout_package_to_prefix_map ) , line_ ( 0 ) { }
// Parses a check of input, returning success/failure.
bool ParseChunk ( StringPiece chunk ) ;
// Should be called to finish parsing (after all input has been provided via
// ParseChunk()). Returns success/failure.
bool Finish ( ) ;
int last_line ( ) const { return line_ ; }
string error_str ( ) const { return error_str_ ; }
private :
bool ParseLoop ( ) ;
map < string , string > * prefix_map_ ;
int line_ ;
string error_str_ ;
StringPiece p_ ;
string leftover_ ;
} ;
bool Parser : : ParseChunk ( StringPiece chunk ) {
if ( ! leftover_ . empty ( ) ) {
chunk . AppendToString ( & leftover_ ) ;
p_ = StringPiece ( leftover_ ) ;
} else {
p_ = chunk ;
}
bool result = ParseLoop ( ) ;
if ( p_ . empty ( ) ) {
leftover_ . clear ( ) ;
} else {
leftover_ = p_ . ToString ( ) ;
}
return result ;
}
bool Parser : : Finish ( ) {
if ( leftover_ . empty ( ) ) {
return true ;
}
// Force a newline onto the end to finish parsing.
p_ = StringPiece ( leftover_ + " \n " ) ;
if ( ! ParseLoop ( ) ) {
return false ;
}
return p_ . empty ( ) ; // Everything used?
}
static bool ascii_isnewline ( char c ) { return c = = ' \n ' | | c = = ' \r ' ; }
bool ReadLine ( StringPiece * input , StringPiece * line ) {
for ( int len = 0 ; len < input - > size ( ) ; + + len ) {
if ( ascii_isnewline ( ( * input ) [ len ] ) ) {
@ -942,15 +897,6 @@ bool ReadLine(StringPiece* input, StringPiece* line) {
return false ; // Ran out of input with no newline.
}
void TrimWhitespace ( StringPiece * input ) {
while ( ! input - > empty ( ) & & ascii_isspace ( * input - > data ( ) ) ) {
input - > remove_prefix ( 1 ) ;
}
while ( ! input - > empty ( ) & & ascii_isspace ( ( * input ) [ input - > length ( ) - 1 ] ) ) {
input - > remove_suffix ( 1 ) ;
}
}
void RemoveComment ( StringPiece * input ) {
int offset = input - > find ( ' # ' ) ;
if ( offset ! = StringPiece : : npos ) {
@ -958,29 +904,35 @@ void RemoveComment(StringPiece* input) {
}
}
bool Parser : : ParseLoop ( ) {
StringPiece line ;
while ( ReadLine ( & p_ , & line ) ) {
+ + line_ ;
RemoveComment ( & line ) ;
TrimWhitespace ( & line ) ;
if ( line . size ( ) = = 0 ) {
continue ; // Blank line.
}
int offset = line . find ( ' = ' ) ;
if ( offset = = StringPiece : : npos ) {
error_str_ =
string ( " Line without equal sign: ' " ) + line . ToString ( ) + " '. " ;
return false ;
}
StringPiece package ( line , 0 , offset ) ;
StringPiece prefix ( line , offset + 1 , line . length ( ) - offset - 1 ) ;
TrimWhitespace ( & package ) ;
TrimWhitespace ( & prefix ) ;
// Don't really worry about error checking the package/prefix for
// being valid. Assume the file is validated when it is created/edited.
( * prefix_map_ ) [ package . ToString ( ) ] = prefix . ToString ( ) ;
namespace {
class ExpectedPrefixesCollector : public LineConsumer {
public :
ExpectedPrefixesCollector ( map < string , string > * inout_package_to_prefix_map )
: prefix_map_ ( inout_package_to_prefix_map ) { }
virtual bool ConsumeLine ( const StringPiece & line , string * out_error ) ;
private :
map < string , string > * prefix_map_ ;
} ;
bool ExpectedPrefixesCollector : : ConsumeLine (
const StringPiece & line , string * out_error ) {
int offset = line . find ( ' = ' ) ;
if ( offset = = StringPiece : : npos ) {
* out_error =
string ( " Expected prefixes file line without equal sign: ' " ) +
line . ToString ( ) + " '. " ;
return false ;
}
StringPiece package ( line , 0 , offset ) ;
StringPiece prefix ( line , offset + 1 , line . length ( ) - offset - 1 ) ;
StringPieceTrimWhitespace ( & package ) ;
StringPieceTrimWhitespace ( & prefix ) ;
// Don't really worry about error checking the package/prefix for
// being valid. Assume the file is validated when it is created/edited.
( * prefix_map_ ) [ package . ToString ( ) ] = prefix . ToString ( ) ;
return true ;
}
@ -991,36 +943,9 @@ bool LoadExpectedPackagePrefixes(const Options &generation_options,
return true ;
}
int fd ;
do {
fd = open ( generation_options . expected_prefixes_path . c_str ( ) , O_RDONLY ) ;
} while ( fd < 0 & & errno = = EINTR ) ;
if ( fd < 0 ) {
* out_error =
string ( " error: Unable to open \" " ) +
generation_options . expected_prefixes_path +
" \" , " + strerror ( errno ) ;
return false ;
}
io : : FileInputStream file_stream ( fd ) ;
file_stream . SetCloseOnDelete ( true ) ;
Parser parser ( prefix_map ) ;
const void * buf ;
int buf_len ;
while ( file_stream . Next ( & buf , & buf_len ) ) {
if ( buf_len = = 0 ) {
continue ;
}
if ( ! parser . ParseChunk ( StringPiece ( static_cast < const char * > ( buf ) , buf_len ) ) ) {
* out_error =
string ( " error: " ) + generation_options . expected_prefixes_path +
" Line " + SimpleItoa ( parser . last_line ( ) ) + " , " + parser . error_str ( ) ;
return false ;
}
}
return parser . Finish ( ) ;
ExpectedPrefixesCollector collector ( prefix_map ) ;
return ParseSimpleFile (
generation_options . expected_prefixes_path , & collector , out_error ) ;
}
} // namespace
@ -1121,6 +1046,10 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file,
return true ;
}
TextFormatDecodeData : : TextFormatDecodeData ( ) { }
TextFormatDecodeData : : ~ TextFormatDecodeData ( ) { }
void TextFormatDecodeData : : AddString ( int32 key ,
const string & input_for_decode ,
const string & desired_output ) {
@ -1329,6 +1258,116 @@ string TextFormatDecodeData::DecodeDataForString(const string& input_for_decode,
return builder . Finish ( ) + ( char ) ' \0 ' ;
}
namespace {
class Parser {
public :
Parser ( LineConsumer * line_consumer )
: line_consumer_ ( line_consumer ) , line_ ( 0 ) { }
// Parses a check of input, returning success/failure.
bool ParseChunk ( StringPiece chunk ) ;
// Should be called to finish parsing (after all input has been provided via
// ParseChunk()). Returns success/failure.
bool Finish ( ) ;
int last_line ( ) const { return line_ ; }
string error_str ( ) const { return error_str_ ; }
private :
bool ParseLoop ( ) ;
LineConsumer * line_consumer_ ;
int line_ ;
string error_str_ ;
StringPiece p_ ;
string leftover_ ;
} ;
bool Parser : : ParseChunk ( StringPiece chunk ) {
if ( ! leftover_ . empty ( ) ) {
chunk . AppendToString ( & leftover_ ) ;
p_ = StringPiece ( leftover_ ) ;
} else {
p_ = chunk ;
}
bool result = ParseLoop ( ) ;
if ( p_ . empty ( ) ) {
leftover_ . clear ( ) ;
} else {
leftover_ = p_ . ToString ( ) ;
}
return result ;
}
bool Parser : : Finish ( ) {
if ( leftover_ . empty ( ) ) {
return true ;
}
// Force a newline onto the end to finish parsing.
p_ = StringPiece ( leftover_ + " \n " ) ;
if ( ! ParseLoop ( ) ) {
return false ;
}
return p_ . empty ( ) ; // Everything used?
}
bool Parser : : ParseLoop ( ) {
StringPiece line ;
while ( ReadLine ( & p_ , & line ) ) {
+ + line_ ;
RemoveComment ( & line ) ;
StringPieceTrimWhitespace ( & line ) ;
if ( line . size ( ) = = 0 ) {
continue ; // Blank line.
}
if ( ! line_consumer_ - > ConsumeLine ( line , & error_str_ ) ) {
return false ;
}
}
return true ;
}
} // namespace
LineConsumer : : LineConsumer ( ) { }
LineConsumer : : ~ LineConsumer ( ) { }
bool ParseSimpleFile (
const string & path , LineConsumer * line_consumer , string * out_error ) {
int fd ;
do {
fd = open ( path . c_str ( ) , O_RDONLY ) ;
} while ( fd < 0 & & errno = = EINTR ) ;
if ( fd < 0 ) {
* out_error =
string ( " error: Unable to open \" " ) + path + " \" , " + strerror ( errno ) ;
return false ;
}
io : : FileInputStream file_stream ( fd ) ;
file_stream . SetCloseOnDelete ( true ) ;
Parser parser ( line_consumer ) ;
const void * buf ;
int buf_len ;
while ( file_stream . Next ( & buf , & buf_len ) ) {
if ( buf_len = = 0 ) {
continue ;
}
if ( ! parser . ParseChunk ( StringPiece ( static_cast < const char * > ( buf ) , buf_len ) ) ) {
* out_error =
string ( " error: " ) + path +
" Line " + SimpleItoa ( parser . last_line ( ) ) + " , " + parser . error_str ( ) ;
return false ;
}
}
return parser . Finish ( ) ;
}
} // namespace objectivec
} // namespace compiler
} // namespace protobuf