On 29.05.2012 00:49, Michal Kubecek wrote:
> On Mon, May 28, 2012 at 07:34:28PM +0200, Michal Kubecek wrote:
>>
>> I did experiment a bit and it seems that locale (most likely LC_CTYPE,
>> unfortunately the one that needs to be set for libedit to work), affects
>> only output with "set list off", with "set list on", the output seems to
>> be OK. So the interference might be with the code responsible for column
>> formatting - and the output looks as if all non-printable characters
>> (according to locale setting) were omitted.
As you are on it at the moment, I have been working on a patch for isql
to use an unicode enabled editline fork
(http://www.thrysoee.dk/editline/libedit-20110802-3.0.tar.gz slightly
patched, see below)
The version I have now is doing what we want, but I haven't tested it
with charsets other than UTF8 and ISO8859_1.
Here is what i have so far:
You may ignore the SWITCH_NOHEADINGS part.
mit freundlichen Grüßen
Frank Schlottmann-Gödde
--
"Fascinating creatures, phoenixes, they can carry immensely heavy loads,
their tears have healing powers and they make highly faithful pets."
- J.K. Rowling
Index: Makefile.in.firebird
===================================================================
--- Makefile.in.firebird (Revision 54560)
+++ Makefile.in.firebird (Arbeitskopie)
@@ -576,7 +576,7 @@
$(RM) $(SRC_ROOT)/include/gen/blrtable.h
clean_gpre_gen:
- -$(RM) `find $(SRC_ROOT) -type f -name '*.epp' -print | sed 's/epp$$/cpp/'`
+# -$(RM) `find $(SRC_ROOT) -type f -name '*.epp' -print | sed 's/epp$$/cpp/'`
clean_yacc_gen:
$(RM) $(ROOT)/src/dsql/parse.cpp $(ROOT)/src/dsql/dsql.tab.h
Index: Makefile.in.extern.editline
===================================================================
--- Makefile.in.extern.editline (Revision 54560)
+++ Makefile.in.extern.editline (Arbeitskopie)
@@ -62,8 +62,8 @@
libeditline : $(LIB)/libedit.a
$(LIB)/libedit.a:
- cd $(ROOT)/extern/editline; chmod +x configure; ./configure --enable-static --disable-shared
- $(MAKE) -C $(ROOT)/extern/editline
+ cd $(ROOT)/extern/editline; chmod +x configure; CFLAGS="-ggdb -pedandic -O0" ./configure --enable-static --disable-shared --enable-widec
+ CFLAGS="-ggdb -pedandic -O0" $(MAKE) -C $(ROOT)/extern/editline
cp $(ROOT)/extern/editline/src/.libs/libedit.a $(LIB)
diff -urdX exclude.list ../svndata/fb25_release/extern/editline/src//eln.c ../build_posix/firebird2/extern/editline/src//eln.c
--- ../svndata/fb25_release/extern/editline/src//eln.c 2011-08-02 08:52:08.000000000 +0200
+++ ../build_posix/firebird2/extern/editline/src//eln.c 2012-02-06 11:25:59.000000000 +0100
@@ -75,10 +75,12 @@
el_gets(EditLine *el, int *nread)
{
const wchar_t *tmp;
-
- el->el_flags |= IGNORE_EXTCHARS;
+//we don't want to ignore extended chars with UTF8 charsets /FSG 2012
+ if (!(el->el_flags & CHARSET_IS_UTF8))
+ el->el_flags |= IGNORE_EXTCHARS;
tmp = el_wgets(el, nread);
- el->el_flags &= ~IGNORE_EXTCHARS;
+ if (!(el->el_flags & CHARSET_IS_UTF8))
+ el->el_flags &= ~IGNORE_EXTCHARS;
return ct_encode_string(tmp, &el->el_lgcyconv);
}
Index: isql.epp
===================================================================
--- isql.epp (Revision 54560)
+++ isql.epp (Arbeitskopie)
@@ -82,6 +82,7 @@
// This is a local file included in our distribution - but not always
// compiled into the system
#include "editline.h"
+#include <locale.h>
#endif
enum literal_string_type
@@ -130,8 +131,8 @@
#include "../isql/ColList.h"
#include "../isql/InputDevices.h"
#include "../isql/OptionsBase.h"
+#include <unicode/utf8.h>
-
DATABASE DB = COMPILETIME "yachts.lnk";
IsqlGlobals isqlGlob;
@@ -177,6 +178,7 @@
SWITCH_MERGE2,
SWITCH_NOAUTOCOMMIT,
SWITCH_NODBTRIGGERS,
+ SWITCH_NOHEADINGS,
SWITCH_NOWARN,
SWITCH_OUTPUT,
SWITCH_PAGE,
@@ -224,6 +226,7 @@
{ SWITCH_INPUT, "input", 1, SWARG_STRING, 126 },
{ SWITCH_MERGE, "merge", 1, SWARG_NONE, 127 },
{ SWITCH_MERGE2, "m2", 2, SWARG_NONE, 128 },
+ { SWITCH_NOHEADINGS, "noheadings", 3, SWARG_NONE, 199 },
{ SWITCH_NOAUTOCOMMIT, "noautocommit", 1, SWARG_NONE, 129 },
{ SWITCH_NODBTRIGGERS, "nodbtriggers", 3, SWARG_NONE, 154 },
{ SWITCH_NOWARN, "nowarnings", 3, SWARG_NONE, 130 },
@@ -245,6 +248,99 @@
};
+
+namespace IcuUtil
+{
+ // Duplicate from ICU to not need to link ISQL with it. It's used by U8_NEXT_UNSAFE.
+ static const uint8_t utf8_countTrailBytes[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3,
+ 3, 3, 3, /* illegal in Unicode */
+ 4, 4, 4, 4, /* illegal in Unicode */
+ 5, 5, /* illegal in Unicode */
+ 0, 0 /* illegal bytes 0xfe and 0xff */
+ };
+
+ // Return the number of characters of a string.
+ static unsigned charLength(SSHORT sqlsubtype, unsigned len, const char* str)
+ {
+ if (sqlsubtype != CS_UNICODE_FSS && sqlsubtype != CS_UTF8)
+ return len;
+
+ unsigned charLen = 0;
+ unsigned i = 0;
+
+ while (i < len)
+ {
+ UChar32 c;
+ U8_NEXT_UNSAFE(str, i, c);
+ ++charLen;
+ }
+
+ return charLen;
+ }
+
+ // Pads a string to a specified column width.
+ static void pad(char* buffer, SSHORT sqlsubtype, unsigned len, const char* str, unsigned width,
+ bool right)
+ {
+ if (sqlsubtype != CS_UNICODE_FSS && sqlsubtype != CS_UTF8)
+ {
+ // Truncate if necessary.
+ if (len > width)
+ len = width;
+
+ sprintf(buffer, (right ? "%*.*s" : "%-*.*s"), width, len, str);
+ return;
+ }
+
+ unsigned i = 0;
+
+ while (i < len && width > 0)
+ {
+ UChar32 c;
+ U8_NEXT_UNSAFE(str, i, c);
+ --width;
+ }
+
+ if (right)
+ {
+ while (width-- > 0)
+ *buffer++ = ' ';
+ }
+
+ memcpy(buffer, str, i);
+ buffer += i;
+
+ if (!right)
+ {
+ while (width-- > 0)
+ *buffer++ = ' ';
+ }
+
+ *buffer = '\0';
+ }
+}
+
+
static inline bool commit_trans(isc_tr_handle* x)
{
if (isc_commit_transaction (isc_status, x)) {
@@ -535,6 +631,9 @@
isqlGlob.major_ods = 0;
isqlGlob.minor_ods = 0;
+#ifdef HAVE_EDITLINE_H
+ setlocale(LC_CTYPE, "");
+#endif
int rc = ISQL_main(argc, argv);
return rc;
}
@@ -583,7 +682,7 @@
TEXT tabname[WORDLENGTH];
tabname[0] = '\0';
isqlGlob.db_SQL_dialect = 0;
-
+ isqlGlob.att_charset = 0;
// Output goes to stdout by default
isqlGlob.Out = stdout;
isqlGlob.Errfp = stderr;
@@ -5862,6 +5961,7 @@
isc_info_ods_version,
isc_info_ods_minor_version,
isc_info_db_sql_dialect,
+ frb_info_att_charset,
Version_info ? isc_info_firebird_version: isc_info_end,
isc_info_end
};
@@ -6017,6 +6117,9 @@
}
}
break;
+ case frb_info_att_charset:
+ isqlGlob.att_charset = gds__vax_integer(p, length);
+ break;
default:
isqlGlob.printf("Internal error: Unexpected isc_info_value %d%s",
@@ -7093,6 +7196,10 @@
Merge_diagnostic = true;
break;
+ case SWITCH_NOHEADINGS:
+ Heading = false;
+ break;
+
case SWITCH_NOAUTOCOMMIT:
Autocommit = false;
break;
@@ -7650,10 +7757,8 @@
}
else
{
- // Truncate if necessary
- if (length < var->sqllen)
- string[length] = '\0';
- sprintf(p, "%-*s ", length, var->sqldata);
+ IcuUtil::pad(p, var->sqlsubtype, strlen(var->sqldata), var->sqldata, length, false);
+ strcat(p, " ");
}
break;
@@ -7746,10 +7851,8 @@
}
else
{
- // Truncate if necessary
- if (length < avary->vary_length)
- avary->vary_length = length;
- sprintf(p, "%-*.*s ", length, (int) avary->vary_length, avary->vary_string);
+ IcuUtil::pad(p, var->sqlsubtype, avary->vary_length, avary->vary_string, length, false);
+ strcat(p, " ");
}
break;
}
@@ -7999,6 +8102,10 @@
isqlGlob.printf(NEWLINE);
return (CONT);
}
+ // No headings wanted? Ok, let's also trim the output.
+ if (!Heading) {
+ fb_utils::exact_name(line);
+ }
isqlGlob.printf("%s%s", line, NEWLINE);
@@ -8187,16 +8294,19 @@
for (const XSQLVAR* const end = var + sqlda->sqld; var < end; var++, i++)
{
const SSHORT type = var->sqltype & ~1;
- if (type == SQL_TEXT || type == SQL_VARYING)
- sprintf(p, "%-*.*s ", pad[i], pad[i], var->aliasname);
- else
- sprintf(p, "%*s ", pad[i], var->aliasname);
+ IcuUtil::pad(p, isqlGlob.att_charset, var->aliasname_length, var->aliasname, pad[i],
+ (type != SQL_TEXT && type != SQL_VARYING));
+ strcat(p, " ");
+
+ p += strlen(p);
+
// Separators need not go on forever no more than a line
- size_t limit = strlen(p);
- for (size_t j = 1; j < limit && j < 80; j++)
+ unsigned limit = IcuUtil::charLength(isqlGlob.att_charset, var->aliasname_length, var->aliasname);
+ limit = MAX(limit, pad[i]) + 1;
+
+ for (unsigned j = 1; j < limit && j < 80; j++)
*p2++ = '=';
*p2++ = BLANK;
- p += limit;
}
*p2 = '\0';
}
@@ -8435,7 +8545,7 @@
USHORT data_length, disp_length, alignment;
data_length = disp_length = alignment = var->sqllen;
- SSHORT namelength = var->aliasname_length;
+ SSHORT namelength = IcuUtil::charLength(isqlGlob.att_charset, var->aliasname_length, var->aliasname);
// Minimum display length should not be less than that needed
// for displaying null
@@ -8484,6 +8594,8 @@
// OCTETS data is displayed in hex
if (var->sqlsubtype == 1)
disp_length = 2 * var->sqllen;
+ else if (var->sqlsubtype == 4)
+ disp_length /= 4;
break;
case SQL_SHORT:
disp_length = SHORT_LEN;
Index: isql.h
===================================================================
--- isql.h (Revision 54560)
+++ isql.h (Arbeitskopie)
@@ -254,6 +254,7 @@
const int PASS_FILE_OPEN = 162; // could not open password file @1, errno @2
const int PASS_FILE_READ = 163; // could not read password file @1, errno @2
const int EMPTY_PASS = 164; // empty password file @1
+const int USAGE_NOHEADING = 199;
// Initialize types
@@ -362,6 +363,7 @@
// from isql.epp
USHORT major_ods;
USHORT minor_ods;
+ USHORT att_charset;
void printf(const char* buffer, ...);
void prints(const char* buffer);
};
Index: messages2.sql
===================================================================
RCS file: /cvsroot/firebird/firebird2/src/msgs/messages2.sql,v
retrieving revision 1.102.2.7
diff -u -r1.102.2.7 messages2.sql
--- messages2.sql 1 Feb 2010 14:27:48 -0000 1.102.2.7
+++ messages2.sql 17 Mar 2010 14:44:26 -0000
@@ -1,3 +1,6 @@
+
+delete from MESSAGES;
+commit;
set bulk_insert INSERT INTO MESSAGES (SYMBOL, ROUTINE, MODULE, TRANS_NOTES, FAC_CODE, NUMBER, FLAGS, TEXT, "ACTION", EXPLANATION) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
-- JRD
(NULL, NULL, 'jrd.c', NULL, 0, 0, NULL, '', NULL, NULL);
@@ -3079,6 +3082,7 @@
('PASS_FILE_READ', 'ISQL_main', 'isql.epp', NULL, 17, 163, NULL, 'could not read password file @1, errno @2', NULL, NULL);
('EMPTY_PASS', 'ISQL_main', 'isql.epp', NULL, 17, 164, NULL, 'empty password file @1', NULL, NULL);
('HLP_SETROWCOUNT', 'help', 'isql.epp', NULL, 17, 165, NULL, ' SET ROWCOUNT [<n>] -- limit select stmt to <n> rows, zero is no limit', NULL, NULL);
+('USAGE_NOHEADING', 'ISQL_main', 'isql.epp', NULL, 17, 199, NULL, ' -noh(eadings) no page headings (set headings off)', NULL, NULL);
-- GSEC
('GsecMsg1', 'get_line', 'gsec.e', NULL, 18, 1, NULL, 'GSEC>', NULL, NULL);
('GsecMsg2', 'printhelp', 'gsec.e', 'This message is used in the Help display. It should be the same as number 1 (but in lower case).', 18, 2, NULL, 'gsec', NULL, NULL);
------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and
threat landscape has changed and how IT managers can respond. Discussions
will include endpoint security, mobile security and the latest in malware
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
Firebird-Devel mailing list, web interface at
https://lists.sourceforge.net/lists/listinfo/firebird-devel