| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | /* String manipulation functions. */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-24 10:57:46 +00:00
										 |  |  |  | let lib = import ./default.nix; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  | inherit (builtins) length; | 
					
						
							| 
									
										
										
										
											2009-05-24 10:57:46 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | in | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | rec { | 
					
						
							| 
									
										
										
										
											2013-11-12 13:48:19 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   inherit (builtins) stringLength substring head tail isString; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Concatenate a list of strings. | 
					
						
							|  |  |  |  |   concatStrings = lib.fold (x: y: x + y) ""; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Map a function over a list and concatenate the resulting strings. | 
					
						
							|  |  |  |  |   concatMapStrings = f: list: concatStrings (map f list); | 
					
						
							| 
									
										
										
										
											2011-08-19 02:42:34 +00:00
										 |  |  |  |   concatImapStrings = f: list: concatStrings (lib.imap f list); | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Place an element between each element of a list, e.g., | 
					
						
							|  |  |  |  |   # `intersperse "," ["a" "b" "c"]' returns ["a" "," "b" "," "c"]. | 
					
						
							|  |  |  |  |   intersperse = separator: list: | 
					
						
							| 
									
										
										
										
											2012-08-13 14:19:31 -04:00
										 |  |  |  |     if list == [] || length list == 1 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |     then list | 
					
						
							|  |  |  |  |     else [(head list) separator] | 
					
						
							|  |  |  |  |          ++ (intersperse separator (tail list)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Concatenate a list of strings with a separator between each element, e.g. | 
					
						
							|  |  |  |  |   # concatStringsSep " " ["foo" "bar" "xyzzy"] == "foo bar xyzzy" | 
					
						
							|  |  |  |  |   concatStringsSep = separator: list: | 
					
						
							|  |  |  |  |     concatStrings (intersperse separator list); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-25 10:23:10 +02:00
										 |  |  |  |   concatMapStringsSep = sep: f: list: concatStringsSep sep (map f list); | 
					
						
							|  |  |  |  |   concatImapStringsSep = sep: f: list: concatStringsSep sep (lib.imap f list); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-05 18:05:11 +00:00
										 |  |  |  |   # Construct a Unix-style search path consisting of each `subDir" | 
					
						
							|  |  |  |  |   # directory of the given list of packages.  For example, | 
					
						
							|  |  |  |  |   # `makeSearchPath "bin" ["x" "y" "z"]' returns "x/bin:y/bin:z/bin". | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  |   makeSearchPath = subDir: packages: | 
					
						
							| 
									
										
										
										
											2009-04-05 18:05:11 +00:00
										 |  |  |  |     concatStringsSep ":" (map (path: path + "/" + subDir) packages); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Construct a library search path (such as RPATH) containing the | 
					
						
							|  |  |  |  |   # libraries for a set of packages, e.g. "${pkg1}/lib:${pkg2}/lib:...". | 
					
						
							|  |  |  |  |   makeLibraryPath = makeSearchPath "lib"; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-05 12:54:37 +00:00
										 |  |  |  |   # Idem for Perl search paths. | 
					
						
							|  |  |  |  |   makePerlPath = makeSearchPath "lib/perl5/site_perl"; | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-01-05 12:54:37 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  |   # Dependening on the boolean `cond', return either the given string | 
					
						
							|  |  |  |  |   # or the empty string. | 
					
						
							|  |  |  |  |   optionalString = cond: string: if cond then string else ""; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-13 11:05:37 +02:00
										 |  |  |  |   # Determine whether a string has given prefix/suffix. | 
					
						
							|  |  |  |  |   hasPrefix = pref: str: | 
					
						
							| 
									
										
										
										
											2014-06-10 13:55:25 +04:00
										 |  |  |  |     eqStrings (substring 0 (stringLength pref) str) pref; | 
					
						
							| 
									
										
										
										
											2014-05-13 11:05:37 +02:00
										 |  |  |  |   hasSuffix = suff: str: | 
					
						
							| 
									
										
										
										
											2014-06-10 13:55:25 +04:00
										 |  |  |  |     let | 
					
						
							|  |  |  |  |       lenStr = stringLength str; | 
					
						
							|  |  |  |  |       lenSuff = stringLength suff; | 
					
						
							| 
									
										
										
										
											2014-05-13 11:05:37 +02:00
										 |  |  |  |     in lenStr >= lenSuff && | 
					
						
							| 
									
										
										
										
											2014-06-10 13:55:25 +04:00
										 |  |  |  |        eqStrings (substring (lenStr - lenSuff) lenStr str) suff; | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Convert a string to a list of characters (i.e. singleton strings). | 
					
						
							|  |  |  |  |   # For instance, "abc" becomes ["a" "b" "c"].  This allows you to, | 
					
						
							|  |  |  |  |   # e.g., map a function over each character.  However, note that this | 
					
						
							|  |  |  |  |   # will likely be horribly inefficient; Nix is not a general purpose | 
					
						
							|  |  |  |  |   # programming language.  Complex string manipulations should, if | 
					
						
							|  |  |  |  |   # appropriate, be done in a derivation. | 
					
						
							|  |  |  |  |   stringToCharacters = s: let l = stringLength s; in | 
					
						
							|  |  |  |  |     if l == 0 | 
					
						
							|  |  |  |  |     then [] | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |     else map (p: substring p 1 s) (lib.range 0 (l - 1)); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-06 09:21:52 +00:00
										 |  |  |  |   # Manipulate a string charcater by character and replace them by strings | 
					
						
							|  |  |  |  |   # before concatenating the results. | 
					
						
							|  |  |  |  |   stringAsChars = f: s: | 
					
						
							|  |  |  |  |     concatStrings ( | 
					
						
							|  |  |  |  |       map f (stringToCharacters s) | 
					
						
							|  |  |  |  |     ); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-06 16:06:41 +00:00
										 |  |  |  |   # same as vim escape function. | 
					
						
							|  |  |  |  |   # Each character contained in list is prefixed by "\" | 
					
						
							|  |  |  |  |   escape = list : string : | 
					
						
							| 
									
										
										
										
											2009-10-06 09:21:52 +00:00
										 |  |  |  |     stringAsChars (c: if lib.elem c list then "\\${c}" else c) string; | 
					
						
							| 
									
										
										
										
											2009-05-06 16:06:41 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-06 16:06:41 +00:00
										 |  |  |  |   # still ugly slow. But more correct now | 
					
						
							|  |  |  |  |   # [] for zsh | 
					
						
							|  |  |  |  |   escapeShellArg = lib.escape (stringToCharacters "\\ ';$`()|<>\t*[]"); | 
					
						
							| 
									
										
										
										
											2009-02-09 16:51:03 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-06 09:21:52 +00:00
										 |  |  |  |   # replace characters by their substitutes.  This function is equivalent to | 
					
						
							|  |  |  |  |   # the `tr' command except that one character can be replace by multiple | 
					
						
							|  |  |  |  |   # ones.  e.g., | 
					
						
							|  |  |  |  |   # replaceChars ["<" ">"] ["<" ">"] "<foo>" returns "<foo>". | 
					
						
							|  |  |  |  |   replaceChars = del: new: s: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       subst = c: | 
					
						
							|  |  |  |  |         (lib.fold | 
					
						
							|  |  |  |  |           (sub: res: if sub.fst == c then sub else res) | 
					
						
							|  |  |  |  |           {fst = c; snd = c;} (lib.zipLists del new) | 
					
						
							|  |  |  |  |         ).snd; | 
					
						
							|  |  |  |  |     in | 
					
						
							|  |  |  |  |       stringAsChars subst s; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-09 18:38:26 +01:00
										 |  |  |  |   # Case conversion utilities | 
					
						
							|  |  |  |  |   lowerChars = stringToCharacters "abcdefghijklmnopqrstuvwxyz"; | 
					
						
							|  |  |  |  |   upperChars = stringToCharacters "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | 
					
						
							|  |  |  |  |   toLower = replaceChars upperChars lowerChars; | 
					
						
							|  |  |  |  |   toUpper = replaceChars lowerChars upperChars; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-10 13:55:25 +04:00
										 |  |  |  |   # Appends string context from another string | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |   addContextFrom = a: b: substring 0 0 a + b; | 
					
						
							| 
									
										
										
										
											2013-02-09 18:38:26 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-02-24 16:19:08 +00:00
										 |  |  |  |   # Compares strings not requiring context equality | 
					
						
							|  |  |  |  |   # Obviously, a workaround but works on all Nix versions | 
					
						
							| 
									
										
										
										
											2014-06-10 13:55:25 +04:00
										 |  |  |  |   eqStrings = a: b: addContextFrom b a == addContextFrom a b; | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:37 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:37 +00:00
										 |  |  |  |   # Cut a string with a separator and produces a list of strings which were | 
					
						
							|  |  |  |  |   # separated by this separator. e.g., | 
					
						
							|  |  |  |  |   # `splitString "." "foo.bar.baz"' returns ["foo" "bar" "baz"]. | 
					
						
							| 
									
										
										
										
											2014-06-10 13:55:25 +04:00
										 |  |  |  |   splitString = _sep: _s: | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:37 +00:00
										 |  |  |  |     let | 
					
						
							| 
									
										
										
										
											2014-06-10 13:55:25 +04:00
										 |  |  |  |       sep = addContextFrom _s _sep; | 
					
						
							|  |  |  |  |       s = addContextFrom _sep _s; | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:37 +00:00
										 |  |  |  |       sepLen = stringLength sep; | 
					
						
							|  |  |  |  |       sLen = stringLength s; | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |       lastSearch = sLen - sepLen; | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:37 +00:00
										 |  |  |  |       startWithSep = startAt: | 
					
						
							|  |  |  |  |         substring startAt sepLen s == sep; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       recurse = index: startAt: | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |         let cutUntil = i: [(substring startAt (i - startAt) s)]; in | 
					
						
							|  |  |  |  |         if index < lastSearch then | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:37 +00:00
										 |  |  |  |           if startWithSep index then | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |             let restartAt = index + sepLen; in | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:37 +00:00
										 |  |  |  |             cutUntil index ++ recurse restartAt restartAt | 
					
						
							|  |  |  |  |           else | 
					
						
							| 
									
										
										
										
											2014-10-04 17:02:29 +02:00
										 |  |  |  |             recurse (index + 1) startAt | 
					
						
							| 
									
										
										
										
											2009-09-28 18:22:37 +00:00
										 |  |  |  |         else | 
					
						
							|  |  |  |  |           cutUntil sLen; | 
					
						
							|  |  |  |  |     in | 
					
						
							|  |  |  |  |       recurse 0 0; | 
					
						
							| 
									
										
										
										
											2009-10-06 09:21:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-28 15:43:39 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-10-06 09:21:39 +00:00
										 |  |  |  |   # return the suffix of the second argument if the first argument match its | 
					
						
							|  |  |  |  |   # prefix. e.g., | 
					
						
							|  |  |  |  |   # `removePrefix "foo." "foo.bar.baz"' returns "bar.baz". | 
					
						
							|  |  |  |  |   removePrefix = pre: s: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       preLen = stringLength pre; | 
					
						
							|  |  |  |  |       sLen = stringLength s; | 
					
						
							|  |  |  |  |     in | 
					
						
							| 
									
										
										
										
											2014-05-08 13:07:02 +02:00
										 |  |  |  |       if hasPrefix pre s then | 
					
						
							|  |  |  |  |         substring preLen (sLen - preLen) s | 
					
						
							| 
									
										
										
										
											2009-10-06 09:21:39 +00:00
										 |  |  |  |       else | 
					
						
							|  |  |  |  |         s; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-09 15:50:40 +02:00
										 |  |  |  |   removeSuffix = suf: s: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       sufLen = stringLength suf; | 
					
						
							|  |  |  |  |       sLen = stringLength s; | 
					
						
							|  |  |  |  |     in | 
					
						
							| 
									
										
										
										
											2014-06-10 13:55:25 +04:00
										 |  |  |  |       if sufLen <= sLen && eqStrings suf (substring (sLen - sufLen) sufLen s) then | 
					
						
							| 
									
										
										
										
											2014-05-09 15:50:40 +02:00
										 |  |  |  |         substring 0 (sLen - sufLen) s | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         s; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-19 18:04:47 +00:00
										 |  |  |  |   # Return true iff string v1 denotes a version older than v2. | 
					
						
							|  |  |  |  |   versionOlder = v1: v2: builtins.compareVersions v2 v1 == 1; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-05 13:45:27 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-17 11:14:26 +02:00
										 |  |  |  |   # Return true iff string v1 denotes a version equal to or newer than v2. | 
					
						
							|  |  |  |  |   versionAtLeast = v1: v2: !versionOlder v1 v2; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-05 13:45:27 -04:00
										 |  |  |  |   # Get the version of the specified derivation, as specified in its | 
					
						
							|  |  |  |  |   # ‘name’ attribute. | 
					
						
							|  |  |  |  |   getVersion = drv: (builtins.parseDrvName drv.name).version; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-24 19:28:38 +01:00
										 |  |  |  |   # Extract name with version from URL. Ask for separator which is | 
					
						
							| 
									
										
										
										
											2012-09-13 13:59:23 +04:00
										 |  |  |  |   # supposed to start extension | 
					
						
							|  |  |  |  |   nameFromURL = url: sep: let | 
					
						
							|  |  |  |  |     components = splitString "/" url; | 
					
						
							|  |  |  |  |     filename = lib.last components; | 
					
						
							|  |  |  |  |     name = builtins.head (splitString sep filename); | 
					
						
							|  |  |  |  |   in | 
					
						
							|  |  |  |  |   assert ! eqStrings name filename; | 
					
						
							|  |  |  |  |   name; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-24 19:28:24 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Create an --{enable,disable}-<feat> string that can be passed to | 
					
						
							|  |  |  |  |   # standard GNU Autoconf scripts. | 
					
						
							|  |  |  |  |   enableFeature = enable: feat: "--${if enable then "enable" else "disable"}-${feat}"; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-08 18:29:14 +01:00
										 |  |  |  |   # Create a fixed width string with additional prefix to match required width | 
					
						
							|  |  |  |  |   fixedWidthString = width: filler: str: | 
					
						
							|  |  |  |  |     let | 
					
						
							|  |  |  |  |       strw = lib.stringLength str; | 
					
						
							|  |  |  |  |       reqWidth = width - (lib.stringLength filler); | 
					
						
							|  |  |  |  |     in | 
					
						
							|  |  |  |  |       assert strw <= width; | 
					
						
							|  |  |  |  |       if strw == width then str else filler + fixedWidthString reqWidth filler str; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   # Format a number adding leading zeroes up to fixed width | 
					
						
							|  |  |  |  |   fixedWidthNumber = width: n: fixedWidthString width "0" (toString n); | 
					
						
							| 
									
										
										
										
											2009-02-24 16:19:08 +00:00
										 |  |  |  | } |