/Anton.Dobrov/Perl/practice/ParseINI/ParseINI.pm
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;