+/*
+ * copy string from str to dest padding with the fill character to a
+ * size of wid characters. if wid is negative, the string is right
+ * aligned no more than max characters are copied
+ */
+void
+cptrimmed(charstring_t dest, char *str, int wid, char fill, size_t max) {
+ int remaining; /* remaining output width available */
+ int rjust;
+ struct charstring *trimmed;
+ size_t end; /* number of input bytes remaining in str */
+#ifdef MULTIBYTE_SUPPORT
+ int char_len; /* bytes in current character */
+ int w;
+ wchar_t wide_char;
+ char *altstr = NULL;
+#endif
+ char *sp; /* current position in source string */
+ int prevCtrl = 1;
+
+ /* get alignment */
+ rjust = 0;
+ if ((remaining = wid) < 0) {
+ remaining = -remaining;
+ rjust++;
+ }
+ if (remaining > (int) max) { remaining = max; }
+
+ trimmed = rjust ? charstring_create(remaining) : dest;
+
+ if ((sp = str)) {
+#ifdef MULTIBYTE_SUPPORT
+ if (mbtowc(NULL, NULL, 0)) {} /* reset shift state */
+#endif
+ end = strlen(str);
+ while (*sp && remaining > 0 && end > 0) {
+#ifdef MULTIBYTE_SUPPORT
+ char_len = mbtowc(&wide_char, sp, end);
+
+ /*
+ * See the relevant comments in cpstripped() to explain what's
+ * going on here; we want to handle the case where we get
+ * characters that mbtowc() cannot handle
+ */
+
+ if (char_len < 0) {
+ altstr = "?";
+ char_len = mbtowc(&wide_char, altstr, 1);
+ }
+
+ if (char_len <= 0) {
+ break;
+ }
+
+ w = wcwidth(wide_char);
+
+ /* If w > remaining, w must be positive. */
+ if (w > remaining) {
+ break;
+ }
+
+ end -= char_len;
+
+ if (iswcntrl(wide_char) || iswspace(wide_char)) {
+ sp += char_len;
+#else
+ int c;
+ end--;
+ /* isnctrl(), etc., take an int argument. Cygwin's ctype.h
+ intentionally warns if they are passed a char. */
+ c = (unsigned char) *sp;
+ if (iscntrl(c) || isspace(c)) {
+ sp++;
+#endif
+ if (!prevCtrl) {
+ charstring_push_back (trimmed, ' ');
+ remaining--;