COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/get.e151693.75%21729573.56%78
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
Get2()406066.67%20
Get()375567.27%18
get_qchar()0150.00%15
read_comment()41625.00%12
get_number()616791.04%6
get_value()121580.00%3
get_string()141687.50%2
escape_char()4580.00%1
get_ch()91090.00%1
char()22100.00%0
defaulted_value()77100.00%0
get()22100.00%0
natural()22100.00%0
plus_or_minus()22100.00%0
skip_blanks()55100.00%0
value()22100.00%0
LINE COVERAGE DETAIL
#Executed
1
-- (c) Copyright - See License.txt
2
--
3
namespace stdget
4
5
include std/io.e
6
include std/error.e
7
8
--****
9
-- == Input Routines
10
--
11
-- <>
12
--
13
--
14
15
--****
16
-- === Error Status Constants
17
-- These are returned from [[:get]] and [[:value]].
18
19
public constant
20101
GET_SUCCESS = 0,
21101
GET_EOF = -1,
22101
GET_FAIL = 1,
23101
GET_NOTHING = -2
24
25101
constant DIGITS = "0123456789",
26101
HEX_DIGITS = DIGITS & "ABCDEF",
27101
START_NUMERIC = DIGITS & "-+.#"
28
29101
constant TRUE = 1
30
31921
32921
return x >= 0
33
end type
34
351720
361720
return x >= -1 and x <= 255
37
end type
38
39
natural input_file -- file to be read from
40
41
object input_string -- string to be read from
42
natural string_next
43
44
char ch -- the current character
45
46
471696
48
-- set ch to the next character in the input stream (either string or file)
49
501696
if sequence(input_string) then
51539
if string_next <= length(input_string) then
52445
ch = input_string[string_next]
53445
string_next += 1
54
else
5594
ch = GET_EOF
56
end if
57
else
581157
ch = getc(input_file)
591157
if ch = GET_EOF then
600
string_next += 1
61
end if
62
end if
631696
end procedure
64
65101
constant white_space = " \t\n\r"
6672
67
-- skip white space
68
-- ch is "live" at entry and exit
69
7072
while find(ch, white_space) do
7140
get_ch()
7240
end while
7372
end procedure
74
75101
constant ESCAPE_CHARS = "n'\"t\\r",
76101
ESCAPED_CHARS = "\n'\"\t\\\r"
77
7812
79
-- return escape character
80
natural i
81
8212
i = find(c, ESCAPE_CHARS)
8312
if i = 0 then
840
return GET_FAIL
85
else
8612
return ESCAPED_CHARS[i]
87
end if
88
end function
89
900
91
-- get a single-quoted character
92
-- ch is "live" at exit
93
char c
94
950
get_ch()
960
c = ch
970
if ch = '\\' then
980
get_ch()
990
c = escape_char(ch)
1000
if c = GET_FAIL then
1010
return {GET_FAIL, 0}
102
end if
1030
elsif ch = '\'' then
1040
return {GET_FAIL, 0}
105
end if
1060
get_ch()
1070
if ch != '\'' then
1080
return {GET_FAIL, 0}
109
else
1100
get_ch()
1110
return {GET_SUCCESS, c}
112
end if
113
end function
114
11567
116
-- get a double-quoted character string
117
-- ch is "live" at exit
118
sequence text
119
12067
text = ""
12167
while TRUE do
1221060
get_ch()
1231060
if ch = GET_EOF or ch = '\n' then
1240
return {GET_FAIL, 0}
1251060
elsif ch = '"' then
12667
get_ch()
12767
return {GET_SUCCESS, text}
128993
elsif ch = '\\' then
12912
get_ch()
13012
ch = escape_char(ch)
13112
if ch = GET_FAIL then
1320
return {GET_FAIL, 0}
133
end if
134
end if
135993
text = text & ch
136993
end while
137
end function
138
13985
14085
return x = -1 or x = +1
141
end type
142
143101
constant GET_IGNORE = GET_NOTHING
1441
1451
if atom(input_string) then
1460
while ch!='\n' and ch!='\r' and ch!=-1 do
1470
get_ch()
1480
end while
1490
get_ch()
1500
if ch=-1 then
1510
return {GET_EOF, 0}
152
else
1530
return {GET_IGNORE, 0}
154
end if
155
else
1561
for i=string_next to length(input_string) do
1570
ch=input_string[i]
1580
if ch='\n' or ch='\r' then
1590
string_next=i+1
1600
return {GET_IGNORE, 0}
161
end if
1620
end for
1631
return {GET_EOF, 0}
164
end if
165
end function
166
16779
168
-- read a number or a comment
169
-- ch is "live" at entry and exit
170
plus_or_minus sign, e_sign
171
natural ndigits
172
integer hex_digit
173
atom mantissa, dec, e_mag
174
17579
sign = +1
17679
mantissa = 0
17779
ndigits = 0
178
179
-- process sign
18079
if ch = '-' then
1811
sign = -1
1821
get_ch()
1831
if ch='-' then
1841
return read_comment()
185
end if
18678
elsif ch = '+' then
1872
get_ch()
188
end if
189
190
-- get mantissa
19178
if ch = '#' then
192
-- process hex integer and return
1936
get_ch()
1946
while TRUE do
19516
hex_digit = find(ch, HEX_DIGITS)-1
19616
if hex_digit >= 0 then
19710
ndigits += 1
19810
mantissa = mantissa * 16 + hex_digit
19910
get_ch()
200
else
2016
if ndigits > 0 then
2025
return {GET_SUCCESS, sign * mantissa}
203
else
2041
return {GET_FAIL, 0}
205
end if
206
end if
20710
end while
208
end if
209
210
-- decimal integer or floating point
21172
while ch >= '0' and ch <= '9' do
212157
ndigits += 1
213157
mantissa = mantissa * 10 + (ch - '0')
214157
get_ch()
215157
end while
216
21772
if ch = '.' then
218
-- get fraction
21912
get_ch()
22012
dec = 10
22112
while ch >= '0' and ch <= '9' do
22216
ndigits += 1
22316
mantissa += (ch - '0') / dec
22416
dec *= 10
22516
get_ch()
22616
end while
227
end if
228
22972
if ndigits = 0 then
2301
return {GET_FAIL, 0}
231
end if
232
23371
mantissa = sign * mantissa
234
23571
if ch = 'e' or ch = 'E' then
236
-- get exponent sign
2374
e_sign = +1
2384
e_mag = 0
2394
get_ch()
2404
if ch = '-' then
2411
e_sign = -1
2421
get_ch()
2433
elsif ch = '+' then
2441
get_ch()
245
end if
246
-- get exponent magnitude
2474
if ch >= '0' and ch <= '9' then
2483
e_mag = ch - '0'
2493
get_ch()
2503
while ch >= '0' and ch <= '9' do
2512
e_mag = e_mag * 10 + ch - '0'
2522
get_ch()
2532
end while
254
else
2551
return {GET_FAIL, 0} -- no exponent
256
end if
2573
e_mag *= e_sign
2583
if e_mag > 308 then
259
-- rare case: avoid power() overflow
2600
mantissa *= power(10, 308)
2610
if e_mag > 1000 then
2620
e_mag = 1000
263
end if
2640
for i = 1 to e_mag - 308 do
2650
mantissa *= 10
2660
end for
267
else
2683
mantissa *= power(10, e_mag)
269
end if
270
end if
271
27270
return {GET_SUCCESS, mantissa}
273
end function
274
27599
276
-- read a Euphoria data object as a string of characters
277
-- and return {error_flag, value}
278
-- Note: ch is "live" at entry and exit of this routine
279
sequence s, e
280
integer e1
281
282
-- init
28399
while find(ch, white_space) do
284113
get_ch()
285113
end while
286
28799
if ch = -1 then -- string is made of whitespace only
2882
return {GET_EOF, 0}
289
end if
290
29197
while 1 do
29297
if find(ch, START_NUMERIC) then
29335
e = get_number()
29435
if e[1] != GET_IGNORE then -- either a number or something illegal was read, so exit: the other goto
29535
return e
296
end if -- else go read next item, starting at top of loop
2970
skip_blanks()
2980
if ch=-1 or ch='}' then -- '}' is expected only in the "{--\n}" case
2990
return {GET_NOTHING, 0} -- just a comment
300
end if
301
30262
elsif ch = '{' then
303
-- process a sequence
30413
s = {}
30513
get_ch()
30613
skip_blanks()
30713
if ch = '}' then -- empty sequence
3080
get_ch()
3090
return {GET_SUCCESS, s} -- empty sequence
310
end if
311
31213
while TRUE do -- read: comment(s), element, comment(s), comma and so on till it terminates or errors out
31349
while 1 do -- read zero or more comments and an element
31449
e = Get() -- read next element, using standard function
31549
e1 = e[1]
31649
if e1 = GET_SUCCESS then
31749
s = append(s, e[2])
31849
exit -- element read and added to result
3190
elsif e1 != GET_IGNORE then
3200
return e
321
-- else it was a comment, keep going
3220
elsif ch='}' then
3230
get_ch()
3240
return {GET_SUCCESS, s} -- empty sequence
325
end if
3260
end while
327
32849
while 1 do -- now read zero or more post element comments
32949
skip_blanks()
33049
if ch = '}' then
33113
get_ch()
33213
return {GET_SUCCESS, s}
33336
elsif ch!='-' then
33436
exit
335
else -- comment starts after item and before comma
3360
e = get_number() -- reads anything starting with '-'
3370
if e[1] != GET_IGNORE then -- it wasn't a comment, this is illegal
3380
return {GET_FAIL, 0}
339
end if
340
-- read next comment or , or }
341
end if
3420
end while
34336
if ch != ',' then
3440
return {GET_FAIL, 0}
345
end if
34636
get_ch() -- skip comma
34736
end while
348
34949
elsif ch = '\"' then
35046
return get_string()
3513
elsif ch = '\'' then
3520
return get_qchar()
353
else
3543
return {GET_FAIL, 0}
355
356
end if
357
3580
end while
359
360
end function
361
362
integer leading_whitespace
363
36473
365
-- read a Euphoria data object as a string of characters
366
-- and return {error_flag, value, total number of characters, leading whitespace}
367
-- Note: ch is "live" at entry and exit of this routine.
368
-- Uses the regular Get() to read sequence elements.
369
sequence s, e
370
integer e1
371
natural offset
372
373
-- init
37473
offset = string_next-1
37573
get_ch()
37673
while find(ch, white_space) do
3771
get_ch()
3781
end while
379
38073
if ch = -1 then -- string is made of whitespace only
3810
return {GET_EOF, 0, string_next-1-offset ,string_next-1}
382
end if
383
38473
leading_whitespace = string_next-2-offset -- index of the last whitespace: string_next points past the first non whitespace
385
38673
while 1 do
38773
if find(ch, START_NUMERIC) then
38844
e = get_number()
38944
if e[1] != GET_IGNORE then -- either a number or something illegal was read, so exit: the other goto
39044
return e & {string_next-1-offset-(ch!=-1), leading_whitespace}
391
end if -- else go read next item, starting at top of loop
3920
get_ch()
3930
if ch=-1 then
3940
return {GET_NOTHING, 0, string_next-1-offset-(ch!=-1), leading_whitespace} -- empty sequence
395
end if
396
39729
elsif ch = '{' then
398
-- process a sequence
3993
s = {}
4003
get_ch()
4013
skip_blanks()
4023
if ch = '}' then -- empty sequence
4030
get_ch()
4040
return {GET_SUCCESS, s, string_next-1-offset-(ch!=-1), leading_whitespace} -- empty sequence
405
end if
406
4073
while TRUE do -- read: comment(s), element, comment(s), comma and so on till it terminates or errors out
4087
while 1 do -- read zero or more comments and an element
4097
e = Get() -- read next element, using standard function
4107
e1 = e[1]
4117
if e1 = GET_SUCCESS then
4127
s = append(s, e[2])
4137
exit -- element read and added to result
4140
elsif e1 != GET_IGNORE then
4150
return e & {string_next-1-offset-(ch!=-1), leading_whitespace}
416
-- else it was a comment, keep going
4170
elsif ch='}' then
4180
get_ch()
4190
return {GET_SUCCESS, s, string_next-1-offset-(ch!=-1),leading_whitespace} -- empty sequence
420
end if
4210
end while
422
4237
while 1 do -- now read zero or more post element comments
4247
skip_blanks()
4257
if ch = '}' then
4263
get_ch()
4273
return {GET_SUCCESS, s, string_next-1-offset-(ch!=-1), leading_whitespace}
4284
elsif ch!='-' then
4294
exit
430
else -- comment starts after item and before comma
4310
e = get_number() -- reads anything starting with '-'
4320
if e[1] != GET_IGNORE then -- it was not a comment, this is illegal
4330
return {GET_FAIL, 0, string_next-1-offset-(ch!=-1),leading_whitespace}
434
end if
435
-- read next comment or , or }
436
end if
4370
end while
4384
if ch != ',' then
4390
return {GET_FAIL, 0, string_next-1-offset-(ch!=-1), leading_whitespace}
440
end if
4414
get_ch() -- skip comma
4424
end while
443
44426
elsif ch = '\"' then
44521
e = get_string()
44621
return e & {string_next-1-offset-(ch!=-1), leading_whitespace}
4475
elsif ch = '\'' then
4480
e = get_qchar()
4490
return e & {string_next-1-offset-(ch!=-1), leading_whitespace}
450
else
4515
return {GET_FAIL, 0, string_next-1-offset-(ch!=-1), leading_whitespace}
452
453
end if
454
4550
end while
456
457
end function
458
459
--****
460
-- === Answer Types
461
462
public constant
463101
GET_SHORT_ANSWER = routine_id("Get"),
464101
GET_LONG_ANSWER = routine_id("Get2")
465
466116
467116
if answer_type != GET_SHORT_ANSWER and answer_type != GET_LONG_ANSWER then
4680
crash("Invalid type of answer, please only use %s (the default) or %s.", {"GET_SHORT_ANSWER", "GET_LONG_ANSWER"})
469
end if
470116
if atom(target) then -- get()
47113
input_file = target
47213
if start_point then
4730
if seek(target, where(target)+start_point) then
4740
crash("Initial seek() for get() failed!")
475
end if
476
end if
47713
string_next = 1
47813
input_string = 0
479
else
480103
input_string = target
481103
string_next = start_point
482
end if
483116
if answer_type = GET_SHORT_ANSWER then
48443
get_ch()
485
end if
486116
return call_func(answer_type, {})
487
end function
488
489
--****
490
-- === Routines
491
--
492
493
--**
494
-- Input, from an open file, a human-readable string of characters representing a Euphoria object.
495
-- Convert the string into the numeric value of that object.
496
--
497
-- Parameters:
498
-- # ##file## : an integer, the handle to an open file from which to read
499
-- # ##offset## : an integer, an offset to apply to file position before reading. Defaults to 0.
500
-- # ##answer## : an integer, either ##GET_SHORT_ANSWER## (the default) or ##GET_LONG_ANSWER##.
501
--
502
-- Returns:
503
-- A **sequence**, of length 2 (##GET_SHORT_ANSWER##) or 4 (##GET_LONG_ANSWER##), made of
504
--
505
-- * an integer, the return status. This is any of:
506
-- ** ##GET_SUCCESS## ~-- object was read successfully
507
-- ** ##GET_EOF## ~-- end of file before object was read completely
508
-- ** ##GET_FAIL## ~-- object is not syntactically correct
509
-- ** ##GET_NOTHING## ~-- nothing was read, even a partial object string, before end of input
510
-- * an object, the value that was read. This is valid only if return status is ##GET_SUCCESS##.
511
-- * an integer, the number of characters read. On an error, this is the point at which the
512
-- error was detected.
513
-- * an integer, the amount of initial whitespace read before the first active character was found
514
--
515
-- Comments:
516
-- When ##answer## is not specified, or explicitly ##GET_SHORT_ANSWER##, only the first two
517
-- elements in the returned sequence are actually returned.
518
--
519
-- The ##GET_NOTHING## return status will not be returned if ##answer## is ##GET_SHORT_ANSWER##.
520
--
521
-- ##get()## can read arbitrarily complicated Euphoria objects. You
522
-- could have a long sequence of values in braces and separated by
523
-- commas and comments, e.g. ##{23, {49, 57}, 0.5, -1, 99, 'A', "john"}##.
524
-- A single call to get() will read in this entire sequence and return its value as a result,
525
-- as well as complementary information.
526
--
527
-- If a nonzero offset is supplied, it is interpreted as an offset to the current file
528
-- position, and the file will be seek()ed there first.
529
--
530
-- ##get()## returns a 2 or 4 element sequence, like ##[[:value]]()## does:
531
--
532
-- * a status code (success/error/end of file/no value at all)
533
-- * the value just read (meaningful only when the status code is ##GET_SUCCESS##)
534
-- (optionally)
535
-- * the total number of characters read
536
-- * the amount of initial whitespace read.
537
--
538
-- Using the default value for answer, or setting it to ##GET_SHORT_ANSWER##, returns 2 elements.
539
-- Setting it to ##GET_LONG_ANSWER## causes 4 elements to be returned.
540
--
541
-- Each call to ##get()## picks up where the previous call left off. For instance, a series of 5
542
-- calls to ##get()## would be needed to read in
543
--
544
-- {{{
545
-- "99 5.2 {1, 2, 3} "Hello" -1"
546
-- }}}
547
--
548
-- On the sixth and any subsequent call to ##get()## you would see a ##GET_EOF## status. If you had
549
-- something like
550
--
551
-- {{{
552
-- {1, 2, xxx}
553
-- }}}
554
--
555
-- in the input stream you would see a ##GET_FAIL## error status because xxx is not a Euphoria
556
-- object. And seeing
557
--
558
-- {{{
559
-- -- something\nBut no value
560
-- }}}
561
--
562
-- and the input stream stops right there, you'll receive a status code of ##GET_NOTHING##,
563
-- because nothing but whitespace or comments was read. If you had opted for a short answer,
564
-- you'd get ##GET_EOF## instead.
565
--
566
-- Multiple "top-level" objects in the input stream must be
567
-- separated from each other with one or more "whitespace"
568
-- characters (blank, tab, \r or \n). At the very least, a top
569
-- level number must be followed by a white space from the following object.
570
-- Whitespace is not necessary //within// a top-level object. Comments, terminated by either
571
-- '\n' or '\r', are allowed anywhere inside sequences, and ignored if at the top level.
572
-- A call to ##get()## will read one entire top-level object, plus possibly one additional
573
-- (whitespace) character, after a top level number, even though the next object may have an
574
-- identifiable starting point.
575
--
576
-- The combination of ##[[:print]]()## and ##get()## can be used to save a
577
-- Euphoria object to disk and later read it back. This technique
578
-- could be used to implement a database as one or more large
579
-- Euphoria sequences stored in disk files. The sequences could be
580
-- read into memory, updated and then written back to disk after
581
-- each series of transactions is complete. Remember to write out
582
-- a whitespace character (using ##[[:puts]]()##) after each call to ##[[:print]]()##,
583
-- at least when a top level number was just printed.
584
--
585
-- The value returned is not meaningful unless you have a ##GET_SUCCESS## status.
586
--
587
-- Example 1:
588
--
589
-- -- If he types 77.5, get(0) would return:
590
-- {GET_SUCCESS, 77.5}
591
--
592
-- -- whereas gets(0) would return:
593
-- "77.5\n"
594
--
595
--
596
-- Example 2:
597
-- See ##bin\mydata.ex##
598
--
599
-- See Also:
600
-- [[:value]]
601
60213
603
-- Read the string representation of a Euphoria object
604
-- from a file. Convert to the value of the object.
605
-- Return {error_status, value}.
606
-- Embedded comments inside sequences are now supported.
60713
return get_value(file, offset, answer)
608
end function
609
610
--**
611
-- Read, from a string, a human-readable string of characters representing a Euphoria object.
612
-- Convert the string into the numeric value of that object.
613
--
614
-- Parameters:
615
-- # ##st## : a sequence, from which to read text
616
-- # ##offset## : an integer, the position at which to start reading. Defaults to 1.
617
-- # ##answer## : an integer, either GET_SHORT_ANSWER (the default) or GET_LONG_ANSWER.
618
--
619
-- Returns:
620
-- A **sequence**, of length 2 (GET_SHORT_ANSWER) or 4 (GET_LONG_ANSWER), made of
621
--
622
-- * an integer, the return status. This is any of
623
-- ** ##GET_SUCCESS## ~-- object was read successfully
624
-- ** ##GET_EOF## ~-- end of file before object was read completely
625
-- ** ##GET_FAIL## ~-- object is not syntactically correct
626
-- ** ##GET_NOTHING## ~-- nothing was read, even a partial object string, before end of input
627
-- * an object, the value that was read. This is valid only if return status is ##GET_SUCCESS##.
628
-- * an integer, the number of characters read. On an error, this is the point at which the
629
-- error was detected.
630
-- * an integer, the amount of initial whitespace read before the first active character was found
631
--
632
-- Comments:
633
-- When ##answer## is not specified, or explicitly ##GET_SHORT_ANSWER##, only the first two
634
-- elements in the returned sequence are actually returned.
635
--
636
-- This works the same as [[:get]](), but it reads from a string that you supply, rather than
637
-- from a file or device.
638
--
639
-- After reading one valid representation of a Euphoria object, ##value()## will stop reading
640
-- and ignore any additional characters in the string. For example, "36" and "36P" will
641
-- both give you ##{GET_SUCCESS, 36}##.
642
--
643
-- The function returns ##{return_status, value}## if the answer type is not passed or set to
644
-- ##GET_SHORT_ANSWER##. If set to ##GET_LONG_ANSWER##, the number of characters read and the
645
-- amount of leading whitespace are returned in 3rd and 4th position. The ##GET_NOTHING## return
646
-- status can occur only on a long answer.
647
--
648
-- Example 1:
649
--
650
-- s = value("12345"}
651
-- s is {GET_SUCCESS, 12345}
652
--
653
--
654
-- Example 2:
655
--
656
-- s = value("{0, 1, -99.9}")
657
-- -- s is {GET_SUCCESS, {0, 1, -99.9}}
658
--
659
--
660
-- Example 3:
661
--
662
-- s = value("+++")
663
-- -- s is {GET_FAIL, 0}
664
--
665
--
666
-- See Also:
667
-- [[:get]]
668
66995
670
-- Read the representation of a Euphoria object
671
-- from a sequence of characters. Convert to the value of the object.
672
-- Trailing whitespace or comments are not considered.
673
-- Return {error_status, value}.
674
-- Embedded comments inside sequence are now supported.
67595
return get_value(st, start_point, answer)
676
end function
677
678
--**
679
-- Perform a value() operation on a sequence, returning the value on success or
680
-- the default on failure.
681
--
682
-- Parameters:
683
-- # ##st## : object to retrieve value from.
684
-- # ##def## : the value returned if ##st## is an atom or ##value(st)## fails.
685
-- # ##start_point## : an integer, the position in ##st## at which to start
686
-- getting the value from. Defaults to 1
687
--
688
-- Returns:
689
-- * If ##st##, is an atom then ##def## is returned.
690
-- * If ##value(st)##, call is a success, then ##value()[2]##, otherwise it will return
691
-- the parameter #def#.
692
--
693
-- Examples:
694
--
695
-- object i = defaulted_value("10", 0)
696
-- -- i is 10
697
--
698
-- i = defaulted_value("abc", 39)
699
-- -- i is 39
700
--
701
-- i = defaulted_value(12, 42)
702
-- -- i is 42
703
--
704
-- i = defaulted_value("{1,2}", 42)
705
-- -- i is {1,2}
706
--
707
--
708
-- See Also:
709
-- [[:value]]
710
--
711
7129
7139
if atom(st) then
7141
return def
715
end if
716
7178
object result = get_value(st,start_point, GET_SHORT_ANSWER)
718
7198
if result[1] = GET_SUCCESS then
7206
return result[2]
721
end if
722
7232
return def
724
end function