MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
my_conio.c
1 /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 
17 #include "mysys_priv.h"
18 
19 #ifdef __WIN__
20 
21 
22 /* Windows console handling */
23 
24 /*
25  TODO : Find a relationship between the following
26  two macros and get rid of one.
27 */
28 
29 /* Maximum line length on Windows console */
30 #define MAX_CONSOLE_LINE_SIZE 65535
31 
32 /*
33  Maximum number of characters that can be entered
34  on single line in the console (including \r\n).
35 */
36 #define MAX_NUM_OF_CHARS_TO_READ 24530
37 
47 my_bool
48 my_win_is_console(FILE *file)
49 {
50  DWORD mode;
51  if (GetConsoleMode((HANDLE) _get_osfhandle(_fileno(file)), &mode))
52  return 1;
53  return 0;
54 }
55 
56 
72 char *
73 my_win_console_readline(const CHARSET_INFO *cs, char *mbbuf, size_t mbbufsize)
74 {
75  uint dummy_errors;
76  static wchar_t u16buf[MAX_CONSOLE_LINE_SIZE + 1];
77  size_t mblen= 0;
78 
79  DWORD console_mode;
80  DWORD nchars;
81 
82  HANDLE console= GetStdHandle(STD_INPUT_HANDLE);
83 
84  DBUG_ASSERT(mbbufsize > 0); /* Need space for at least trailing '\0' */
85  GetConsoleMode(console, &console_mode);
86  SetConsoleMode(console, ENABLE_LINE_INPUT |
87  ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT);
88 
89  if (!ReadConsoleW(console, u16buf, MAX_NUM_OF_CHARS_TO_READ, &nchars, NULL))
90  {
91  SetConsoleMode(console, console_mode);
92  return NULL;
93  }
94 
95  /* Set length of string */
96  if (nchars >= 2 && u16buf[nchars - 2] == L'\r')
97  nchars-= 2;
98  else if ((nchars == MAX_NUM_OF_CHARS_TO_READ) &&
99  (u16buf[nchars - 1] == L'\r'))
100  /* Special case 1 - \r\n straddles the boundary */
101  nchars--;
102  else if ((nchars == 1) && (u16buf[0] == L'\n'))
103  /* Special case 2 - read a single '\n'*/
104  nchars--;
105 
106  SetConsoleMode(console, console_mode);
107 
108  /* Convert Unicode to session character set */
109  if (nchars != 0)
110  mblen= my_convert(mbbuf, mbbufsize - 1, cs,
111  (const char *) u16buf, nchars * sizeof(wchar_t),
112  &my_charset_utf16le_bin, &dummy_errors);
113 
114  DBUG_ASSERT(mblen < mbbufsize); /* Safety */
115  mbbuf[mblen]= 0;
116  return mbbuf;
117 }
118 
119 
132 static size_t
133 my_mbstou16s(const CHARSET_INFO *cs, const uchar * from, size_t from_length,
134  wchar_t *to, size_t to_chars)
135 {
136  const CHARSET_INFO *to_cs= &my_charset_utf16le_bin;
137  const uchar *from_end= from + from_length;
138  wchar_t *to_orig= to, *to_end= to + to_chars;
139  my_charset_conv_mb_wc mb_wc= cs->cset->mb_wc;
140  my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
141  while (from < from_end)
142  {
143  int cnvres;
144  my_wc_t wc;
145  if ((cnvres= (*mb_wc)(cs, &wc, from, from_end)) > 0)
146  {
147  if (!wc)
148  break;
149  from+= cnvres;
150  }
151  else if (cnvres == MY_CS_ILSEQ)
152  {
153  wc= (my_wc_t) (uchar) *from; /* Fallback to ISO-8859-1 */
154  from+= 1;
155  }
156  else if (cnvres > MY_CS_TOOSMALL)
157  {
158  /*
159  A correct multibyte sequence detected
160  But it doesn't have Unicode mapping.
161  */
162  wc= '?';
163  from+= (-cnvres); /* Note: cnvres is negative here */
164  }
165  else /* Incomplete character */
166  {
167  wc= (my_wc_t) (uchar) *from; /* Fallback to ISO-8859-1 */
168  from+= 1;
169  }
170 outp:
171  if ((cnvres= (*wc_mb)(to_cs, wc, (uchar *) to, (uchar *) to_end)) > 0)
172  {
173  /* We can never convert only a part of wchar_t */
174  DBUG_ASSERT((cnvres % sizeof(wchar_t)) == 0);
175  /* cnvres returns number of bytes, convert to number of wchar_t's */
176  to+= cnvres / sizeof(wchar_t);
177  }
178  else if (cnvres == MY_CS_ILUNI && wc != '?')
179  {
180  wc= '?';
181  goto outp;
182  }
183  else
184  break; /* Not enough space */
185  }
186  return to - to_orig;
187 }
188 
189 
202 void
203 my_win_console_write(const CHARSET_INFO *cs, const char *data, size_t datalen)
204 {
205  static wchar_t u16buf[MAX_CONSOLE_LINE_SIZE + 1];
206  size_t nchars= my_mbstou16s(cs, (const uchar *) data, datalen,
207  u16buf, sizeof(u16buf));
208  DWORD nwritten;
209  WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
210  u16buf, (DWORD) nchars, &nwritten, NULL);
211 }
212 
213 
223 void
224 my_win_console_putc(const CHARSET_INFO *cs, int c)
225 {
226  char ch= (char) c;
227  my_win_console_write(cs, &ch, 1);
228 }
229 
230 
237 void
238 my_win_console_fputs(const CHARSET_INFO *cs, const char *data)
239 {
240  my_win_console_write(cs, data, strlen(data));
241 }
242 
243 
244 /*
245  Handle formatted output on the Windows console.
246 */
247 void
248 my_win_console_vfprintf(const CHARSET_INFO *cs, const char *fmt, va_list args)
249 {
250  static char buff[MAX_CONSOLE_LINE_SIZE + 1];
251  size_t len= vsnprintf(buff, sizeof(buff) - 1, fmt, args);
252  my_win_console_write(cs, buff, len);
253 }
254 
255 
256 #include <shellapi.h>
257 
267 int
268 my_win_translate_command_line_args(const CHARSET_INFO *cs, int *argc, char ***argv)
269 {
270  int i, ac;
271  char **av;
272  wchar_t *command_line= GetCommandLineW();
273  wchar_t **wargs= CommandLineToArgvW(command_line, &ac);
274  size_t nbytes= (ac + 1) * sizeof(char *);
275 
276  /* Allocate new command line parameter */
277  av= (char **) my_once_alloc(nbytes, MYF(MY_ZEROFILL));
278 
279  for(i= 0; i < ac; i++)
280  {
281  uint dummy_errors;
282  size_t arg_len= wcslen(wargs[i]);
283  size_t len, alloced_len= arg_len * cs->mbmaxlen + 1;
284  av[i]= (char *) my_once_alloc(alloced_len, MYF(0));
285  len= my_convert(av[i], alloced_len, cs,
286  (const char *) wargs[i], arg_len * sizeof(wchar_t),
287  &my_charset_utf16le_bin, &dummy_errors);
288  DBUG_ASSERT(len < alloced_len);
289  av[i][len]= '\0';
290  }
291  *argv= av;
292  *argc= ac;
293  /* Cleanup on exit */
294  LocalFree((HLOCAL) wargs);
295  return 0;
296 }
297 
298 #endif /* __WIN__ */