1# - Manage String by utility functions
2#
3# Defines the following functions:
4#   STRING_APPEND(<var> <str> [<separator>])
5#     - Append a string to a variable.
6#       * Parameters:
7#         + var: A variable that stores the result.
8#         + str: A string to be appended to end of line.
9#         + separator: Separator to separate between strings.
10#
11#   STRING_ESCAPE_BACKSLASH(<var> <str>)
12#     - Escape the backslash (\).
13#       * Parameters:
14#         + var: A variable that stores the result.
15#         + str: A string.
16#
17#   STRING_ESCAPE_DOLLAR(<var> <str>)
18#     - Escape the dollar sign ($).
19#       * Parameters:
20#         + var: A variable that stores the result.
21#         + str: A string.
22#
23#   STRING_ESCAPE_QUOTE(<var> <str>)
24#     - Escape the double quote (").
25#       * Parameters:
26#         + var: A variable that stores the result.
27#         + str: A string.
28#
29#   STRING_ESCAPE_SEMICOLON(<var> <str>)
30#     - Escape the semicolon (;).
31#       * Parameters:
32#         + var: A variable that stores the result.
33#         + str: A string.
34#
35#   STRING_PADDING(<var> <str> <length> [<padStr>])
36#     - Padding the string to specified length.
37#       * Parameters:
38#         + var: A variable that stores the result.
39#         + str: A string.
40#         + length: Required length.
41#         + padStr: String that used in padding. Default: " "
42#
43#   STRING_PREPEND(<var> <str> [<separator>])
44#     - Prepend a string to a variable.
45#       * Parameters:
46#         + var: A variable that stores the result.
47#         + str: A string to be appended to end of line.
48#         + separator: Separator to separate between strings.
49#
50#   STRING_SPLIT(<var> <delimiter> <str>
51#       [NOESCAPE_SEMICOLON] [ESCAPE_VARIABLE] [ALLOW_EMPTY]
52#     )
53#     - Split a string into a list using a delimiter,
54#       which can be in 1 or more characters long.
55#       * Parameters:
56#         + var: A variable that stores the result.
57#         + delimiter: To separate a string.
58#         + str: A string.
59#         + NOESCAPE_SEMICOLON: (Optional) Do not escape semicolons.
60#         + ESCAPE_VARIABLE: (Optional) Escape variables.
61#         + ALLOW_EMPTY: (Optional) Allow empty element exist in the array.
62#
63#   STRING_TRIM(<var> <str> [NOUNQUOTE])
64#     - Trim a string by removing the leading and trailing spaces,
65#       just like STRING(STRIP ...) in CMake 2.6 and later.
66#       This macro was developed as CMake 2.4 does not support
67#        STRING(STRIP ..)
68#       This macro also remove quote and double quote marks around
69#       the string, unless NOUNQUOTE is defined.
70#       * Parameters:
71#         + var: A variable that stores the result.
72#         + str: A string.
73#         + NOUNQUOTE: (Optional) do not remove the double quote mark
74#           around the string.
75#
76#   STRING_UNQUOTE(<var> <str>)
77#     - Remove double quote marks and quote marks around a string.
78#       If the string is not quoted, then content of str is copied to var
79#       * Parameters:
80#         + var: A variable that stores the result.
81#         + str: A string.
82#
83# Defines the following macros:
84#   STRING_JOIN(<var> <delimiter> <strList> [<str> ...])
85#     - Concatenate strings, with delimiter inserted between strings.
86#       * Parameters:
87#         + var: A variable that stores the result.
88#         + strList: A list of strings.
89#         + str: (Optional) more string to be join.
90#
91
92IF(DEFINED _MANAGE_STRING_CMAKE_)
93    RETURN()
94ENDIF(DEFINED _MANAGE_STRING_CMAKE_)
95SET(_MANAGE_STRING_CMAKE_ "DEFINED")
96
97FUNCTION(STRING_APPEND var str)
98    IF(${ARGC} GREATER 2)
99	SET(_sep "${ARGV2}")
100    ELSE(${ARGC} GREATER 2)
101	SET(_sep "")
102    ENDIF(${ARGC} GREATER 2)
103    IF (POLICY CMP0054)
104	CMAKE_POLICY(PUSH)
105	CMAKE_POLICY(SET CMP0054 "NEW")
106    ENDIF()
107    IF("${${var}}" STREQUAL "")
108	SET(${var} "${str}" PARENT_SCOPE)
109    ELSE("${${var}}" STREQUAL "")
110	SET(${var} "${${var}}${_sep}${str}" PARENT_SCOPE)
111    ENDIF("${${var}}" STREQUAL "")
112    IF (POLICY CMP0054)
113	CMAKE_POLICY(POP)
114    ENDIF()
115ENDFUNCTION(STRING_APPEND var str)
116
117FUNCTION(STRING_ESCAPE_BACKSLASH var str)
118    IF(str STREQUAL "")
119	SET(${var} "" PARENT_SCOPE)
120    ELSE(str STREQUAL "")
121	STRING(REPLACE "\\" "\\\\" output "${str}")
122	SET(${var} "${output}" PARENT_SCOPE)
123    ENDIF(str STREQUAL "")
124ENDFUNCTION(STRING_ESCAPE_BACKSLASH)
125
126FUNCTION(STRING_ESCAPE_DOLLAR var str)
127    IF(str STREQUAL "")
128	SET(${var} "" PARENT_SCOPE)
129    ELSE(str STREQUAL "")
130	STRING(REPLACE "\$" "\\\$" output "${str}")
131	SET(${var} "${output}" PARENT_SCOPE)
132    ENDIF(str STREQUAL "")
133ENDFUNCTION(STRING_ESCAPE_DOLLAR)
134
135FUNCTION(STRING_ESCAPE_QUOTE var str)
136    IF(str STREQUAL "")
137	SET(${var} "" PARENT_SCOPE)
138    ELSE(str STREQUAL "")
139	STRING(REPLACE "\"" "\\\"" output "${str}")
140	SET(${var} "${output}" PARENT_SCOPE)
141    ENDIF(str STREQUAL "")
142ENDFUNCTION(STRING_ESCAPE_QUOTE)
143
144FUNCTION(STRING_ESCAPE_SEMICOLON var str)
145    IF(str STREQUAL "")
146	SET(${var} "" PARENT_SCOPE)
147    ELSE(str STREQUAL "")
148	STRING(REPLACE ";" "\\;" output "${str}")
149	SET(${var} "${output}" PARENT_SCOPE)
150    ENDIF(str STREQUAL "")
151ENDFUNCTION(STRING_ESCAPE_SEMICOLON var str)
152
153FUNCTION(STRING_PADDING var str length)
154    SET(_ret "${str}")
155    IF(${ARGN})
156	SET(_padStr ${ARGN})
157    ELSE(${ARGN})
158	SET(_padStr " ")
159    ENDIF(${ARGN})
160    STRING(LENGTH "${str}" _strLen)
161    STRING(LENGTH "${_padStr}" _padLen)
162    WHILE( _strLen LESS length)
163	SET(_ret "${_ret}${_padStr}")
164	MATH(EXPR _strLen ${_strLen}+${_padLen})
165    ENDWHILE( _strLen LESS length)
166    SET(${var} "${_ret}" PARENT_SCOPE)
167ENDFUNCTION(STRING_PADDING var str length)
168
169FUNCTION(STRING_PREPEND var str)
170    IF(${ARGC} GREATER 2)
171	SET(_sep "${ARGV2}")
172    ELSE(${ARGC} GREATER 2)
173	SET(_sep "")
174    ENDIF(${ARGC} GREATER 2)
175    IF("${${var}}" STREQUAL "")
176	SET(${var} "${str}" PARENT_SCOPE)
177    ELSE("${${var}}" STREQUAL "")
178	SET(${var} "${str}${_sep}${${var}}" PARENT_SCOPE)
179    ENDIF("${${var}}" STREQUAL "")
180ENDFUNCTION(STRING_PREPEND var str)
181
182# Return (index of lefttmost non match character)
183# Return _strLen if all characters matches regex
184FUNCTION(STRING_LEFTMOST_NOTMATCH_INDEX var str regex)
185    STRING(LENGTH "${str}" _strLen)
186    SET(_index 0)
187    SET(_ret ${_strLen})
188    WHILE(_index LESS _strLen)
189	STRING(SUBSTRING "${str}" ${_index} 1 _strCursor)
190	#MESSAGE("***STRING_UNQUOTE: _i=${_index} _strCursor=${_strCursor}")
191	IF(NOT "${_strCursor}" MATCHES "${regex}")
192	    SET(_ret ${_index})
193	    SET(_index ${_strLen})
194	ENDIF(NOT "${_strCursor}" MATCHES "${regex}")
195
196	MATH(EXPR _index ${_index}+1)
197    ENDWHILE(_index LESS _strLen)
198    SET(${var} ${_ret} PARENT_SCOPE)
199ENDFUNCTION(STRING_LEFTMOST_NOTMATCH_INDEX var str)
200
201# Return (index of rightmost non match character) +1
202# Return 0 if all characters matches regex
203#
204FUNCTION(STRING_RIGHTMOST_NOTMATCH_INDEX var str regex)
205    STRING(LENGTH "${str}" _strLen)
206    MATH(EXPR _index ${_strLen})
207    SET(_ret 0)
208    WHILE(_index GREATER 0)
209	MATH(EXPR _index_1 ${_index}-1)
210	STRING(SUBSTRING "${str}" ${_index_1} 1 _strCursor)
211	#MESSAGE("***STRING_UNQUOTE: _i=${_index} _strCursor=${_strCursor}")
212
213	IF(NOT "${_strCursor}" MATCHES "${regex}")
214	    SET(_ret ${_index})
215	    SET(_index 0)
216	ENDIF(NOT "${_strCursor}" MATCHES "${regex}")
217	MATH(EXPR _index ${_index}-1)
218    ENDWHILE(_index GREATER 0)
219    SET(${var} ${_ret} PARENT_SCOPE)
220ENDFUNCTION(STRING_RIGHTMOST_NOTMATCH_INDEX var str)
221
222FUNCTION(STRING_TRIM var str)
223    #_STRING_ESCAPE(_ret "${str}" ${ARGN})
224    STRING_LEFTMOST_NOTMATCH_INDEX(_leftIndex "${str}" "[ \t\n\r]")
225    STRING_RIGHTMOST_NOTMATCH_INDEX(_rightIndex "${str}" "[ \t\n\r]")
226    # MESSAGE("_left=${_leftIndex} _rightIndex=${_rightIndex} str=|${str}|")
227    MATH(EXPR _subLen ${_rightIndex}-${_leftIndex})
228    SET(_NOUNQUOTE 0)
229    FOREACH( _arg ${ARGN})
230	IF(_arg STREQUAL "NOUNQUOTE")
231	    SET(_NOUNQUOTE 1)
232	ENDIF(_arg STREQUAL "NOUNQUOTE")
233    ENDFOREACH( _arg ${ARGN})
234
235    IF(_subLen GREATER 0)
236	STRING(SUBSTRING "${str}" ${_leftIndex} ${_subLen} _ret)
237	# IF _subLen > 1
238	#   IF UNQUOTE; then unquote
239	# Otherwise don't touch
240	IF (_subLen GREATER 1)
241	    IF(NOT _NOUNQUOTE)
242		STRING_UNQUOTE(_ret "${_ret}")
243	    ENDIF(NOT _NOUNQUOTE)
244	ENDIF (_subLen GREATER 1)
245    ELSE(_subLen GREATER 0)
246	SET(_ret "")
247    ENDIF(_subLen GREATER 0)
248    SET(${var} "${_ret}" PARENT_SCOPE)
249
250    # Unencoding
251    #_STRING_UNESCAPE(${var} "${_ret}" ${ARGN})
252ENDFUNCTION(STRING_TRIM var str)
253
254# Internal function
255# Nested Variable cannot be escaped here, as variable is already substituted
256# at the time it passes to this macro.
257FUNCTION(_STRING_ESCAPE var str)
258    # ';' and '\' are tricky, need to be encoded.
259    # '#' => '#H'
260    # '\' => '#B'
261    # ';' => '#S'
262    # '$' => '#D'
263    SET(_NOESCAPE_SEMICOLON "")
264    SET(_ESCAPE_VARIABLE "")
265
266    FOREACH(_arg ${ARGN})
267	IF(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
268	    SET(_NOESCAPE_SEMICOLON "NOESCAPE_SEMICOLON")
269	ELSEIF(${_arg} STREQUAL "ESCAPE_VARIABLE")
270	    SET(_ESCAPE_VARIABLE "ESCAPE_VARIABLE")
271	ENDIF(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
272    ENDFOREACH(_arg ${ARGN})
273
274    STRING(REGEX REPLACE "#" "#H" _ret "${str}")
275
276    STRING(REGEX REPLACE "\\\\" "#B" _ret "${_ret}")
277
278    IF(NOT _ESCAPE_VARIABLE STREQUAL "")
279	STRING(REGEX REPLACE "$" "#D" _ret "${_ret}")
280    ENDIF(NOT _ESCAPE_VARIABLE STREQUAL "")
281
282    IF(_NOESCAPE_SEMICOLON STREQUAL "")
283	STRING(REGEX REPLACE ";" "#S" _ret "${_ret}")
284    ENDIF(_NOESCAPE_SEMICOLON STREQUAL "")
285    #MESSAGE("_STRING_ESCAPE:_ret=${_ret}")
286    SET(${var} "${_ret}" PARENT_SCOPE)
287ENDFUNCTION(_STRING_ESCAPE var str)
288
289FUNCTION(_STRING_UNESCAPE var str)
290    # '#B' => '\'
291    # '#H' => '#'
292    # '#D' => '$'
293    # '#S' => ';'
294    SET(_ESCAPE_VARIABLE "")
295    SET(_NOESCAPE_SEMICOLON "")
296    SET(_ret "${str}")
297    FOREACH(_arg ${ARGN})
298	IF(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
299	    SET(_NOESCAPE_SEMICOLON "NOESCAPE_SEMICOLON")
300	ELSEIF(${_arg} STREQUAL "ESCAPE_VARIABLE")
301	    SET(_ESCAPE_VARIABLE "ESCAPE_VARIABLE")
302	    STRING(REGEX REPLACE "#D" "$" _ret "${_ret}")
303	ENDIF(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
304    ENDFOREACH(_arg ${ARGN})
305    #MESSAGE("###_STRING_UNESCAPE: var=${var} _ret=${_ret} _NOESCAPE_SEMICOLON=${_NOESCAPE_SEMICOLON} ESCAPE_VARIABLE=${_ESCAPE_VARIABLE}")
306
307    STRING(REGEX REPLACE "#B" "\\\\" _ret "${_ret}")
308    IF("${_NOESCAPE_SEMICOLON}" STREQUAL "")
309	# ESCAPE_SEMICOLON
310	STRING(REGEX REPLACE "#S" "\\\\;" _ret "${_ret}")
311    ELSE("${_NOESCAPE_SEMICOLON}" STREQUAL "")
312	# Don't ESCAPE_SEMICOLON
313	STRING(REGEX REPLACE "#S" ";" _ret "${_ret}")
314    ENDIF("${_NOESCAPE_SEMICOLON}" STREQUAL "")
315
316    IF(NOT _ESCAPE_VARIABLE STREQUAL "")
317	# '#D' => '$'
318	STRING(REGEX REPLACE "#D" "$" _ret "${_ret}")
319    ENDIF(NOT _ESCAPE_VARIABLE STREQUAL "")
320    STRING(REGEX REPLACE "#H" "#" _ret "${_ret}")
321    SET(${var} "${_ret}" PARENT_SCOPE)
322    #MESSAGE("*** _STRING_UNESCAPE: ${var}=${${var}}")
323ENDFUNCTION(_STRING_UNESCAPE var str)
324
325FUNCTION(STRING_UNQUOTE var str)
326    SET(_ret "${str}")
327    STRING(LENGTH "${str}" _strLen)
328
329    # IF _strLen > 1
330    #   IF lCh and rCh are both "\""
331    #      Remove _lCh and _rCh
332    #   ELSEIF lCh and rCh are both "'"
333    #      Remove _lCh and _rCh
334    # Otherwise don't touch
335    IF(_strLen GREATER 1)
336	STRING(SUBSTRING "${str}" 0 1 _lCh)
337	MATH(EXPR _strLen_1 ${_strLen}-1)
338	MATH(EXPR _strLen_2 ${_strLen_1}-1)
339	STRING(SUBSTRING "${str}" ${_strLen_1} 1 _rCh)
340	#MESSAGE("_lCh=${_lCh} _rCh=${_rCh} _ret=|${_ret}|")
341	IF("${_lCh}" STREQUAL "\"" AND "${_rCh}" STREQUAL "\"")
342	    STRING(SUBSTRING "${_ret}" 1 ${_strLen_2} _ret)
343	ELSEIF("${_lCh}" STREQUAL "'" AND "${_rCh}" STREQUAL "'")
344	    STRING(SUBSTRING "${_ret}" 1 ${_strLen_2} _ret)
345	ENDIF("${_lCh}" STREQUAL "\"" AND "${_rCh}" STREQUAL "\"")
346    ENDIF (_strLen GREATER 1)
347    SET(${var} "${_ret}" PARENT_SCOPE)
348ENDFUNCTION(STRING_UNQUOTE var str)
349
350MACRO(STRING_JOIN var delimiter)
351    SET(_ret "")
352    FOREACH(_str ${ARGN})
353	STRING_APPEND(_ret "${_str}" "${delimiter}")
354    ENDFOREACH(_str ${ARGN})
355    SET(${var} "${_ret}")
356ENDMACRO(STRING_JOIN var delimiter)
357
358FUNCTION(STRING_FIND var str search_str)
359    STRING(LENGTH "${str}" _str_len)
360    STRING(LENGTH "${search_str}" _search_len)
361    MATH(EXPR _str_end ${_str_len}-${_search_len}+1)
362
363    SET(_index 0)
364    SET(_str_remain "")
365    SET(_result -1)
366    WHILE(_index LESS _str_end)
367	STRING(SUBSTRING "${str}" ${_index} ${_search_len} _str_window)
368	IF(_str_window STREQUAL search_str)
369	    SET(_result ${_index})
370	    BREAK()
371	ELSE(_str_window STREQUAL search_str)
372	    MATH(EXPR _index ${_index}+1)
373	ENDIF(_str_window STREQUAL search_str)
374    ENDWHILE(_index LESS _str_end)
375    SET(${var} ${_result} PARENT_SCOPE)
376ENDFUNCTION(STRING_FIND var str search)
377
378FUNCTION(STRING_SPLIT_2 var str_remain has_delimiter delimiter str)
379    STRING_FIND(_index "${str}" "${delimiter}")
380    IF(_index EQUAL -1)
381	SET(${has_delimiter} "0" PARENT_SCOPE)
382	SET(${var} "${str}" PARENT_SCOPE)
383	SET(${str_remain} "" PARENT_SCOPE)
384    ELSE(_index EQUAL -1)
385	SET(${has_delimiter} "1" PARENT_SCOPE)
386	STRING(SUBSTRING "${str}" 0 ${_index} _var)
387	SET(${var} "${_var}" PARENT_SCOPE)
388
389	STRING(LENGTH "${str}" _str_len)
390	STRING(LENGTH "${delimiter}" _delimiter_len)
391	MATH(EXPR _str_2_start ${_index}+${_delimiter_len})
392	MATH(EXPR _str_2_len ${_str_len}-${_index}-${_delimiter_len})
393	STRING(SUBSTRING "${str}" ${_str_2_start} ${_str_2_len} _str_remain)
394	SET(${str_remain} "${_str_remain}" PARENT_SCOPE)
395    ENDIF(_index EQUAL -1)
396ENDFUNCTION(STRING_SPLIT_2 var str_remain has_delimiter delimiter str)
397
398FUNCTION(STRING_SPLIT var delimiter str)
399    #MESSAGE("***STRING_SPLIT: var=${var} str=${str}")
400    SET(_max_tokens "")
401    SET(_NOESCAPE_SEMICOLON "")
402    SET(_ESCAPE_VARIABLE "")
403    SET(_ALLOW_EMPTY "")
404    FOREACH(_arg ${ARGN})
405	IF(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
406	    SET(_NOESCAPE_SEMICOLON "NOESCAPE_SEMICOLON")
407	ELSEIF(${_arg} STREQUAL "ESCAPE_VARIABLE")
408	    SET(_ESCAPE_VARIABLE "ESCAPE_VARIABLE")
409	ELSEIF(${_arg} STREQUAL "ALLOW_EMPTY")
410	    SET(_ALLOW_EMPTY "ALLOW_EMPTY")
411	ELSE(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
412	    SET(_max_tokens ${_arg})
413	ENDIF(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
414    ENDFOREACH(_arg ${ARGN})
415
416    IF(NOT _max_tokens)
417	SET(_max_tokens -1)
418    ENDIF(NOT _max_tokens)
419
420    _STRING_ESCAPE(_str "${str}" ${_NOESCAPE_SEMICOLON} ${_ESCAPE_VARIABLE})
421    _STRING_ESCAPE(_delimiter "${delimiter}" ${_NOESCAPE_SEMICOLON} ${_ESCAPE_VARIABLE})
422    SET(_str_list "")
423    SET(_token_count 1)
424
425    WHILE(NOT _token_count EQUAL _max_tokens)
426	STRING_SPLIT_2(_token _str _has_delimiter "${_delimiter}" "${_str}")
427	#MESSAGE("_token_count=${_token_count} _max_tokens=${_max_tokens} _token=|${_token}| _str=${_str}")
428	MATH(EXPR _token_count ${_token_count}+1)
429	# Use length check to avoid the reserved word like "type"
430	STRING(LENGTH "${_token}" _token_len)
431
432	IF(_token_len GREATER 0 OR _ALLOW_EMPTY)
433    	    LIST(APPEND _str_list "${_token}")
434	ENDIF(_token_len GREATER 0 OR _ALLOW_EMPTY)
435	IF(_has_delimiter EQUAL 0)
436	    ## No more tokens
437	    BREAK()
438	ENDIF(_has_delimiter EQUAL 0)
439    ENDWHILE(NOT _token_count EQUAL _max_tokens)
440
441    IF(_has_delimiter EQUAL 1)
442	LIST(APPEND _str_list "${_str}")
443    ENDIF(_has_delimiter EQUAL 1)
444
445    # Unencoding
446    _STRING_UNESCAPE(_var "${_str_list}" ${_NOESCAPE_SEMICOLON} ${_ESCAPE_VARIABLE})
447    #MESSAGE("***STRING_SPLIT: tokens=${${var}}")
448    SET(${var} "${_var}" PARENT_SCOPE)
449ENDFUNCTION(STRING_SPLIT var delimiter str)
450
451