Fix encoding issues for anyone using a somewhat modern Ruby (1.9 or greater)

This commit is contained in:
Mark VanderVoord
2014-02-28 10:58:57 -05:00
parent 5547caf0ee
commit 26b3f6ef65
4 changed files with 44 additions and 37 deletions
+3
View File
@@ -13,6 +13,9 @@
"cmock_generator_utils",
"cmock_unityhelper_parser"].each {|req| require "#{File.expand_path(File.dirname(__FILE__))}/#{req}"}
$QUICK_RUBY_VERSION = RUBY_VERSION.split('.').inject(0){|vv,v| vv * 100 + v.to_i }
class CMock
def initialize(options=nil)
+1 -1
View File
@@ -30,7 +30,7 @@ class CMockConfig
:includes_h_pre_orig_header => nil,
:includes_h_post_orig_header => nil,
:includes_c_pre_header => nil,
:includes_c_post_header => nil
:includes_c_post_header => nil,
}
def initialize(options=nil)
+39 -36
View File
@@ -2,12 +2,12 @@
# CMock Project - Automatic Mock Generation for C
# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
# [Released under MIT License. Please refer to license.txt for details]
# ==========================================
# ==========================================
class CMockHeaderParser
attr_accessor :funcs, :c_attributes, :treat_as_void, :treat_externs
def initialize(cfg)
@funcs = []
@c_strippables = cfg.strippables
@@ -22,31 +22,34 @@ class CMockHeaderParser
@treat_externs = cfg.treat_externs
@c_strippables += ['extern'] if (@treat_externs == :include) #we'll need to remove the attribute if we're allowing externs
end
def parse(name, source)
@module_name = name.gsub(/\W/,'')
@typedefs = []
@funcs = []
function_names = []
parse_functions( import_source(source) ).map do |decl|
parse_functions( import_source(source) ).map do |decl|
func = parse_declaration(decl)
unless (function_names.include? func[:name])
@funcs << func
function_names << func[:name]
end
end
{ :includes => nil,
:functions => @funcs,
:typedefs => @typedefs
}
end
private if $ThisIsOnlyATest.nil? ################
def import_source(source)
# let's clean up the encoding in case they've done anything weird with the characters we might find
source = source.force_encoding("ISO-8859-1").encode("utf-8", replace: nil) if ($QUICK_RUBY_VERSION > 10900)
# void must be void for cmock _ExpectAndReturn calls to process properly, not some weird typedef which equates to void
# to a certain extent, this action assumes we're chewing on pre-processed header files, otherwise we'll most likely just get stuff from @treat_as_void
@local_as_void = @treat_as_void
@@ -54,25 +57,25 @@ class CMockHeaderParser
if void_types
@local_as_void += void_types.flatten.uniq.compact
end
# smush multiline macros into single line (checking for continuation character at end of line '\')
source.gsub!(/\s*\\\s*/m, ' ')
#remove comments (block and line, in three steps to ensure correct precedence)
source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
source.gsub!(/\/\*.*?\*\//m, '') # remove block comments
source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain)
# remove assembler pragma sections
source.gsub!(/^\s*#\s*pragma\s+asm\s+.*?#\s*pragma\s+endasm/m, '')
# remove gcc's __attribute__ tags
source.gsub(/__attrbute__\s*\(\(\.*\)\)/, '')
# remove preprocessor statements and extern "C"
# remove preprocessor statements and extern "C"
source.gsub!(/^\s*#.*/, '')
source.gsub!(/extern\s+\"C\"\s+\{/, '')
# enums, unions, structs, and typedefs can all contain things (e.g. function pointers) that parse like function prototypes, so yank them
# forward declared structs are removed before struct definitions so they don't mess up real thing later. we leave structs keywords in function prototypes
source.gsub!(/^[\w\s]*struct[^;\{\}\(\)]+;/m, '') # remove forward declared structs
@@ -81,21 +84,21 @@ class CMockHeaderParser
source.gsub!(/\s*=\s*['"a-zA-Z0-9_\.]+\s*/, '') # remove default value statements from argument lists
source.gsub!(/^(?:[\w\s]*\W)?typedef\W[^;]*/m, '') # remove typedef statements
source.gsub!(/(^|\W+)(?:#{@c_strippables.join('|')})(?=$|\W+)/,'\1') unless @c_strippables.empty? # remove known attributes slated to be stripped
#scan for functions which return function pointers, because they are a pain
source.gsub!(/([\w\s\*]+)\(*\(\s*\*([\w\s\*]+)\s*\(([\w\s\*,]*)\)\)\s*\(([\w\s\*,]*)\)\)*/) do |m|
functype = "cmock_#{@module_name}_func_ptr#{@typedefs.size + 1}"
@typedefs << "typedef #{$1.strip}(*#{functype})(#{$4});"
"#{functype} #{$2.strip}(#{$3});"
end
#drop extra white space to make the rest go faster
source.gsub!(/^\s+/, '') # remove extra white space from beginning of line
source.gsub!(/\s+$/, '') # remove extra white space from end of line
source.gsub!(/\s*\(\s*/, '(') # remove extra white space from before left parens
source.gsub!(/\s*\)\s*/, ')') # remove extra white space from before right parens
source.gsub!(/\s+/, ' ') # remove remaining extra white space
#split lines on semicolons and remove things that are obviously not what we are looking for
src_lines = source.split(/\s*;\s*/)
src_lines.delete_if {|line| line.strip.length == 0} # remove blank lines
@@ -113,23 +116,23 @@ class CMockHeaderParser
if funcs.empty?
case @when_no_prototypes
when :error
raise "ERROR: No function prototypes found!"
raise "ERROR: No function prototypes found!"
when :warn
puts "WARNING: No function prototypes found!" unless (@verbosity < 1)
end
end
return funcs
end
def parse_args(arg_list)
args = []
arg_list.split(',').each do |arg|
arg.strip!
arg.strip!
return args if (arg =~ /^\s*((\.\.\.)|(void))\s*$/) # we're done if we reach void by itself or ...
arg_array = arg.split
arg_elements = arg_array - @c_attributes # split up words and remove known attributes
args << { :type => (arg_type =arg_elements[0..-2].join(' ')),
:name => arg_elements[-1],
args << { :type => (arg_type =arg_elements[0..-2].join(' ')),
:name => arg_elements[-1],
:ptr? => divine_ptr(arg_type),
:const? => arg_array.include?('const')
}
@@ -151,7 +154,7 @@ class CMockHeaderParser
arg_list.gsub!(/(\w+)(?:\s*\[[\s\d\w+-]*\])+/,'*\1') # magically turn brackets into asterisks
arg_list.gsub!(/\s+\*/,'*') # remove space to place asterisks with type (where they belong)
arg_list.gsub!(/\*(\w)/,'* \1') # pull asterisks away from arg to place asterisks with type (where they belong)
#scan argument list for function pointers and replace them with custom types
arg_list.gsub!(/([\w\s\*]+)\(+\s*\*[\*\s]*([\w\s]*)\s*\)+\s*\(((?:[\w\s\*]*,?)*)\s*\)*/) do |m|
@@ -168,25 +171,25 @@ class CMockHeaderParser
funcname = "cmock_arg#{c+=1}" if (funcname.empty?)
"#{functype} #{funconst}#{funcname}"
end
#automatically name unnamed arguments (those that only had a type)
arg_list.split(/\s*,\s*/).map { |arg|
arg_list.split(/\s*,\s*/).map { |arg|
parts = (arg.split - ['struct', 'union', 'enum', 'const', 'const*'])
if ((parts.size < 2) or (parts[-1][-1].chr == '*') or (@standards.include?(parts[-1])))
"#{arg} cmock_arg#{c+=1}"
"#{arg} cmock_arg#{c+=1}"
else
arg
end
}.join(', ')
end
end
def parse_declaration(declaration)
decl = {}
regex_match = @declaration_parse_matcher.match(declaration)
raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil?
raise "Failed parsing function declaration: '#{declaration}'" if regex_match.nil?
#grab argument list
args = regex_match[2].strip
@@ -214,17 +217,17 @@ class CMockHeaderParser
decl[:modifier] = decl[:modifier].join(' ')
rettype = rettype.join(' ')
rettype = 'void' if (@local_as_void.include?(rettype.strip))
decl[:return] = { :type => rettype,
:name => 'cmock_to_return',
decl[:return] = { :type => rettype,
:name => 'cmock_to_return',
:ptr? => divine_ptr(rettype),
:const? => rettype.split(/\s/).include?('const'),
:str => "#{rettype} cmock_to_return",
:void? => (rettype == 'void')
}
#remove default argument statements from mock definitions
args.gsub!(/=\s*[a-zA-Z0-9_\.]+\s*/, ' ')
#check for var args
if (args =~ /\.\.\./)
decl[:var_arg] = args.match( /[\w\s]*\.\.\./ ).to_s.strip
@@ -241,7 +244,7 @@ class CMockHeaderParser
decl[:args] = parse_args(args)
decl[:args_call] = decl[:args].map{|a| a[:name]}.join(', ')
decl[:contains_ptr?] = decl[:args].inject(false) {|ptr, arg| arg[:ptr?] ? true : ptr }
if (decl[:return][:type].nil? or decl[:name].nil? or decl[:args].nil? or
decl[:return][:type].empty? or decl[:name].empty?)
raise "Failed Parsing Declaration Prototype!\n" +
+1
View File
@@ -5,6 +5,7 @@
# ==========================================
$ThisIsOnlyATest = true
$QUICK_RUBY_VERSION = RUBY_VERSION.split('.').inject(0){|vv,v| vv * 100 + v.to_i }
require File.expand_path(File.dirname(__FILE__)) + "/../test_helper"
require 'cmock_header_parser'