OILS / spec / builtin-printf.test.sh View on Github | oils.pub

1286 lines, 689 significant
1## oils_failures_allowed: 0
2## compare_shells: dash bash mksh zsh ash
3
4# printf
5# bash-completion uses this odd printf -v construction. It seems to mostly use
6# %s and %q though.
7#
8# %s should just be
9# declare $var='val'
10#
11# NOTE:
12# /usr/bin/printf %q "'" seems wrong.
13# $ /usr/bin/printf %q "'"
14# ''\'''
15#
16# I suppose it is technically correct, but it looks very ugly.
17
18#### printf with no args
19printf
20## status: 2
21## OK mksh/zsh status: 1
22## stdout-json: ""
23
24#### printf -v %s
25var=foo
26printf -v $var %s 'hello there'
27argv.py "$foo"
28## STDOUT:
29['hello there']
30## END
31## N-I mksh/zsh/ash STDOUT:
32-v['']
33## END
34## N-I dash STDOUT:
35['']
36## END
37
38#### printf -v %q
39val='"quoted" with spaces and \'
40
41# quote 'val' and store it in foo
42printf -v foo %q "$val"
43# then round trip back to eval
44eval "bar=$foo"
45
46# debugging:
47#echo foo="$foo"
48#echo bar="$bar"
49#echo val="$val"
50
51test "$bar" = "$val" && echo OK
52## STDOUT:
53OK
54## END
55## N-I mksh/zsh/ash stdout-json: "-v"
56## N-I mksh/zsh/ash status: 1
57## N-I dash stdout-json: ""
58## N-I dash status: 1
59
60#### printf -v a[1]
61a=(a b c)
62printf -v 'a[1]' %s 'foo'
63echo status=$?
64argv.py "${a[@]}"
65## STDOUT:
66status=0
67['a', 'foo', 'c']
68## END
69## N-I mksh/zsh STDOUT:
70-vstatus=0
71['a', 'b', 'c']
72## END
73## N-I dash/ash stdout-json: ""
74## N-I dash/ash status: 2
75
76#### printf -v syntax error
77printf -v 'a[' %s 'foo'
78echo status=$?
79## STDOUT:
80status=2
81## END
82## N-I ash/mksh/zsh stdout: -vstatus=0
83
84#### dynamic declare instead of %s
85var=foo
86declare $var='hello there'
87argv.py "$foo"
88## STDOUT:
89['hello there']
90## END
91## N-I dash/mksh/ash STDOUT:
92['']
93## END
94
95#### dynamic declare instead of %q
96var=foo
97val='"quoted" with spaces and \'
98# I think this is bash 4.4 only.
99declare $var="${val@Q}"
100echo "$foo"
101## STDOUT:
102'"quoted" with spaces and \'
103## END
104## OK osh STDOUT:
105$'"quoted" with spaces and \\'
106## END
107## N-I dash/ash stdout-json: ""
108## N-I dash/ash status: 2
109## N-I mksh STDOUT:
110
111## END
112## N-I zsh stdout-json: ""
113## N-I zsh status: 1
114
115#### printf -v dynamic scope
116case $SH in mksh|zsh|dash|ash) echo not implemented; exit ;; esac
117# OK so printf is like assigning to a var.
118# printf -v foo %q "$bar" is like
119# foo=${bar@Q}
120dollar='dollar'
121f() {
122 local mylocal=foo
123 printf -v dollar %q '$' # assign foo to a quoted dollar
124 printf -v mylocal %q 'mylocal'
125 echo dollar=$dollar
126 echo mylocal=$mylocal
127}
128echo dollar=$dollar
129echo --
130f
131echo --
132echo dollar=$dollar
133echo mylocal=$mylocal
134## STDOUT:
135dollar=dollar
136--
137dollar=\$
138mylocal=mylocal
139--
140dollar=\$
141mylocal=
142## END
143## OK osh STDOUT:
144dollar=dollar
145--
146dollar='$'
147mylocal=mylocal
148--
149dollar='$'
150mylocal=
151## END
152## N-I dash/ash/mksh/zsh STDOUT:
153not implemented
154## END
155
156#### printf with too few arguments
157printf -- '-%s-%s-%s-\n' 'a b' 'x y'
158## STDOUT:
159-a b-x y--
160## END
161
162#### printf with too many arguments
163printf -- '-%s-%s-\n' a b c d e
164## STDOUT:
165-a-b-
166-c-d-
167-e--
168## END
169
170#### printf width strings
171printf '[%5s]\n' abc
172printf '[%-5s]\n' abc
173## STDOUT:
174[ abc]
175[abc ]
176## END
177
178#### printf integer
179printf '%d\n' 42
180printf '%i\n' 42 # synonym
181printf '%d\n' \'a # if first character is a quote, use character code
182printf '%d\n' \"a # double quotes work too
183printf '[%5d]\n' 42
184printf '[%-5d]\n' 42
185printf '[%05d]\n' 42
186#printf '[%-05d]\n' 42 # the leading 0 is meaningless
187#[42 ]
188## STDOUT:
18942
19042
19197
19297
193[ 42]
194[42 ]
195[00042]
196## END
197
198#### printf %6.4d -- "precision" does padding for integers
199printf '[%6.4d]\n' 42
200printf '[%.4d]\n' 42
201printf '[%6.d]\n' 42
202echo --
203printf '[%6.4d]\n' -42
204printf '[%.4d]\n' -42
205printf '[%6.d]\n' -42
206## STDOUT:
207[ 0042]
208[0042]
209[ 42]
210--
211[ -0042]
212[-0042]
213[ -42]
214## END
215
216#### printf %6.4x X o
217printf '[%6.4x]\n' 42
218printf '[%.4x]\n' 42
219printf '[%6.x]\n' 42
220echo --
221printf '[%6.4X]\n' 42
222printf '[%.4X]\n' 42
223printf '[%6.X]\n' 42
224echo --
225printf '[%6.4o]\n' 42
226printf '[%.4o]\n' 42
227printf '[%6.o]\n' 42
228## STDOUT:
229[ 002a]
230[002a]
231[ 2a]
232--
233[ 002A]
234[002A]
235[ 2A]
236--
237[ 0052]
238[0052]
239[ 52]
240## END
241
242#### %06d zero padding vs. %6.6d
243printf '[%06d]\n' 42
244printf '[%06d]\n' -42 # 6 TOTAL
245echo --
246printf '[%6.6d]\n' 42
247printf '[%6.6d]\n' -42 # 6 + 1 for the - sign!!!
248## STDOUT:
249[000042]
250[-00042]
251--
252[000042]
253[-000042]
254## END
255
256#### %06x %06X %06o
257printf '[%06x]\n' 42
258printf '[%06X]\n' 42
259printf '[%06o]\n' 42
260## STDOUT:
261[00002a]
262[00002A]
263[000052]
264## END
265
266#### %06s is no-op
267printf '(%6s)\n' 42
268printf '(%6s)\n' -42
269printf '(%06s)\n' 42
270printf '(%06s)\n' -42
271echo status=$?
272## STDOUT:
273( 42)
274( -42)
275( 42)
276( -42)
277status=0
278## END
279# mksh is stricter
280## OK mksh STDOUT:
281( 42)
282( -42)
283((status=1
284## END
285
286#### printf %6.4s does both truncation and padding
287printf '[%6s]\n' foo
288printf '[%6.4s]\n' foo
289printf '[%-6.4s]\n' foo
290printf '[%6s]\n' spam-eggs
291printf '[%6.4s]\n' spam-eggs
292printf '[%-6.4s]\n' spam-eggs
293## STDOUT:
294[ foo]
295[ foo]
296[foo ]
297[spam-eggs]
298[ spam]
299[spam ]
300## END
301
302#### printf %6.0s and %0.0s
303printf '[%6.0s]\n' foo
304printf '[%0.0s]\n' foo
305## STDOUT:
306[ ]
307[]
308## END
309## N-I mksh stdout-json: "[ ]\n["
310## N-I mksh status: 1
311
312#### printf %6.s and %0.s
313printf '[%6.s]\n' foo
314printf '[%0.s]\n' foo
315## STDOUT:
316[ ]
317[]
318## END
319## BUG zsh STDOUT:
320[ foo]
321[foo]
322## END
323## N-I mksh stdout-json: "[ ]\n["
324## N-I mksh status: 1
325
326#### printf %*.*s (width/precision from args)
327printf '[%*s]\n' 9 hello
328printf '[%.*s]\n' 3 hello
329printf '[%*.3s]\n' 9 hello
330printf '[%9.*s]\n' 3 hello
331printf '[%*.*s]\n' 9 3 hello
332## STDOUT:
333[ hello]
334[hel]
335[ hel]
336[ hel]
337[ hel]
338## END
339
340#### unsigned / octal / hex
341printf '[%u]\n' 42
342printf '[%o]\n' 42
343printf '[%x]\n' 42
344printf '[%X]\n' 42
345echo
346
347printf '[%X]\n' \'a # if first character is a quote, use character code
348printf '[%X]\n' \'ab # extra chars ignored
349
350## STDOUT:
351[42]
352[52]
353[2a]
354[2A]
355
356[61]
357[61]
358## END
359
360#### unsigned / octal / hex big
361
362for big in $(( 1 << 32 )) $(( (1 << 63) - 1 )); do
363 printf '[%u]\n' $big
364 printf '[%o]\n' $big
365 printf '[%x]\n' $big
366 printf '[%X]\n' $big
367 echo
368done
369
370## STDOUT:
371[4294967296]
372[40000000000]
373[100000000]
374[100000000]
375
376[9223372036854775807]
377[777777777777777777777]
378[7fffffffffffffff]
379[7FFFFFFFFFFFFFFF]
380
381## END
382
383## BUG mksh STDOUT:
384[1]
385[1]
386[1]
387[1]
388
389[2147483647]
390[17777777777]
391[7fffffff]
392[7FFFFFFF]
393
394## END
395
396#### empty string (osh is more strict)
397printf '%d\n' ''
398## OK osh stdout-json: ""
399## OK osh status: 1
400## OK ash status: 1
401## STDOUT:
4020
403## END
404
405#### No char after ' => zero code point
406
407# most shells use 0 here
408printf '%d\n' \'
409printf '%d\n' \"
410
411## OK mksh status: 1
412## STDOUT:
4130
4140
415## END
416
417#### Unicode char with '
418case $SH in mksh) echo 'weird bug'; exit ;; esac
419
420# the mu character is U+03BC
421
422printf '%x\n' \'μ
423printf '%u\n' \'μ
424printf '%o\n' \'μ
425echo
426
427u3=三
428# u4=😘
429
430printf '%x\n' \'$u3
431printf '%u\n' \'$u3
432printf '%o\n' \'$u3
433echo
434
435# mksh DOES respect unicode on the new Debian bookworm.
436# but even building the SAME SOURCE from scratch, somehow it doesn't on Ubuntu 8.
437# TBH I should probably just upgrade the mksh version.
438#
439# $ ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
440# printf: warning: : character(s) following character constant have been ignored
441# 206
442#
443# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ cat /etc/os-release
444# NAME="Ubuntu"
445# VERSION="18.04.5 LTS (Bionic Beaver)"
446# ID=ubuntu
447# ID_LIKE=debian
448# PRETTY_NAME="Ubuntu 18.04.5 LTS"
449# VERSION_ID="18.04"
450# HOME_URL="https://www.ubuntu.com/"
451# SUPPORT_URL="https://help.ubuntu.com/"
452# BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
453# PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
454# VERSION_CODENAME=bionic
455# UBUNTU_CODENAME=bionic
456# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ env|egrep 'LC|LANG'
457# LANG=en_US.UTF-8
458# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LC_CTYPE=C.UTF-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
459# printf: warning: : character(s) following character constant have been ignored
460# 206
461# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LANG=C.UTF-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
462# printf: warning: : character(s) following character constant have been ignored
463# 206
464# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LC_ALL=C.UTF-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
465# printf: warning: : character(s) following character constant have been ignored
466# 206
467# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LC_ALL=en_US.UTF-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
468# printf: warning: : character(s) following character constant have been ignored
469# 206
470# andy@lenny:~/wedge/oils-for-unix.org/pkg/mksh/R52c$ LC_ALL=en_US.utf-8 ./mksh -c 'printf "%u\n" \"$1' dummy $'\u03bc'
471# printf: warning: : character(s) following character constant have been ignored
472# 206
473
474
475## STDOUT:
4763bc
477956
4781674
479
4804e09
48119977
48247011
483
484## END
485## BUG dash/ash STDOUT:
486ce
487206
488316
489
490e4
491228
492344
493
494## END
495
496## BUG mksh STDOUT:
497weird bug
498## END
499
500#### Invalid UTF-8
501
502echo bytes1
503not_utf8=$(python2 -c 'print("\xce\xce")')
504
505printf '%x\n' \'$not_utf8
506printf '%u\n' \'$not_utf8
507printf '%o\n' \'$not_utf8
508echo
509
510echo bytes2
511not_utf8=$(python2 -c 'print("\xbc\xbc")')
512printf '%x\n' \'$not_utf8
513printf '%u\n' \'$not_utf8
514printf '%o\n' \'$not_utf8
515echo
516
517# Copied from data_lang/utf8_test.cc
518
519echo overlong2
520overlong2=$(python2 -c 'print("\xC1\x81")')
521printf '%x\n' \'$overlong2
522printf '%u\n' \'$overlong2
523printf '%o\n' \'$overlong2
524echo
525
526echo overlong3
527overlong3=$(python2 -c 'print("\xE0\x81\x81")')
528printf '%x\n' \'$overlong3
529printf '%u\n' \'$overlong3
530printf '%o\n' \'$overlong3
531echo
532
533## STDOUT:
534bytes1
535ce
536206
537316
538
539bytes2
540bc
541188
542274
543
544overlong2
545c1
546193
547301
548
549overlong3
550e0
551224
552340
553
554## END
555
556
557#### Too large
558case $SH in mksh) echo 'weird bug'; exit ;; esac
559
560echo too large
561too_large=$(python2 -c 'print("\xF4\x91\x84\x91")')
562printf '%x\n' \'$too_large
563printf '%u\n' \'$too_large
564printf '%o\n' \'$too_large
565echo
566
567## STDOUT:
568too large
569111111
5701118481
5714210421
572
573## END
574
575## BUG dash/ash STDOUT:
576too large
577f4
578244
579364
580
581## END
582
583## BUG mksh STDOUT:
584weird bug
585## END
586
587# osh rejects code points that are too large for a DIFFERENT reason
588
589## OK osh STDOUT:
590too large
591f4
592244
593364
594
595## END
596
597
598#### negative numbers with unsigned / octal / hex
599printf '[%u]\n' -42
600echo status=$?
601
602printf '[%o]\n' -42
603echo status=$?
604
605printf '[%x]\n' -42
606echo status=$?
607
608printf '[%X]\n' -42
609echo status=$?
610
611## STDOUT:
612[18446744073709551574]
613status=0
614[1777777777777777777726]
615status=0
616[ffffffffffffffd6]
617status=0
618[FFFFFFFFFFFFFFD6]
619status=0
620## END
621
622# osh DISALLOWS this because the output depends on the machine architecture.
623## N-I osh STDOUT:
624status=1
625status=1
626status=1
627status=1
628## END
629
630#### printf floating point (not required, but they all implement it)
631printf '[%f]\n' 3.14159
632printf '[%.2f]\n' 3.14159
633printf '[%8.2f]\n' 3.14159
634printf '[%-8.2f]\n' 3.14159
635printf '[%-f]\n' 3.14159
636printf '[%-f]\n' 3.14
637## STDOUT:
638[3.141590]
639[3.14]
640[ 3.14]
641[3.14 ]
642[3.141590]
643[3.140000]
644## END
645## N-I osh stdout-json: ""
646## N-I osh status: 2
647
648#### printf floating point with - and 0
649printf '[%8.4f]\n' 3.14
650printf '[%08.4f]\n' 3.14
651printf '[%8.04f]\n' 3.14 # meaning less 0
652printf '[%08.04f]\n' 3.14
653echo ---
654# these all boil down to the same thing. The -, 8, and 4 are respected, but
655# none of the 0 are.
656printf '[%-8.4f]\n' 3.14
657printf '[%-08.4f]\n' 3.14
658printf '[%-8.04f]\n' 3.14
659printf '[%-08.04f]\n' 3.14
660## STDOUT:
661[ 3.1400]
662[003.1400]
663[ 3.1400]
664[003.1400]
665---
666[3.1400 ]
667[3.1400 ]
668[3.1400 ]
669[3.1400 ]
670## END
671## N-I osh STDOUT:
672---
673## END
674## N-I osh status: 2
675
676#### printf eE fF gG
677printf '[%e]\n' 3.14
678printf '[%E]\n' 3.14
679printf '[%f]\n' 3.14
680# bash is the only one that implements %F? Is it a synonym?
681#printf '[%F]\n' 3.14
682printf '[%g]\n' 3.14
683printf '[%G]\n' 3.14
684## STDOUT:
685[3.140000e+00]
686[3.140000E+00]
687[3.140000]
688[3.14]
689[3.14]
690## END
691## N-I osh stdout-json: ""
692## N-I osh status: 2
693
694#### printf backslash escapes
695argv.py "$(printf 'a\tb')"
696argv.py "$(printf '\xE2\x98\xA0')"
697argv.py "$(printf '\044e')"
698argv.py "$(printf '\0377')" # out of range
699## STDOUT:
700['a\tb']
701['\xe2\x98\xa0']
702['$e']
703['\x1f7']
704## END
705## N-I dash STDOUT:
706['a\tb']
707['\\xE2\\x98\\xA0']
708['$e']
709['\x1f7']
710## END
711
712#### printf octal backslash escapes
713argv.py "$(printf '\0377')"
714argv.py "$(printf '\377')"
715## STDOUT:
716['\x1f7']
717['\xff']
718## END
719
720#### printf unicode backslash escapes
721argv.py "$(printf '\u2620')"
722argv.py "$(printf '\U0000065f')"
723## STDOUT:
724['\xe2\x98\xa0']
725['\xd9\x9f']
726## END
727## N-I dash/ash STDOUT:
728['\\u2620']
729['\\U0000065f']
730## END
731
732#### printf invalid backslash escape (is ignored)
733printf '[\Z]\n'
734## STDOUT:
735[\Z]
736## END
737
738#### printf % escapes
739printf '[%%]\n'
740## STDOUT:
741[%]
742## END
743
744#### printf %b backslash escaping
745printf '[%s]\n' '\044' # escapes not evaluated
746printf '[%b]\n' '\044' # YES, escapes evaluated
747echo status=$?
748## STDOUT:
749[\044]
750[$]
751status=0
752## END
753
754#### printf %b with \c early return
755printf '[%b]\n' 'ab\ncd\cxy'
756echo $?
757## STDOUT:
758[ab
759cd0
760## END
761
762#### printf %c -- doesn't respect UTF-8! Bad.
763twomu=$'\u03bc\u03bc'
764printf '[%s]\n' "$twomu"
765printf '%c' "$twomu" | wc --bytes
766## STDOUT:
767[μμ]
7681
769## END
770## N-I dash STDOUT:
771[$\u03bc\u03bc]
7721
773## END
774## N-I ash STDOUT:
775[\u03bc\u03bc]
7761
777## END
778## N-I osh STDOUT:
779[μμ]
7800
781## END
782
783#### printf invalid format
784printf '%z' 42
785echo status=$?
786printf '%-z' 42
787echo status=$?
788## STDOUT:
789status=1
790status=1
791## END
792# osh emits parse errors
793## OK dash/osh STDOUT:
794status=2
795status=2
796## END
797
798#### printf %q
799x='a b'
800printf '[%q]\n' "$x"
801## STDOUT:
802['a b']
803## END
804## OK bash/zsh STDOUT:
805[a\ b]
806## END
807## N-I ash/dash stdout-json: "["
808## N-I ash status: 1
809## N-I dash status: 2
810
811#### printf %6q (width)
812# NOTE: coreutils /usr/bin/printf does NOT implement this %6q !!!
813x='a b'
814printf '[%6q]\n' "$x"
815printf '[%1q]\n' "$x"
816## STDOUT:
817[ 'a b']
818['a b']
819## END
820## OK bash/zsh STDOUT:
821[ a\ b]
822[a\ b]
823## END
824## N-I mksh/ash/dash stdout-json: "[["
825## N-I mksh/ash status: 1
826## N-I dash status: 2
827
828#### printf negative numbers
829printf '[%d] ' -42
830echo status=$?
831printf '[%i] ' -42
832echo status=$?
833
834# extra LEADING space too
835printf '[%d] ' ' -42'
836echo status=$?
837printf '[%i] ' ' -42'
838echo status=$?
839
840# extra TRAILING space too
841printf '[%d] ' ' -42 '
842echo status=$?
843printf '[%i] ' ' -42 '
844echo status=$?
845
846# extra TRAILING chars
847printf '[%d] ' ' -42z'
848echo status=$?
849printf '[%i] ' ' -42z'
850echo status=$?
851
852exit 0 # ok
853
854## STDOUT:
855[-42] status=0
856[-42] status=0
857[-42] status=0
858[-42] status=0
859[-42] status=1
860[-42] status=1
861[-42] status=1
862[-42] status=1
863## END
864# zsh is LESS STRICT
865## OK zsh STDOUT:
866[-42] status=0
867[-42] status=0
868[-42] status=0
869[-42] status=0
870[-42] status=0
871[-42] status=0
872[0] status=1
873[0] status=1
874## END
875
876# osh is like zsh but has a hard failure (TODO: could be an option?)
877## OK osh STDOUT:
878[-42] status=0
879[-42] status=0
880[-42] status=0
881[-42] status=0
882[-42] status=0
883[-42] status=0
884status=1
885status=1
886## END
887
888# ash is MORE STRICT
889## OK ash STDOUT:
890[-42] status=0
891[-42] status=0
892[-42] status=0
893[-42] status=0
894[0] status=1
895[0] status=1
896[0] status=1
897[0] status=1
898## END
899
900
901#### printf + and space flags
902# I didn't know these existed -- I only knew about - and 0 !
903printf '[%+d]\n' 42
904printf '[%+d]\n' -42
905printf '[% d]\n' 42
906printf '[% d]\n' -42
907## STDOUT:
908[+42]
909[-42]
910[ 42]
911[-42]
912## END
913## N-I osh stdout-json: ""
914## N-I osh status: 2
915
916#### printf # flag
917# I didn't know these existed -- I only knew about - and 0 !
918# Note: '#' flag for integers outputs a prefix ONLY WHEN the value is non-zero
919printf '[%#o][%#o]\n' 0 42
920printf '[%#x][%#x]\n' 0 42
921printf '[%#X][%#X]\n' 0 42
922echo ---
923# Note: '#' flag for %f, %g always outputs the decimal point.
924printf '[%.0f][%#.0f]\n' 3 3
925# Note: In addition, '#' flag for %g does not omit zeroes in fraction
926printf '[%g][%#g]\n' 3 3
927## STDOUT:
928[0][052]
929[0][0x2a]
930[0][0X2A]
931---
932[3][3.]
933[3][3.00000]
934## END
935## N-I osh STDOUT:
936---
937## END
938## N-I osh status: 2
939
940#### Runtime error for invalid integer
941x=3abc
942printf '%d\n' $x
943echo status=$?
944printf '%d\n' xyz
945echo status=$?
946## STDOUT:
9473
948status=1
9490
950status=1
951## END
952# zsh should exit 1 in both cases
953## BUG zsh STDOUT:
9540
955status=1
9560
957status=0
958## END
959# fails but also prints 0 instead of 3abc
960## BUG ash STDOUT:
9610
962status=1
9630
964status=1
965## END
966# osh doesn't print anything invalid
967## OK osh STDOUT:
968status=1
969status=1
970## END
971
972#### %(strftime format)T
973# The result depends on timezone
974export TZ=Asia/Tokyo
975printf '%(%Y-%m-%d)T\n' 1557978599
976export TZ=US/Eastern
977printf '%(%Y-%m-%d)T\n' 1557978599
978echo status=$?
979## STDOUT:
9802019-05-16
9812019-05-15
982status=0
983## END
984## N-I mksh/zsh/ash STDOUT:
985status=1
986## END
987## N-I dash STDOUT:
988status=2
989## END
990
991#### %(strftime format)T doesn't respect TZ if not exported
992
993# note: this test leaks! It assumes that /etc/localtime is NOT Portugal.
994
995TZ=Portugal # NOT exported
996localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
997
998# TZ is respected
999export TZ=Portugal
1000tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
1001
1002#echo $localtime
1003#echo $tz
1004
1005if ! test "$localtime" = "$tz"; then
1006 echo 'not equal'
1007fi
1008## STDOUT:
1009not equal
1010## END
1011## N-I mksh/zsh/ash/dash stdout-json: ""
1012
1013#### %(strftime format)T TZ in environ but not in shell's memory
1014
1015# note: this test leaks! It assumes that /etc/localtime is NOT Portugal.
1016
1017# TZ is respected
1018export TZ=Portugal
1019tz=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
1020
1021unset TZ # unset in the shell, but still in the environment
1022
1023localtime=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' 1557978599)
1024
1025if ! test "$localtime" = "$tz"; then
1026 echo 'not equal'
1027fi
1028
1029## STDOUT:
1030not equal
1031## END
1032## N-I mksh/zsh/ash/dash stdout-json: ""
1033
1034#### %10.5(strftime format)T
1035# The result depends on timezone
1036export TZ=Asia/Tokyo
1037printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
1038export TZ=US/Eastern
1039printf '[%10.5(%Y-%m-%d)T]\n' 1557978599
1040echo status=$?
1041## STDOUT:
1042[ 2019-]
1043[ 2019-]
1044status=0
1045## END
1046## N-I mksh/zsh/ash STDOUT:
1047[[status=1
1048## END
1049## N-I dash STDOUT:
1050[[status=2
1051## END
1052
1053#### Regression for 'printf x y'
1054printf x y
1055printf '%s\n' z
1056## STDOUT:
1057xz
1058## END
1059
1060#### bash truncates long strftime string at 128
1061
1062case $SH in (ash|dash|mksh|zsh) exit ;; esac
1063
1064strftime-format() {
1065 local n=$1
1066
1067 # Prints increasingly long format strings:
1068 # %(%Y)T %(%Y)T %(%Y%Y)T ...
1069
1070 echo -n '%('
1071 for i in $(seq $n); do
1072 echo -n '%Y'
1073 done
1074 echo -n ')T'
1075}
1076
1077printf $(strftime-format 1) | wc --bytes
1078printf $(strftime-format 10) | wc --bytes
1079printf $(strftime-format 30) | wc --bytes
1080printf $(strftime-format 31) | wc --bytes
1081printf $(strftime-format 32) | wc --bytes
1082
1083case $SH in
1084 (*/_bin/cxx-dbg/*)
1085 # Ensure that oils-for-unix detects the truncation of a fixed buffer.
1086 # bash has a buffer of 128.
1087
1088 set +o errexit
1089 (
1090 printf $(strftime-format 1000)
1091 )
1092 status=$?
1093 if test $status -ne 1; then
1094 echo FAIL
1095 fi
1096 ;;
1097esac
1098
1099## STDOUT:
11004
110140
1102120
1103124
11040
1105## END
1106## OK osh STDOUT:
11074
110840
1109120
1110124
1111128
1112## END
1113
1114## N-I ash/dash/mksh/zsh STDOUT:
1115## END
1116
1117
1118#### printf with explicit NUL byte
1119case $SH in (dash|ash) return ;; esac
1120
1121printf $'x\U0z'
1122
1123printf $'\U0z'
1124
1125## stdout-json: "x"
1126## OK zsh stdout-repr: "x\0z\0z"
1127## N-I dash/ash stdout-json: ""
1128
1129#### printf positive integer overflow
1130
1131# %i seems like a synonym for %d
1132
1133for fmt in '%u\n' '%d\n'; do
1134 # bash considers this in range for %u
1135 # same with mksh
1136 # zsh cuts everything off after 19 digits
1137 # ash truncates everything
1138 printf "$fmt" '18446744073709551615'
1139 echo status=$?
1140 printf "$fmt" '18446744073709551616'
1141 echo status=$?
1142 echo
1143done
1144
1145## STDOUT:
1146status=1
1147status=1
1148
1149status=1
1150status=1
1151
1152## END
1153
1154## OK bash status: 0
1155## OK bash STDOUT:
115618446744073709551615
1157status=0
115818446744073709551615
1159status=0
1160
11619223372036854775807
1162status=0
11639223372036854775807
1164status=0
1165
1166## END
1167
1168## OK dash/mksh status: 0
1169## OK dash/mksh STDOUT:
117018446744073709551615
1171status=0
117218446744073709551615
1173status=1
1174
11759223372036854775807
1176status=1
11779223372036854775807
1178status=1
1179
1180## END
1181
1182## BUG ash status: 0
1183## BUG ash STDOUT:
118418446744073709551615
1185status=0
11860
1187status=1
1188
11890
1190status=1
11910
1192status=1
1193
1194## END
1195
1196## BUG zsh status: 0
1197## BUG zsh STDOUT:
11981844674407370955161
1199status=0
12001844674407370955161
1201status=0
1202
12031844674407370955161
1204status=0
12051844674407370955161
1206status=0
1207
1208## END
1209
1210#### printf negative integer overflow
1211
1212# %i seems like a synonym for %d
1213
1214for fmt in '%u\n' '%d\n'; do
1215
1216 printf "$fmt" '-18446744073709551615'
1217 echo status=$?
1218 printf "$fmt" '-18446744073709551616'
1219 echo status=$?
1220 echo
1221done
1222
1223## STDOUT:
1224status=1
1225status=1
1226
1227status=1
1228status=1
1229
1230## END
1231
1232## OK bash status: 0
1233## OK bash STDOUT:
12341
1235status=0
123618446744073709551615
1237status=0
1238
1239-9223372036854775808
1240status=0
1241-9223372036854775808
1242status=0
1243
1244## END
1245
1246## OK dash/mksh status: 0
1247## OK dash/mksh STDOUT:
12481
1249status=0
125018446744073709551615
1251status=1
1252
1253-9223372036854775808
1254status=1
1255-9223372036854775808
1256status=1
1257
1258## END
1259
1260## BUG zsh status: 0
1261## BUG zsh STDOUT:
126216602069666338596455
1263status=0
126416602069666338596455
1265status=0
1266
1267-1844674407370955161
1268status=0
1269-1844674407370955161
1270status=0
1271
1272## END
1273
1274## BUG ash status: 0
1275## BUG ash STDOUT:
12760
1277status=1
12780
1279status=1
1280
12810
1282status=1
12830
1284status=1
1285
1286## END