PageRenderTime 54ms CodeModel.GetById 32ms app.highlight 14ms RepoModel.GetById 2ms app.codeStats 0ms

/Anton.Dobrov/Perl/practice/ParseINI/ParseINI.pm

http://usu-wtf.googlecode.com/
Perl | 167 lines | 155 code | 9 blank | 3 comment | 22 complexity | 00d8d61d4a6d859056194ada975a728c MD5 | raw file
  1package ParseINI;
  2
  3=machine info
  4
  5Input:
  6[ - symbol '['
  7] - symbol ']'
  8= - symbol '='
  9_ - symbol '_'
 10# - symbol '#' or ';'
 11$ - the end of the line (/\r?\n/)
 12. - any symbol (except $)
 13\ - escape symbol
 14l - some letter
 15d - some digit
 16w - some whitespace (/\t /)
 17
 18States:
 1900 - initial state
 2010 - reading Section's name (first symbol)
 2111 - reading Section's name
 2212 - reading Section's name (end)
 2313 - writing Section's name
 2420 - reading Key's name (first symbol)
 2521 - reading Key's name
 2622 - reading Key's name (end)
 2723 - writing Key's name
 2830 - reading Value
 2931 - escape symbol while reading Value
 3032 - reading Value (end)
 3133 - writing Value
 3240 - ignore input (inside Section)
 3341 - ignore input (outside Section)
 3442 - ignore input (inside Section, already read at least one Value)
 3550 - error
 36
 37Terminating states:
 3800 32 33 41 42
 39
 40=cut
 41
 42my %switchTo =
 43(
 44	'00#' => 41,
 45	'41$' => '00',
 46	'00[' => 10,
 47	'00$' => '00',
 48	'00.' => '00',
 49	'10l' => 11,
 50	'10w' => 10,
 51	'11l' => 11,
 52	'11d' => 11,
 53	'11_' => 11,
 54	'11w' => 12,
 55	'11]' => 13,
 56	'12w' => 12,
 57	'12]' => 13,
 58	'13$' => 20,
 59	'20#' => 40,
 60	'40$' => 20,
 61	'20$' => 20,
 62	'20l' => 21,
 63	'20w' => 20,
 64	'21l' => 21,
 65	'21d' => 21,
 66	'21_' => 21,
 67	'21w' => 22,
 68	'21=' => 23,
 69	'22=' => 23,
 70	'23w' => 23,
 71	'23\\' => 31,
 72	'23.' => 30,
 73	'30.' => 30,
 74	'30\\' => 31,
 75	'31w' => 30,
 76	'31\\' => 30,
 77	'31#' => 30,
 78	'30$' => 33,
 79	'30w' => 32,
 80	'32w' => 32,
 81	'32$' => 33,
 82	'32#' => 42,
 83	'33$' => 33,
 84	'33#' => 42,
 85	'33w' => 33,
 86	'42$' => 33,
 87	'33l' => 21,
 88	'33[' => 10,
 89	'40.' => 40,
 90	'40w' => 40,
 91	'40\\' => 40,
 92	'41.' => 41,
 93	'41w' => 41,
 94	'41\\' => 41,
 95	'42.' => 42,
 96	'42w' => 42,
 97	'42\\' => 42
 98);
 99
100my %shouldAccumulate = ('10', '', '11', '', '20', '', '21', '', '30', '');
101my %shouldWrite = ('13', '', '23', '', '33', '');
102my %ini;
103my ($currentSection, $currentKey, $accumulator, $state) = ('', '', '', '00');
104my %termStates = ('00', '', '32', '', '33', '', '41', '', '42', '');
105
106sub parseINI
107{
108	my $fileName = shift;
109	local *INIFILE;
110	return "Sorry, bad symbol in input file's name: '$1'" if $fileName =~ /(["\/\\|<>*?`\0]|(?:\\0))/;
111	open INIFILE, "<", $fileName or return "Input file ('$fileName') opening error: $!";
112	my @result;
113	while (! eof INIFILE)
114	{
115		my $c = getc INIFILE;
116		@result = switchMachine($c);
117		return "Error: syntax error in '$fileName' file" if $result[0] eq '50';
118	}
119	close INIFILE;
120	# return "error(2): some machine error" unless exists $termStates{$result[0]};
121	my %result = %ini;
122	return \%result;
123}
124
125sub switchMachine
126{
127	my $char = shift;
128	my $input;  # [ ] = _ # $ . \ l d w
129	$input = $char if $char =~ /[\[\]_\\=]/;
130	$input = '$' if $char eq "\n";
131	$input = '#' if $char =~ /[;#]/;
132	$input = 'l' if $char =~ /[a-z]/i;
133	$input = 'd' if $char =~ /[0-9]/;
134	$input = 'w' if $char =~ /[ \t]/;
135	# print "$state : $input : '$char'";
136	if ((exists $switchTo{$state.$input}) || ($char =~ /[^\n]/ && exists $switchTo{$state.'.'} && ($input = '.')))
137	{
138		my $prevState = $state;
139		$state = $switchTo{$state.$input};
140		$accumulator .= ($char =~ /[^\[\n ]/ || $prevState eq '31') ? $char : '' if exists $shouldAccumulate{$state} || $prevState eq '31';
141		if ($state eq '13')
142		{
143			$currentSection = $accumulator;
144			$ini{$currentSection} = {};
145			$accumulator = '';
146		}
147		if ($state eq '23')
148		{
149			$currentKey = $accumulator unless $currentKey;
150			$accumulator = '';
151		}
152		if ($state eq '33')
153		{
154			${$ini{$currentSection}}{$currentKey} = $accumulator if (!exists ${$ini{$currentSection}}{$currentKey}) && length $currentKey;
155			$currentKey = '';
156			$accumulator = '';
157		}
158		
159		return $state, $accumulator;
160	}
161	else
162	{
163		return '50', 'error';
164	}
165}
166
1671;