1 # Oil builtins
2
3 #### append onto a=(1 2)
4 shopt -s parse_at
5 a=(1 2)
6 append :a '3 4' '5'
7 argv.py @a
8 append -- :a 6
9 argv.py @a
10 ## STDOUT:
11 ['1', '2', '3 4', '5']
12 ['1', '2', '3 4', '5', '6']
13 ## END
14
15 #### append onto var a = %(1 2)
16 shopt -s parse_at parse_proc
17 var a = %(1 2)
18 append a '3 4' '5' # : is optional
19 argv.py @a
20 ## STDOUT:
21 ['1', '2', '3 4', '5']
22 ## END
23
24 #### append onto var a = ['1', '2']
25 shopt -s parse_at parse_proc
26 var a = ['1', '2']
27 append a '3 4' '5' # : is optional
28 argv.py @a
29 ## STDOUT:
30 ['1', '2', '3 4', '5']
31 ## END
32
33 #### append with invalid type
34 s=''
35 append :s a b
36 echo status=$?
37 ## stdout: status=1
38
39 #### append with invalid var name
40 append - a b
41 echo status=$?
42 ## stdout: status=2
43
44 #### write --sep, --end, -n, varying flag syntax
45 shopt -s oil:all
46 var a = %('a b' 'c d')
47 write @a
48 write .
49 write -- @a
50 write .
51
52 write --sep '' --end '' @a; write
53 write .
54
55 write --sep '_' -- @a
56 write --sep '_' --end $' END\n' -- @a
57
58 # with =
59 write --sep='_' --end=$' END\n' -- @a
60
61 write -n x
62 write -n y
63 write
64
65 ## STDOUT:
66 a b
67 c d
68 .
69 a b
70 c d
71 .
72 a bc d
73 .
74 a b_c d
75 a b_c d END
76 a b_c d END
77 xy
78 ## END
79
80 #### write --qsn
81 write --qsn foo bar
82 write __
83
84 write --qsn 'abc def' ' 123 456'
85 write __
86
87 write --qsn $'one\ttwo\n'
88
89 write __
90 write --qsn $'\u{3bc}'
91
92
93 ## STDOUT:
94 foo
95 bar
96 __
97 'abc def'
98 ' 123 456'
99 __
100 'one\ttwo\n'
101 __
102 'μ'
103 ## END
104
105
106 #### write --qsn --unicode
107 write --qsn $'\u{3bc}'
108 write --qsn --unicode u $'\u{3bc}'
109 write --qsn --unicode x $'\u{3bc}'
110
111 ## STDOUT:
112 'μ'
113 '\u{3bc}'
114 '\xce\xbc'
115 ## END
116
117 #### write -e not supported
118 shopt -s oil:all
119 write -e foo
120 write status=$?
121 ## stdout-json: ""
122 ## status: 2
123
124 #### write syntax error
125 shopt -s oil:all
126 write ---end foo
127 write status=$?
128 ## stdout-json: ""
129 ## status: 2
130
131 #### write --
132 shopt -s oil:all
133 write --
134 # This is annoying
135 write -- --
136 write done
137
138 # this is a syntax error! Doh.
139 write ---
140 ## status: 2
141 ## STDOUT:
142
143 --
144 done
145 ## END
146
147 #### read flag usage
148 read --lin
149 echo status=$?
150
151 read --line :var extra
152 echo status=$?
153 ## STDOUT:
154 status=2
155 status=2
156 ## END
157
158 #### read :x :y is allowed
159 shopt --set parse_proc
160
161 echo 'foo bar' | read :x :y
162 echo x=$x y=$y
163
164 proc p {
165 # If these aren't here, it will LEAK because 'read' uses DYNAMIC SCOPE.
166 # TODO: Change semantics of : to be enforce that a local exists too?
167 var x = ''
168 var y = ''
169 echo 'spam eggs' | read x :y # OPTIONAL
170 echo x=$x y=$y
171 }
172 p
173
174 echo x=$x y=$y
175
176 ## STDOUT:
177 x=foo y=bar
178 x=spam y=eggs
179 x=foo y=bar
180 ## END
181
182 #### Idiom for returning 'read'
183 shopt --set parse_proc
184
185 proc p(:out) {
186 #var tmp = ''
187
188 # We can't do read :out in Oil. I think that's OK -- there's consistency in
189 # using setref everywhere.
190 echo foo | read :tmp
191 setref out = tmp
192 }
193 p :z
194 echo z=$z
195 ## STDOUT:
196 z=foo
197 ## END
198
199 #### read --line --with-eol
200 shopt -s oil:upgrade
201
202 # Hm this preserves the newline?
203 seq 3 | while read --line {
204 write line=$_line # implisict
205 }
206 write a b | while read --line --with-eol :myline {
207 write --end '' line=$myline
208 }
209 ## STDOUT:
210 line=1
211 line=2
212 line=3
213 line=a
214 line=b
215 ## END
216
217 #### read --line --qsn
218 read --line --qsn <<EOF
219 'foo\n'
220 EOF
221 write --qsn -- "$_line"
222
223 read --line --qsn <<EOF
224 'foo\tbar hex=\x01 mu=\u{3bc}'
225 EOF
226 write --qsn --unicode u -- "$_line"
227
228 echo '$' | read --line --qsn
229 write --qsn -- "$_line"
230
231 ## STDOUT:
232 'foo\n'
233 'foo\tbar hex=\u{1} mu=\u{3bc}'
234 '$'
235 ## END
236
237 #### read --line --qsn accepts optional $''
238
239 # PROBLEM: is it limited to $' ? What about $3.99 ?
240 # I think you just check for those 2 chars
241
242 echo $'$\'foo\'' | read --line --qsn
243 write -- "$_line"
244 ## STDOUT:
245 foo
246 ## END
247
248 #### read --line --with-eol --qsn
249
250 # whitespace is allowed after closing single quote; it doesn't make a
251 # difference.
252
253 read --line --with-eol --qsn <<EOF
254 'foo\n'
255 EOF
256 write --qsn -- "$_line"
257 ## STDOUT:
258 'foo\n'
259 ## END
260
261 #### read --qsn usage
262 read --qsn << EOF
263 foo
264 EOF
265 echo status=$?
266
267 ## STDOUT:
268 status=2
269 ## END
270
271 #### read --all-lines
272 seq 3 | read --all-lines :nums
273 write --sep ' ' -- @nums
274 ## STDOUT:
275 1 2 3
276 ## END
277
278 #### read --all-lines --with-eol
279 seq 3 | read --all-lines --with-eol :nums
280 write --sep '' -- @nums
281 ## STDOUT:
282 1
283 2
284 3
285 ## END
286
287 #### read --all-lines --qsn --with-eol
288 read --all-lines --qsn --with-eol :lines << EOF
289 foo
290 bar
291 'one\ntwo'
292 EOF
293 write --sep '' -- @lines
294 ## STDOUT:
295 foo
296 bar
297 one
298 two
299 ## END
300
301 #### read --all
302 echo foo | read --all
303 echo "[$_all]"
304
305 echo bad > tmp.txt
306 read --all :x < tmp.txt
307 echo "[$x]"
308
309 ## STDOUT:
310 [foo
311 ]
312 [bad
313 ]
314 ## END
315
316 #### read --line from directory is an error (EISDIR)
317 mkdir -p ./dir
318 read --line < ./dir
319 echo status=$?
320 ## STDOUT:
321 status=1
322 ## END
323
324 #### read --all from directory is an error (EISDIR)
325 mkdir -p ./dir
326 read --all < ./dir
327 echo status=$?
328 ## STDOUT:
329 status=1
330 ## END
331
332 #### read -0 is like read -r -d ''
333 set -o errexit
334
335 mkdir -p read0
336 cd read0
337 touch a\\b\\c\\d
338
339 find . -type f -a -print0 | read -r -d '' name
340 echo "[$name]"
341
342 find . -type f -a -print0 | read -0
343 echo "[$REPLY]"
344
345 ## STDOUT:
346 [./a\b\c\d]
347 [./a\b\c\d]
348 ## END
349
350 #### simple_test_builtin
351
352 test -n "foo"
353 echo status=$?
354
355 test -n "foo" -a -n "bar"
356 echo status=$?
357
358 [ -n foo ]
359 echo status=$?
360
361 shopt --set oil:all
362 shopt --unset errexit
363
364 test -n "foo" -a -n "bar"
365 echo status=$?
366
367 [ -n foo ]
368 echo status=$?
369
370 test -z foo
371 echo status=$?
372
373 ## STDOUT:
374 status=0
375 status=0
376 status=0
377 status=2
378 status=2
379 status=1
380 ## END
381
382 #### long flags to test
383 # no options necessary!
384
385 test --dir /
386 echo status=$?
387
388 touch foo
389 test --file foo
390 echo status=$?
391
392 test --exists /
393 echo status=$?
394
395 test --symlink foo
396 echo status=$?
397
398 test --typo foo
399 echo status=$?
400
401 ## STDOUT:
402 status=0
403 status=0
404 status=0
405 status=1
406 status=2
407 ## END
408
409
410 #### push-registers
411 shopt --set oil:upgrade
412 shopt --unset errexit
413
414 status_code() {
415 return $1
416 }
417
418 [[ foo =~ (.*) ]]
419
420 status_code 42
421 push-registers {
422 status_code 43
423 echo status=$?
424
425 [[ bar =~ (.*) ]]
426 echo ${BASH_REMATCH[@]}
427 }
428 # WEIRD SEMANTIC TO REVISIT: push-registers is "SILENT" as far as exit code
429 # This is for the headless shell, but hasn't been tested.
430 # Better method: maybe we should provide a way of SETTING $?
431
432 echo status=$?
433
434 echo ${BASH_REMATCH[@]}
435 ## STDOUT:
436 status=43
437 bar bar
438 status=42
439 foo foo
440 ## END
441
442 #### push-registers usage
443 shopt --set parse_brace
444
445 push-registers
446 echo status=$?
447
448 push-registers a b
449 echo status=$?
450
451 push-registers a b { # hm extra args are ignored
452 echo hi
453 }
454 echo status=$?
455
456 ## STDOUT:
457 status=2
458 status=2
459 hi
460 status=0
461 ## END
462
463
464 #### module
465 shopt --set oil:upgrade
466
467 module 'main' || return 0
468 source $REPO_ROOT/spec/testdata/module/common.oil
469 source $REPO_ROOT/spec/testdata/module/module1.oil
470 ## STDOUT:
471 common
472 module1
473 ## END
474
475
476 #### runproc
477 shopt --set parse_proc
478
479 f() {
480 write -- f "$@"
481 }
482 proc p {
483 write -- p "$@"
484 }
485 runproc f 1 2
486 echo status=$?
487
488 runproc p 3 4
489 echo status=$?
490
491 runproc invalid 5 6
492 echo status=$?
493
494 runproc
495 echo status=$?
496
497 ## STDOUT:
498 f
499 1
500 2
501 status=0
502 p
503 3
504 4
505 status=0
506 status=1
507 status=2
508 ## END
509
510 #### runproc typed args
511 shopt --set parse_brace parse_proc
512
513 proc p {
514 echo hi
515 }
516
517 # The block is ignored for now
518 runproc p {
519 echo myblock
520 }
521 ## STDOUT:
522 hi
523 ## END
524
525
526 #### fopen
527 shopt --set parse_brace parse_proc
528
529 proc p {
530 echo 'proc'
531 }
532
533 fopen >out.txt {
534 p
535 echo 'builtin'
536 }
537
538 cat out.txt
539
540 echo ---
541
542 fopen <out.txt {
543 tac
544 }
545
546 # Awkward bash syntax, but we'll live with it
547 fopen {left}>left.txt {right}>right.txt {
548 echo 1 >& $left
549 echo 1 >& $right
550
551 echo 2 >& $left
552 echo 2 >& $right
553
554 echo 3 >& $left
555 }
556
557 echo ---
558 comm -23 left.txt right.txt
559
560 ## STDOUT:
561 proc
562 builtin
563 ---
564 builtin
565 proc
566 ---
567 3
568 ## END