| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  | ! Copyright (C) 2010 John Benediktsson | 
					
						
							|  |  |  | ! See http://factorcode.org/license.txt for BSD license | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | USING: arrays assocs combinators combinators.short-circuit | 
					
						
							|  |  |  | formatting hashtables io io.streams.string kernel make math | 
					
						
							|  |  |  | namespaces quoting sequences splitting strings strings.parser ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | IN: ini-file | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <PRIVATE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : escape ( ch -- ch' )
 | 
					
						
							|  |  |  |     H{ | 
					
						
							|  |  |  |         { CHAR: a   CHAR: \a } | 
					
						
							| 
									
										
										
										
											2014-06-03 21:15:47 -04:00
										 |  |  |         { CHAR: b   CHAR: \b } | 
					
						
							|  |  |  |         { CHAR: f   CHAR: \f } | 
					
						
							| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  |         { CHAR: n   CHAR: \n } | 
					
						
							|  |  |  |         { CHAR: r   CHAR: \r } | 
					
						
							|  |  |  |         { CHAR: t   CHAR: \t } | 
					
						
							| 
									
										
										
										
											2014-06-03 21:15:47 -04:00
										 |  |  |         { CHAR: v   CHAR: \v } | 
					
						
							| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  |         { CHAR: '   CHAR: ' } | 
					
						
							| 
									
										
										
										
											2016-09-04 00:40:43 -04:00
										 |  |  |         { CHAR: \"   CHAR: \" } | 
					
						
							| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  |         { CHAR: \\  CHAR: \\ } | 
					
						
							|  |  |  |         { CHAR: ?   CHAR: ? } | 
					
						
							|  |  |  |         { CHAR: ;   CHAR: ; } | 
					
						
							|  |  |  |         { CHAR: [   CHAR: [ } | 
					
						
							|  |  |  |         { CHAR: ]   CHAR: ] } | 
					
						
							|  |  |  |         { CHAR: =   CHAR: = } | 
					
						
							|  |  |  |     } ?at [ bad-escape ] unless ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : (unescape-string) ( str -- )
 | 
					
						
							|  |  |  |     CHAR: \\ over index [ | 
					
						
							|  |  |  |         cut-slice [ % ] dip rest-slice
 | 
					
						
							|  |  |  |         dup empty? [ "Missing escape code" throw ] when
 | 
					
						
							|  |  |  |         unclip-slice escape , (unescape-string) | 
					
						
							|  |  |  |     ] [ % ] if* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : unescape-string ( str -- str' )
 | 
					
						
							|  |  |  |     [ (unescape-string) ] "" make ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | USE: xml.entities | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : escape-string ( str -- str' )
 | 
					
						
							|  |  |  |     H{ | 
					
						
							|  |  |  |         { CHAR: \a   "\\a"  } | 
					
						
							| 
									
										
										
										
											2011-11-23 21:49:33 -05:00
										 |  |  |         { 0x08    "\\b"  } | 
					
						
							|  |  |  |         { 0x0c    "\\f"  } | 
					
						
							| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  |         { CHAR: \n   "\\n"  } | 
					
						
							|  |  |  |         { CHAR: \r   "\\r"  } | 
					
						
							|  |  |  |         { CHAR: \t   "\\t"  } | 
					
						
							| 
									
										
										
										
											2011-11-23 21:49:33 -05:00
										 |  |  |         { 0x0b    "\\v"  } | 
					
						
							| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  |         { CHAR: '    "\\'"  } | 
					
						
							| 
									
										
										
										
											2016-09-04 00:40:43 -04:00
										 |  |  |         { CHAR: \"    "\\\"" } | 
					
						
							| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  |         { CHAR: \\   "\\\\" } | 
					
						
							|  |  |  |         { CHAR: ?    "\\?"  } | 
					
						
							|  |  |  |         { CHAR: ;    "\\;"  } | 
					
						
							|  |  |  |         { CHAR: [    "\\["  } | 
					
						
							|  |  |  |         { CHAR: ]    "\\]"  } | 
					
						
							|  |  |  |         { CHAR: =    "\\="  } | 
					
						
							|  |  |  |     } escape-string-by ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : space? ( ch -- ? )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         [ CHAR: \s = ] | 
					
						
							|  |  |  |         [ CHAR: \t = ] | 
					
						
							|  |  |  |         [ CHAR: \n = ] | 
					
						
							|  |  |  |         [ CHAR: \r = ] | 
					
						
							| 
									
										
										
										
											2011-11-23 21:49:33 -05:00
										 |  |  |         [ 0x0c = ] ! \f | 
					
						
							|  |  |  |         [ 0x0b = ] ! \v | 
					
						
							| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  |     } 1|| ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : unspace ( str -- str' )
 | 
					
						
							|  |  |  |     [ space? ] trim ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : unwrap ( str -- str' )
 | 
					
						
							|  |  |  |     1 swap [ length 1 - ] keep subseq ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : uncomment ( str -- str' )
 | 
					
						
							|  |  |  |     ";#" [ over index [ head ] when* ] each ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : cleanup-string ( str -- str' )
 | 
					
						
							|  |  |  |     unspace unquote unescape-string ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SYMBOL: section | 
					
						
							|  |  |  | SYMBOL: option | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : section? ( line -- index/f )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         [ length 1 > ] | 
					
						
							|  |  |  |         [ first CHAR: [ = ] | 
					
						
							|  |  |  |         [ CHAR: ] swap last-index ] | 
					
						
							|  |  |  |     } 1&& ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : line-continues? ( line -- ? )
 | 
					
						
							|  |  |  |     { [ empty? not ] [ last CHAR: \ = ] } 1&& ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : section, ( -- )
 | 
					
						
							|  |  |  |     section get [ , ] when* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : option, ( name value -- )
 | 
					
						
							|  |  |  |     section get [ second swapd set-at ] [ 2array , ] if* ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : [section] ( line -- )
 | 
					
						
							|  |  |  |     unwrap cleanup-string H{ } clone 2array section set ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : name=value ( line -- )
 | 
					
						
							|  |  |  |     option [ | 
					
						
							|  |  |  |         [ swap [ first2 ] dip ] [ | 
					
						
							|  |  |  |             "=" split1 [ cleanup-string "" ] [ "" or ] bi*
 | 
					
						
							|  |  |  |         ] if*
 | 
					
						
							|  |  |  |         dup line-continues? [ | 
					
						
							|  |  |  |             dup length 1 - head cleanup-string | 
					
						
							|  |  |  |             dup last space? [ " " append ] unless append 2array
 | 
					
						
							|  |  |  |         ] [ | 
					
						
							|  |  |  |             cleanup-string append option, f
 | 
					
						
							|  |  |  |         ] if
 | 
					
						
							|  |  |  |     ] change ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : parse-line ( line -- )
 | 
					
						
							|  |  |  |     uncomment unspace dup section? [ | 
					
						
							|  |  |  |         section, 1 + cut [ [section] ] [ unspace ] bi*
 | 
					
						
							|  |  |  |     ] when* [ name=value ] unless-empty ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIVATE>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : read-ini ( -- assoc )
 | 
					
						
							|  |  |  |     section off option off
 | 
					
						
							|  |  |  |     [ [ parse-line ] each-line section, ] { } make | 
					
						
							|  |  |  |     >hashtable ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : write-ini ( assoc -- )
 | 
					
						
							|  |  |  |     [ | 
					
						
							|  |  |  |         dup string?
 | 
					
						
							|  |  |  |         [ [ escape-string ] bi@ "%s=%s\n" printf ] | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             [ escape-string "[%s]\n" printf ] dip
 | 
					
						
							|  |  |  |             [ [ escape-string ] bi@ "%s=%s\n" printf ] | 
					
						
							|  |  |  |             assoc-each nl
 | 
					
						
							|  |  |  |         ] if
 | 
					
						
							|  |  |  |     ] assoc-each ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! FIXME: escaped comments "\;" don't work | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : string>ini ( str -- assoc )
 | 
					
						
							|  |  |  |     [ read-ini ] with-string-reader ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-23 15:15:36 -04:00
										 |  |  | : ini>string ( assoc -- str )
 | 
					
						
							| 
									
										
										
										
											2011-08-19 20:22:16 -04:00
										 |  |  |     [ write-ini ] with-string-writer ;
 |