summaryrefslogtreecommitdiffstats
path: root/generic/tclStringObj.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2006-08-28 16:05:31 (GMT)
committerdgp <dgp@users.sourceforge.net>2006-08-28 16:05:31 (GMT)
commit9571f2381728758877fe7ef50963e3e373aad92f (patch)
treed56b5c209ddc88aa2b96deabf31937377f8a7010 /generic/tclStringObj.c
parent484ddcb6a498fab5690d6e8d58fb6b75f16195c7 (diff)
downloadtcl-9571f2381728758877fe7ef50963e3e373aad92f.zip
tcl-9571f2381728758877fe7ef50963e3e373aad92f.tar.gz
tcl-9571f2381728758877fe7ef50963e3e373aad92f.tar.bz2
* generic/tclStringObj.c: Revised ObjPrintfVA to take care
* generic/tclParseExpr.c: to copy only whole characters when doing %s formatting. This relieves callers of TclObjPrintf() and TclFormatToErrorInfo() from needing to fix arguments to character boundaries. Tcl_ParseExpr() simplified by taking advantage. [Bug 1547786]
Diffstat (limited to 'generic/tclStringObj.c')
-rw-r--r--generic/tclStringObj.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c
index c0736f3..40ec1bf 100644
--- a/generic/tclStringObj.c
+++ b/generic/tclStringObj.c
@@ -33,7 +33,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclStringObj.c,v 1.56 2006/08/28 14:13:22 dgp Exp $ */
+ * RCS: @(#) $Id: tclStringObj.c,v 1.57 2006/08/28 16:05:32 dgp Exp $ */
#include "tclInt.h"
#include "tommath.h"
@@ -2392,7 +2392,7 @@ ObjPrintfVA(
Tcl_IncrRefCount(list);
while (*p != '\0') {
int size = 0, seekingConversion = 1, gotPrecision = 0;
- int lastNum = -1, numBytes = -1;
+ int lastNum = -1;
if (*p++ != '%') {
continue;
@@ -2408,27 +2408,40 @@ ObjPrintfVA(
seekingConversion = 0;
break;
case 's': {
- char *bytes = va_arg(argList, char *);
+ CONST char *q, *end, *bytes = va_arg(argList, char *);
seekingConversion = 0;
- if (gotPrecision) {
- char *end = bytes + lastNum;
- char *q = bytes;
- while ((q < end) && (*q != '\0')) {
- q++;
- }
- numBytes = (int)(q - bytes);
+
+ /*
+ * The buffer to copy characters from starts at bytes
+ * and ends at either the first NUL byte, or after
+ * lastNum bytes, when caller has indicated a limit.
+ */
+
+ end = bytes;
+ while ((!gotPrecision || lastNum--) && (*end != '\0')) {
+ end++;
}
- Tcl_ListObjAppendElement(NULL, list,
- Tcl_NewStringObj(bytes , numBytes));
/*
- * We took no more than numBytes bytes from the (char *). In
- * turn, [format] will take no more than numBytes characters
- * from the Tcl_Obj. Since numBytes characters must be no less
- * than numBytes bytes, the character limit will have no
- * effect and we can just pass it through.
+ * Within that buffer, we trim both ends if needed so that
+ * we copy only whole characters, and avoid copying any
+ * partial multi-byte characters.
*/
+ q = Tcl_UtfPrev(end, bytes);
+ if (!Tcl_UtfCharComplete(q, (int)(end - q))) {
+ end = q;
+ }
+
+ q = bytes + TCL_UTF_MAX;
+ while ((bytes < end) && (bytes < q)
+ && ((*bytes & 0xC0) == 0x80)) {
+ bytes++;
+ }
+
+ Tcl_ListObjAppendElement(NULL, list,
+ Tcl_NewStringObj(bytes , (int)(end - bytes)));
+
break;
}
case 'c':