strbuf: provide CRLF-aware helper to read until a specified delimiter

Many of our commands support reading input that is separated either via newlines or via NUL characters. Furthermore, in order to be a better cross platform citizen, these commands typically know to strip the CRLF sequence so that we also support reading newline-separated inputs on e.g. the Windows platform. This results in the following kind of awkward pattern: ``` struct strbuf input = STRBUF_INIT; while (1) { int ret; if (nul_terminated) ret = strbuf_getline_nul(&input, stdin); else ret = strbuf_getline(&input, stdin); if (ret) break; ... } ``` Introduce a new CRLF-aware helper function that can read up to a user specified delimiter. If the delimiter is `\n` the function knows to also strip CRLF, otherwise it will only strip the specified delimiter. This results in the following, much more readable code pattern: ``` struct strbuf input = STRBUF_INIT; while (strbuf_getdelim_strip_crlf(&input, stdin, delim) != EOF) { ... } ``` The new function will be used in a subsequent commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jun 6, 2023 at 07:19 UTC af35e56b0f83f872a8d82d8293fae87c80b491ef
2 files changed +20 -3
strbuf.c
+8 -3
@@ -721,11 +721,11 @@ static int strbuf_getdelim(struct strbuf *sb, FILE *fp, int term)
721 return 0;
722 }
723
724 -int strbuf_getline(struct strbuf *sb, FILE *fp)
724 +int strbuf_getdelim_strip_crlf(struct strbuf *sb, FILE *fp, int term)
725 {
726 - if (strbuf_getwholeline(sb, fp, '\n'))
726 + if (strbuf_getwholeline(sb, fp, term))
727 return EOF;
728 - if (sb->buf[sb->len - 1] == '\n') {
728 + if (term == '\n' && sb->buf[sb->len - 1] == '\n') {
729 strbuf_setlen(sb, sb->len - 1);
730 if (sb->len && sb->buf[sb->len - 1] == '\r')
731 strbuf_setlen(sb, sb->len - 1);
@@ -733,6 +733,11 @@ int strbuf_getline(struct strbuf *sb, FILE *fp)
733 return 0;
734 }
735
736 +int strbuf_getline(struct strbuf *sb, FILE *fp)
737 +{
738 + return strbuf_getdelim_strip_crlf(sb, fp, '\n');
739 +}
740 +
741 int strbuf_getline_lf(struct strbuf *sb, FILE *fp)
742 {
743 return strbuf_getdelim(sb, fp, '\n');
strbuf.h
+12
@@ -475,6 +475,18 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
475 */
476 ssize_t strbuf_write(struct strbuf *sb, FILE *stream);
477
478 +/**
479 + * Read from a FILE * until the specified terminator is encountered,
480 + * overwriting the existing contents of the strbuf.
481 + *
482 + * Reading stops after the terminator or at EOF. The terminator is
483 + * removed from the buffer before returning. If the terminator is LF
484 + * and if it is preceded by a CR, then the whole CRLF is stripped.
485 + * Returns 0 unless there was nothing left before EOF, in which case
486 + * it returns `EOF`.
487 + */
488 +int strbuf_getdelim_strip_crlf(struct strbuf *sb, FILE *fp, int term);
489 +
490 /**
491 * Read a line from a FILE *, overwriting the existing contents of
492 * the strbuf. The strbuf_getline*() family of functions share