COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/text.e151693.75%62973685.46%107
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
format()28731989.97%32
load_code_page()235541.82%32
get_text()0280.00%28
keyvalues()11713090.00%13
dequote()303196.77%1
set_encoding_properties()121392.31%1
escape()88100.00%0
get_encoding_properties()22100.00%0
lower()55100.00%0
proper()3434100.00%0
quote()4040100.00%0
sprint()1414100.00%0
trim()2323100.00%0
trim_head()1212100.00%0
trim_tail()1212100.00%0
upper()55100.00%0
LINE COVERAGE DETAIL
#Executed
1
-- (c) Copyright - See License.txt
2
--
3
namespace text
4
5
--****
6
-- == Text Manipulation
7
-- **Page Contents**
8
--
9
-- <>
10
--
11
12
--****
13
-- === Routines
14
15
include std/filesys.e
16
include std/types.e
17
include std/sequence.e
18
include std/io.e
19
include std/search.e
20
include std/convert.e
21
include std/serialize.e
22
include std/pretty.e
23
include std/error.e
24
include std/eds.e
25
include std/convert.e
26
27
--****
28
-- Signature:
29
-- function sprintf(sequence format, object values)
30
--
31
-- Description:
32
-- This is exactly the same as [[:printf]](), except that the output is returned as a sequence
33
-- of characters, rather than being sent to a file or device.
34
--
35
-- Parameters:
36
-- # ##format## : a sequence, the text to print. This text may contain format specifiers.
37
-- # ##values## : usually, a sequence of values. It should have as many elements as format specifiers in ##format##, as these values will be substituted to the specifiers.
38
--
39
-- Returns:
40
-- A **sequence**, of printable characters, representing ##format## with the values in ##values## spliced in.
41
--
42
-- Comments:
43
--
44
-- ##printf(fn, st, x)## is equivalent to ##puts(fn, sprintf(st, x))##.
45
--
46
-- Some typical uses of ##sprintf()## are:
47
--
48
-- # Converting numbers to strings.
49
-- # Creating strings to pass to system().
50
-- # Creating formatted error messages that can be passed to a common error message handler.
51
--
52
-- Example 1:
53
--
54
-- s = sprintf("%08d", 12345)
55
-- -- s is "00012345"
56
--
57
--
58
-- See Also:
59
-- [[:printf]], [[:sprint]], [[:format]]
60
61
--**
62
-- Returns the representation of any Euphoria object as a string of characters.
63
--
64
-- Parameters:
65
-- # ##x## : Any Euphoria object.
66
--
67
-- Returns:
68
-- A **sequence**, a string representation of ##x##.
69
--
70
-- Comments:
71
--
72
-- This is exactly the same as ##print(fn, x)##, except that the output is returned as a sequence of characters, rather
73
-- than being sent to a file or device. x can be any Euphoria object.
74
--
75
-- The atoms contained within ##x## will be displayed to a maximum of 10 significant digits,
76
-- just as with [[:print]]().
77
--
78
-- Example 1:
79
--
80
-- s = sprint(12345)
81
-- -- s is "12345"
82
--
83
--
84
-- Example 2:
85
--
86
-- s = sprint({10,20,30}+5)
87
-- -- s is "{15,25,35}"
88
--
89
--
90
-- See Also:
91
-- [[:sprintf]], [[:printf]]
92
931010
94
-- Return the string representation of any Euphoria data object.
95
-- This is the same as the output from print(1, x) or '?', but it's
96
-- returned as a string sequence rather than printed.
97
sequence s
98
991010
if atom(x) then
1001006
return sprintf("%.10g", x)
101
else
1024
s = "{"
1034
for i = 1 to length(x) do
1048
if atom(x[i]) then
1056
s &= sprintf("%.10g", x[i])
106
else
1072
s &= sprint(x[i])
108
end if
1098
s &= ','
1108
end for
1114
if s[$] = ',' then
1123
s[$] = '}'
113
else
1141
s &= '}'
115
end if
1164
return s
117
end if
118
end function
119
120
--**
121
-- Trim all items in the supplied set from the leftmost (start or head) of a sequence.
122
--
123
-- Parameters:
124
-- # ##source## : the sequence to trim.
125
-- # ##what## : the set of item to trim from ##source## (defaults to " \t\r\n").
126
-- # ##ret_index## : If zero (the default) returns the trimmed sequence, otherwise
127
-- it returns the index of the leftmost item **not** in ##what##.
128
--
129
-- Returns:
130
-- A **sequence**, if ##ret_index## is zero, which is the trimmed version of ##source##\\
131
-- A **integer**, if ##ret_index## is not zero, which is index of the leftmost
132
-- element in ##source## that is not in ##what##.
133
--
134
-- Example 1:
135
--
136
-- object s
137
-- s = trim_head("\r\nSentence read from a file\r\n", "\r\n")
138
-- -- s is "Sentence read from a file\r\n"
139
-- s = trim_head("\r\nSentence read from a file\r\n", "\r\n", TRUE)
140
-- -- s is 3
141
--
142
--
143
--
144
-- See Also:
145
-- [[:trim_tail]], [[:trim]], [[:pad_head]]
146
1476
148
integer lpos
1496
if atom(what) then
1503
what = {what}
151
end if
152
1536
lpos = 1
1546
while lpos <= length(source) do
15523
if not find(source[lpos], what) then
1565
exit
157
end if
15818
lpos += 1
15918
end while
160
1616
if ret_index then
1621
return lpos
163
else
1645
return source[lpos .. $]
165
end if
166
end function
167
168
--**
169
-- Trim all items in the supplied set from the rightmost (end or tail) of a sequence.
170
--
171
-- Parameters:
172
-- # ##source## : the sequence to trim.
173
-- # ##what## : the set of item to trim from ##source## (defaults to " \t\r\n").
174
-- # ##ret_index## : If zero (the default) returns the trimmed sequence, otherwise
175
-- it returns the index of the rightmost item **not** in ##what##.
176
--
177
-- Returns:
178
-- A **sequence**, if ##ret_index## is zero, which is the trimmed version of ##source##\\
179
-- A **integer**, if ##ret_index## is not zero, which is index of the rightmost
180
-- element in ##source## that is not in ##what##.
181
--
182
-- Example 1:
183
--
184
-- object s
185
-- s = trim_tail("\r\nSentence read from a file\r\n", "\r\n")
186
-- -- s is "\r\nSentence read from a file"
187
-- s = trim_tail("\r\nSentence read from a file\r\n", "\r\n", TRUE)
188
-- -- s is 27
189
--
190
--
191
-- See Also:
192
-- [[:trim_head]], [[:trim]], [[:pad_tail]]
193
19414
195
integer rpos
196
19714
if atom(what) then
1983
what = {what}
199
end if
200
20114
rpos = length(source)
20214
while rpos > 0 do
20326
if not find(source[rpos], what) then
20413
exit
205
end if
20613
rpos -= 1
20713
end while
208
20914
if ret_index then
2101
return rpos
211
else
21213
return source[1..rpos]
213
end if
214
end function
215
216
--**
217
-- Trim all items in the supplied set from both the left end (head/start) and right end (tail/end)
218
-- of a sequence.
219
--
220
-- Parameters:
221
-- # ##source## : the sequence to trim.
222
-- # ##what## : the set of item to trim from ##source## (defaults to " \t\r\n").
223
-- # ##ret_index## : If zero (the default) returns the trimmed sequence, otherwise
224
-- it returns a 2-element sequence containing the index of the
225
-- leftmost item and rightmost item **not** in ##what##.
226
--
227
-- Returns:
228
-- A **sequence**, if ##ret_index## is zero, which is the trimmed version of ##source##\\
229
-- A **2-element sequence**, if ##ret_index## is not zero, in the form {left_index, right_index}.
230
--
231
-- Example 1:
232
--
233
-- object s
234
-- s = trim("\r\nSentence read from a file\r\n", "\r\n")
235
-- -- s is "Sentence read from a file"
236
-- s = trim("\r\nSentence read from a file\r\n", "\r\n", TRUE)
237
-- -- s is {3,27}
238
--
239
--
240
-- See Also:
241
-- [[:trim_head]], [[:trim_tail]]
242
243347
244
integer rpos
245
integer lpos
246
247347
if atom(what) then
2484
what = {what}
249
end if
250
251347
lpos = 1
252347
while lpos <= length(source) do
253474
if not find(source[lpos], what) then
254293
exit
255
end if
256181
lpos += 1
257181
end while
258
259347
rpos = length(source)
260347
while rpos > lpos do
261323
if not find(source[rpos], what) then
262260
exit
263
end if
26463
rpos -= 1
26563
end while
266
267347
if ret_index then
2681
return {lpos, rpos}
269
else
270346
if lpos = 1 then
271301
if rpos = length(source) then
272272
return source
273
end if
274
end if
27574
if lpos > length(source) then
2765
return {}
277
end if
27869
return source[lpos..rpos]
279
end if
280
end function
281
282
283101
constant TO_LOWER = 'a' - 'A'
284
285101
sequence lower_case_SET = {}
286101
sequence upper_case_SET = {}
287101
sequence encoding_NAME = "ASCII"
288
2891
290
object cpdata
291
integer pos
292
sequence kv
293
sequence cp_source
294
sequence cp_db
295
2961
cp_source = defaultext(cpname, ".ecp")
2971
cp_source = locate_file(cp_source)
298
2991
cpdata = read_lines(cp_source)
3001
if sequence(cpdata) then
301
3020
pos = 0
3030
while pos < length(cpdata) do
3040
pos += 1
3050
cpdata[pos] = trim(cpdata[pos])
3060
if begins("--HEAD--", cpdata[pos]) then
3070
continue
308
end if
3090
if cpdata[pos][1] = ';' then
3100
continue -- A comment line
311
end if
3120
if begins("--CASE--", cpdata[pos]) then
3130
exit
314
end if
315
3160
kv = keyvalues(cpdata[pos],,,,"")
3170
if equal(lower(kv[1][1]), "title") then
3180
encoding_NAME = kv[1][2]
319
end if
3200
end while
3210
if pos > length(cpdata) then
3220
return -2 -- No Case Conversion table found.
323
end if
324
3250
upper_case_SET = ""
3260
lower_case_SET = ""
3270
while pos < length(cpdata) do
3280
pos += 1
3290
cpdata[pos] = trim(cpdata[pos])
3300
if length(cpdata[pos]) < 3 then
3310
continue
332
end if
3330
if cpdata[pos][1] = ';' then
3340
continue -- A comment line
335
end if
3360
if cpdata[pos][1] = '-' then
3370
exit
338
end if
339
3400
kv = keyvalues(cpdata[pos])
3410
upper_case_SET &= hex_text(kv[1][1])
3420
lower_case_SET &= hex_text(kv[1][2])
3430
end while
344
345
else
346
-- See if its in the database.
3471
cp_db = locate_file("ecp.dat")
3481
integer fh = open(cp_db, "rb")
3491
if fh = -1 then
3500
return -2 -- Couldn't open DB
351
end if
3521
object idx
3531
object vers
3541
vers = deserialize(fh) -- get the database version
3551
if vers[1] = 1 then
3561
idx = deserialize(fh) -- get Code Page index offset
3571
pos = seek(fh, idx)
3581
idx = deserialize(fh) -- get the Code Page Index
3591
pos = find(cpname, idx[1])
3601
if pos != 0 then
3611
pos = seek(fh, idx[2][pos])
3621
upper_case_SET = deserialize(fh) -- "uppercase"
3631
lower_case_SET = deserialize(fh) -- "lowercase"
3641
encoding_NAME = deserialize(fh) -- "title"
365
end if
366
end if
3671
close(fh)
368
369
end if
3701
return 0
371
end function
372
373
--**
374
-- Sets the table of lowercase and uppercase characters that is used by
375
-- [[:lower]] and [[:upper]]
376
--
377
-- Parameters:
378
-- # ##en## : The name of the encoding represented by these character sets
379
-- # ##lc## : The set of lowercase characters
380
-- # ##uc## : The set of upper case characters
381
--
382
--
383
-- Comments:
384
-- * ##lc## and ##uc## must be the same length.
385
-- * If no parameters are given, the default ASCII table is set.
386
--
387
-- Example 1:
388
--
389
-- set_encoding_properties( "Elvish", "aeiouy", "AEIOUY")
390
--
391
--
392
-- Example 1:
393
--
394
-- set_encoding_properties( "1251") -- Loads a predefined code page.
395
--
396
--
397
-- See Also:
398
-- [[:lower]], [[:upper]], [[:get_encoding_properties]]
399
4004
401
integer res
402
4034
if length(en) > 0 and length(lc) = 0 and length(uc) = 0 then
4041
res = load_code_page(en)
4051
if res != 0 then
4060
printf(2, "Failed to load code page '%s'. Error # %d\n", {en, res})
407
end if
4081
return
409
end if
410
4113
if length(lc) = length(uc) then
4123
if length(lc) = 0 and length(en) = 0 then
4132
en = "ASCII"
414
end if
4153
lower_case_SET = lc
4163
upper_case_SET = uc
4173
encoding_NAME = en
418
end if
4193
end procedure
420
421
--**
422
-- Gets the table of lowercase and uppercase characters that is used by
423
-- [[:lower]] and [[:upper]]
424
--
425
-- Parameters:
426
-- none
427
--
428
-- Returns:
429
-- A **sequence**, containing three items.\\
430
-- {Encoding_Name, LowerCase_Set, UpperCase_Set}
431
--
432
-- Example 1:
433
--
434
-- encode_sets = get_encoding_properties()
435
--
436
--
437
-- See Also:
438
-- [[:lower]], [[:upper]], [[:set_encoding_properties]]
439
--
4403
4413
return {encoding_NAME, lower_case_SET, upper_case_SET}
442
end function
443
444
445101
ifdef WINDOWS then
446
include std/dll.e
447
include std/machine.e
448
include std/types.e
449
atom
450
user32 = open_dll( "user32.dll"),
451
api_CharLowerBuff = define_c_func(user32, "CharLowerBuffA", {C_POINTER, C_INT}, C_INT),
452
api_CharUpperBuff = define_c_func(user32, "CharUpperBuffA", {C_POINTER, C_INT}, C_INT),
453
tm_size = 1024,
454
temp_mem = allocate(1024)
455
456
function change_case(object x, object api)
457
sequence changed_text
458
integer single_char = 0
459
integer len
460
461
if not string(x) then
462
if atom(x) then
463
if x = 0 then
464
return 0
465
end if
466
x = {x}
467
single_char = 1
468
else
469
for i = 1 to length(x) do
470
x[i] = change_case(x[i], api)
471
end for
472
return x
473
end if
474
end if
475
if length(x) = 0 then
476
return x
477
end if
478
if length(x) >= tm_size then
479
tm_size = length(x) + 1
480
free(temp_mem)
481
temp_mem = allocate(tm_size)
482
end if
483
poke(temp_mem, x)
484
len = c_func(api, {temp_mem, length(x)} )
485
if len < 1 then
486
len = length(x)
487
end if
488
changed_text = peek({temp_mem, len})
489
if single_char then
490
return changed_text[1]
491
else
492
return changed_text
493
end if
494
end function
495
end ifdef
496
497
--**
498
-- Convert an atom or sequence to lower case.
499
--
500
-- Parameters:
501
-- # ##x## : Any Euphoria object.
502
--
503
-- Returns:
504
-- A **sequence**, the lowercase version of ##x##
505
--
506
-- Comments:
507
-- * For Windows systems, this uses the current code page for conversion
508
-- * For non-Windows, this only works on ASCII characters. It alters characters in
509
-- the 'a'..'z' range. If you need to do case conversion with other encodings
510
-- use the [[:set_encoding_properties]] first.
511
-- * ##x## may be a sequence of any shape, all atoms of which will be acted upon.
512
--
513
-- **WARNING**, When using ASCII encoding, this can also affect floating point
514
-- numbers in the range 65 to 90.
515
--
516
-- Example 1:
517
--
518
-- s = lower("Euphoria")
519
-- -- s is "euphoria"
520
--
521
-- a = lower('B')
522
-- -- a is 'b'
523
--
524
-- s = lower({"Euphoria", "Programming"})
525
-- -- s is {"euphoria", "programming"}
526
--
527
--
528
-- See Also:
529
-- [[:upper]], [[:proper]], [[:set_encoding_properties]], [[:get_encoding_properties]]
53098
531
-- convert atom or sequence to lower case
53298
if length(lower_case_SET) != 0 then
5331
return mapping(x, upper_case_SET, lower_case_SET)
534
end if
535
53697
ifdef WINDOWS then
537
return change_case(x, api_CharLowerBuff)
538
elsedef
53997
return x + (x >= 'A' and x <= 'Z') * TO_LOWER
540
end ifdef
541
end function
542
543
--**
544
-- Convert an atom or sequence to upper case.
545
--
546
-- Parameters:
547
-- # ##x## : Any Euphoria object.
548
--
549
-- Returns:
550
-- A **sequence**, the uppercase version of ##x##
551
--
552
-- Comments:
553
-- * For Windows systems, this uses the current code page for conversion
554
-- * For non-Windows, this only works on ASCII characters. It alters characters in
555
-- the 'a'..'z' range. If you need to do case conversion with other encodings
556
-- use the [[:set_encoding_properties]] first.
557
-- * ##x## may be a sequence of any shape, all atoms of which will be acted upon.
558
--
559
-- **WARNING**, When using ASCII encoding, this can also affects floating point
560
-- numbers in the range 97 to 122.
561
--
562
-- Example 1:
563
--
564
-- s = upper("Euphoria")
565
-- -- s is "EUPHORIA"
566
--
567
-- a = upper('b')
568
-- -- a is 'B'
569
--
570
-- s = upper({"Euphoria", "Programming"})
571
-- -- s is {"EUPHORIA", "PROGRAMMING"}
572
--
573
--
574
-- See Also:
575
-- [[:lower]], [[:proper]], [[:set_encoding_properties]], [[:get_encoding_properties]]
576
5771135
578
-- convert atom or sequence to upper case
5791135
if length(upper_case_SET) != 0 then
5803
return mapping(x, lower_case_SET, upper_case_SET)
581
end if
5821132
ifdef WINDOWS then
583
return change_case(x, api_CharUpperBuff)
584
elsedef
5851132
return x - (x >= 'a' and x <= 'z') * TO_LOWER
586
end ifdef
587
588
end function
589
590
--**
591
-- Convert a text sequence to capitalized words.
592
--
593
-- Parameters:
594
-- # ##x## : A text sequence.
595
--
596
-- Returns:
597
-- A **sequence**, the Capitalized Version of ##x##
598
--
599
-- Comments:
600
-- A text sequence is one in which all elements are either characters or
601
-- text sequences. This means that if a non-character is found in the input,
602
-- it is not converted. However this rule only applies to elements on the
603
-- same level, meaning that sub-sequences could be converted if they are
604
-- actually text sequences.
605
--
606
--
607
-- Example 1:
608
--
609
-- s = proper("euphoria programming language")
610
-- -- s is "Euphoria Programming Language"
611
-- s = proper("EUPHORIA PROGRAMMING LANGUAGE")
612
-- -- s is "Euphoria Programming Language"
613
-- s = proper({"EUPHORIA PROGRAMMING", "language", "rapid dEPLOYMENT", "sOfTwArE"})
614
-- -- s is {"Euphoria Programming", "Language", "Rapid Deployment", "Software"}
615
-- s = proper({'a', 'b', 'c'})
616
-- -- s is {'A', 'b', c'} -- "Abc"
617
-- s = proper({'a', 'b', 'c', 3.1472})
618
-- -- s is {'a', 'b', c', 3.1472} -- Unchanged because it contains a non-character.
619
-- s = proper({"abc", 3.1472})
620
-- -- s is {"Abc", 3.1472} -- The embedded text sequence is converted.
621
--
622
--
623
-- See Also:
624
-- [[:lower]] [[:upper]]
625
62618
627
-- Converts text to lowercase and makes each word start with an uppercase.
628
integer pos
629
integer inword
630
integer convert
631
sequence res
632
63318
inword = 0 -- Initially not in a word
63418
convert = 1 -- Initially convert text
63518
res = x -- Work on a copy of the original, in case we need to restore.
63618
for i = 1 to length(res) do
637214
if integer(res[i]) then
638201
if convert then
639
-- Check for upper case
640200
pos = t_upper(res[i])
641200
if pos = 0 then
642
-- Not upper, so check for lower case
643125
pos = t_lower(res[i])
644125
if pos = 0 then
645
-- Not lower so check for digits
646
-- n.b. digits have no effect on if its in a word or not.
64727
pos = t_digit(res[i])
64827
if pos = 0 then
649
-- not digit so check for special word chars
65020
pos = t_specword(res[i])
65120
if pos then
6523
inword = 1
653
else
65417
inword = 0
655
end if
656
end if
657
else
65898
if inword = 0 then
659
-- start of word, so convert only lower to upper.
66018
if pos <= 26 then
66118
res[i] = upper(res[i]) -- Convert to uppercase
662
end if
66318
inword = 1 -- now we are in a word
664
end if
665
end if
666
else
66775
if inword = 1 then
668
-- Upper, but as we are in a word convert it to lower.
66966
res[i] = lower(res[i]) -- Convert to lowercase
670
else
6719
inword = 1 -- now we are in a word
672
end if
673
end if
674
end if
675
else
676
-- A non-integer means this is NOT a text sequence, so
677
-- only convert sub-sequences.
67813
if convert then
679
-- Restore any values that might have been converted.
6805
for j = 1 to i-1 do
6813
if atom(x[j]) then
6823
res[j] = x[j]
683
end if
6843
end for
685
-- Turn conversion off for the rest of this level.
6865
convert = 0
687
end if
688
68913
if sequence(res[i]) then
69010
res[i] = proper(res[i]) -- recursive conversion
691
end if
692
end if
693214
end for
69418
return res
695
end function
696
697
--**
698
-- Converts a string containing Key/Value pairs into a set of
699
-- sequences, one per K/V pair.
700
--
701
-- Parameters:
702
-- # ##source## : a text sequence, containing the representation of the key/values.
703
-- # ##pair_delim## : an object containing a list of elements that delimit one
704
-- key/value pair from the next. The defaults are semi-colon (;)
705
-- and comma (,).
706
-- # ##kv_delim## : an object containing a list of elements that delimit the
707
-- key from its value. The defaults are colon (:) and equal (=).
708
-- # ##quotes## : an object containing a list of elements that can be used to
709
-- enclose either keys or values that contain delimiters or
710
-- whitespace. The defaults are double-quote ("), single-quote (')
711
-- and back-quote (`)
712
-- # ##whitespace## : an object containing a list of elements that are regarded
713
-- as whitespace characters. The defaults are space, tab, new-line,
714
-- and carriage-return.
715
-- # ##haskeys## : an integer containing true or false. The default is true. When
716
-- ##true##, the ##kv_delim## values are used to separate keys from values, but
717
-- when ##false## it is assumed that each 'pair' is actually just a value.
718
--
719
-- Returns:
720
-- A **sequence**, of pairs. Each pair is in the form {key, value}.
721
--
722
-- Comments:
723
--
724
-- String representations of atoms are not converted, either in the key or value part, but returned as any regular string instead.
725
--
726
-- If ##haskeys## is ##true##, but a substring only holds what appears to be a value, the key
727
-- is synthesized as ##p[n]##, where ##n## is the number of the pair. See example #2.
728
--
729
-- By default, pairs can be delimited by either a comma or semi-colon ",;" and
730
-- a key is delimited from its value by either an equal or a colon "=:".
731
-- Whitespace between pairs, and between delimiters is ignored.
732
--
733
-- If you need to have one of the delimiters in the value data, enclose it in
734
-- quotation marks. You can use any of single, double and back quotes, which
735
-- also means you can quote quotation marks themselves. See example #3.
736
--
737
-- It is possible that the value data itself is a nested set of pairs. To do
738
-- this enclose the value in parentheses. Nested sets can nested to any level.
739
-- See example #4.
740
--
741
-- If a sub-list has only data values and not keys, enclose it in either braces
742
-- or square brackets. See example #5.
743
-- If you need to have a bracket as the first character in a data value, prefix
744
-- it with a tilde. Actually a leading tilde will always just be stripped off
745
-- regardless of what it prefixes. See example #6.
746
--
747
-- Example 1:
748
--
749
-- s = keyvalues("foo=bar, qwe=1234, asdf='contains space, comma, and equal(=)'")
750
-- -- s is { {"foo", "bar"}, {"qwe", "1234"}, {"asdf", "contains space, comma, and equal(=)"}}
751
--
752
--
753
-- Example 2:
754
--
755
-- s = keyvalues("abc fgh=ijk def")
756
-- -- s is { {"p[1]", "abc"}, {"fgh", "ijk"}, {"p[3]", "def"} }
757
--
758
--
759
-- Example 3:
760
--
761
-- s = keyvalues("abc=`'quoted'`")
762
-- -- s is { {"abc", "'quoted'"} }
763
--
764
--
765
-- Example 4:
766
--
767
-- s = keyvalues("colors=(a=black, b=blue, c=red)")
768
-- -- s is { {"colors", {{"a", "black"}, {"b", "blue"},{"c", "red"}} } }
769
-- s = keyvalues("colors=(black=[0,0,0], blue=[0,0,FF], red=[FF,0,0])")
770
-- -- s is { {"colors", {{"black",{"0", "0", "0"}}, {"blue",{"0", "0", "FF"}},{"red", {"FF","0","0"}}}} }
771
--
772
--
773
-- Example 5:
774
--
775
-- s = keyvalues("colors=[black, blue, red]")
776
-- -- s is { {"colors", { "black", "blue", "red"} } }
777
--
778
--
779
-- Example 6:
780
--
781
-- s = keyvalues("colors=~[black, blue, red]")
782
-- -- s is { {"colors", "[black, blue, red]"} } }
783
-- -- The following is another way to do the same.
784
-- s = keyvalues("colors=`[black, blue, red]`")
785
-- -- s is { {"colors", "[black, blue, red]"} } }
786
--
787
78843
789
object kv_delim = ":=", object quotes = "\"'`",
790
object whitespace = " \t\n\r", integer haskeys = 1)
791
792
sequence lKeyValues
793
sequence value_
794
sequence key_
795
sequence lAllDelim
796
sequence lWhitePair
797
sequence lStartBracket
798
sequence lEndBracket
799
sequence lBracketed
800
integer lQuote
801
integer pos_
802
integer lChar
803
integer lBPos
804
integer lWasKV
805
80643
source = trim(source)
80743
if length(source) = 0 then
8081
return {}
809
end if
810
81142
if atom(pair_delim) then
8121
pair_delim = {pair_delim}
813
end if
81442
if atom(kv_delim) then
8151
kv_delim = {kv_delim}
816
end if
81742
if atom(quotes) then
8181
quotes = {quotes}
819
end if
82042
if atom(whitespace) then
8211
whitespace = {whitespace}
822
end if
823
82442
lAllDelim = whitespace & pair_delim & kv_delim
82542
lWhitePair = whitespace & pair_delim
82642
lStartBracket = "{[("
82742
lEndBracket = "}])"
828
82942
lKeyValues = {}
83042
pos_ = 1
83142
while pos_ <= length(source) do
832
-- ignore leading whitespace
83389
while pos_ < length(source) do
834112
if find(source[pos_], whitespace) = 0 then
83586
exit
836
end if
83726
pos_ +=1
83826
end while
839
840
-- Get key. Ends at any of unquoted whitespace or unquoted delimiter
84189
key_ = ""
84289
lQuote = 0
84389
lChar = 0
84489
lWasKV = 0
84589
if haskeys then
84650
while pos_ <= length(source) do
847239
lChar = source[pos_]
848239
if find(lChar, quotes) != 0 then
8490
if lChar = lQuote then
850
-- End of quoted span
8510
lQuote = 0
8520
lChar = -1
8530
elsif lQuote = 0 then
854
-- Start of quoted span
8550
lQuote = lChar
8560
lChar = -1
857
end if
858
859239
elsif lQuote = 0 and find(lChar, lAllDelim) != 0 then
86048
exit
861
862
end if
863191
if lChar > 0 then
864191
key_ &= lChar
865
end if
866191
pos_ += 1
867191
end while
868
869
-- ignore next whitespace
87050
if find(lChar, whitespace) != 0 then
8716
pos_ += 1
8726
while pos_ <= length(source) do
87324
lChar = source[pos_]
87424
if find(lChar, whitespace) = 0 then
8756
exit
876
end if
87718
pos_ +=1
87818
end while
879
end if
880
else
88139
pos_ -= 1 -- Put back the last char.
882
end if
883
88489
value_ = ""
88589
if find(lChar, kv_delim) != 0 or not haskeys then
886
88785
if find(lChar, kv_delim) != 0 then
88846
lWasKV = 1
889
end if
890
891
-- ignore next whitespace
89285
pos_ += 1
89385
while pos_ <= length(source) do
89490
lChar = source[pos_]
89590
if find(lChar, whitespace) = 0 then
89685
exit
897
end if
8985
pos_ +=1
8995
end while
900
901
-- Get value. Ends at any of unquoted whitespace or unquoted delimiter
90285
lQuote = 0
90385
lChar = 0
90485
lBracketed = {}
90585
while pos_ <= length(source) do
906769
lChar = source[pos_]
907769
if length(lBracketed) = 0 and find(lChar, quotes) != 0 then
90835
if lChar = lQuote then
909
-- End of quoted span
91015
lQuote = 0
91115
lChar = -1
91220
elsif lQuote = 0 then
913
-- Start of quoted span
91415
lQuote = lChar
91515
lChar = -1
916
end if
917734
elsif find(lChar, lStartBracket) > 0 then
91826
lBPos = find(lChar, lStartBracket)
91926
lBracketed &= lEndBracket[lBPos]
920
921708
elsif length(value_) = 1 and value_[1] = '~' and find(lChar, lStartBracket) > 0 then
9220
lBPos = find(lChar, lStartBracket)
9230
lBracketed &= lEndBracket[lBPos]
924
925708
elsif length(lBracketed) != 0 and lChar = lBracketed[$] then
92626
lBracketed = lBracketed[1..$-1]
927
928682
elsif length(lBracketed) = 0 and lQuote = 0 and find(lChar, lWhitePair) != 0 then
92945
exit
930
931
end if
932
933724
if lChar > 0 then
934694
value_ &= lChar
935
end if
936724
pos_ += 1
937724
end while
938
93985
if find(lChar, whitespace) != 0 then
940
-- ignore next whitespace
9416
pos_ += 1
9426
while pos_ <= length(source) do
9436
lChar = source[pos_]
9446
if find(lChar, whitespace) = 0 then
9456
exit
946
end if
9470
pos_ +=1
9480
end while
949
end if
950
95185
if find(lChar, pair_delim) != 0 then
95239
pos_ += 1
95339
if pos_ <= length(source) then
95439
lChar = source[pos_]
955
end if
956
end if
957
end if
958
95989
if find(lChar, pair_delim) != 0 then
9600
pos_ += 1
961
end if
962
96389
if length(value_) = 0 then
9644
if length(key_) = 0 then
9650
lKeyValues = append(lKeyValues, {})
9660
continue
967
end if
968
9694
if not lWasKV then
9704
value_ = key_
9714
key_ = ""
972
end if
973
end if
974
97589
if length(key_) = 0 then
97643
if haskeys then
9774
key_ = sprintf("p[%d]", length(lKeyValues) + 1)
978
end if
979
end if
980
98189
if length(value_) > 0 then
98289
lChar = value_[1]
98389
lBPos = find(lChar, lStartBracket)
98489
if lBPos > 0 and value_[$] = lEndBracket[lBPos] then
98516
if lChar = '(' then
9864
value_ = keyvalues(value_[2..$-1], pair_delim, kv_delim, quotes, whitespace, haskeys)
987
else
98812
value_ = keyvalues(value_[2..$-1], pair_delim, kv_delim, quotes, whitespace, 0)
989
end if
99073
elsif lChar = '~' then
9912
value_ = value_[2 .. $]
992
end if
993
end if
994
99589
key_ = trim(key_)
99689
value_ = trim(value_)
99789
if length(key_) = 0 then
99839
lKeyValues = append(lKeyValues, value_)
999
else
100050
lKeyValues = append(lKeyValues, {key_, value_})
1001
end if
1002
100389
end while
1004
100542
return lKeyValues
1006
end function
1007
1008
--**
1009
-- Escape special characters in a string
1010
--
1011
-- Parameters:
1012
-- # ##s##: string to escape
1013
-- # ##what##: sequence of characters to escape
1014
-- defaults to escaping a double quote.
1015
--
1016
-- Returns:
1017
-- An escaped ##sequence## representing ##s##.
1018
--
1019
-- Example 1:
1020
--
1021
-- sequence s = escape("John \"Mc\" Doe")
1022
-- puts(1, s)
1023
-- -- output is: John \"Mc\" Doe
1024
--
1025
--
1026
-- See Also:
1027
-- [[:quote]]
1028
--
1029
10303
10313
sequence r = ""
1032
10333
for i = 1 to length(s) do
103440
if find(s[i], what) then
10359
r &= "\\"
1036
end if
103740
r &= s[i]
103840
end for
1039
10403
return r
1041
end function
1042
1043
1044
--**
1045
-- Return a quoted version of the first argument.
1046
--
1047
-- Parameters:
1048
-- # ##text_in## : The string or set of strings to quote.
1049
-- # ##quote_pair## : A sequence of two strings. The first string is the opening
1050
-- quote to use, and the second string is the closing quote to use.
1051
-- The default is {"\"", "\""} which means that the output will be
1052
-- enclosed by double-quotation marks.
1053
-- # ##esc## : A single escape character. If this is not negative (the default),
1054
-- then this is used to 'escape' any embedded quote characters and
1055
-- 'esc' characters already in the ##text_in## string.
1056
-- # ##sp## : A list of zero or more special characters. The ##text_in## is only
1057
-- quoted if it contains any of the special characters. The default
1058
-- is "" which means that the ##text_in## is always quoted.
1059
--
1060
-- Returns:
1061
-- A **sequence**, the quoted version of ##text_in##.
1062
--
1063
-- Example 1:
1064
--
1065
-- -- Using the defaults. Output enclosed in double-quotes, no escapes and no specials.
1066
-- s = quote("The small man")
1067
-- -- 's' now contains '"the small man"' including the double-quote characters.
1068
--
1069
--
1070
-- Example 2:
1071
--
1072
-- s = quote("The small man", {"(", ")"} )
1073
-- -- 's' now contains '(the small man)'
1074
--
1075
--
1076
-- Example 3:
1077
--
1078
-- s = quote("The (small) man", {"(", ")"}, '~' )
1079
-- -- 's' now contains '(The ~(small~) man)'
1080
--
1081
--
1082
-- Example 4:
1083
--
1084
-- s = quote("The (small) man", {"(", ")"}, '~', "#" )
1085
-- -- 's' now contains "the (small) man"
1086
-- -- because the input did not contain a '#' character.
1087
--
1088
--
1089
-- Example 5:
1090
--
1091
-- s = quote("The #1 (small) man", {"(", ")"}, '~', "#" )
1092
-- -- 's' now contains '(the #1 ~(small~) man)'
1093
-- -- because the input did contain a '#' character.
1094
--
1095
--
1096
-- Example 6:
1097
--
1098
-- -- input is a set of strings...
1099
-- s = quote({"a b c", "def", "g hi"},)
1100
-- -- 's' now contains three quoted strings: '"a b c"', '"def"', and '"g hi"'
1101
--
1102
--
1103
-- See Also:
1104
-- [[:escape]]
1105
--
1106
1107222
1108
t_text sp = "" )
1109222
if length(text_in) = 0 then
11101
return text_in
1111
end if
1112
1113221
if atom(quote_pair) then
11141
quote_pair = {{quote_pair}, {quote_pair}}
1115220
elsif length(quote_pair) = 1 then
11164
quote_pair = {quote_pair[1], quote_pair[1]}
1117216
elsif length(quote_pair) = 0 then
11181
quote_pair = {"\"", "\""}
1119
end if
1120
1121221
if sequence(text_in[1]) then
112214
for i = 1 to length(text_in) do
1123193
if sequence(text_in[i]) then
1124193
text_in[i] = quote(text_in[i], quote_pair, esc, sp)
1125
end if
1126193
end for
1127
112814
return text_in
1129
end if
1130
1131
-- Only quote the input if it contains any of the items in 'sp'
1132207
for i = 1 to length(sp) do
1133195
if find(sp[i], text_in) then
113415
exit
1135
end if
1136
1137180
if i = length(sp) then
1138
-- Contains none of them, so just return the input untouched.
1139179
return text_in
1140
end if
11411
end for
1142
114328
if esc >= 0 then
1144
-- If the input already contains a quote, replace them with esc-quote,
1145
-- but make sure that if the input already contains esc-quote that all
1146
-- embedded escapes are replaced with esc-esc first.
114721
if atom(quote_pair[1]) then
11481
quote_pair[1] = {quote_pair[1]}
1149
end if
115021
if atom(quote_pair[2]) then
11511
quote_pair[2] = {quote_pair[2]}
1152
end if
1153
115421
if equal(quote_pair[1], quote_pair[2]) then
1155
-- Simple case where both open and close quote are the same.
115616
if match(quote_pair[1], text_in) then
11574
if match(esc & quote_pair[1], text_in) then
11581
text_in = replace_all(text_in, esc, esc & esc)
1159
end if
11604
text_in = replace_all(text_in, quote_pair[1], esc & quote_pair[1])
1161
end if
1162
else
11635
if match(quote_pair[1], text_in) or
1164
match(quote_pair[2], text_in) then
11655
if match(esc & quote_pair[1], text_in) then
11661
text_in = replace_all(text_in, esc & quote_pair[1], esc & esc & quote_pair[1])
1167
end if
11685
text_in = replace_all(text_in, quote_pair[1], esc & quote_pair[1])
1169
end if
1170
11715
if match(quote_pair[2], text_in) then
11725
if match(esc & quote_pair[2], text_in) then
11731
text_in = replace_all(text_in, esc & quote_pair[2], esc & esc & quote_pair[2])
1174
end if
11755
text_in = replace_all(text_in, quote_pair[2], esc & quote_pair[2])
1176
end if
1177
end if
1178
end if
1179
118028
return quote_pair[1] & text_in & quote_pair[2]
1181
1182
end function
1183
1184
--**
1185
-- Removes 'quotation' text from the argument.
1186
--
1187
-- Parameters:
1188
-- # ##text_in## : The string or set of strings to de-quote.
1189
-- # ##quote_pairs## : A set of one or more sub-sequences of two strings,
1190
-- or an atom representing a single character to be used as
1191
-- both the open and close quotes.
1192
-- The first string in each sub-sequence is the opening
1193
-- quote to look for, and the second string is the closing quote.
1194
-- The default is {{{"\"", "\""}}} which means that the output is
1195
-- 'quoted' if it is enclosed by double-quotation marks.
1196
-- # ##esc## : A single escape character. If this is not negative (the default),
1197
-- then this is used to 'escape' any embedded occurrences of the
1198
-- quote characters. In which case the 'escape' character is also
1199
-- removed.
1200
--
1201
-- Returns:
1202
-- A **sequence**, the original text but with 'quote' strings stripped of quotes.
1203
--
1204
-- Example 1:
1205
--
1206
-- -- Using the defaults.
1207
-- s = dequote("\"The small man\"")
1208
-- -- 's' now contains "The small man"
1209
--
1210
--
1211
-- Example 2:
1212
--
1213
-- -- Using the defaults.
1214
-- s = dequote("(The small ?(?) man)", {{"(",")"}}, '?')
1215
-- -- 's' now contains "The small () man"
1216
--
1217
--
12188
1219
12208
if length(text_in) = 0 then
12211
return text_in
1222
end if
1223
12247
if atom(quote_pairs) then
12251
quote_pairs = {{{quote_pairs}, {quote_pairs}}}
12266
elsif length(quote_pairs) = 1 then
12272
quote_pairs = {quote_pairs[1], quote_pairs[1]}
12284
elsif length(quote_pairs) = 0 then
12291
quote_pairs = {{"\"", "\""}}
1230
end if
1231
12327
if sequence(text_in[1]) then
12331
for i = 1 to length(text_in) do
12342
if sequence(text_in[i]) then
12352
text_in[i] = dequote(text_in[i], quote_pairs, esc)
1236
end if
12372
end for
1238
12391
return text_in
1240
end if
1241
1242
-- If the text begins and ends with a quote-pair then strip them off and
1243
-- remove the 'escape' from any 'escaped' quote_pairs within the text.
12446
for i = 1 to length(quote_pairs) do
12457
if length(text_in) >= length(quote_pairs[i][1]) + length(quote_pairs[i][2]) then
12467
if begins(quote_pairs[i][1], text_in) and ends(quote_pairs[i][2], text_in) then
12476
text_in = text_in[1 + length(quote_pairs[i][1]) .. $ - length(quote_pairs[i][2])]
12486
integer pos = 1
12496
while pos > 0 with entry do
12504
if begins(quote_pairs[i][1], text_in[pos+1 .. $]) then
12512
text_in = text_in[1 .. pos-1] & text_in[pos + 1 .. $]
12522
elsif begins(quote_pairs[i][2], text_in[pos+1 .. $]) then
12532
text_in = text_in[1 .. pos-1] & text_in[pos + 1 .. $]
1254
else
12550
pos += 1
1256
end if
1257
entry
125810
pos = find_from(esc, text_in, pos)
125910
end while
12606
exit
1261
end if
1262
end if
12631
end for
1264
12656
return text_in
1266
end function
1267
1268
--**
1269
-- Formats a set of arguments in to a string based on a supplied pattern.
1270
--
1271
-- Parameters:
1272
-- # ##format_pattern## : A sequence: the pattern string that contains zero or more tokens.
1273
-- # ##arg_list## : An object: Zero or more arguments used in token replacement.
1274
--
1275
-- Returns:
1276
-- A string **sequence**, the original ##format_pattern## but with tokens replaced by
1277
-- corresponding arguments.
1278
--
1279
-- Comments:
1280
-- The ##format_pattern## string contains text and argument tokens. The resulting string
1281
-- is the same as the format string except that each token is replaced by an
1282
-- item from the argument list.
1283
--
1284
-- A token has the form **##[]##**, where is are optional qualifier codes.
1285
--
1286
-- The qualifier. #### is a set of zero or more codes that modify the default
1287
-- way that the argument is used to replace the token. The default replacement
1288
-- method is to convert the argument to its shortest string representation and
1289
-- use that to replace the token. This may be modified by the following codes,
1290
-- which can occur in any order.
1291
-- |= Qualifier |= Usage |
1292
-- | N | ('N' is an integer) The index of the argument to use|
1293
-- | {id} | Uses the argument that begins with "id=" where "id" \\
1294
-- is an identifier name. |
1295
-- | %envvar% | Uses the Environment Symbol 'envar' as an argument |
1296
-- | w | For string arguments, if capitalizes the first\\
1297
-- letter in each word |
1298
-- | u | For string arguments, it converts it to upper case. |
1299
-- | l | For string arguments, it converts it to lower case. |
1300
-- | < | For numeric arguments, it left justifies it. |
1301
-- | > | For string arguments, it right justifies it. |
1302
-- | c | Centers the argument. |
1303
-- | z | For numbers, it zero fills the left side. |
1304
-- | :S | ('S' is an integer) The maximum size of the\\
1305
-- resulting field. Also, if 'S' begins with '0' the\\
1306
-- field will be zero-filled if the argument is an integer|
1307
-- | .N | ('N' is an integer) The number of digits after\\
1308
-- the decimal point |
1309
-- | + | For positive numbers, show a leading plus sign |
1310
-- | ( | For negative numbers, enclose them in parentheses |
1311
-- | b | For numbers, causes zero to be all blanks |
1312
-- | s | If the resulting field would otherwise be zero\\
1313
-- length, this ensures that at least one space occurs\\
1314
-- between this token's field |
1315
-- | t | After token replacement, the resulting string up to this point is trimmed. |
1316
-- | X | Outputs integer arguments using hexadecimal digits. |
1317
-- | B | Outputs integer arguments using binary digits. |
1318
-- | ? | The corresponding argument is a set of two strings. This\\
1319
-- uses the first string if the previous token's argument is\\
1320
-- not the value 1 or a zero-length string, otherwise it\\
1321
-- uses the second string. |
1322
-- | [ | Does not use any argument. Outputs a left-square-bracket symbol |
1323
-- | ,X | Insert thousands separators. The is the character\\
1324
-- to use. If this is a dot "." then the decimal point\\
1325
-- is rendered using a comma. Does not apply to zero-filled\\
1326
-- fields. \\
1327
-- N.B. if hex or binary output was specified, the \\
1328
-- separators are every 4 digits otherwise they are \\
1329
-- every three digits. |
1330
--
1331
-- Clearly, certain combinations of these qualifier codes do not make sense and in
1332
-- those situations, the rightmost clashing code is used and the others are ignored.
1333
--
1334
-- Any tokens in the format that have no corresponding argument are simply removed
1335
-- from the result. Any arguments that are not used in the result are ignored.
1336
--
1337
-- Any sequence argument that is not a string will be converted to its
1338
-- //pretty// format before being used in token replacement.
1339
--
1340
-- If a token is going to be replaced by a zero-length argument, all white space
1341
-- following the token until the next non-whitespace character is not copied to
1342
-- the result string.
1343
--
1344
-- Examples:
1345
--
1346
-- format("Cannot open file '[]' - code []", {"/usr/temp/work.dat", 32})
1347
-- -- "Cannot open file '/usr/temp/work.dat' - code 32"
1348
--
1349
-- format("Err-[2], Cannot open file '[1]'", {"/usr/temp/work.dat", 32})
1350
-- -- "Err-32, Cannot open file '/usr/temp/work.dat'"
1351
--
1352
-- format("[4w] [3z:2] [6] [5l] [2z:2], [1:4]", {2009,4,21,"DAY","MONTH","of"})
1353
-- -- "Day 21 of month 04, 2009"
1354
--
1355
-- format("The answer is [:6.2]%", {35.22341})
1356
-- -- "The answer is 35.22%"
1357
--
1358
-- format("The answer is [.6]", {1.2345})
1359
-- -- "The answer is 1.234500"
1360
--
1361
-- format("The answer is [,,.2]", {1234.56})
1362
-- -- "The answer is 1,234.56"
1363
--
1364
-- format("The answer is [,..2]", {1234.56})
1365
-- -- "The answer is 1.234,56"
1366
--
1367
-- format("The answer is [,:.2]", {1234.56})
1368
-- -- "The answer is 1:234.56"
1369
--
1370
-- format("[] [?]", {5, {"cats", "cat"}})
1371
-- -- "5 cats"
1372
--
1373
-- format("[] [?]", {1, {"cats", "cat"}})
1374
-- -- "1 cat"
1375
--
1376
-- format("[<:4]", {"abcdef"})
1377
-- -- "abcd"
1378
--
1379
-- format("[>:4]", {"abcdef"})
1380
-- -- "cdef"
1381
--
1382
-- format("[>:8]", {"abcdef"})
1383
-- -- " abcdef"
1384
--
1385
-- format("seq is []", {{1.2, 5, "abcdef", {3}}})
1386
-- -- `seq is {1.2,5,"abcdef",{3}}`
1387
--
1388
-- format("Today is [{day}], the [{date}]", {"date=10/Oct/2012", "day=Wednesday"})
1389
-- -- "Today is Wednesday, the 10/Oct/2012"
1390
--
1391
--
1392
-- See Also:
1393
-- [[:sprintf]]
1394
--
1395
139664
1397
sequence result
1398
integer in_token
1399
integer tch
1400
integer i
1401
integer tstart
1402
integer tend
1403
integer cap
1404
integer align
1405
integer psign
1406
integer msign
1407
integer zfill
1408
integer bwz
1409
integer spacer
1410
integer alt
1411
integer width
1412
integer decs
1413
integer pos
1414
integer argn
1415
integer argl
1416
integer trimming
1417
integer hexout
1418
integer binout
1419
integer tsep
1420
object prevargv
1421
object currargv
1422
sequence idname
1423
object envsym
1424
object envvar
1425
142664
if atom(arg_list) then
142721
arg_list = {arg_list}
1428
end if
1429
143064
result = ""
143164
in_token = 0
1432
1433
143464
i = 0
143564
tstart = 0
143664
tend = 0
143764
argl = 0
143864
spacer = 0
143964
prevargv = 0
144064
while i < length(format_pattern) do
1441642
i += 1
1442642
tch = format_pattern[i]
1443642
if not in_token then
1444408
if tch = '[' then
144592
in_token = 1
144692
tstart = i
144792
tend = 0
144892
cap = 0
144992
align = 0
145092
psign = 0
145192
msign = 0
145292
zfill = 0
145392
bwz = 0
145492
spacer = 0
145592
alt = 0
145692
width = 0
145792
decs = -1
145892
argn = 0
145992
hexout = 0
146092
binout = 0
146192
trimming = 0
146292
tsep = 0
146392
idname = ""
146492
envvar = ""
146592
envsym = ""
1466
else
1467316
result &= tch
1468
end if
1469
else
1470234
switch tch do
1471
case ']' then
147291
in_token = 0
147391
tend = i
1474
1475
case '[' then
14761
result &= tch
14771
while i < length(format_pattern) do
147810
i += 1
147910
if format_pattern[i] = ']' then
14801
in_token = 0
14811
tstart = 0
14821
tend = 0
14831
exit
1484
end if
14859
end while
1486
1487
case 'w', 'u', 'l' then
14885
cap = tch
1489
1490
case 'b' then
14912
bwz = 1
1492
1493
case 's' then
14941
spacer = 1
1495
1496
case 't' then
14973
trimming = 1
1498
1499
case 'z' then
150019
zfill = 1
1501
1502
case 'X' then
15033
hexout = 1
1504
1505
case 'B' then
15064
binout = 1
1507
1508
case 'c', '<', '>' then
15098
align = tch
1510
1511
case '+' then
151210
psign = 1
1513
1514
case '(' then
15156
msign = 1
1516
1517
case '?' then
15184
alt = 1
1519
1520
case ':' then
152132
while i < length(format_pattern) do
152267
i += 1
152367
tch = format_pattern[i]
152467
pos = find(tch, "0123456789")
152567
if pos = 0 then
152632
i -= 1
152732
exit
1528
end if
152935
width = width * 10 + pos - 1
153035
if width = 0 then
15311
zfill = '0'
1532
end if
153335
end while
1534
1535
case '.' then
153611
decs = 0
153711
while i < length(format_pattern) do
153822
i += 1
153922
tch = format_pattern[i]
154022
pos = find(tch, "0123456789")
154122
if pos = 0 then
154211
i -= 1
154311
exit
1544
end if
154511
decs = decs * 10 + pos - 1
154611
end while
1547
1548
case '{' then
1549
-- Use a named argument.
15502
integer sp
1551
15522
sp = i + 1
15532
i = sp
15542
while i < length(format_pattern) do
15559
if format_pattern[i] = '}' then
15562
exit
1557
end if
15587
if format_pattern[i] = ']' then
15590
exit
1560
end if
15617
i += 1
15627
end while
15632
idname = trim(format_pattern[sp .. i-1]) & '='
15642
if format_pattern[i] = ']' then
15650
i -= 1
1566
end if
1567
15682
for j = 1 to length(arg_list) do
15693
if begins(idname, arg_list[j]) then
15702
if argn = 0 then
15712
argn = j
15722
exit
1573
end if
1574
end if
15751
if j = length(arg_list) then
15760
idname = ""
15770
argn = -1
1578
end if
15791
end for
1580
case '%' then
1581
-- Use the environment symbol
15821
integer sp
1583
15841
sp = i + 1
15851
i = sp
15861
while i < length(format_pattern) do
15878
if format_pattern[i] = '%' then
15881
exit
1589
end if
15907
if format_pattern[i] = ']' then
15910
exit
1592
end if
15937
i += 1
15947
end while
15951
envsym = trim(format_pattern[sp .. i-1])
15961
if format_pattern[i] = ']' then
15970
i -= 1
1598
end if
1599
16001
envvar = getenv(envsym)
1601
16021
argn = -1
16031
if atom(envvar) then
16040
envvar = ""
1605
end if
1606
1607
1608
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' then
160926
if argn = 0 then
161026
i -= 1
161126
while i < length(format_pattern) do
161252
i += 1
161352
tch = format_pattern[i]
161452
pos = find(tch, "0123456789")
161552
if pos = 0 then
161626
i -= 1
161726
exit
1618
end if
161926
argn = argn * 10 + pos - 1
162026
end while
1621
end if
1622
1623
case ',' then
16245
if i < length(format_pattern) then
16255
i +=1
16265
tsep = format_pattern[i]
1627
end if
1628
1629
case else
1630
-- ignore it
1631
end switch
1632
1633234
if tend > 0 then
1634
-- Time to replace the token.
163591
sequence argtext = ""
1636
163791
if argn = 0 then
163862
argn = argl + 1
1639
end if
164091
argl = argn
1641
164291
if argn < 1 or argn > length(arg_list) then
16431
if length(envvar) > 0 then
16441
argtext = envvar
16451
currargv = envvar
1646
else
16470
argtext = ""
16480
currargv =""
1649
end if
1650
else
165190
if string(arg_list[argn]) then
165234
if length(idname) > 0 then
16532
argtext = arg_list[argn][length(idname) + 1 .. $]
1654
else
165532
argtext = arg_list[argn]
1656
end if
1657
165856
elsif integer(arg_list[argn]) then
165936
if bwz != 0 and arg_list[argn] = 0 then
16602
argtext = ""
166134
elsif binout = 1 then
16624
argtext = reverse(int_to_bits(arg_list[argn], 32)) + '0'
16634
for ib = 1 to length(argtext) do
166476
if argtext[ib] = '1' then
16654
argtext = argtext[ib .. $]
16664
exit
1667
end if
166872
end for
1669
167030
elsif hexout = 0 then
167127
argtext = sprintf("%d", arg_list[argn])
167227
if zfill != 0 and width > 0 then
167315
if length(argtext) > 0 then
167415
if argtext[1] = '-' then
16752
if width > length(argtext) then
16762
argtext = '-' & repeat('0', width - length(argtext)) & argtext[2..$]
1677
end if
1678
else
167913
if width > length(argtext) then
168012
argtext = repeat('0', width - length(argtext)) & argtext
1681
end if
1682
end if
1683
else
16840
argtext = repeat('0', width - length(argtext)) & argtext
1685
end if
1686
end if
1687
168827
if arg_list[argn] > 0 then
168920
if psign then
16902
if zfill = 0 then
16911
argtext = '+' & argtext
16921
elsif argtext[1] = '0' then
16931
argtext[1] = '+'
1694
end if
1695
end if
16967
elsif arg_list[argn] < 0 then
16974
if msign then
16982
if zfill = 0 then
16991
argtext = '(' & argtext[2..$] & ')'
1700
else
17011
if argtext[2] = '0' then
17021
argtext = '(' & argtext[3..$] & ')'
1703
else
17040
argtext = argtext[2..$] & ')'
1705
end if
1706
end if
1707
end if
1708
end if
1709
else
17103
argtext = sprintf("%x", arg_list[argn])
17113
if zfill != 0 and width > 0 then
17122
if width > length(argtext) then
17132
argtext = repeat('0', width - length(argtext)) & argtext
1714
end if
1715
end if
1716
end if
1717
171820
elsif atom(arg_list[argn]) then
171915
if bwz != 0 and arg_list[argn] = 0 then
17200
argtext = ""
1721
else
172215
if hexout then
17230
argtext = sprintf("%x", arg_list[argn])
17240
if zfill != 0 and width > 0 then
17250
if width > length(argtext) then
17260
argtext = repeat('0', width - length(argtext)) & argtext
1727
end if
1728
end if
1729
else
173015
argtext = trim(sprintf("%15.15g", arg_list[argn]))
173115
if zfill != 0 and width > 0 then
17323
if length(argtext) > 0 then
17333
if width > length(argtext) then
17343
if argtext[1] = '-' then
17352
argtext = '-' & repeat('0', width - length(argtext)) & argtext[2..$]
1736
else
17371
argtext = repeat('0', width - length(argtext)) & argtext
1738
end if
1739
end if
1740
else
17410
argtext = repeat('0', width - length(argtext)) & argtext
1742
end if
1743
end if
174415
if arg_list[argn] > 0 then
174511
if psign then
17462
if zfill = 0 then
17471
argtext = '+' & argtext
17481
elsif argtext[1] = '0' then
17491
argtext[1] = '+'
1750
end if
1751
end if
17524
elsif arg_list[argn] < 0 then
17534
if msign then
17542
if zfill = 0 then
17551
argtext = '(' & argtext[2..$] & ')'
1756
else
17571
if argtext[2] = '0' then
17581
argtext = '(' & argtext[3..$] & ')'
1759
else
17600
argtext = argtext[2..$] & ')'
1761
end if
1762
end if
1763
end if
1764
end if
1765
end if
1766
end if
1767
1768
else
17695
if alt != 0 and length(arg_list[argn]) = 2 then
17704
object tempv
17714
if atom(prevargv) then
17722
if prevargv != 1 then
17731
tempv = arg_list[argn][1]
1774
else
17751
tempv = arg_list[argn][2]
1776
end if
1777
else
17782
if length(prevargv) = 0 then
17791
tempv = arg_list[argn][1]
1780
else
17811
tempv = arg_list[argn][2]
1782
end if
1783
end if
1784
17854
if string(tempv) then
17864
argtext = tempv
17870
elsif integer(tempv) then
17880
if bwz != 0 and tempv = 0 then
17890
argtext = ""
1790
else
17910
argtext = sprintf("%d", tempv)
1792
end if
1793
17940
elsif atom(tempv) then
17950
if bwz != 0 and tempv = 0 then
17960
argtext = ""
1797
else
17980
argtext = trim(sprintf("%15.15g", tempv))
1799
end if
1800
else
18010
argtext = pretty_sprint( tempv,
1802
{2,0,1,1000,"%d","%.15g",32,127,1,0}
1803
)
1804
end if
1805
else
18061
argtext = pretty_sprint( arg_list[argn],
1807
{2,0,1,1000,"%d","%.15g",32,127,1,0}
1808
)
1809
end if
1810
end if
181190
currargv = arg_list[argn]
1812
end if
1813
1814
181591
if length(argtext) > 0 then
181684
switch cap do
1817
case 'u' then
18181
argtext = upper(argtext)
1819
case 'l' then
18203
argtext = lower(argtext)
1821
case 'w' then
18221
argtext = proper(argtext)
1823
case 0 then
1824
-- do nothing
182579
cap = cap
1826
1827
case else
18280
crash("logic error: 'cap' mode in format.")
1829
1830
end switch
1831
183284
if atom(currargv) then
183349
if find('e', argtext) = 0 then
1834
-- Only applies to non-scientific notation.
183548
if decs != -1 then
18368
pos = find('.', argtext)
18378
if pos then
18387
if decs = 0 then
18391
argtext = argtext [1 .. pos-1 ]
1840
else
18416
pos = length(argtext) - pos
18426
if pos > decs then
18432
argtext = argtext[ 1 .. $ - pos + decs ]
18444
elsif pos < decs then
18451
argtext = argtext & repeat('0', decs - pos)
1846
end if
1847
end if
18481
elsif decs > 0 then
18491
argtext = argtext & '.' & repeat('0', decs)
1850
end if
1851
end if
1852
1853
end if
1854
end if
1855
185684
if align = 0 then
185776
if atom(currargv) then
185849
align = '>'
1859
else
186027
align = '<'
1861
end if
1862
end if
1863
186484
if atom(currargv) then
186549
if tsep != 0 and zfill = 0 then
18665
integer dpos
18675
integer dist
18685
integer bracketed
1869
18705
if binout or hexout then
18712
dist = 4
1872
else
18733
dist = 3
1874
end if
18755
bracketed = (argtext[1] = '(')
18765
if bracketed then
18770
argtext = argtext[2 .. $-1]
1878
end if
18795
dpos = find('.', argtext)
18805
if dpos = 0 then
18812
dpos = length(argtext) + 1
1882
else
18833
if tsep = '.' then
18841
argtext[dpos] = ','
1885
end if
1886
end if
18875
while dpos > dist do
18887
dpos -= dist
18897
if dpos > 1 then
18905
argtext = argtext[1.. dpos - 1] & tsep & argtext[dpos .. $]
1891
end if
18927
end while
18935
if bracketed then
18940
argtext = '(' & argtext & ')'
1895
end if
1896
end if
1897
end if
1898
189984
if width <= 0 then
190052
width = length(argtext)
1901
end if
1902
1903
190484
if width < length(argtext) then
19054
if align = '>' then
19061
argtext = argtext[ $ - width + 1 .. $]
19073
elsif align = 'c' then
19082
pos = length(argtext) - width
19092
if remainder(pos, 2) = 0 then
19101
pos = pos / 2
19111
argtext = argtext[ pos + 1 .. $ - pos ]
1912
else
19131
pos = floor(pos / 2)
19141
argtext = argtext[ pos + 1 .. $ - pos - 1]
1915
end if
1916
else
19171
argtext = argtext[ 1 .. width]
1918
end if
191980
elsif width > length(argtext) then
19207
if align = '>' then
19213
argtext = repeat(' ', width - length(argtext)) & argtext
19224
elsif align = 'c' then
19232
pos = width - length(argtext)
19242
if remainder(pos, 2) = 0 then
19252
pos = pos / 2
19262
argtext = repeat(' ', pos) & argtext & repeat(' ', pos)
1927
else
19280
pos = floor(pos / 2)
19290
argtext = repeat(' ', pos) & argtext & repeat(' ', pos + 1)
1930
end if
1931
1932
else
19332
argtext = argtext & repeat(' ', width - length(argtext))
1934
end if
1935
end if
193684
result &= argtext
1937
1938
else
19397
if spacer then
19401
result &= ' '
1941
end if
1942
end if
1943
194491
if trimming then
19453
result = trim(result)
1946
end if
1947
194891
tend = 0
194991
prevargv = currargv
1950
end if
1951
end if
1952642
end while
1953
195464
return result
1955
end function
1956
1957
--**
1958
-- Get the text associated with the message number in the requested locale.
1959
--
1960
-- Parameters:
1961
-- # ##MsgNum## : An integer. The message number whose text you are trying to get.
1962
-- # ##LocalQuals## : A sequence. Zero or more locale codes. Default is {}.
1963
-- # ##DBBase##: A sequence. The base name for the database files containing the
1964
-- locale text strings. The default is "teksto".
1965
--
1966
-- Returns:
1967
-- A string **sequence**, the text associated with the message number and locale.\\
1968
-- An **integer**, if not associated text can be found.
1969
--
1970
-- Comments:
1971
-- * This first scans the database(s) linked to the locale codes supplied.
1972
-- * The database name for each locale takes the format of "_.edb"
1973
-- so if the default DBBase is used, and the locales supplied are {"enus", "enau"}
1974
-- the databases scanned are "teksto_enus.edb" and "teksto_enau.edb".
1975
-- The database table name searched is "1" with the key being the message number,
1976
-- and the text is the record data.
1977
-- * If the message is not found in these databases (or the databases don't exist)
1978
-- a database called ".edb" is searched. Again the table name is "1" but
1979
-- it first looks for keys with the format {,msgnum} and failing that it
1980
-- looks for keys in the format {"", msgnum}, and if that fails it looks for a
1981
-- key of just the msgnum.
1982
--
19830
19840
integer idx = 1
1985
integer db_res
1986
object lMsgText
1987
19880
db_res = -1
19890
lMsgText = 0
1990
-- First, scan through the specialized local dbs
19910
for i = 1 to length(LocalQuals) do
19920
db_res = db_select( locate_file( DBBase & "_" & LocalQuals[i] & ".edb" ), DB_LOCK_NO)
19930
if db_res = DB_OK then
19940
db_res = db_select_table("1")
19950
if db_res = DB_OK then
19960
lMsgText = db_fetch_record(MsgNum)
19970
if sequence(lMsgText) then
19980
exit
1999
end if
2000
end if
2001
end if
20020
end for
2003
2004
-- Next, scan through the generic db
20050
if atom(lMsgText) then
20060
db_res = db_select( locate_file( DBBase & ".edb" ), DB_LOCK_NO)
20070
if db_res = DB_OK then
20080
db_res = db_select_table("1")
20090
if db_res = DB_OK then
20100
for i = 1 to length(LocalQuals) do
20110
lMsgText = db_fetch_record({LocalQuals[i],MsgNum})
20120
if sequence(lMsgText) then
20130
exit
2014
end if
20150
end for
20160
if atom(lMsgText) then
20170
lMsgText = db_fetch_record({"",MsgNum})
2018
end if
20190
if atom(lMsgText) then
20200
lMsgText = db_fetch_record(MsgNum)
2021
end if
2022
end if
2023
end if
2024
end if
2025
20260
return lMsgText
2027
2028
end function
2029