Hi, Noticed a typo below On Mon, Dec 19, 2022 at 11:02 PM Alejandro Colomar <alx.manpages@xxxxxxxxx> wrote: > > This is an opportunity to use consistent language across the > documentation for all string-copying functions. > > It is also easier to show the similarities and differences between all > of the functions, so that a reader can use this page to know which > function is needed for a given task. > > Alternative functions not provided by libc have been given in the same > page, with reference implementations. > > Cc: Martin Sebor <msebor@xxxxxxxxxx> > Cc: "G. Branden Robinson" <g.branden.robinson@xxxxxxxxx> > Cc: Douglas McIlroy <douglas.mcilroy@xxxxxxxxxxxxx> > Cc: Jakub Wilk <jwilk@xxxxxxxxx> > Cc: Serge Hallyn <serge@xxxxxxxxxx> > Cc: Iker Pedrosa <ipedrosa@xxxxxxxxxx> > Cc: Andrew Pinski <pinskia@xxxxxxxxx> > Cc: Stefan Puiu <stefan.puiu@xxxxxxxxx> > Signed-off-by: Alejandro Colomar <alx@xxxxxxxxxx> > --- > man7/string_copy.7 | 855 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 855 insertions(+) > create mode 100644 man7/string_copy.7 > > diff --git a/man7/string_copy.7 b/man7/string_copy.7 > new file mode 100644 > index 000000000..a32b93c01 > --- /dev/null > +++ b/man7/string_copy.7 > @@ -0,0 +1,855 @@ > +.\" Copyright 2022 Alejandro Colomar <alx@xxxxxxxxxx> > +.\" > +.\" SPDX-License-Identifier: BSD-3-Clause > +.\" > +.TH string_copy 7 (date) "Linux man-pages (unreleased)" > +.\" ----- NAME :: -----------------------------------------------------/ > +.SH NAME > +stpcpy, > +strcpy, strcat, > +stpecpy, stpecpyx, > +strlcpy, strlcat, > +stpncpy, > +strncpy, > +zustr2ustp, zustr2stp, > +strncat, > +ustpcpy, ustr2stp > +\- copy strings and character sequences > +.\" ----- SYNOPSIS :: -------------------------------------------------/ > +.SH SYNOPSIS > +.\" ----- SYNOPSIS :: (Null-terminated) strings -----------------------/ > +.SS Strings > +.nf > +// Chain-copy a string. > +.BI "char *stpcpy(char *restrict " dst ", const char *restrict " src ); > +.PP > +// Copy/catenate a string. > +.BI "char *strcpy(char *restrict " dst ", const char *restrict " src ); > +.BI "char *strcat(char *restrict " dst ", const char *restrict " src ); > +.PP > +// Chain-copy a string with truncation. > +.BI "char *stpecpy(char *" dst ", char " end "[0], const char *restrict " src ); > +.PP > +// Chain-copy a string with truncation and SIGSEGV on UB. > +.BI "char *stpecpyx(char *" dst ", char " end "[0], const char *restrict " src ); > +.PP > +// Copy/catenate a string with truncation and SIGSEGV on UB. > +.BI "size_t strlcpy(char " dst "[restrict ." sz "], \ > +const char *restrict " src , > +.BI " size_t " sz ); > +.BI "size_t strlcat(char " dst "[restrict ." sz "], \ > +const char *restrict " src , > +.BI " size_t " sz ); > +.fi > +.\" ----- SYNOPSIS :: Null-padded character sequences --------/ > +.SS Null-padded character sequences > +.nf > +// Zero a fixed-width buffer, and > +// copy a string into a character sequence with truncation. > +.BI "char *stpncpy(char " dst "[restrict ." sz "], \ > +const char *restrict " src , > +.BI " size_t " sz ); > +.PP > +// Zero a fixed-width buffer, and > +// copy a string into a character sequence with truncation. > +.BI "char *strncpy(char " dest "[restrict ." sz "], \ > +const char *restrict " src , > +.BI " size_t " sz ); > +.PP > +// Chain-copy a null-padded character sequence into a character sequence. > +.BI "char *zustr2ustp(char *restrict " dst ", \ > +const char " src "[restrict ." sz ], > +.BI " size_t " sz ); > +.PP > +// Chain-copy a null-padded character sequence into a string. > +.BI "char *zustr2stp(char *restrict " dst ", \ > +const char " src "[restrict ." sz ], > +.BI " size_t " sz ); > +.PP > +// Catenate a null-padded character sequence into a string. > +.BI "char *strncat(char *restrict " dst ", const char " src "[restrict ." sz ], > +.BI " size_t " sz ); > +.fi > +.\" ----- SYNOPSIS :: Measured character sequences --------------------/ > +.SS Measured character sequences > +.nf > +// Chain-copy a measured character sequence. > +.BI "char *ustpcpy(char *restrict " dst ", \ > +const char " src "[restrict ." len ], > +.BI " size_t " len ); > +.PP > +// Chain-copy a measured character sequence into a string. > +.BI "char *ustr2stp(char *restrict " dst ", \ > +const char " src "[restrict ." len ], > +.BI " size_t " len ); > +.fi > +.SH DESCRIPTION > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: -----------------/ > +.SS Terms (and abbreviations) > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: string (str) ----/ > +.TP > +.IR "string " ( str ) > +is a sequence of zero or more non-null characters followed by a null byte. > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: null-padded character seq > +.TP > +.I character sequence > +is a sequence of zero or more non-null characters. > +A program should never usa a character sequence where a string is required. Here I think you want s/usa/use above. Thanks, Stefan. > +However, with appropriate care, > +a string can be used in the place of a character sequence. > +.RS > +.TP > +.IR "null-padded character sequence " ( zustr ) > +Character sequences can be contained in fixed-width buffers, > +which contain padding null bytes after the character sequence, > +to fill the rest of the buffer > +without affecting the character sequence; > +however, those padding null bytes are not part of the character sequence. > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: measured character sequence > +.TP > +.IR "measured character sequence " ( ustr ) > +Character sequence delimited by its length. > +It may be a slice of a larger character sequence, > +or even of a string. > +.RE > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: length (len) ----/ > +.TP > +.IR "length " ( len ) > +is the number of non-null characters in a string or character sequence. > +It is the return value of > +.I strlen(str) > +and of > +.IR "strnlen(ustr, sz)" . > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: size (sz) -------/ > +.TP > +.IR "size " ( sz ) > +refers to the entire buffer > +where the string or character sequence is contained. > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: end -------------/ > +.TP > +.I end > +is the name of a pointer to one past the last element of a buffer. > +It is equivalent to > +.IR &str[sz] . > +It is used as a sentinel value, > +to be able to truncate strings or character sequences > +instead of overrunning the containing buffer. > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: copy ------------/ > +.TP > +.I copy > +This term is used when > +the writing starts at the first element pointed to by > +.IR dst . > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: catenate --------/ > +.TP > +.I catenate > +This term is used when > +a function first finds the terminating null byte in > +.IR dst , > +and then starts writing at that position. > +.\" ----- DESCRIPTION :: Terms (and abbreviations) :: chain -----------/ > +.TP > +.I chain > +This term is used when > +it's the programmer who provides > +a pointer to the terminating null byte in the string > +.I dst > +(or one after the last character in a character sequence), > +and the function starts writing at that location. > +The function returns > +a pointer to the new location of the terminating null byte > +(or one after the last character in a character sequence) > +after the call, > +so that the programmer can use it to chain such calls. > +.\" ----- DESCRIPTION :: Copy, catenate, and chain-copy ---------------/ > +.SS Copy, catenate, and chain-copy > +Originally, > +there was a distinction between functions that copy and those that catenate. > +However, newer functions that copy while allowing chaining > +cover both use cases with a single API. > +They are also algorithmically faster, > +since they don't need to search for > +the terminating null byte of the existing string. > +However, functions that catenate have a much simpler use, > +so if performance is not important, > +it can make sense to use them for improving readability. > +.PP > +The pointer returned by functions that allow chaining > +is a byproduct of the copy operation, > +so it has no performance costs. > +Functions that return such a pointer, > +and thus can be chained, > +have names of the form > +.RB * stp *(), > +since it's common to name the pointer just > +.IR p . > +.PP > +Chain-copying functions that truncate > +should accept a pointer to the end of the destination buffer, > +and have names of the form > +.RB * stpe *(). > +This allows not having to recalculate the remaining size after each call. > +.\" ----- DESCRIPTION :: Truncate or not? -----------------------------/ > +.SS Truncate or not? > +The first thing to note is that programmers should be careful with buffers, > +so they always have the correct size, > +and truncation is not necessary. > +.PP > +In most cases, > +truncation is not desired, > +and it is simpler to just do the copy. > +Simpler code is safer code. > +Programming against programming mistakes by adding more code > +just adds more points where mistakes can be made. > +.PP > +Nowadays, > +compilers can detect most programmer errors with features like > +compiler warnings, > +static analyzers, and > +.BR \%_FORTIFY_SOURCE > +(see > +.BR ftm (7)). > +Keeping the code simple > +helps these overflow-detection features be more precise. > +.PP > +When validating user input, > +however, > +it makes sense to truncate. > +Remember to check the return value of such function calls. > +.PP > +Functions that truncate: > +.IP \(bu 3 > +.BR stpecpy (3) > +is the most efficient string copy function that performs truncation. > +It only requires to check for truncation once after all chained calls. > +.IP \(bu > +.BR stpecpyx (3) > +is a variant of > +.BR stpecpy (3) > +that consumes the entire source string, > +to catch bugs in the program > +by forcing a segmentation fault (as > +.BR strlcpy (3bsd) > +and > +.BR strlcat (3bsd) > +do). > +.IP \(bu > +.BR strlcpy (3bsd) > +and > +.BR strlcat (3bsd) > +are designed to crash if the input string is invalid > +(doesn't contain a terminating null byte). > +.IP \(bu > +.BR stpncpy (3) > +and > +.BR strncpy (3) > +also truncate, but they don't write strings, > +but rather null-padded character sequences. > +.\" ----- DESCRIPTION :: Null-padded character sequences --------------/ > +.SS Null-padded character sequences > +For historic reasons, > +some standard APIs, > +such as > +.BR utmpx (5), > +use null-padded character sequences in fixed-width buffers. > +To interface with them, > +specialized functions need to be used. > +.PP > +To copy strings into them, use > +.BR stpncpy (3). > +.PP > +To copy from an unterminated string within a fixed-width buffer into a string, > +ignoring any trailing null bytes in the source fixed-width buffer, > +you should use > +.BR zustr2stp (3) > +or > +.BR strncat (3). > +.PP > +To copy from an unterminated string within a fixed-width buffer > +into a character sequence, > +ingoring any trailing null bytes in the source fixed-width buffer, > +you should use > +.BR zustr2ustp (3). > +.\" ----- DESCRIPTION :: Measured character sequences -----------------/ > +.SS Measured character sequences > +The simplest character sequence copying function is > +.BR mempcpy (3). > +It requires always knowing the length of your character sequences, > +for which structures can be used. > +It makes the code much faster, > +since you always know the length of your character sequences, > +and can do the minimal copies and length measurements. > +.BR mempcpy (3) > +copies character sequences, > +so you need to explicitly set the terminating null byte if you need a string. > +.PP > +However, > +for keeping type safety, > +it's good to add a wrapper that uses > +.I char\~* > +instead of > +.IR void\~* : > +.BR ustpcpy (3). > +.PP > +In programs that make considerable use of strings or character sequences, > +and need the best performance, > +using overlapping character sequences can make a big difference. > +It allows holding subsequences of a larger character sequence. > +while not duplicating memory > +nor using time to do a copy. > +.PP > +However, this is delicate, > +since it requires using character sequences. > +C library APIs use strings, > +so programs that use character sequences > +will have to take care of differentiating strings from character sequences. > +.PP > +To copy a measured character sequence, use > +.BR ustpcpy (3). > +.PP > +To copy a measured character sequence into a string, use > +.BR ustr2stp (3). > +.PP > +Because these functions ask for the length, > +and a string is by nature composed of a character sequence of the same length > +plus a terminating null byte, > +a string is also accepted as input. > +.\" ----- DESCRIPTION :: String vs character sequence -----------------/ > +.SS String vs character sequence > +Some functions only operate on strings. > +Those require that the input > +.I src > +is a string, > +and guarantee an output string > +(even when truncation occurs). > +Functions that catenate > +also require that > +.I dst > +holds a string before the call. > +List of functions: > +.IP \(bu 3 > +.PD 0 > +.BR stpcpy (3) > +.IP \(bu > +.BR strcpy "(3), \c" > +.BR strcat (3) > +.IP \(bu > +.BR stpecpy "(3), \c" > +.BR stpecpyx (3) > +.IP \(bu > +.BR strlcpy "(3bsd), \c" > +.BR strlcat (3bsd) > +.PD > +.PP > +Other functions require an input string, > +but create a character sequence as output. > +These functions have confusing names, > +and have a long history of misuse. > +List of functions: > +.IP \(bu 3 > +.PD 0 > +.BR stpncpy (3) > +.IP \(bu > +.BR strncpy (3) > +.PD > +.PP > +Other functions operate on an input character sequence, > +and create an output string. > +Functions that catenate > +also require that > +.I dst > +holds a string before the call. > +.BR strncat (3) > +has an even more misleading name than the functions above. > +List of functions: > +.IP \(bu 3 > +.PD 0 > +.BR zustr2stp (3) > +.IP \(bu > +.BR strncat (3) > +.IP \(bu > +.BR ustr2stp (3) > +.PD > +.PP > +Other functions operate on an input character sequence > +to create an output character sequence. > +List of functions: > +.IP \(bu 3 > +.PD 0 > +.BR ustpcpy (3) > +.IP \(bu > +.BR zustr2stp (3) > +.PD > +.\" ----- DESCRIPTION :: Functions :: ---------------------------------/ > +.SS Functions > +.\" ----- DESCRIPTION :: Functions :: stpcpy(3) -----------------------/ > +.TP > +.BR stpcpy (3) > +This function copies the input string into a destination string. > +The programmer is responsible for allocating a buffer large enough. > +It returns a pointer suitable for chaining. > +.\" ----- DESCRIPTION :: Functions :: strcpy(3), strcat(3) ------------/ > +.TP > +.BR strcpy (3) > +.TQ > +.BR strcat (3) > +These functions copy and catenate the input string into a destination string. > +The programmer is responsible for allocating a buffer large enough. > +The return value is useless. > +.IP > +.BR stpcpy (3) > +is a faster alternative to these functions. > +.\" ----- DESCRIPTION :: Functions :: stpecpy(3), stpecpyx(3) ---------/ > +.TP > +.BR stpecpy (3) > +.TQ > +.BR stpecpyx (3) > +These functions copy the input string into a destination string. > +If the destination buffer, > +limited by a pointer to its end, > +isn't large enough to hold the copy, > +the resulting string is truncated > +(but it is guaranteed to be null-terminated). > +They return a pointer suitable for chaining. > +Truncation needs to be detected only once after the last chained call. > +.BR stpecpyx (3) > +has identical semantics to > +.BR stpecpy (3), > +except that it forces a SIGSEGV if the > +.I src > +pointer is not a string. > +.IP > +These functions are not provided by any library; > +See EXAMPLES for a reference implementation. > +.\" ----- DESCRIPTION :: Functions :: strlcpy(3bsd), strlcat(3bsd) ----/ > +.TP > +.BR strlcpy (3bsd) > +.TQ > +.BR strlcat (3bsd) > +These functions copy and catenate the input string into a destination string. > +If the destination buffer, > +limited by its size, > +isn't large enough to hold the copy, > +the resulting string is truncated > +(but it is guaranteed to be null-terminated). > +They return the length of the total string they tried to create. > +These functions force a SIGSEGV if the > +.I src > +pointer is not a string. > +.IP > +.BR stpecpyx (3) > +is a faster alternative to these functions. > +.\" ----- DESCRIPTION :: Functions :: stpncpy(3) ----------------------/ > +.TP > +.BR stpncpy (3) > +This function copies the input string into > +a destination null-padded character sequence in a fixed-width buffer. > +If the destination buffer, > +limited by its size, > +isn't large enough to hold the copy, > +the resulting character sequence is truncated. > +Since it creates a character sequence, > +it doesn't need to write a terminating null byte. > +It's impossible to distinguish truncation by the result of the call, > +from a character sequence that just fits the destination buffer; > +truncation should be detected by > +comparing the length of the input string > +with the size of the destination buffer. > +.\" ----- DESCRIPTION :: Functions :: strncpy(3) ----------------------/ > +.TP > +.BR strncpy (3) > +This function is identical to > +.BR stpncpy (3) > +except for the useless return value. > +.IP > +.BR stpncpy (3) > +is a more useful alternative to this function. > +.\" ----- DESCRIPTION :: Functions :: zustr2ustp(3) --------------------/ > +.TP > +.BR zustr2ustp (3) > +This function copies the input character sequence > +contained in a null-padded wixed-width buffer, > +into a destination character sequence. > +The programmer is responsible for allocating a buffer large enough. > +It returns a pointer suitable for chaining. > +.IP > +A truncating version of this function doesn't exist, > +since the size of the original character sequence is always known, > +so it wouldn't be very useful. > +.IP > +This function is not provided by any library; > +See EXAMPLES for a reference implementation. > +.\" ----- DESCRIPTION :: Functions :: zustr2stp(3) --------------------/ > +.TP > +.BR zustr2stp (3) > +This function copies the input character sequence > +contained in a null-padded wixed-width buffer, > +into a destination string. > +The programmer is responsible for allocating a buffer large enough. > +It returns a pointer suitable for chaining. > +.IP > +A truncating version of this function doesn't exist, > +since the size of the original character sequence is always known, > +so it wouldn't be very useful. > +.IP > +This function is not provided by any library; > +See EXAMPLES for a reference implementation. > +.\" ----- DESCRIPTION :: Functions :: strncat(3) ----------------------/ > +.TP > +.BR strncat (3) > +Do not confuse this function with > +.BR strncpy (3); > +they are not related at all. > +.IP > +This function catenates the input character sequence > +contained in a null-padded wixed-width buffer, > +into a destination string. > +The programmer is responsible for allocating a buffer large enough. > +The return value is useless. > +.IP > +.BR zustr2stp (3) > +is a faster alternative to this function. > +.\" ----- DESCRIPTION :: Functions :: ustpcpy(3) ----------------------/ > +.TP > +.BR ustpcpy (3) > +This function copies the input character sequence, > +limited by its length, > +into a destination character sequence. > +The programmer is responsible for allocating a buffer large enough. > +It returns a pointer suitable for chaining. > +.\" ----- DESCRIPTION :: Functions :: ustr2stp(3) ---------------------/ > +.TP > +.BR ustr2stp (3) > +This function copies the input character sequence, > +limited by its length, > +into a destination string. > +The programmer is responsible for allocating a buffer large enough. > +It returns a pointer suitable for chaining. > +.\" ----- RETURN VALUE :: ---------------------------------------------/ > +.SH RETURN VALUE > +The following functions return > +a pointer to the terminating null byte in the destination string. > +.IP \(bu 3 > +.PD 0 > +.BR stpcpy (3) > +.IP \(bu > +.BR ustr2stp (3) > +.IP \(bu > +.BR zustr2stp (3) > +.PD > +.PP > +The following functions return > +a pointer to the terminating null byte in the destination string, > +except when truncation occurs; > +if truncation occurs, > +they return a pointer to the end of the destination buffer. > +.IP \(bu 3 > +.BR stpecpy (3), > +.BR stpecpyx (3) > +.PP > +The following function returns > +a pointer to one after the last character > +in the destination character sequence; > +if truncation occurs, > +that pointer is equivalent to > +a pointer to the end of the destination buffer. > +.IP \(bu 3 > +.BR stpncpy (3) > +.PP > +The following functions return > +a pointer to one after the last character > +in the destination character sequence. > +.IP \(bu 3 > +.PD 0 > +.BR zustr2ustp (3) > +.IP \(bu > +.BR ustpcpy (3) > +.PD > +.PP > +The following functions return > +the length of the total string that they tried to create > +(as if truncation didn't occur). > +.IP \(bu 3 > +.BR strlcpy (3bsd), > +.BR strlcat (3bsd) > +.PP > +The following functions return the > +.I dst > +pointer, > +which is useless. > +.IP \(bu 3 > +.PD 0 > +.BR strcpy (3), > +.BR strcat (3) > +.IP \(bu > +.BR strncpy (3) > +.IP \(bu > +.BR strncat (3) > +.PD > +.\" ----- NOTES :: strscpy(9) -----------------------------------------/ > +.SH NOTES > +The Linux kernel has an internal function for copying strings, > +which is similar to > +.BR stpecpy (3), > +except that it can't be chained: > +.TP > +.BR strscpy (9) > +This function copies the input string into a destination string. > +If the destination buffer, > +limited by its size, > +isn't large enough to hold the copy, > +the resulting string is truncated > +(but it is guaranteed to be null-terminated). > +It returns the length of the destination string, or > +.B \-E2BIG > +on truncation. > +.IP > +.BR stpecpy (3) > +is a simpler and faster alternative to this function. > +.RE > +.\" ----- CAVEATS :: --------------------------------------------------/ > +.SH CAVEATS > +Don't mix chain calls to truncating and non-truncating functions. > +It is conceptually wrong > +unless you know that the first part of a copy will always fit. > +Anyway, the performance difference will probably be negligible, > +so it will probably be more clear if you use consistent semantics: > +either truncating or non-truncating. > +Calling a non-truncating function after a truncating one is necessarily wrong. > +.\" ----- BUGS :: -----------------------------------------------------/ > +.SH BUGS > +All catenation functions share the same performance problem: > +.UR https://www.joelonsoftware.com/\:2001/12/11/\:back\-to\-basics/ > +Shlemiel the painter > +.UE . > +.\" ----- EXAMPLES :: -------------------------------------------------/ > +.SH EXAMPLES > +The following are examples of correct use of each of these functions. > +.\" ----- EXAMPLES :: stpcpy(3) ---------------------------------------/ > +.TP > +.BR stpcpy (3) > +.EX > +p = buf; > +p = stpcpy(p, "Hello "); > +p = stpcpy(p, "world"); > +p = stpcpy(p, "!"); > +len = p \- buf; > +puts(buf); > +.EE > +.\" ----- EXAMPLES :: strcpy(3), strcat(3) ----------------------------/ > +.TP > +.BR strcpy (3) > +.TQ > +.BR strcat (3) > +.EX > +strcpy(buf, "Hello "); > +strcat(buf, "world"); > +strcat(buf, "!"); > +len = strlen(buf); > +puts(buf); > +.EE > +.\" ----- EXAMPLES :: stpecpy(3), stpecpyx(3) -------------------------/ > +.TP > +.BR stpecpy (3) > +.TQ > +.BR stpecpyx (3) > +.EX > +end = buf + sizeof(buf); > +p = buf; > +p = stpecpy(p, end, "Hello "); > +p = stpecpy(p, end, "world"); > +p = stpecpy(p, end, "!"); > +if (p == end) { > + p\-\-; > + goto toolong; > +} > +len = p \- buf; > +puts(buf); > +.EE > +.\" ----- EXAMPLES :: strlcpy(3bsd), strlcat(3bsd) --------------------/ > +.TP > +.BR strlcpy (3bsd) > +.TQ > +.BR strlcat (3bsd) > +.EX > +if (strlcpy(buf, "Hello ", sizeof(buf)) >= sizeof(buf)) > + goto toolong; > +if (strlcat(buf, "world", sizeof(buf)) >= sizeof(buf)) > + goto toolong; > +len = strlcat(buf, "!", sizeof(buf)); > +if (len >= sizeof(buf)) > + goto toolong; > +puts(buf); > +.EE > +.\" ----- EXAMPLES :: strscpy(9) --------------------------------------/ > +.TP > +.BR strscpy (9) > +.EX > +len = strscpy(buf, "Hello world!", sizeof(buf)); > +if (len == \-E2BIG) > + goto toolong; > +puts(buf); > +.EE > +.\" ----- EXAMPLES :: stpncpy(3) --------------------------------------/ > +.TP > +.BR stpncpy (3) > +.EX > +p = stpncpy(buf, "Hello world!", sizeof(buf)); > +if (sizeof(buf) < strlen("Hello world!")) > + goto toolong; > +len = p \- buf; > +for (size_t i = 0; i < sizeof(buf); i++) > + putchar(buf[i]); > +.EE > +.\" ----- EXAMPLES :: strncpy(3) --------------------------------------/ > +.TP > +.BR strncpy (3) > +.EX > +strncpy(buf, "Hello world!", sizeof(buf)); > +if (sizeof(buf) < strlen("Hello world!")) > + goto toolong; > +len = strnlen(buf, sizeof(buf)); > +for (size_t i = 0; i < sizeof(buf); i++) > + putchar(buf[i]); > +.EE > +.\" ----- EXAMPLES :: zustr2ustp(3) -----------------------------------/ > +.TP > +.BR zustr2ustp (3) > +.EX > +p = buf; > +p = zustr2ustp(p, "Hello ", 6); > +p = zustr2ustp(p, "world", 42); // Padding null bytes ignored. > +p = zustr2ustp(p, "!", 1); > +len = p \- buf; > +printf("%.*s\en", (int) len, buf); > +.EE > +.\" ----- EXAMPLES :: zustr2stp(3) ------------------------------------/ > +.TP > +.BR zustr2stp (3) > +.EX > +p = buf; > +p = zustr2stp(p, "Hello ", 6); > +p = zustr2stp(p, "world", 42); // Padding null bytes ignored. > +p = zustr2stp(p, "!", 1); > +len = p \- buf; > +puts(buf); > +.EE > +.\" ----- EXAMPLES :: strncat(3) --------------------------------------/ > +.TP > +.BR strncat (3) > +.EX > +buf[0] = \(aq\e0\(aq; // There's no 'cpy' function to this 'cat'. > +strncat(buf, "Hello ", 6); > +strncat(buf, "world", 42); // Padding null bytes ignored. > +strncat(buf, "!", 1); > +len = strlen(buf); > +puts(buf); > +.EE > +.\" ----- EXAMPLES :: ustpcpy(3) --------------------------------------/ > +.TP > +.BR ustpcpy (3) > +.EX > +p = buf; > +p = ustpcpy(p, "Hello ", 6); > +p = ustpcpy(p, "world", 5); > +p = ustpcpy(p, "!", 1); > +len = p \- buf; > +printf("%.*s\en", (int) len, buf); > +.EE > +.\" ----- EXAMPLES :: ustr2stp(3) -------------------------------------/ > +.TP > +.BR ustr2stp (3) > +.EX > +p = buf; > +p = ustr2stp(p, "Hello ", 6); > +p = ustr2stp(p, "world", 5); > +p = ustr2stp(p, "!", 1); > +len = p \- buf; > +puts(buf); > +.EE > +.\" ----- EXAMPLES :: Implementations :: ------------------------------/ > +.SS Implementations > +Here are reference implementations for functions not provided by libc. > +.PP > +.in +4n > +.EX > +/* This code is in the public domain. */ > + > +.\" ----- EXAMPLES :: Implementations :: stpecpy(3) -------------------/ > +char * > +.IR stpecpy "(char *dst, char end[0], const char *restrict src)" > +{ > + char *p; > + > + if (dst == end) > + return end; > + > + p = memccpy(dst, src, \(aq\e0\(aq, end \- dst); > + if (p != NULL) > + return p \- 1; > + > + /* truncation detected */ > + end[\-1] = \(aq\e0\(aq; > + return end; > +} > + > +.\" ----- EXAMPLES :: Implementations :: stpecpy(3) -------------------/ > +char * > +.IR stpecpyx "(char *dst, char end[0], const char *restrict src)" > +{ > + if (src[strlen(src)] != \(aq\e0\(aq) > + raise(SIGSEGV); > + > + return stpecpy(dst, end, src); > +} > + > +.\" ----- EXAMPLES :: Implementations :: zustr2ustp(3) ----------------/ > +char * > +.IR zustr2ustp "(char *restrict dst, const char *restrict src, size_t sz)" > +{ > + return ustpcpy(dst, src, strnlen(src, sz)); > +} > + > +.\" ----- EXAMPLES :: Implementations :: zustr2stp(3) -----------------/ > +char * > +.IR zustr2stp "(char *restrict dst, const char *restrict src, size_t sz)" > +{ > + char *p; > + > + p = zustr2ustp(dst, src, sz); > + *p = \(aq\e0\(aq; > + > + return p; > +} > + > +.\" ----- EXAMPLES :: Implementations :: ustpcpy(3) -------------------/ > +char * > +.IR ustpcpy "(char *restrict dst, const char *restrict src, size_t len)" > +{ > + return mempcpy(dst, src, len); > +} > + > +.\" ----- EXAMPLES :: Implementations :: ustr2stp(3) ------------------/ > +char * > +.IR ustr2stp "(char *restrict dst, const char *restrict src, size_t len)" > +{ > + char *p; > + > + p = ustpcpy(dst, src, len); > + *p = \(aq\e0\(aq; > + > + return p; > +} > +.EE > +.in > +.\" ----- SEE ALSO :: -------------------------------------------------/ > +.SH SEE ALSO > +.BR bzero (3), > +.BR memcpy (3), > +.BR memccpy (3), > +.BR mempcpy (3), > +.BR stpcpy (3), > +.BR strlcpy (3bsd), > +.BR strncat (3), > +.BR stpncpy (3), > +.BR string (3) > -- > 2.39.0 >