xref: /openbsd-src/lib/libc/stdio/printf.3 (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1.\"	$OpenBSD: printf.3,v 1.64 2013/07/17 05:42:11 schwarze Exp $
2.\"
3.\" Copyright (c) 1990, 1991, 1993
4.\"	The Regents of the University of California.  All rights reserved.
5.\"
6.\" This code is derived from software contributed to Berkeley by
7.\" Chris Torek and the American National Standards Committee X3,
8.\" on Information Processing Systems.
9.\"
10.\" Redistribution and use in source and binary forms, with or without
11.\" modification, are permitted provided that the following conditions
12.\" are met:
13.\" 1. Redistributions of source code must retain the above copyright
14.\"    notice, this list of conditions and the following disclaimer.
15.\" 2. Redistributions in binary form must reproduce the above copyright
16.\"    notice, this list of conditions and the following disclaimer in the
17.\"    documentation and/or other materials provided with the distribution.
18.\" 3. Neither the name of the University nor the names of its contributors
19.\"    may be used to endorse or promote products derived from this software
20.\"    without specific prior written permission.
21.\"
22.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32.\" SUCH DAMAGE.
33.\"
34.\"     @(#)printf.3	8.1 (Berkeley) 6/4/93
35.\"
36.Dd $Mdocdate: July 17 2013 $
37.Dt PRINTF 3
38.Os
39.Sh NAME
40.Nm printf ,
41.Nm fprintf ,
42.Nm sprintf ,
43.Nm snprintf ,
44.Nm asprintf ,
45.Nm dprintf ,
46.Nm vprintf ,
47.Nm vfprintf ,
48.Nm vsprintf ,
49.Nm vsnprintf ,
50.Nm vasprintf ,
51.Nm vdprintf
52.Nd formatted output conversion
53.Sh SYNOPSIS
54.In stdio.h
55.Ft int
56.Fn printf "const char *format" ...
57.Ft int
58.Fn fprintf "FILE *stream" "const char *format" ...
59.Ft int
60.Fn sprintf "char *str" "const char *format" ...
61.Ft int
62.Fn snprintf "char *str" "size_t size" "const char *format" ...
63.Ft int
64.Fn asprintf "char **ret" "const char *format" ...
65.Ft int
66.Fn dprintf "int fd" "const char * restrict format" ...
67.In stdarg.h
68.In stdio.h
69.Ft int
70.Fn vprintf "const char *format" "va_list ap"
71.Ft int
72.Fn vfprintf "FILE *stream" "const char *format" "va_list ap"
73.Ft int
74.Fn vsprintf "char *str" "const char *format" "va_list ap"
75.Ft int
76.Fn vsnprintf "char *str" "size_t size" "const char *format" "va_list ap"
77.Ft int
78.Fn vasprintf "char **ret" "const char *format" "va_list ap"
79.Ft int
80.Fn vdprintf "int fd" "const char * restrict format" "va_list ap"
81.Sh DESCRIPTION
82The
83.Fn printf
84family of functions produce output according to the given
85.Fa format
86as described below.
87This format may contain
88.Dq conversion specifiers ;
89the results of such conversions, if any, depend on the arguments
90following the
91.Fa format
92string.
93.Pp
94The
95.Fn printf
96and
97.Fn vprintf
98functions write output to the standard output stream,
99.Em stdout ;
100.Fn fprintf
101and
102.Fn vfprintf
103write output to the supplied stream pointer
104.Fa stream ;
105.Fn dprintf
106and
107.Fn vdprintf
108write output to the given file descriptor;
109.Fn sprintf ,
110.Fn snprintf ,
111.Fn vsprintf ,
112and
113.Fn vsnprintf
114write to the character string
115.Fa str ;
116.Fn asprintf
117and
118.Fn vasprintf
119write to a dynamically allocated string that is stored in
120.Fa ret .
121.Pp
122These functions write the output under the control of a
123.Fa format
124string that specifies how subsequent arguments
125(or arguments accessed via the variable-length argument facilities of
126.Xr stdarg 3 )
127are converted for output.
128.Pp
129.Fn snprintf
130and
131.Fn vsnprintf
132will write at most
133.Fa size Ns \-1
134of the characters printed into the output string
135(the
136.Fa size Ns 'th
137character then gets the terminating
138.Ql \e0 ) ;
139if the return value is greater than or equal to the
140.Fa size
141argument, the string was too short
142and some of the printed characters were discarded.
143If
144.Fa size
145is zero,
146.Fa str
147may be a null pointer and no characters will be written;
148the number of bytes that would have been written excluding the terminating
149.Ql \e0
150byte, or \-1 on error, will be returned.
151.Pp
152.Fn sprintf
153and
154.Fn vsprintf
155effectively assume an infinite
156.Fa size .
157.Pp
158The format string is composed of zero or more directives:
159ordinary
160.\" multibyte
161characters (not
162.Cm % ) ,
163which are copied unchanged to the output stream,
164and conversion specifications, each of which results
165in fetching zero or more subsequent arguments.
166Each conversion specification is introduced by the character
167.Cm % .
168The arguments must correspond properly (after type promotion)
169with the conversion specifier.
170After the
171.Cm % ,
172the following appear in sequence:
173.Bl -bullet
174.It
175An optional field, consisting of a decimal digit string followed by a
176.Cm $
177specifying the next argument to access.
178If this field is not provided, the argument following the last
179argument accessed will be used.
180Arguments are numbered starting at
181.Cm 1 .
182.It
183Zero or more of the following flags:
184.Bl -hyphen
185.It
186A hash
187.Sq Cm #
188character
189specifying that the value should be converted to an ``alternate form''.
190For
191.Cm c ,
192.Cm d ,
193.Cm i ,
194.Cm n ,
195.Cm p ,
196.Cm s ,
197and
198.Cm u
199conversions, this option has no effect.
200For
201.Cm o
202conversions, the precision of the number is increased to force the first
203character of the output string to a zero (except if a zero value is printed
204with an explicit precision of zero).
205For
206.Cm x
207and
208.Cm X
209conversions, a non-zero result has the string
210.Ql 0x
211(or
212.Ql 0X
213for
214.Cm X
215conversions) prepended to it.
216For
217.Cm a ,
218.Cm A ,
219.Cm e ,
220.Cm E ,
221.Cm f ,
222.Cm F ,
223.Cm g ,
224and
225.Cm G
226conversions, the result will always contain a decimal point, even if no
227digits follow it (normally, a decimal point appears in the results of
228those conversions only if a digit follows).
229For
230.Cm g
231and
232.Cm G
233conversions, trailing zeros are not removed from the result as they
234would otherwise be.
235.It
236A zero
237.Sq Cm \&0
238character specifying zero padding.
239For all conversions except
240.Cm n ,
241the converted value is padded on the left with zeros rather than blanks.
242If a precision is given with a numeric conversion
243.Pf ( Cm d ,
244.Cm i ,
245.Cm o ,
246.Cm u ,
247.Cm x ,
248and
249.Cm X ) ,
250the
251.Sq Cm \&0
252flag is ignored.
253.It
254A negative field width flag
255.Sq Cm \-
256indicates the converted value is to be left adjusted on the field boundary.
257Except for
258.Cm n
259conversions, the converted value is padded on the right with blanks,
260rather than on the left with blanks or zeros.
261A
262.Sq Cm \-
263overrides a
264.Sq Cm \&0
265if both are given.
266.It
267A space, specifying that a blank should be left before a positive number
268produced by a signed conversion
269.Pf ( Cm d ,
270.Cm a ,
271.Cm A ,
272.Cm e ,
273.Cm E ,
274.Cm f ,
275.Cm F ,
276.Cm g ,
277.Cm G ,
278or
279.Cm i ) .
280.It
281A
282.Sq Cm +
283character specifying that a sign always be placed before a
284number produced by a signed conversion.
285A
286.Sq Cm +
287overrides a space if both are used.
288.El
289.It
290An optional decimal digit string specifying a minimum field width.
291If the converted value has fewer characters than the field width, it will
292be padded with spaces on the left (or right, if the left-adjustment
293flag has been given) to fill out
294the field width.
295.It
296An optional precision, in the form of a period
297.Sq Cm \&.
298followed by an
299optional digit string.
300If the digit string is omitted, the precision is taken as zero.
301This gives the minimum number of digits to appear for
302.Cm d ,
303.Cm i ,
304.Cm o ,
305.Cm u ,
306.Cm x ,
307and
308.Cm X
309conversions, the number of digits to appear after the decimal-point for
310.Cm a ,
311.Cm A ,
312.Cm e ,
313.Cm E ,
314.Cm f ,
315and
316.Cm F
317conversions, the maximum number of significant digits for
318.Cm g
319and
320.Cm G
321conversions, or the maximum number of characters to be printed from a
322string for
323.Cm s
324conversions.
325.It
326An optional length modifier, that specifies the size of the argument.
327The following length modifiers are valid for the
328.Cm d , i , n ,
329.Cm o , u , x ,
330or
331.Cm X
332conversion:
333.Bl -column "(deprecated)" "signed char" "unsigned long long" "long long *"
334.It Sy Modifier Ta Sy "d, i" Ta Sy "o, u, x, X" Ta Sy n
335.It hh Ta "signed char" Ta "unsigned char" Ta "signed char *"
336.It h Ta short Ta "unsigned short" Ta "short *"
337.It "l (ell)" Ta long Ta "unsigned long" Ta "long *"
338.It "ll (ell ell)" Ta "long long" Ta "unsigned long long" Ta "long long *"
339.It j Ta intmax_t Ta uintmax_t Ta "intmax_t *"
340.It t Ta ptrdiff_t Ta (see note) Ta "ptrdiff_t *"
341.It z Ta "(see note)" Ta size_t Ta "(see note)"
342.It "q (deprecated)" Ta quad_t Ta u_quad_t Ta "quad_t *"
343.El
344.Pp
345Note:
346the
347.Cm t
348modifier, when applied to an
349.Cm o , u , x ,
350or
351.Cm X
352conversion, indicates that the argument is of an unsigned type
353equivalent in size to a
354.Vt ptrdiff_t .
355The
356.Cm z
357modifier, when applied to a
358.Cm d
359or
360.Cm i
361conversion, indicates that the argument is of a signed type equivalent in
362size to a
363.Vt size_t .
364Similarly, when applied to an
365.Cm n
366conversion, it indicates that the argument is a pointer to a signed type
367equivalent in size to a
368.Vt size_t .
369.Pp
370The following length modifier is valid for the
371.Cm a ,
372.Cm A ,
373.Cm e ,
374.Cm E ,
375.Cm f ,
376.Cm F ,
377.Cm g ,
378or
379.Cm G
380conversion:
381.Bl -column "Modifier" "e, E, f, F, g, G"
382.It Sy Modifier Ta Sy "e, E, f, F, g, G"
383.It "l (ell)" Ta double (ignored: same behavior as without it)
384.It L Ta "long double"
385.El
386.Pp
387The following length modifier is valid for the
388.Cm c
389or
390.Cm s
391conversion:
392.Bl -column "Modifier" "wint_t" "wchar_t *"
393.It Sy Modifier Ta Sy c Ta Sy s
394.It "l (ell)" Ta wint_t Ta "wchar_t *"
395.El
396.It
397A character that specifies the type of conversion to be applied.
398.El
399.Pp
400A field width or precision, or both, may be indicated by
401an asterisk
402.Ql *
403or an asterisk followed by one or more decimal digits and a
404.Ql $
405instead of a
406digit string.
407In this case, an
408.Li int
409argument supplies the field width or precision.
410A negative field width is treated as a left adjustment flag followed by a
411positive field width; a negative precision is treated as though it were
412missing.
413If a single format directive mixes positional (nn$) and
414non-positional arguments, the results are undefined.
415.Pp
416The conversion specifiers and their meanings are:
417.Bl -tag -width "diouxX"
418.It Cm diouxX
419The
420.Li int
421(or appropriate variant) argument is converted to signed decimal
422.Pf ( Cm d
423and
424.Cm i ) ,
425unsigned octal
426.Pq Cm o ,
427unsigned decimal
428.Pq Cm u ,
429or unsigned hexadecimal
430.Pf ( Cm x
431and
432.Cm X )
433notation.
434The letters
435.Cm abcdef
436are used for
437.Cm x
438conversions; the letters
439.Cm ABCDEF
440are used for
441.Cm X
442conversions.
443The precision, if any, gives the minimum number of digits that must
444appear; if the converted value requires fewer digits, it is padded on
445the left with zeros.
446.It Cm DOU
447The
448.Li long int
449argument is converted to signed decimal, unsigned octal, or unsigned
450decimal, as if the format had been
451.Cm ld ,
452.Cm lo ,
453or
454.Cm lu
455respectively.
456These conversion characters are deprecated, and will eventually disappear.
457.It Cm eE
458The
459.Li double
460argument is rounded and converted in the style
461.Sm off
462.Pf [\-]d Cm \&. No ddd Cm e No \*(Pmdd
463.Sm on
464where there is one digit before the
465decimal-point character
466and the number of digits after it is equal to the precision;
467if the precision is missing,
468it is taken as 6; if the precision is
469zero, no decimal-point character appears.
470An
471.Cm E
472conversion uses the letter
473.Cm E
474(rather than
475.Cm e )
476to introduce the exponent.
477The exponent always contains at least two digits; if the value is zero,
478the exponent is 00.
479.Pp
480If the argument is infinity, it will be converted to [-]inf
481.Pq Cm e
482or [-]INF
483.Pq Cm E ,
484respectively.
485If the argument is not-a-number (NaN), it will be converted to
486[-]nan
487.Pq Cm e
488or [-]NAN
489.Pq Cm E ,
490respectively.
491.It Cm fF
492The
493.Li double
494argument is rounded and converted to decimal notation in the style
495.Sm off
496.Pf [-]ddd Cm \&. No ddd ,
497.Sm on
498where the number of digits after the decimal-point character
499is equal to the precision specification.
500If the precision is missing, it is taken as 6; if the precision is
501explicitly zero, no decimal-point character appears.
502If a decimal point appears, at least one digit appears before it.
503.Pp
504If the argument is infinity, it will be converted to [-]inf
505.Pq Cm f
506or [-]INF
507.Pq Cm F ,
508respectively.
509If the argument is not-a-number (NaN), it will be converted to
510[-]nan
511.Pq Cm f
512or [-]NAN
513.Pq Cm F ,
514respectively.
515.It Cm gG
516The
517.Li double
518argument is converted in style
519.Cm f
520or
521.Cm e
522(or
523.Cm E
524for
525.Cm G
526conversions).
527The precision specifies the number of significant digits.
528If the precision is missing, 6 digits are given; if the precision is zero,
529it is treated as 1.
530Style
531.Cm e
532is used if the exponent from its conversion is less than -4 or greater than
533or equal to the precision.
534Trailing zeros are removed from the fractional part of the result; a
535decimal point appears only if it is followed by at least one digit.
536.Pp
537If the argument is infinity, it will be converted to [-]inf
538.Pq Cm g
539or [-]INF
540.Pq Cm G ,
541respectively.
542If the argument is not-a-number (NaN), it will be converted to
543[-]nan
544.Pq Cm g
545or [-]NAN
546.Pq Cm G ,
547respectively.
548.It Cm aA
549The
550.Li double
551argument is rounded and converted to hexadecimal notation in the style
552.Sm off
553.Pf [\-]0xh Cm \&. No hhh Cm p No [\*(Pm]d
554.Sm on
555where the number of digits after the hexadecimal-point character
556is equal to the precision specification.
557If the precision is missing, it is taken as enough to represent
558the floating-point number exactly, and no rounding occurs.
559If the precision is zero, no hexadecimal-point character appears.
560The
561.Cm p
562is a literal character
563.Ql p ,
564and the exponent consists of a positive or negative sign
565followed by a decimal number representing an exponent of 2.
566The
567.Cm A
568conversion uses the prefix
569.Dq Li 0X
570(rather than
571.Dq Li 0x ) ,
572the letters
573.Dq Li ABCDEF
574(rather than
575.Dq Li abcdef )
576to represent the hex digits, and the letter
577.Ql P
578(rather than
579.Ql p )
580to separate the mantissa and exponent.
581.Pp
582Note that there may be multiple valid ways to represent floating-point
583numbers in this hexadecimal format.
584For example,
585.Li 0x3.24p+0 , 0x6.48p-1
586and
587.Li 0xc.9p-2
588are all equivalent.
589The format chosen depends on the internal representation of the
590number, but the implementation guarantees that the length of the
591mantissa will be minimized.
592Zeroes are always represented with a mantissa of 0 (preceded by a
593.Ql -
594if appropriate) and an exponent of
595.Li +0 .
596.Pp
597If the argument is infinity, it will be converted to [-]inf
598.Pq Cm a
599or [-]INF
600.Pq Cm A ,
601respectively.
602If the argument is not-a-number (NaN), it will be converted to
603[-]nan
604.Pq Cm a
605or [-]NAN
606.Pq Cm A ,
607respectively.
608.It Cm c
609The
610.Li int
611argument is converted to an
612.Li unsigned char ,
613and the resulting character is written.
614.It Cm s
615The
616.Li char *
617argument is expected to be a pointer to an array of character type (pointer
618to a string).
619Characters from the array are written up to (but not including)
620a terminating
621.Tn NUL
622character;
623if a precision is specified, no more than the number specified are
624written.
625If a precision is given, no NUL character
626need be present; if the precision is not specified, or is greater than
627the size of the array, the array must contain a terminating
628.Tn NUL
629character.
630.It Cm p
631The
632.Li void *
633pointer argument is printed in hexadecimal (as if by
634.Ql %#x
635or
636.Ql %#lx ) .
637.It Cm n
638The number of characters written so far is stored into the
639integer indicated by the
640.Li int *
641(or variant) pointer argument.
642No argument is converted.
643.It Cm %
644A
645.Ql %
646is written.
647No argument is converted.
648The complete conversion specification is
649.Ql %% .
650.El
651.Pp
652In no case does a non-existent or small field width cause truncation of
653a field; if the result of a conversion is wider than the field width, the
654field is expanded to contain the conversion result.
655.Sh RETURN VALUES
656For all these functions if an output or encoding error occurs, a value
657of \-1 is returned.
658.Pp
659The
660.Fn printf ,
661.Fn fprintf ,
662.Fn sprintf ,
663.Fn vprintf ,
664.Fn vfprintf ,
665.Fn vsprintf ,
666.Fn asprintf ,
667and
668.Fn vasprintf
669functions
670return the number of characters printed
671(not including the trailing
672.Ql \e0
673used to end output to strings).
674.Pp
675The
676.Fn snprintf
677and
678.Fn vsnprintf
679functions return the number of characters that would have
680been output if the
681.Fa size
682were unlimited
683.Po
684again, not including the final
685.Ql \e0 .
686.Pc .
687.Pp
688The
689.Fn asprintf
690and
691.Fn vasprintf
692functions return the number of characters that were output
693to the newly allocated string
694(excluding the final
695.Ql \e0 ) .
696A pointer to the newly allocated string is returned in
697.Fa ret ;
698it should be passed to
699.Xr free 3
700to release the allocated storage
701when it is no longer needed.
702If sufficient space cannot be allocated, these functions
703will return \-1.
704The value of
705.Fa ret
706in this situation is implementation-dependent
707(on
708.Ox ,
709.Fa ret
710will be set to the null pointer, but this behavior should not be relied upon).
711.Sh EXAMPLES
712To print a date and time in the form `Sunday, July 3, 10:02',
713where
714.Va weekday
715and
716.Va month
717are pointers to strings:
718.Bd -literal -offset indent
719#include <stdio.h>
720
721fprintf(stdout, "%s, %s %d, %.2d:%.2d\en",
722    weekday, month, day, hour, min);
723.Ed
724.Pp
725To print \*(Pi
726to five decimal places:
727.Bd -literal -offset indent
728#include <math.h>
729#include <stdio.h>
730
731fprintf(stdout, "pi = %.5f\en", 4 * atan(1.0));
732.Ed
733.Pp
734To allocate a 128-byte string and print into it:
735.Bd -literal -offset indent
736#include <stdarg.h>
737#include <stdio.h>
738#include <stdlib.h>
739
740char *
741newfmt(const char *fmt, ...)
742{
743	char *p;
744	va_list ap;
745
746	if ((p = malloc(128)) == NULL)
747		return (NULL);
748	va_start(ap, fmt);
749	(void) vsnprintf(p, 128, fmt, ap);
750	va_end(ap);
751	return (p);
752}
753.Ed
754.Sh SEE ALSO
755.Xr printf 1 ,
756.Xr scanf 3
757.Sh STANDARDS
758The
759.Fn fprintf ,
760.Fn printf ,
761.Fn snprintf ,
762.Fn sprintf ,
763.Fn vfprintf ,
764.Fn vprintf ,
765.Fn vsnprintf ,
766and
767.Fn vsprintf
768functions conform to
769.St -isoC-99 .
770The
771.Fn dprintf
772and
773.Fn vdprintf
774functions conform to
775.St -p1003.1-2008 .
776.Sh HISTORY
777The predecessors
778.Fn ftoa
779and
780.Fn itoa
781first appeared in
782.At v1 .
783The function
784.Fn printf
785first appeared in
786.At v2 ,
787and
788.Fn fprintf
789and
790.Fn sprintf
791in
792.At v7 .
793.Pp
794The functions
795.Fn snprintf
796and
797.Fn vsnprintf
798first appeared in
799.Bx 4.4 .
800.Pp
801The functions
802.Fn asprintf
803and
804.Fn vasprintf
805first appeared in the GNU C library.
806This implementation first appeared in
807.Ox 2.3 .
808.Pp
809The functions
810.Fn dprintf
811and
812.Fn vdprintf
813first appeared in
814.Ox 5.3 .
815.Sh CAVEATS
816The conversion formats
817.Cm \&%D ,
818.Cm \&%O ,
819and
820.Cm %U
821are not standard and
822are provided only for backward compatibility.
823The effect of padding the
824.Cm %p
825format with zeros (either by the
826.Sq Cm 0
827flag or by specifying a precision), and the benign effect (i.e., none)
828of the
829.Sq Cm #
830flag on
831.Cm %n
832and
833.Cm %p
834conversions, as well as other
835nonsensical combinations such as
836.Cm %Ld ,
837are not standard; such combinations
838should be avoided.
839.Pp
840Because
841.Fn sprintf
842and
843.Fn vsprintf
844assume an infinitely long string,
845callers must be careful not to overflow the actual space;
846this is often impossible to assure.
847For safety, programmers should use the
848.Fn snprintf
849and
850.Fn asprintf
851family of interfaces instead.
852Unfortunately, the
853.Fn snprintf
854interface is not available on older
855systems and the
856.Fn asprintf
857interface is not portable.
858.Pp
859It is important never to pass a string with user-supplied data as a
860format without using
861.Ql %s .
862An attacker can put format specifiers in the string to mangle the stack,
863leading to a possible security hole.
864This holds true even if the string has been built
865.Dq by hand
866using a function like
867.Fn snprintf ,
868as the resulting string may still contain user-supplied conversion specifiers
869for later interpolation by
870.Fn printf .
871.Pp
872Be sure to use the proper secure idiom:
873.Bd -literal -offset indent
874snprintf(buffer, sizeof(buffer), "%s", string);
875.Ed
876.Pp
877There is no way for
878.Fn printf
879to know the size of each argument passed.
880If positional arguments are used, care must be taken to ensure that all
881parameters, up to the
882last positionally specified parameter, are used in the format string.
883This allows for the format string to be parsed for this information.
884Failure to do this will mean the code is non-portable and liable to fail.
885