diff --git a/Makefile.am b/Makefile.am index 127b747..4a2ac7b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,6 +33,7 @@ src/pv/format/name.c \ src/pv/format/previousline.c \ src/pv/format/progressbar.c \ src/pv/format/rate.c \ +src/pv/format/sgr.c \ src/pv/format/timer.c \ src/pv/loop.c \ src/pv/number.c \ diff --git a/configure.ac b/configure.ac index deeaf14..d36bef5 100644 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,20 @@ AC_ARG_ENABLE([ipc], [ --disable-ipc turn off IPC messaging], IPC_SUPPORT="yes" ) +AC_ARG_WITH([ncurses], + [AS_HELP_STRING([--without-ncurses], [disable the use of ncurses for terminal info])], + [], + [with_curses=yes]) +AS_IF([test "x$with_ncurses" != xno], +[ + AC_SEARCH_LIBS([tigetnum],[tinfo ncurses], [ + AC_CHECK_HEADERS([term.h],[ + AC_DEFINE([ENABLE_NCURSES], [1], [Build with ncurses support]) + ]) + ], []) +], +[]) + AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static], [enable static linking])], [ diff --git a/docs/NEWS.md b/docs/NEWS.md index 37d5463..06063f8 100644 --- a/docs/NEWS.md +++ b/docs/NEWS.md @@ -2,6 +2,7 @@ * *feature:* new **--bar-style** option to change the default bar style ([#15](https://codeberg.org/a-j-wood/pv/issues/15)) * *feature:* new bar formats "**%{bar-plain}**", "**%{bar-block}**", "**%{bar-granular}**", "**%{bar-shaded}**" ([#15](https://codeberg.org/a-j-wood/pv/issues/15)) + * *feature:* new bar format "**%{sgr:colour,...}**" to use ECMA-48 Select Graphic Rendition codes to add colours * *feature:* allow decimal values such as "1.5G" with "**--size**", "**--rate-limit**", "**--buffer-size**", and "**error-skip-block**" ([#35](https://codeberg.org/a-j-wood/pv/issues/35)) * *cleanup:* track transfer percentage as a floating point value for better precision (and rounding) * *cleanup:* correct detection of **--remote** usability on GNU Hurd diff --git a/docs/pv.1 b/docs/pv.1 index 7b08ad8..7e16699 100644 --- a/docs/pv.1 +++ b/docs/pv.1 @@ -484,6 +484,61 @@ Shows only spaces if the transfer is being done with \fBsplice\fR(2). Show the name prefix given by \*(lq\fB\-\-name\fR\*(rq. Padded to 9 characters with spaces, and suffixed with \*(lq:\*(rq. .TP +.B %{sgr:colour,...} +Emit ECMA-48 SGR (Select Graphic Rendition) codes if the terminal supports +colours, where \fIcolour,...\fR is a comma-separated list of any of the +keywords below, or the numeric values from \fBconsole_codes\fR(4). If +colour support is not available, nothing is emitted. +.TP +.B "" +Supported keywords are: +\fBreset\fR or \fBnone\fR, +\fBblack\fR, +\fBred\fR, +\fBgreen\fR, +\fBbrown\fR or \fByellow\fR, +\fBblue\fR, +\fBmagenta\fR, +\fBcyan\fR, +\fBwhite\fR, +\fBfg\-black\fR, +\fBfg\-red\fR, +\fBfg\-green\fR, +\fBfg\-brown\fR or \fBfg\-yellow\fR, +\fBfg\-blue\fR, +\fBfg\-magenta\fR, +\fBfg\-cyan\fR, +\fBfg\-white\fR, +\fBfg\-default\fR, +\fBbg\-black\fR, +\fBbg\-red\fR, +\fBbg\-green\fR, +\fBbg\-brown\fR or \fBbg\-yellow\fR, +\fBbg\-blue\fR, +\fBbg\-magenta\fR, +\fBbg\-cyan\fR, +\fBbg\-white\fR, +\fBbg\-default\fR, +\fBbold\fR, +\fBdim\fR, +\fBitalic\fR, +\fBunderscore\fR or \fBunderline\fR, +\fBblink\fR, +\fBreverse\fR, +\fBno\-bold\fR or \fBno\-dim\fR, +\fBno\-italic\fR, +\fBno\-underscore\fR or \fBno\-underline\fR, +\fBno\-blink\fR, +\fBno\-reverse\fR. +.TP +.B "" +With colours, the optional "fg-" prefix indicates foreground; a prefix of +"bg-" indicates background. +.TP +.B "" +For example, \*(lq\fB%{sgr:green,bold}TEXT%{sgr:reset}\fR\*(lq will make +\fITEXT\fR bold green on supported terminals. +.TP .B %% A single \*(lq%\*(rq. .PP @@ -736,7 +791,8 @@ Alternatively, use the issue tracker linked from the .BR splice (2), .BR fdatasync (2), .BR open (2) -(for \fBO_DIRECT\fR) +(for \fBO_DIRECT\fR), +.BR console_codes (4) .\" .SH COPYRIGHT Copyright \(co 2002-2008, 2010, 2012-2015, 2017, 2021, 2023-2024 Andrew Wood. diff --git a/docs/pv.1.md b/docs/pv.1.md index e34ba92..03f2d02 100644 --- a/docs/pv.1.md +++ b/docs/pv.1.md @@ -507,6 +507,31 @@ contain the following sequences: : Show the name prefix given by "**\--name**". Padded to 9 characters with spaces, and suffixed with ":". +**%{sgr:colour,\...}** + +: Emit ECMA-48 SGR (Select Graphic Rendition) codes if the terminal + supports colours, where *colour,\...* is a comma-separated list of + any of the keywords below, or the numeric values from + **console_codes**(4). If colour support is not available, nothing is + emitted. + +: Supported keywords are: **reset** or **none**, **black**, **red**, + **green**, **brown** or **yellow**, **blue**, **magenta**, **cyan**, + **white**, **fg-black**, **fg-red**, **fg-green**, **fg-brown** or + **fg-yellow**, **fg-blue**, **fg-magenta**, **fg-cyan**, + **fg-white**, **fg-default**, **bg-black**, **bg-red**, + **bg-green**, **bg-brown** or **bg-yellow**, **bg-blue**, + **bg-magenta**, **bg-cyan**, **bg-white**, **bg-default**, **bold**, + **dim**, **italic**, **underscore** or **underline**, **blink**, + **reverse**, **no-bold** or **no-dim**, **no-italic**, + **no-underscore** or **no-underline**, **no-blink**, **no-reverse**. + +: With colours, the optional \"fg-\" prefix indicates foreground; a + prefix of \"bg-\" indicates background. + +: For example, "**%{sgr:green,bold}TEXT%{sgr:reset}**" will make + *TEXT* bold green on supported terminals. + **%%** : A single "%". @@ -717,7 +742,7 @@ page](https://www.ivarch.com/programs/pv.shtml). # SEE ALSO **cat**(1), **splice**(2), **fdatasync**(2), **open**(2) (for -**O_DIRECT**) +**O_DIRECT**), **console_codes**(4) # COPYRIGHT diff --git a/po/POTFILES.in b/po/POTFILES.in index e89b740..9a7d4e0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -19,6 +19,7 @@ src/pv/format/name.c src/pv/format/previousline.c src/pv/format/progressbar.c src/pv/format/rate.c +src/pv/format/sgr.c src/pv/format/timer.c src/pv/loop.c src/pv/number.c diff --git a/po/cs.po b/po/cs.po index 9180149..65d9f93 100644 --- a/po/cs.po +++ b/po/cs.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: pv@ivarch.com\n" -"POT-Creation-Date: 2024-12-14 00:00+0000\n" +"POT-Creation-Date: 2024-12-15 23:05+0000\n" "PO-Revision-Date: 2024-10-13 20:43+0000\n" "Last-Translator: mmatous \n" "Language-Team: Czech \n" @@ -321,33 +321,33 @@ msgstr "selhala alokace struktury pro argv" msgid "numeric value not understood" msgstr "" -#: src/main/options.c:436 +#: src/main/options.c:435 msgid "integer argument expected" msgstr "očekáván celočíselný argument" -#: src/main/options.c:448 +#: src/main/options.c:447 msgid "numeric argument expected" msgstr "očekáván číselný argument" -#: src/main/options.c:459 +#: src/main/options.c:458 msgid "process ID or pid:fd pair expected" msgstr "očekáváno ID procesu nebo dvojice PID:DS" -#: src/main/options.c:466 +#: src/main/options.c:465 msgid "invalid process ID" msgstr "neplatné ID procesu" -#: src/main/options.c:699 +#: src/main/options.c:698 #, c-format msgid "Try `%s --help' for more information." msgstr "Zkuste `%s --help' pro více informací." -#: src/main/options.c:701 +#: src/main/options.c:700 #, c-format msgid "Try `%s -h' for more information." msgstr "Zkuste `%s --h' pro více informací." -#: src/main/options.c:732 +#: src/main/options.c:731 msgid "" "cannot use line mode or transfer modifier options when watching file " "descriptors" @@ -355,19 +355,19 @@ msgstr "" "při sledování deskriptorů souborů nelze použít řádkový mód nebo volby pro " "modifikaci přenosu" -#: src/main/options.c:741 +#: src/main/options.c:740 msgid "cannot use cursor positioning when watching file descriptors" msgstr "při sledování deskriptorů souborů nelze pozicování kurzoru použít" -#: src/main/options.c:750 +#: src/main/options.c:749 msgid "cannot use remote control when watching file descriptors" msgstr "při sledování deskriptorů souborů nelze použít vzdálené ovládání" -#: src/main/options.c:759 +#: src/main/options.c:758 msgid "cannot transfer files when watching file descriptors" msgstr "při sledování deskriptorů souborů nelze použít přenos souborů" -#: src/main/options.c:774 +#: src/main/options.c:773 msgid "not available on systems without /proc/self/fdinfo" msgstr "není dostupné na systémech bez /proc/self/fdinfo" @@ -411,15 +411,15 @@ msgstr "selhal pokus o uzamčení" msgid "failed to open terminal" msgstr "selhalo otevření terminálu" -#: src/pv/display.c:232 +#: src/pv/display.c:239 msgid "yzafpnum kMGTPEZY" msgstr "yzafpnum kMGTPEZY" -#: src/pv/display.c:250 +#: src/pv/display.c:257 msgid "yzafpnum KMGTPEZY" msgstr "yzafpnum KMGTPEZY" -#: src/pv/display.c:918 src/pv/transfer.c:1056 +#: src/pv/display.c:1004 src/pv/transfer.c:1056 msgid "buffer allocation failed" msgstr "selhala alokace vyrovnávací paměti" diff --git a/po/de.po b/po/de.po index b537f1e..5ea9511 100644 --- a/po/de.po +++ b/po/de.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: pv@ivarch.com\n" -"POT-Creation-Date: 2024-12-14 00:00+0000\n" +"POT-Creation-Date: 2024-12-15 23:05+0000\n" "PO-Revision-Date: 2024-10-13 20:43+0000\n" "Last-Translator: fnetX \n" "Language-Team: German \n" @@ -339,33 +339,33 @@ msgstr "Speicherzuweisung für `argv' der Option fehlgeschlagen" msgid "numeric value not understood" msgstr "" -#: src/main/options.c:436 +#: src/main/options.c:435 msgid "integer argument expected" msgstr "Ganzzahliges Argument erwartet" -#: src/main/options.c:448 +#: src/main/options.c:447 msgid "numeric argument expected" msgstr "numerisches Argument erwartet" -#: src/main/options.c:459 +#: src/main/options.c:458 msgid "process ID or pid:fd pair expected" msgstr "Prozess-ID oder PID:FD-Paar erwartet" -#: src/main/options.c:466 +#: src/main/options.c:465 msgid "invalid process ID" msgstr "ungültige Prozess-ID" -#: src/main/options.c:699 +#: src/main/options.c:698 #, c-format msgid "Try `%s --help' for more information." msgstr "`%s --help' zeigt weitere Informationen an." -#: src/main/options.c:701 +#: src/main/options.c:700 #, c-format msgid "Try `%s -h' for more information." msgstr "`%s -h' zeigt weitere Informationen an." -#: src/main/options.c:732 +#: src/main/options.c:731 msgid "" "cannot use line mode or transfer modifier options when watching file " "descriptors" @@ -373,24 +373,24 @@ msgstr "" "Beim Beobachten von Dateideskriptoren können keine Optionen für den " "Zeilenmodus oder den Übertragungsmodifikator verwendet werden" -#: src/main/options.c:741 +#: src/main/options.c:740 msgid "cannot use cursor positioning when watching file descriptors" msgstr "" "Beim Beobachten von Dateideskriptoren kann Cursor-Positionierung nicht " "verwendet werden" -#: src/main/options.c:750 +#: src/main/options.c:749 msgid "cannot use remote control when watching file descriptors" msgstr "" "Beim Beobachten von Dateideskriptoren kann die Fernbedienung nicht verwenden " "werden" -#: src/main/options.c:759 +#: src/main/options.c:758 msgid "cannot transfer files when watching file descriptors" msgstr "" "Beim Beobachten von Dateideskriptoren können Dateien nicht übertragen werden" -#: src/main/options.c:774 +#: src/main/options.c:773 msgid "not available on systems without /proc/self/fdinfo" msgstr "Nicht verfügbar auf Systemen ohne /proc/self/fdinfo" @@ -434,15 +434,15 @@ msgstr "Sperrversuch fehlgeschlagen" msgid "failed to open terminal" msgstr "konnte Terminal nicht öffnen" -#: src/pv/display.c:232 +#: src/pv/display.c:239 msgid "yzafpnum kMGTPEZY" msgstr "yzafpnµm kMGTPEZY" -#: src/pv/display.c:250 +#: src/pv/display.c:257 msgid "yzafpnum KMGTPEZY" msgstr "yzafpnµm KMGTPEZY" -#: src/pv/display.c:918 src/pv/transfer.c:1056 +#: src/pv/display.c:1004 src/pv/transfer.c:1056 msgid "buffer allocation failed" msgstr "Speicherzuweisung für den Puffer fehlgeschlagen" diff --git a/po/es.po b/po/es.po index b23ae21..189916f 100644 --- a/po/es.po +++ b/po/es.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: pv@ivarch.com\n" -"POT-Creation-Date: 2024-12-14 00:00+0000\n" +"POT-Creation-Date: 2024-12-15 23:05+0000\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -315,51 +315,51 @@ msgstr "" msgid "numeric value not understood" msgstr "" -#: src/main/options.c:436 +#: src/main/options.c:435 msgid "integer argument expected" msgstr "" -#: src/main/options.c:448 +#: src/main/options.c:447 msgid "numeric argument expected" msgstr "" -#: src/main/options.c:459 +#: src/main/options.c:458 msgid "process ID or pid:fd pair expected" msgstr "" -#: src/main/options.c:466 +#: src/main/options.c:465 msgid "invalid process ID" msgstr "" -#: src/main/options.c:699 +#: src/main/options.c:698 #, c-format msgid "Try `%s --help' for more information." msgstr "" -#: src/main/options.c:701 +#: src/main/options.c:700 #, c-format msgid "Try `%s -h' for more information." msgstr "" -#: src/main/options.c:732 +#: src/main/options.c:731 msgid "" "cannot use line mode or transfer modifier options when watching file " "descriptors" msgstr "" -#: src/main/options.c:741 +#: src/main/options.c:740 msgid "cannot use cursor positioning when watching file descriptors" msgstr "" -#: src/main/options.c:750 +#: src/main/options.c:749 msgid "cannot use remote control when watching file descriptors" msgstr "" -#: src/main/options.c:759 +#: src/main/options.c:758 msgid "cannot transfer files when watching file descriptors" msgstr "" -#: src/main/options.c:774 +#: src/main/options.c:773 msgid "not available on systems without /proc/self/fdinfo" msgstr "" @@ -403,15 +403,15 @@ msgstr "" msgid "failed to open terminal" msgstr "" -#: src/pv/display.c:232 +#: src/pv/display.c:239 msgid "yzafpnum kMGTPEZY" msgstr "" -#: src/pv/display.c:250 +#: src/pv/display.c:257 msgid "yzafpnum KMGTPEZY" msgstr "" -#: src/pv/display.c:918 src/pv/transfer.c:1056 +#: src/pv/display.c:1004 src/pv/transfer.c:1056 msgid "buffer allocation failed" msgstr "" diff --git a/po/fr.po b/po/fr.po index 3dc7a61..f7076af 100644 --- a/po/fr.po +++ b/po/fr.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: pv@ivarch.com\n" -"POT-Creation-Date: 2024-12-14 00:00+0000\n" +"POT-Creation-Date: 2024-12-15 23:05+0000\n" "PO-Revision-Date: 2024-10-12 11:13+0000\n" "Last-Translator: a-j-wood \n" "Language-Team: French \n" @@ -340,33 +340,33 @@ msgstr "l'allocation pour la structure de l'option argv a échoué" msgid "numeric value not understood" msgstr "" -#: src/main/options.c:436 +#: src/main/options.c:435 msgid "integer argument expected" msgstr "Valeur entière attendue" -#: src/main/options.c:448 +#: src/main/options.c:447 msgid "numeric argument expected" msgstr "Valeur numérique attendue" -#: src/main/options.c:459 +#: src/main/options.c:458 msgid "process ID or pid:fd pair expected" msgstr "ID de processus ou paire pid:fd attendue" -#: src/main/options.c:466 +#: src/main/options.c:465 msgid "invalid process ID" msgstr "ID de processus non valide" -#: src/main/options.c:699 +#: src/main/options.c:698 #, c-format msgid "Try `%s --help' for more information." msgstr "Essayez `%s --help' pour plus d'informations." -#: src/main/options.c:701 +#: src/main/options.c:700 #, c-format msgid "Try `%s -h' for more information." msgstr "Essayez `%s -h' pour plus d'informations." -#: src/main/options.c:732 +#: src/main/options.c:731 msgid "" "cannot use line mode or transfer modifier options when watching file " "descriptors" @@ -374,25 +374,25 @@ msgstr "" "impossible d'utiliser le mode ligne ou les options de modificateur de " "transfert lors de la visualisation des descripteurs de fichiers" -#: src/main/options.c:741 +#: src/main/options.c:740 msgid "cannot use cursor positioning when watching file descriptors" msgstr "" "impossible d'utiliser le positionnement du curseur lors de la visualisation " "des descripteurs de fichier" -#: src/main/options.c:750 +#: src/main/options.c:749 msgid "cannot use remote control when watching file descriptors" msgstr "" "impossible d'utiliser la télécommande lors de la visualisation des " "descripteurs de fichiers" -#: src/main/options.c:759 +#: src/main/options.c:758 msgid "cannot transfer files when watching file descriptors" msgstr "" "impossible de transférer des fichiers lorsque vous regardez des descripteurs " "de fichiers" -#: src/main/options.c:774 +#: src/main/options.c:773 msgid "not available on systems without /proc/self/fdinfo" msgstr "non disponible sur les systèmes sans /proc/self/fdinfo" @@ -438,15 +438,15 @@ msgstr "échec de la tentative de verrouillage" msgid "failed to open terminal" msgstr "échec de l'ouverture du terminal" -#: src/pv/display.c:232 +#: src/pv/display.c:239 msgid "yzafpnum kMGTPEZY" msgstr "" -#: src/pv/display.c:250 +#: src/pv/display.c:257 msgid "yzafpnum KMGTPEZY" msgstr "" -#: src/pv/display.c:918 src/pv/transfer.c:1056 +#: src/pv/display.c:1004 src/pv/transfer.c:1056 msgid "buffer allocation failed" msgstr "échec de l'allocation de mémoire tampon" diff --git a/po/pl.po b/po/pl.po index 0bf39af..b4971dc 100644 --- a/po/pl.po +++ b/po/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: pv@ivarch.com\n" -"POT-Creation-Date: 2024-12-14 00:00+0000\n" +"POT-Creation-Date: 2024-12-15 23:05+0000\n" "PO-Revision-Date: 2024-10-20 14:07+0000\n" "Last-Translator: coralpink \n" "Language-Team: Polish \n" @@ -334,33 +334,33 @@ msgstr "nie udało się zaalokować struktur opcji argv" msgid "numeric value not understood" msgstr "" -#: src/main/options.c:436 +#: src/main/options.c:435 msgid "integer argument expected" msgstr "oczekiwany argument typu liczby całkowitej" -#: src/main/options.c:448 +#: src/main/options.c:447 msgid "numeric argument expected" msgstr "oczekiwany argument liczbowy" -#: src/main/options.c:459 +#: src/main/options.c:458 msgid "process ID or pid:fd pair expected" msgstr "oczekiwany proces ID lub para PID:FD" -#: src/main/options.c:466 +#: src/main/options.c:465 msgid "invalid process ID" msgstr "niepoprawne ID procesu" -#: src/main/options.c:699 +#: src/main/options.c:698 #, c-format msgid "Try `%s --help' for more information." msgstr "Spróbuj `%s --help' by uzyskać więcej informacji." -#: src/main/options.c:701 +#: src/main/options.c:700 #, c-format msgid "Try `%s -h' for more information." msgstr "Spróbuj `%s -h' by uzyskać więcej informacji." -#: src/main/options.c:732 +#: src/main/options.c:731 msgid "" "cannot use line mode or transfer modifier options when watching file " "descriptors" @@ -368,23 +368,23 @@ msgstr "" "nie można użyć trybu zliczania linii lub opcji modyfikujących przesył " "łącznie z opcją obserwowania deskryptorów plików" -#: src/main/options.c:741 +#: src/main/options.c:740 msgid "cannot use cursor positioning when watching file descriptors" msgstr "" "nie można użyć pozycjonowania kursora łącznie z opcją obserwowania " "deskryptorów plików" -#: src/main/options.c:750 +#: src/main/options.c:749 msgid "cannot use remote control when watching file descriptors" msgstr "" "nie można użyć opcji zaktualizowania ustawień procesu łącznie z opcją " "obserwowania deskryptorów plików" -#: src/main/options.c:759 +#: src/main/options.c:758 msgid "cannot transfer files when watching file descriptors" msgstr "nie można przesyłać plików z opcją obserwowania deskryptorów plików" -#: src/main/options.c:774 +#: src/main/options.c:773 msgid "not available on systems without /proc/self/fdinfo" msgstr "niedostępne na systemach bez /proc/self/fdinfo" @@ -429,15 +429,15 @@ msgstr "blokada zasobów nie powiodła się" msgid "failed to open terminal" msgstr "nie udało się otworzyć terminala" -#: src/pv/display.c:232 +#: src/pv/display.c:239 msgid "yzafpnum kMGTPEZY" msgstr "yzafpnum kMGTPEZY" -#: src/pv/display.c:250 +#: src/pv/display.c:257 msgid "yzafpnum KMGTPEZY" msgstr "yzafpnum KMGTPEZY" -#: src/pv/display.c:918 src/pv/transfer.c:1056 +#: src/pv/display.c:1004 src/pv/transfer.c:1056 msgid "buffer allocation failed" msgstr "nie udało się zaalokować bufora" diff --git a/po/pt.po b/po/pt.po index 0334025..d767203 100644 --- a/po/pt.po +++ b/po/pt.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: pv@ivarch.com\n" -"POT-Creation-Date: 2024-12-14 00:00+0000\n" +"POT-Creation-Date: 2024-12-15 23:05+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -325,33 +325,33 @@ msgstr "erro na alocação da estrutura de opções argv" msgid "numeric value not understood" msgstr "" -#: src/main/options.c:436 +#: src/main/options.c:435 msgid "integer argument expected" msgstr "argumento inteiro esperado" -#: src/main/options.c:448 +#: src/main/options.c:447 msgid "numeric argument expected" msgstr "argumento numérico esperado" -#: src/main/options.c:459 +#: src/main/options.c:458 msgid "process ID or pid:fd pair expected" msgstr "ID do processo ou par pid:fd esperado" -#: src/main/options.c:466 +#: src/main/options.c:465 msgid "invalid process ID" msgstr "ID de processo inválido" -#: src/main/options.c:699 +#: src/main/options.c:698 #, c-format msgid "Try `%s --help' for more information." msgstr "Tente `%s --help' para maiores informações." -#: src/main/options.c:701 +#: src/main/options.c:700 #, c-format msgid "Try `%s -h' for more information." msgstr "Tente `%s -h' para maiores informações." -#: src/main/options.c:732 +#: src/main/options.c:731 msgid "" "cannot use line mode or transfer modifier options when watching file " "descriptors" @@ -359,21 +359,21 @@ msgstr "" "não pode usar o modo de linha ou opções de modificador de transferência ao " "assistir os descritores de arquivo" -#: src/main/options.c:741 +#: src/main/options.c:740 msgid "cannot use cursor positioning when watching file descriptors" msgstr "" "não pode usar o posicionamento do cursor ao observar os descritores de " "arquivo" -#: src/main/options.c:750 +#: src/main/options.c:749 msgid "cannot use remote control when watching file descriptors" msgstr "não pode usar o controle remoto ao assistir os descritores de arquivo" -#: src/main/options.c:759 +#: src/main/options.c:758 msgid "cannot transfer files when watching file descriptors" msgstr "não pode transferir arquivos ao assistir descritores de arquivo" -#: src/main/options.c:774 +#: src/main/options.c:773 msgid "not available on systems without /proc/self/fdinfo" msgstr "não disponível em sistemas sem /proc/self/fdinfo" @@ -417,15 +417,15 @@ msgstr "tentativa de bloqueio falhou" msgid "failed to open terminal" msgstr "erro abrindo o terminal" -#: src/pv/display.c:232 +#: src/pv/display.c:239 msgid "yzafpnum kMGTPEZY" msgstr "" -#: src/pv/display.c:250 +#: src/pv/display.c:257 msgid "yzafpnum KMGTPEZY" msgstr "" -#: src/pv/display.c:918 src/pv/transfer.c:1056 +#: src/pv/display.c:1004 src/pv/transfer.c:1056 msgid "buffer allocation failed" msgstr "erro alocando o buffer" diff --git a/po/ru.po b/po/ru.po index c6a7060..8030c86 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: pv@ivarch.com\n" -"POT-Creation-Date: 2024-12-14 00:00+0000\n" +"POT-Creation-Date: 2024-12-15 23:05+0000\n" "PO-Revision-Date: 2024-10-22 18:07+0000\n" "Last-Translator: 0ko <0ko@users.noreply.translate.codeberg.org>\n" "Language-Team: Russian \n" @@ -322,51 +322,51 @@ msgstr "не удалось выделить память для структу msgid "numeric value not understood" msgstr "" -#: src/main/options.c:436 +#: src/main/options.c:435 msgid "integer argument expected" msgstr "ожидалось целое число" -#: src/main/options.c:448 +#: src/main/options.c:447 msgid "numeric argument expected" msgstr "ожидалось число" -#: src/main/options.c:459 +#: src/main/options.c:458 msgid "process ID or pid:fd pair expected" msgstr "ожидался ИД процесса или пара ИДпр:ДФ" -#: src/main/options.c:466 +#: src/main/options.c:465 msgid "invalid process ID" msgstr "неправильный ИД процесса" -#: src/main/options.c:699 +#: src/main/options.c:698 #, c-format msgid "Try `%s --help' for more information." msgstr "Выполните `%s --help' для получения подробностей." -#: src/main/options.c:701 +#: src/main/options.c:700 #, c-format msgid "Try `%s -h' for more information." msgstr "Выполните `%s -h' для получения подробностей." -#: src/main/options.c:732 +#: src/main/options.c:731 msgid "" "cannot use line mode or transfer modifier options when watching file " "descriptors" msgstr "" -#: src/main/options.c:741 +#: src/main/options.c:740 msgid "cannot use cursor positioning when watching file descriptors" msgstr "" -#: src/main/options.c:750 +#: src/main/options.c:749 msgid "cannot use remote control when watching file descriptors" msgstr "удалённое управление невозможно при отслеживании дескрипторов файлов" -#: src/main/options.c:759 +#: src/main/options.c:758 msgid "cannot transfer files when watching file descriptors" msgstr "передача файлов невозможна при отслеживании дескрипторов файлов" -#: src/main/options.c:774 +#: src/main/options.c:773 msgid "not available on systems without /proc/self/fdinfo" msgstr "невозможно на системах без /proc/self/fdinfo" @@ -412,15 +412,15 @@ msgstr "попытка блокировки не удалась" msgid "failed to open terminal" msgstr "не удалось открыть терминал" -#: src/pv/display.c:232 +#: src/pv/display.c:239 msgid "yzafpnum kMGTPEZY" msgstr "" -#: src/pv/display.c:250 +#: src/pv/display.c:257 msgid "yzafpnum KMGTPEZY" msgstr "" -#: src/pv/display.c:918 src/pv/transfer.c:1056 +#: src/pv/display.c:1004 src/pv/transfer.c:1056 msgid "buffer allocation failed" msgstr "не удалось выделить память для буфера" diff --git a/po/tr.po b/po/tr.po index 62ce698..5a610cc 100644 --- a/po/tr.po +++ b/po/tr.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: pv 1.8.14\n" "Report-Msgid-Bugs-To: pv@ivarch.com\n" -"POT-Creation-Date: 2024-12-14 00:00+0000\n" +"POT-Creation-Date: 2024-12-15 23:05+0000\n" "PO-Revision-Date: 2024-10-12 23:51+0000\n" "Last-Translator: a-j-wood \n" "Language-Team: Turkish \n" @@ -322,33 +322,33 @@ msgstr "seçenek yapısı argv tahsisi başarısız oldu" msgid "numeric value not understood" msgstr "" -#: src/main/options.c:436 +#: src/main/options.c:435 msgid "integer argument expected" msgstr "tamsayı bağımsız değişkeni bekleniyor" -#: src/main/options.c:448 +#: src/main/options.c:447 msgid "numeric argument expected" msgstr "sayısal bağımsız değişken bekleniyor" -#: src/main/options.c:459 +#: src/main/options.c:458 msgid "process ID or pid:fd pair expected" msgstr "süreç kimliği (ID) veya pid:fd çifti bekleniyor" -#: src/main/options.c:466 +#: src/main/options.c:465 msgid "invalid process ID" msgstr "geçersiz süreç kimliği (ID)" -#: src/main/options.c:699 +#: src/main/options.c:698 #, c-format msgid "Try `%s --help' for more information." msgstr "Daha fazla bilgi için `%s --help' seçeneğini deneyin." -#: src/main/options.c:701 +#: src/main/options.c:700 #, c-format msgid "Try `%s -h' for more information." msgstr "Daha fazla bilgi için `%s -h' seçeneğini deneyin." -#: src/main/options.c:732 +#: src/main/options.c:731 msgid "" "cannot use line mode or transfer modifier options when watching file " "descriptors" @@ -356,19 +356,19 @@ msgstr "" "dosya tanımlayıcılarını izlerken satır modu veya aktarım değiştirici " "seçeneklerini kullanamaz" -#: src/main/options.c:741 +#: src/main/options.c:740 msgid "cannot use cursor positioning when watching file descriptors" msgstr "dosya tanımlayıcılarını izlerken imleç konumlandırmayı kullanamaz" -#: src/main/options.c:750 +#: src/main/options.c:749 msgid "cannot use remote control when watching file descriptors" msgstr "dosya tanımlayıcılarını izlerken uzaktan kumandayı kullanamaz" -#: src/main/options.c:759 +#: src/main/options.c:758 msgid "cannot transfer files when watching file descriptors" msgstr "dosya tanımlayıcıları izlenirken dosya aktarılamıyor" -#: src/main/options.c:774 +#: src/main/options.c:773 msgid "not available on systems without /proc/self/fdinfo" msgstr "/proc/self/fdinfo olmayan sistemlerde kullanılamaz" @@ -413,15 +413,15 @@ msgstr "kilit denemesi başarısız oldu" msgid "failed to open terminal" msgstr "terminal açılamadı" -#: src/pv/display.c:232 +#: src/pv/display.c:239 msgid "yzafpnum kMGTPEZY" msgstr "yzafpnum kMGTPEZY" -#: src/pv/display.c:250 +#: src/pv/display.c:257 msgid "yzafpnum KMGTPEZY" msgstr "yzafpnum KMGTPEZY" -#: src/pv/display.c:918 src/pv/transfer.c:1056 +#: src/pv/display.c:1004 src/pv/transfer.c:1056 msgid "buffer allocation failed" msgstr "arabellek tahsisi başarısız oldu" diff --git a/src/include/config.h.in b/src/include/config.h.in index 05cd084..acecf5c 100644 --- a/src/include/config.h.in +++ b/src/include/config.h.in @@ -3,6 +3,9 @@ /* Debugging support enabled */ #undef ENABLE_DEBUGGING +/* Build with ncurses support */ +#undef ENABLE_NCURSES + /* Define to 1 if translation of program messages to the user's native language is requested. */ #undef ENABLE_NLS @@ -203,6 +206,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H +/* Define to 1 if you have the header file. */ +#undef HAVE_TERM_H + /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index 40fb3e8..28a9752 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -186,6 +186,8 @@ struct pvstate_s { bool discard_input; /* write nothing to stdout */ bool show_stats; /* show statistics on exit */ bool can_display_utf8; /* whether UTF-8 output is permitted */ + bool can_display_colour; /* whether the terminal supports colour */ + bool checked_colour_support; /* whether we have checked colour support yet */ bool width_set_manually; /* width was set manually, not detected */ bool height_set_manually; /* height was set manually, not detected */ } control; @@ -237,10 +239,12 @@ struct pvstate_s { /* See pv__format_init() for more details. */ int type; /* component type, -1 for static string */ int parameter; /* component parameter, such as bar style index */ + uint8_t string_parameter_bytes; /* number of bytes in string_parameter */ size_t chosen_size; /* "n" from %A, or 0 */ - size_t offset; /* start offset of this segment */ - size_t bytes; /* length of segment in bytes */ + size_t offset; /* start offset of this segment in the build buffer */ + size_t bytes; /* length of segment in bytes in the build buffer */ size_t width; /* displayed width of segment */ + /*@dependent@*/ /*@null@*/ const char *string_parameter; /* parameter after colon in %{x:} */ } format[PV_FORMAT_ARRAY_MAX]; struct pvbarstyle_s barstyle[PV_BARSTYLE_MAX]; @@ -273,6 +277,9 @@ struct pvstate_s { bool showing_last_written; /* set if displaying the last few bytes written */ bool showing_previous_line; /* set if displaying the previously output line */ + bool format_uses_colour; /* set if the format string uses colours */ + bool colour_permitted; /* whether colour is permitted for this display */ + bool sgr_code_active; /* set while SGR code is active in a display line */ bool final_update; /* set internally on the final update */ bool display_visible; /* set once anything written to terminal */ @@ -511,6 +518,7 @@ size_t pv_formatter_buffer_percent(pvformatter_args_t); size_t pv_formatter_last_written(pvformatter_args_t); size_t pv_formatter_previous_line(pvformatter_args_t); size_t pv_formatter_name(pvformatter_args_t); +size_t pv_formatter_sgr(pvformatter_args_t); bool pv_format(pvstate_t, /*@null@*/ const char *, pvdisplay_t, bool, bool); void pv_display(pvstate_t, bool); diff --git a/src/pv/display.c b/src/pv/display.c index 889262c..9f3b948 100644 --- a/src/pv/display.c +++ b/src/pv/display.c @@ -22,6 +22,13 @@ #include #endif +#ifdef ENABLE_NCURSES +#ifdef HAVE_TERM_H +#include +#endif +#endif + + /* * We need sys/ioctl.h for ioctl() regardless of whether TIOCGWINSZ is * defined in termios.h, so we no longer use AC_HEADER_TIOCGWINSZ in @@ -566,6 +573,7 @@ static bool pv__format_numeric(pvstate_t state, pvdisplay_t display) { "{previous-line}", &pv_formatter_previous_line, true }, { "N", &pv_formatter_name, false }, { "{name}", &pv_formatter_name, false }, + { "{sgr:colour,...}", &pv_formatter_sgr, false }, { NULL, NULL, false } }; return format_component_array; @@ -636,6 +644,7 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp display->showing_rate = false; display->showing_last_written = false; display->showing_previous_line = false; + display->format_uses_colour = false; display_format = NULL == format_supplied ? state->control.default_format : format_supplied; @@ -666,6 +675,8 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp for (strpos = 0; display_format[strpos] != '\0' && segment < PV_FORMAT_ARRAY_MAX; strpos++, segment++) { int component_type, component_idx; size_t str_start, str_bytes, chosen_size; + const char *string_parameter = NULL; + size_t string_parameter_bytes = 0; str_start = strpos; str_bytes = 0; @@ -674,7 +685,7 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp if ('%' == display_format[strpos]) { unsigned long number_prefix; - size_t percent_sign_offset, sequence_start, sequence_length; + size_t percent_sign_offset, sequence_start, sequence_length, sequence_colon_offset; #if HAVE_STRTOUL char *number_end_ptr; #endif @@ -705,11 +716,14 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp sequence_start = strpos; sequence_length = 0; + sequence_colon_offset = 0; if ('\0' != display_format[strpos]) sequence_length = 1; if ('{' == display_format[strpos]) { while ('\0' != display_format[strpos] && '}' != display_format[strpos] && '%' != display_format[strpos]) { + if (':' == display_format[strpos]) + sequence_colon_offset = sequence_length; strpos++; sequence_length++; } @@ -718,15 +732,40 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp component_type = -1; for (component_idx = 0; NULL != format_component_array[component_idx].match; component_idx++) { size_t component_sequence_length = strlen(format_component_array[component_idx].match); /* flawfinder: ignore */ + char *component_colon_pointer = + strchr(format_component_array[component_idx].match, (int) ':'); + /* flawfinder - static strings, guaranteed null-terminated. */ - if (component_sequence_length != sequence_length) - continue; - if (0 != - strncmp(format_component_array[component_idx].match, - &(display_format[sequence_start]), sequence_length)) - continue; - component_type = component_idx; - break; + + if ((component_sequence_length == sequence_length) + && (0 == + strncmp(format_component_array[component_idx].match, + &(display_format[sequence_start]), sequence_length)) + ) { + component_type = component_idx; + break; + } + + if (sequence_colon_offset > 0 && NULL != component_colon_pointer) { + size_t component_colon_offset = + (size_t) (1 + component_colon_pointer - + format_component_array[component_idx].match); + if ((component_colon_offset == sequence_colon_offset) + && (0 == + strncmp(format_component_array[component_idx].match, + &(display_format[sequence_start]), sequence_colon_offset)) + ) { + component_type = component_idx; + string_parameter = + &(display_format[sequence_start + sequence_colon_offset]); + string_parameter_bytes = sequence_length - sequence_colon_offset; + if (string_parameter_bytes > 0) + string_parameter_bytes--; /* the closing '}' */ + if (string_parameter_bytes > 255) + string_parameter_bytes = 255; + break; + } + } } if (-1 == component_type) { @@ -770,6 +809,8 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp display->format[segment].type = component_type; display->format[segment].chosen_size = chosen_size; + display->format[segment].string_parameter = string_parameter; + display->format[segment].string_parameter_bytes = string_parameter_bytes; if (-1 == component_type) { if (0 == str_bytes) @@ -824,6 +865,51 @@ static void pv__format_init(pvstate_t state, /*@null@ */ const char *format_supp display->format_segment_count++; } + + if (display->format_uses_colour && !state->control.checked_colour_support) { + state->control.checked_colour_support = true; +#ifdef ENABLE_NCURSES + /* + * If we have terminal info support, check whether the + * current terminal supports colour - or just assume it's + * supported if we're forcing output. + */ + if (true == state->control.force) { + state->control.can_display_colour = true; + debug("%s", "force mode - assuming terminal supports colour"); + } else { + char *term_env = NULL; + + term_env = getenv("TERM"); /* flawfinder: ignore */ + /* + * flawfinder - here we pass responsibility to the + * ncurses library to behave OK with $TERM. + */ + state->control.can_display_colour = false; + if (NULL != term_env) { + int setup_err = 0; + + if ((0 == setupterm(term_env, STDERR_FILENO, &setup_err)) + && (tigetnum("colors") > 1) + ) { + state->control.can_display_colour = true; + debug("%s: %s", term_env, "terminal supports colour"); + } + } else { + /* If TERM is unset, disable colour. */ + state->control.can_display_colour = false; + } + } +#else /* ! ENABLE_NCURSES */ + /* + * Without terminal info support, always assume colour is + * supported. + */ + /* TODO: call "tput colors" with popen() instead. */ + state->control.can_display_colour = true; + debug("%s", "no terminal info support - assuming terminal supports colour"); +#endif /* ENABLE_NCURSES */ + } } @@ -933,6 +1019,9 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl return pv__format_numeric(state, display); } + /* Clear the SGR active codes flag, for the SGR formatter. */ + display->sgr_code_active = false; + /* * Populate the internal segments buffer with each component's * output, in two passes. @@ -1066,6 +1155,16 @@ bool pv_format(pvstate_t state, /*@null@ */ const char *format_supplied, pvdispl segment->bytes, display->display_buffer + display_buffer_offset - segment->bytes); } + /* If the SGR active codes flag is set, we need to emit an SGR reset. */ + if (display->sgr_code_active) { + debug("%s", "SGR codes still active - adding reset"); + (void) pv_strlcat(display->display_buffer, "\033[m", display->display_buffer_size); + new_display_string_bytes += 3; + if (new_display_string_bytes > display->display_buffer_size) + new_display_string_bytes = display->display_buffer_size; + display->sgr_code_active = false; + } + debug("%s: %d", "new display string length in bytes", (int) new_display_string_bytes); debug("%s: %d", "new display string width", (int) new_display_string_width); @@ -1117,6 +1216,13 @@ void pv_display(pvstate_t state, bool final) pv_calculate_transfer_rate(state, final); + /* + * Enable colour on the main display, and disable it on the extra + * display (process title, window title). + */ + state->display.colour_permitted = true; + state->extra_display.colour_permitted = false; + /* * If the display options need reparsing, do so to generate new * formatting parameters. diff --git a/src/pv/format/sgr.c b/src/pv/format/sgr.c new file mode 100644 index 0000000..ffea78f --- /dev/null +++ b/src/pv/format/sgr.c @@ -0,0 +1,213 @@ +/* + * Formatter function for ECMA-48 SGR codes. + * + * Copyright 2024 Andrew Wood + * + * License GPLv3+: GNU GPL version 3 or later; see `docs/COPYING'. + */ + +#include "config.h" +#include "pv.h" +#include "pv-internal.h" + +#include + +struct sgr_keyword_map_s { + /*@null@ */ const char *keyword; + uint8_t bytes; + uint8_t code; +}; + + +/* + * Return an array mapping keywords to ECMA-48 SGR code numbers. + */ +/*@keep@ */ static struct sgr_keyword_map_s *sgr_keywords(void) +{ + /*@keep@ */ static struct sgr_keyword_map_s keywords[] = { + { "reset", 0, 0 }, + { "none", 0, 0 }, + { "bold", 0, 1 }, + { "dim", 0, 2 }, + { "italic", 0, 3 }, + { "underscore", 0, 4 }, + { "underline", 0, 4 }, + { "blink", 0, 5 }, + { "reverse", 0, 7 }, + { "no-bold", 0, 22 }, /* same as no-dim */ + { "no-dim", 0, 22 }, + { "no-italic", 0, 23 }, + { "no-underscore", 0, 24 }, + { "no-underline", 0, 24 }, + { "no-blink", 0, 25 }, + { "no-reverse", 0, 27 }, + { "black", 0, 30 }, + { "red", 0, 31 }, + { "green", 0, 32 }, + { "brown", 0, 33 }, + { "yellow", 0, 33 }, + { "blue", 0, 34 }, + { "magenta", 0, 35 }, + { "cyan", 0, 36 }, + { "white", 0, 37 }, + { "fg-black", 0, 30 }, + { "fg-red", 0, 31 }, + { "fg-green", 0, 32 }, + { "fg-brown", 0, 33 }, + { "fg-yellow", 0, 33 }, + { "fg-blue", 0, 34 }, + { "fg-magenta", 0, 35 }, + { "fg-cyan", 0, 36 }, + { "fg-white", 0, 37 }, + { "fg-default", 0, 39 }, + { "bg-black", 0, 40 }, + { "bg-red", 0, 41 }, + { "bg-green", 0, 42 }, + { "bg-brown", 0, 43 }, + { "bg-yellow", 0, 43 }, + { "bg-blue", 0, 44 }, + { "bg-magenta", 0, 45 }, + { "bg-cyan", 0, 46 }, + { "bg-white", 0, 47 }, + { "bg-default", 0, 49 }, + { NULL, 0, 0 } + }; + int keyword_index; + + /* Calculate the lengths of each keyword on the first call. */ + if (0 == keywords[0].bytes) { + for (keyword_index = 0; NULL != keywords[keyword_index].keyword; keyword_index++) { + keywords[keyword_index].bytes = strlen(keywords[keyword_index].keyword); /* flawfinder: ignore */ + /* flawfinder - strlen() on a static null-terminated string is OK. */ + } + } + + /*@-compmempass@ */ + return keywords; + /*@+compmempass@ */ + /* + * splint - found no other way to pass static back without a false + * positive warning about a memory leak. + */ +} + + +/* + * Display SGR codes if colour output is supported. + */ +size_t pv_formatter_sgr(pvformatter_args_t args) +{ + /*@keep@ */ static struct sgr_keyword_map_s *keywords; + char content[1024]; /* flawfinder: ignore */ + size_t write_position, read_position, keyword_start, keyword_length; + int numeric_value, code_count, most_recent_code; + + /* flawfinder - null-terminated and bounded with pv_snprintf(). */ + + args->display->format_uses_colour = true; + + if (!args->display->colour_permitted) + return 0; + if (!args->state->control.can_display_colour) + return 0; + if (NULL == args->segment->string_parameter) + return 0; + if (0 == args->segment->string_parameter_bytes) + return 0; + + keywords = sgr_keywords(); + + write_position = 0; + content[0] = '\0'; + + debug("%p+%d [%.*s]", args->segment->string_parameter, args->segment->string_parameter_bytes, + args->segment->string_parameter_bytes, args->segment->string_parameter); + + read_position = 0; + keyword_start = 0; + keyword_length = 0; + numeric_value = -1; + code_count = 0; + most_recent_code = -1; + + while (read_position < args->segment->string_parameter_bytes) { + char read_char = args->segment->string_parameter[read_position++]; + if ((',' == read_char) || (';' == read_char)) { + keyword_length = read_position - keyword_start; + if (keyword_length > 0) + keyword_length--; + } else { + if ((read_char >= '0' && read_char <= '9') + && (numeric_value >= 0 || keyword_start == read_position - 1)) { + if (keyword_start == read_position - 1) + numeric_value = 0; + numeric_value = numeric_value * 10 + (int) (read_char - '0'); + } else { + numeric_value = -1; + } + if (read_position >= args->segment->string_parameter_bytes) { + keyword_length = read_position - keyword_start; + } + } + if (keyword_length > 0) { + int code = -1; + + debug("keyword@%d+%d: [%.*s]; numeric=%d", keyword_start, keyword_length, keyword_length, + &(args->segment->string_parameter[keyword_start]), numeric_value); + + if (numeric_value >= 0 && numeric_value < 255) { + code = numeric_value; + } else { + int keyword_index; + for (keyword_index = 0; -1 == code && NULL != keywords[keyword_index].keyword; + keyword_index++) { + if (keyword_length != keywords[keyword_index].bytes) + continue; + if (0 != + strncmp(keywords[keyword_index].keyword, + &(args->segment->string_parameter[keyword_start]), keyword_length)) + continue; + code = (int) (keywords[keyword_index].code); + } + } + + debug("code=%d", code); + + if (code >= 0) { + if (code_count > 15) { + write_position += + pv_snprintf(content + write_position, sizeof(content) - write_position, + "%s", "m"); + code_count = 0; + } + if (0 == code_count) { + write_position += + pv_snprintf(content + write_position, sizeof(content) - write_position, + "%s", "\033["); + } else { + write_position += + pv_snprintf(content + write_position, sizeof(content) - write_position, + "%s", ";"); + } + write_position += + pv_snprintf(content + write_position, sizeof(content) - write_position, "%d", code); + code_count++; + most_recent_code = code; + } + + keyword_length = 0; + keyword_start = read_position; + } + } + + if (code_count > 0) + write_position += pv_snprintf(content + write_position, sizeof(content) - write_position, "%s", "m"); + + if (most_recent_code > 0) { + args->display->sgr_code_active = true; + } else if (0 == most_recent_code) { + args->display->sgr_code_active = false; + } + + return pv_formatter_segmentcontent(content, args); +}