aboutsummaryrefslogtreecommitdiff
path: root/lib/linestack.c
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2016-03-15 02:23:50 -0500
committerRob Landley <rob@landley.net>2016-03-15 02:23:50 -0500
commit2b999e614c48f084f6a14d589d434904aec6d491 (patch)
treec4c4fb5e6c4be3eca4fc47d7c61950a50f82d7eb /lib/linestack.c
parenteb24df9749994d175a2de3b7fc0535abe46a7576 (diff)
downloadtoybox-2b999e614c48f084f6a14d589d434904aec6d491.tar.gz
Add ls -b and make ls -q work with utf8.
Diffstat (limited to 'lib/linestack.c')
-rw-r--r--lib/linestack.c92
1 files changed, 59 insertions, 33 deletions
diff --git a/lib/linestack.c b/lib/linestack.c
index f8ca32a4..eef790b5 100644
--- a/lib/linestack.c
+++ b/lib/linestack.c
@@ -81,56 +81,75 @@ struct linestack *linestack_load(char *name)
// if escout, send it unprintable chars, returns columns output or -1 for
// standard escape: ^X if <32, <XX> if invliad UTF8, U+XXXX if UTF8 !iswprint()
// Returns width in columns, moves *str to end of data consumed.
-int crunch_str(char **str, int width, FILE *out,
- int (*escout)(FILE *out, int cols, char **buf))
+int crunch_str(char **str, int width, FILE *out, char *escmore,
+ int (*escout)(FILE *out, int cols, int wc))
{
int columns = 0, col, bytes;
char *start, *end;
- for (end = start = *str; *end;) {
- wchar_t wc = *end;
+ for (end = start = *str; *end; columns += col, end += bytes) {
+ wchar_t wc;
- bytes = 0;
- if (*end >= ' ' && (bytes = mbrtowc(&wc, end, 99,0))>0
- && (col = wcwidth(wc))>=0)
+ if ((bytes = mbrtowc(&wc, end, MB_CUR_MAX, 0))>0 && (col = wcwidth(wc))>=0)
{
- if (width-columns<col) break;
- if (out) fwrite(end, bytes, 1, out);
- } else if (!escout || 0>(col = escout(out, width-columns, &end))) {
- char buf[32];
-
- tty_esc("7m");
- if (*end < ' ') {
- bytes = 1;
- sprintf(buf, "^%c", '@'+*end);
- } else if (bytes<1) {
- bytes = 1;
- sprintf(buf, "<%02X>", *end);
- } else sprintf(buf, "U+%04X", (unsigned)wc);
- col = strlen(buf);
- if (width-columns<col) buf[col = width-columns] = 0;
- if (out) fputs(buf, out);
- tty_esc("27m");
- } else continue;
- columns += col;
- end += bytes;
+ if (!escmore || wc>255 || !strchr(escmore, wc)) {
+ if (width-columns<col) break;
+ if (out) fwrite(end, bytes, 1, out);
+
+ continue;
+ }
+ }
+
+ if (bytes<1) {
+ bytes = 1;
+ wc = *end;
+ }
+ col = width-columns;
+ if (col<1) break;
+ col = escout(out, col, wc);
}
*str = end;
return columns;
}
+int crunch_escape(FILE *out, int cols, int wc)
+{
+ char buf[8];
+ int rc;
+
+ if (wc<' ') rc = sprintf(buf, "^%c", '@'+wc);
+ else if (wc<256) rc = sprintf(buf, "<%02X>", wc);
+ else rc = sprintf(buf, "U+%04X", wc);
+
+ if (rc > cols) buf[rc = cols] = 0;
+ if (out) fputs(buf, out);
+
+ return rc;
+}
+
+int crunch_rev_escape(FILE *out, int cols, int wc)
+{
+ int rc;
+
+ tty_esc("7m");
+ rc = crunch_escape(out, cols, wc);
+ tty_esc("27m");
+
+ return rc;
+}
+
// Write width chars at start of string to strdout with standard escapes
// Returns length in columns so caller can pad it out with spaces.
int draw_str(char *start, int width)
{
- return crunch_str(&start, width, stdout, 0);
+ return crunch_str(&start, width, stdout, 0, crunch_rev_escape);
}
// Return utf8 columns
int utf8len(char *str)
{
- return crunch_str(&str, INT_MAX, 0, 0);
+ return crunch_str(&str, INT_MAX, 0, 0, crunch_rev_escape);
}
// Return bytes used by (up to) this many columns
@@ -138,14 +157,15 @@ int utf8skip(char *str, int width)
{
char *s = str;
- crunch_str(&s, width, 0, 0);
+ crunch_str(&s, width, 0, 0, crunch_rev_escape);
return s-str;
}
-// Print utf8 to stdout with standard escapes,trimmed to width and padded
+// Print utf8 to stdout with standard escapes, trimmed to width and padded
// out to padto. If padto<0 left justify. Returns columns printed
-int draw_trim(char *str, int padto, int width)
+int draw_trim_esc(char *str, int padto, int width, char *escmore,
+ int (*escout)(FILE *out, int cols, int wc))
{
int apad = abs(padto), len = utf8len(str);
@@ -154,8 +174,14 @@ int draw_trim(char *str, int padto, int width)
// Left pad if right justified
if (padto>0 && apad>len) printf("%*s", apad-len, "");
- crunch_str(&str, len, stdout, 0);
+ crunch_str(&str, len, stdout, 0, crunch_rev_escape);
if (padto<0 && apad>len) printf("%*s", apad-len, "");
return (apad > len) ? apad : len;
}
+
+// draw_trim_esc() with default escape
+int draw_trim(char *str, int padto, int width)
+{
+ return draw_trim_esc(str, padto, width, 0, 0);
+}