1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
#
# $Id$
#
# - Collection of String utility macros.
# Defines the following macros:
# STRING_ESCAPE(var str [NOESCAPE_SEMICOLON] [ESCAPE_VARIABLE])
# - Encode characters that would be expanded '\', ';', '$', '#'
# * Parameters:
# + var: A variable that stores the result.
# + str: The NAME of a variable that holds the string.
# + NOESCAPE_SEMICOLON: (Optional) Do not escape semicolons.
# + ESCAPE_VARIABLE: (Optional) Also escape '$'
#
# STRING_UNESCAPE(var str [NOESCAPE_SEMICOLON] [ESCAPE_VARIABLE])
# - Decode '\', ';', '$', '#', the reverse of STRING_ESCAPE
# * Parameters:
# + var: A variable that stores the result.
# + str: The encoded string
# + NOESCAPE_SEMICOLON: (Optional) Do not decode semicolons.
# + ESCAPE_VARIABLE: (Optional) Also decode '$'
#
# STRING_UNQUOTE(var str)
# - Remove double quote marks and quote marks around a string.
# * Parameters:
# + var: A variable that stores the result.
# + str: The NAME of a variable that holds the string.
#
# STRING_JOIN(var delimiter str_list [str...])
# - Concatenate strings, with delimiter inserted between strings.
# * Parameters:
# + var: A variable that stores the result.
# + str_list: A list of string.
# + str: (Optional) more string to be join.
#
# STRING_SPLIT(var delimiter str [NOESCAPE_SEMICOLON] [ESCAPE_VARIABLE] [NOENCODE])
# - Split a string into a list using a delimiter, which can be in 1 or more
# characters long.
# * Parameters:
# + var: A variable that stores the result.
# + delimiter: The NAME of a variable that holds the delimiter.
# + str: The NAME of a variable that holds the string to split.
# + NOESCAPE_SEMICOLON: (Optional) Do not escape semicolons.
# + NOENCODE: (Optional) Do not encode/decode string
#
# FILE2LIST (var filename [filename...])
# - Read a file to list, escape '#', '\' and ';'
# * Parameters:
# + var: A variable that stores the list.
# + filename: Files to read
#
# GREP (pattern var filename [filename...] [LITERALLY] [INVERT])
# - Read a file to list, escape '#', '\' and ';'
# * Parameters:
# + pattern: Regex to match
# + var: A variable that stores the matching lines.
# + filename: Files to read
# + LITERALLY: (Optional) Match the pattern string literally
# + INVERT: (Optional) Invert match
#
# LIST_REGEX_REPLACE (<regular_expression> <replace_expression>
# <output list> <list> [<list>...] [MATCHES_ONLY] [STRIP])
# - Do REGEX REPLACE for each lelement of list individually.
# * Parameters:
# + MATCHES_ONLY: (Optional) Return only matched elements in output list
# + STRIP: (Optional) Strip whitespace of each element in output list
#
# LIST_REGEX_GET (<regular_expression> <output list>
# <list> [<list>...] [INVERT])
# - Return list with matched elements.
# * Parameters:
# + INVERT: (Optional) invert the selection
#
# STRING_PAD (string length [RIGHT] [PADDING])
# - Pad a string with spaces to the given length. String will be left
# aligned.
# * Parameters:
# + RIGHT: (Optional) right-align the string
# + PADDING: (Optional) apply padding at the location by the marker
# string PADDING
#
# Copyright (c) 1991-2015 by P. Wessel, W. H. F. Smith, R. Scharroo, J. Luis and F. Wobbe
# See LICENSE.TXT file for copying and redistribution conditions.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; version 3 or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# Contact info: gmt.soest.hawaii.edu
#-------------------------------------------------------------------------------
if(NOT DEFINED _MANAGE_STRING_CMAKE_)
set(_MANAGE_STRING_CMAKE_ "DEFINED")
cmake_policy(SET CMP0010 NEW)
cmake_policy(SET CMP0011 NEW)
# STRING_ESCAPE(var str [NOESCAPE_SEMICOLON] [ESCAPE_VARIABLE])
macro(STRING_ESCAPE var str)
# ';' and '\' are tricky, need to be encoded.
# '#' => '#H'
# '$' => '#D'
# ';' => '#S'
# '\' => '#B'
# '|' => '#P'
set(_ESCAPE_VARIABLE)
set(_NOESCAPE_SEMICOLON)
string(REPLACE "#" "#H" _ret "${${str}}")
string(REPLACE "\\" "#B" _ret "${_ret}")
#string(REPLACE "|" "#P" _ret "${_ret}")
foreach(_arg ${ARGN})
if(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
set(_NOESCAPE_SEMICOLON "NOESCAPE_SEMICOLON")
elseif(${_arg} STREQUAL "ESCAPE_VARIABLE")
set(_ESCAPE_VARIABLE "ESCAPE_VARIABLE")
string(REPLACE "$" "#D" _ret "${_ret}")
endif(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
endforeach(_arg)
if(NOT _NOESCAPE_SEMICOLON)
string(REPLACE ";" "#S" _ret "${_ret}")
endif(NOT _NOESCAPE_SEMICOLON)
set(${var} "${_ret}")
endmacro(STRING_ESCAPE var str)
# STRING_UNESCAPE(var str [NOESCAPE_SEMICOLON] [ESCAPE_VARIABLE])
macro(STRING_UNESCAPE var str)
# '#B' => '\'
# '#D' => '$'
# '#H' => '#'
# '#P' => '|'
# '#S' => ';'
set(_ESCAPE_VARIABLE)
set(_NOESCAPE_SEMICOLON)
set(_ret "${str}")
foreach(_arg ${ARGN})
if(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
set(_NOESCAPE_SEMICOLON "NOESCAPE_SEMICOLON")
elseif(${_arg} STREQUAL "ESCAPE_VARIABLE")
set(_ESCAPE_VARIABLE "ESCAPE_VARIABLE")
string(REPLACE "#D" "$" _ret "${_ret}")
endif(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
endforeach(_arg)
if(_NOESCAPE_SEMICOLON)
# ';' => '#s'
string(REPLACE "#S" ";" _ret "${_ret}")
else(_NOESCAPE_SEMICOLON)
string(REPLACE "#S" "\\;" _ret "${_ret}")
endif(_NOESCAPE_SEMICOLON)
if(_ESCAPE_VARIABLE)
# '#d' => '$'
string(REPLACE "#D" "$" _ret "${_ret}")
endif(_ESCAPE_VARIABLE)
#string(REPLACE "#P" "|" _ret "${_ret}")
string(REPLACE "#B" "\\" _ret "${_ret}")
string(REPLACE "#H" "#" _ret "${_ret}")
set(${var} "${_ret}")
endmacro(STRING_UNESCAPE var str)
# STRING_UNQUOTE(var str)
macro(STRING_UNQUOTE var str)
# escape special chars
string_escape(_str ${str} NOESCAPE_SEMICOLON)
if(_str MATCHES "^[ \t\r\n]+")
string(REGEX REPLACE "^[ \t\r\n]+" "" _str "${_str}")
endif(_str MATCHES "^[ \t\r\n]+")
if(_str MATCHES "^\"")
# double quote
string(REGEX REPLACE "\"\(.*\)\"[ \t\r\n]*$" "\\1" _str "${_str}")
elseif(_str MATCHES "^'")
# single quote
string(REGEX REPLACE "'\(.*\)'[ \t\r\n]*$" "\\1" _str "${_str}")
else(_str MATCHES "^\"")
set(_str)
endif(_str MATCHES "^\"")
# unencoding
string_unescape(${var} "${_str}" NOESCAPE_SEMICOLON)
endmacro(STRING_UNQUOTE _var _str)
# STRING_JOIN(var delimiter str_list [str...])
macro(STRING_JOIN var delimiter str_list)
set(_ret)
foreach(_str ${str_list})
if(_ret)
set(_ret "${_ret}${delimiter}${_str}")
else(_ret)
set(_ret "${_str}")
endif(_ret)
endforeach(_str ${str_list})
foreach(_str ${ARGN})
if(_ret)
set(_ret "${_ret}${delimiter}${_str}")
else(_ret)
set(_ret "${_str}")
endif(_ret)
endforeach(_str ${str_list})
set(${var} "${_ret}")
endmacro(STRING_JOIN var delimiter str_list)
# STRING_SPLIT(var delimiter str [NOESCAPE_SEMICOLON] [ESCAPE_VARIABLE] [NOENCODE])
macro(STRING_SPLIT var delimiter str)
set(_max_tokens)
set(_NOESCAPE_SEMICOLON)
set(_ESCAPE_VARIABLE)
set(_NOENCODE)
foreach(_arg ${ARGN})
if(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
set(_NOESCAPE_SEMICOLON "NOESCAPE_SEMICOLON")
elseif(${_arg} STREQUAL "ESCAPE_VARIABLE")
set(_ESCAPE_VARIABLE "ESCAPE_VARIABLE")
elseif(${_arg} STREQUAL "NOENCODE")
set(_NOENCODE "NOENCODE")
else(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
set(_max_tokens ${_arg})
endif(${_arg} STREQUAL "NOESCAPE_SEMICOLON")
endforeach(_arg)
if(NOT _max_tokens)
set(_max_tokens -1)
endif(NOT _max_tokens)
if(_NOENCODE)
set(_str ${${str}})
set(_delimiter ${${delimiter}})
else(_NOENCODE)
string_escape(_str ${str} ${_NOESCAPE_SEMICOLON} ${_ESCAPE_VARIABLE})
string_escape(_delimiter ${delimiter} ${_NOESCAPE_SEMICOLON} ${_ESCAPE_VARIABLE})
endif(_NOENCODE)
set(_str_list)
set(_token_count 0)
string(LENGTH "${_delimiter}" _de_len)
while(NOT _token_count EQUAL _max_tokens)
math(EXPR _token_count ${_token_count}+1)
if(_token_count EQUAL _max_tokens)
# last token, no need splitting
set(_str_list ${_str_list} "${_str}")
else(_token_count EQUAL _max_tokens)
# in case encoded characters are delimiters
string(LENGTH "${_str}" _str_len)
set(_index 0)
set(_token)
set(_str_remain)
math(EXPR _str_end ${_str_len}-${_de_len}+1)
set(_bound "k")
while(_index LESS _str_end)
string(SUBSTRING "${_str}" ${_index} ${_de_len} _str_cursor)
if(_str_cursor STREQUAL _delimiter)
# get the token
string(SUBSTRING "${_str}" 0 ${_index} _token)
# get the rest
math(EXPR _rest_index ${_index}+${_de_len})
math(EXPR _rest_len ${_str_len}-${_index}-${_de_len})
string(SUBSTRING "${_str}" ${_rest_index} ${_rest_len} _str_remain)
set(_index ${_str_end})
else(_str_cursor STREQUAL _delimiter)
math(EXPR _index ${_index}+1)
endif(_str_cursor STREQUAL _delimiter)
endwhile(_index LESS _str_end)
if(_str_remain)
list(APPEND _str_list "${_token}")
set(_str "${_str_remain}")
else(_str_remain)
# meaning: end of string
list(APPEND _str_list "${_str}")
set(_max_tokens ${_token_count})
endif(_str_remain)
endif(_token_count EQUAL _max_tokens)
endwhile(NOT _token_count EQUAL _max_tokens)
if(_NOENCODE)
set(${var} "${_str_list}")
else(_NOENCODE)
# unencoding
string_unescape(${var} "${_str_list}" ${_NOESCAPE_SEMICOLON} ${_ESCAPE_VARIABLE})
endif(_NOENCODE)
endmacro(STRING_SPLIT var delimiter str)
# FILE2LIST (var filename [filename...])
macro (FILE2LIST _OUT _FILE)
set(${_OUT}) # clear
if (NOT FILESIZE_LIMIT)
# default: read max 512KiB
set(FILESIZE_LIMIT 524288)
endif (NOT FILESIZE_LIMIT)
foreach (_file ${_FILE} ${ARGN})
file (READ ${_file} _file_content LIMIT ${FILESIZE_LIMIT})
string_escape (_file_content _file_content) # ; -> #S and \ -> #B
# strip trainling "\n" and convert to list
string (REGEX REPLACE "\n+$" "" _file_content ${_file_content})
string (REPLACE "\n" ";" _file_content ${_file_content})
list(APPEND ${_OUT} "${_file_content}") # quotes -> also append empty lines
endforeach (_file ${_FILE} ${ARGN})
endmacro (FILE2LIST _OUT _FILE)
# HEAD (string): print at most 80 chars of a string
macro (HEAD _STR)
string(LENGTH "${_STR}" _len)
if (_len GREATER 80)
set(_len 80)
endif ()
string(SUBSTRING "${_STR}" 0 ${_len} _prn)
message("H> ${_prn}")
endmacro (HEAD _STR)
# GREP (pattern var filename [filename...] [LITERALLY] [INVERT])
macro (GREP _PATTERN _OUT _FILE)
set (_args ${ARGN})
list (FIND _args "LITERALLY" _LITERALLY)
if (_LITERALLY EQUAL -1)
set(_LITERALLY)
else(_LITERALLY EQUAL -1)
set(_LITERALLY TRUE)
list(REMOVE_ITEM _args "LITERALLY")
endif(_LITERALLY EQUAL -1)
list (FIND _args "INVERT" _INVERT)
if (_INVERT EQUAL -1)
set(_INVERT)
else(_INVERT EQUAL -1)
set(_INVERT TRUE)
list(REMOVE_ITEM _args "INVERT")
endif(_INVERT EQUAL -1)
set(_matches)
foreach (_file ${_FILE} ${_args})
file2list (_list ${_file})
foreach (_line IN LISTS _list)
#message("i> ${_line}")
set(_ismatching)
if (_LITERALLY)
string(FIND "${_line}" ${_PATTERN} _position)
if (_position GREATER 0)
set(_ismatching TRUE)
endif ()
else (_LITERALLY)
string(REGEX MATCH ${_PATTERN} _ismatching "${_line}")
endif (_LITERALLY)
if ((_ismatching AND NOT _INVERT) OR (NOT _ismatching AND _INVERT))
list (APPEND _matches "${_line}")
endif ()
#message("f> ${_file}")
#head(${_line})
endforeach (_line)
endforeach (_file)
set (${_OUT} "${_matches}")
#message("p: ${_PATTERN}")
endmacro(GREP _PATTERN _OUT _FILE)
# LIST_REGEX_REPLACE (<regular_expression> <replace_expression> <output list> <list> [<list>...])
# Note: have to double all escapes!
macro (LIST_REGEX_REPLACE _REGEX _REP _OUT _LIST)
#message("pattern: \"${_REGEX}\"")
set (_args ${ARGN})
list (FIND _args "MATCHES_ONLY" _MATCHES_ONLY)
if (_MATCHES_ONLY EQUAL -1)
set(_MATCHES_ONLY)
else(_MATCHES_ONLY EQUAL -1)
set(_MATCHES_ONLY TRUE)
list(REMOVE_ITEM _args "MATCHES_ONLY")
endif(_MATCHES_ONLY EQUAL -1)
list (FIND _args "STRIP" _STRIP)
if (_STRIP EQUAL -1)
set(_STRIP)
else(_STRIP EQUAL -1)
set(_STRIP TRUE)
list(REMOVE_ITEM _args "STRIP")
endif(_STRIP EQUAL -1)
set(${_OUT})
foreach (_line ${_LIST} ${_args})
string (REGEX REPLACE
"${_REGEX}"
"${_REP}" _replacement ${_line})
if (_MATCHES_ONLY AND (_replacement STREQUAL _line))
set(_replacement)
endif ()
if (_STRIP)
string (STRIP "${_replacement}" _replacement)
endif (_STRIP)
list (APPEND ${_OUT} ${_replacement})
#head("l: ${_line}")
#head("r: ${_replacement}")
endforeach (_line ${_LIST} ${_args})
endmacro (LIST_REGEX_REPLACE _REGEX _REP _OUT _LIST)
# LIST_REGEX_GET (<regular_expression> <output list> <list> [<list>...])
# Note: have to double all escapes!
macro (LIST_REGEX_GET _REGEX _OUT _LIST)
#message("pattern: ${_REGEX}")
set (_args ${ARGN})
list (FIND _args "INVERT" _INVERT)
if (_INVERT EQUAL -1)
set(_INVERT)
else(_INVERT EQUAL -1)
set(_INVERT TRUE)
list(REMOVE_ITEM _args "INVERT")
endif(_INVERT EQUAL -1)
set(${_OUT})
foreach (_line ${_LIST} ${_args})
set(_ismatching)
string(REGEX MATCH ${_REGEX} _ismatching ${_line})
if ((_ismatching AND NOT _INVERT) OR (NOT _ismatching AND _INVERT))
list (APPEND ${_OUT} ${_line})
endif ()
endforeach (_line ${_LIST} ${_args})
endmacro (LIST_REGEX_GET _REGEX _OUT _LIST)
# STRING_PAD (string length): pad a string with spaces to the given length
macro (STRING_PAD _STR _LEN)
set (_args ${ARGN})
list (FIND _args "RIGHT" _RIGHT)
if (_RIGHT EQUAL -1)
set (_RIGHT)
else (_RIGHT EQUAL -1)
set (_RIGHT TRUE)
list (REMOVE_ITEM _args "RIGHT")
endif (_RIGHT EQUAL -1)
# get maker string, split string at marker,
# and make woring copy
list (LENGTH _args _padding)
if (_padding)
list(GET _args 0 _padding)
string_split (_split _padding ${_STR}
NOESCAPE_SEMICOLON
NOENCODE)
if (_RIGHT)
# need to right align 2nd part
list (GET _split 1 _copy)
else (_RIGHT)
# left align 1st part
list (GET _split 0 _copy)
endif (_RIGHT)
else (_padding)
# no marker: copy complete string
set (_copy ${${_STR}})
endif (_padding)
string (LENGTH ${_copy} _orig_len)
if (_orig_len LESS ${_LEN})
set (_big_space " ")
if (_RIGHT)
# right align: prepend space
math (EXPR _extra_len "${_LEN} - ${_orig_len}")
string (SUBSTRING ${_big_space} 0 ${_extra_len} _extra_space)
set (_copy "${_extra_space}${_copy}")
else (_RIGHT)
# left align: append space
set (_big_str "${_copy}${_big_space}")
string (SUBSTRING ${_big_str} 0 ${_LEN} _copy)
endif (_RIGHT)
endif (_orig_len LESS ${_LEN})
# join split string
if (_padding)
if (_RIGHT)
# join copy w 1st part
list (GET _split 0 _part)
set (_copy "${_part}${_copy}")
else (_RIGHT)
# join copy w 2nd part
list (GET _split 1 _part)
set (_copy "${_copy}${_part}")
endif (_RIGHT)
endif (_padding)
# replace string with working copy
set (${_STR} ${_copy})
endmacro (STRING_PAD _STR _LEN)
endif(NOT DEFINED _MANAGE_STRING_CMAKE_)
# vim: textwidth=78 noexpandtab tabstop=2 softtabstop=2 shiftwidth=2
Tip!
Press p or to see the previous file or,
n or to see the next file