Mercurial > hg > xemacs-beta
annotate lib-src/i.c @ 4981:4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
-------------------- ChangeLog entries follow: --------------------
modules/ChangeLog addition:
2010-02-05 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c:
* postgresql/postgresql.c (CHECK_LIVE_CONNECTION):
* postgresql/postgresql.c (Fpq_connectdb):
* postgresql/postgresql.c (Fpq_connect_start):
* postgresql/postgresql.c (Fpq_lo_import):
* postgresql/postgresql.c (Fpq_lo_export):
* ldap/eldap.c (Fldap_open):
* ldap/eldap.c (Fldap_search_basic):
* ldap/eldap.c (Fldap_add):
* ldap/eldap.c (Fldap_modify):
* ldap/eldap.c (Fldap_delete):
* canna/canna_api.c (Fcanna_initialize):
* canna/canna_api.c (Fcanna_store_yomi):
* canna/canna_api.c (Fcanna_parse):
* canna/canna_api.c (Fcanna_henkan_begin):
EXTERNAL_TO_C_STRING returns its argument instead of storing it
in a parameter, and is renamed to EXTERNAL_TO_ITEXT. Similar
things happen to related macros. See entry in src/ChangeLog.
More Mule-izing of postgresql.c. Extract out common code
between `pq-connectdb' and `pq-connect-start'. Fix places
that signal an error string using a formatted string to instead
follow the standard and have a fixed reason followed by the
particular error message stored as one of the frobs.
src/ChangeLog addition:
2010-02-05 Ben Wing <ben@xemacs.org>
* console-msw.c (write_string_to_mswindows_debugging_output):
* console-msw.c (Fmswindows_message_box):
* console-x.c (x_perhaps_init_unseen_key_defaults):
* console.c:
* database.c (dbm_get):
* database.c (dbm_put):
* database.c (dbm_remove):
* database.c (berkdb_get):
* database.c (berkdb_put):
* database.c (berkdb_remove):
* database.c (Fopen_database):
* device-gtk.c (gtk_init_device):
* device-msw.c (msprinter_init_device_internal):
* device-msw.c (msprinter_default_printer):
* device-msw.c (msprinter_init_device):
* device-msw.c (sync_printer_with_devmode):
* device-msw.c (Fmsprinter_select_settings):
* device-x.c (sanity_check_geometry_resource):
* device-x.c (Dynarr_add_validified_lisp_string):
* device-x.c (x_init_device):
* device-x.c (Fx_put_resource):
* device-x.c (Fx_valid_keysym_name_p):
* device-x.c (Fx_set_font_path):
* dialog-msw.c (push_lisp_string_as_unicode):
* dialog-msw.c (handle_directory_dialog_box):
* dialog-msw.c (handle_file_dialog_box):
* dialog-x.c (dbox_descriptor_to_widget_value):
* editfns.c (Fformat_time_string):
* editfns.c (Fencode_time):
* editfns.c (Fset_time_zone_rule):
* emacs.c (make_argc_argv):
* emacs.c (Fdump_emacs):
* emodules.c (emodules_load):
* eval.c:
* eval.c (maybe_signal_error_1):
* event-msw.c (Fdde_alloc_advise_item):
* event-msw.c (mswindows_dde_callback):
* event-msw.c (mswindows_wnd_proc):
* fileio.c (report_error_with_errno):
* fileio.c (Fsysnetunam):
* fileio.c (Fdo_auto_save):
* font-mgr.c (extract_fcapi_string):
* font-mgr.c (Ffc_config_app_font_add_file):
* font-mgr.c (Ffc_config_app_font_add_dir):
* font-mgr.c (Ffc_config_filename):
* frame-gtk.c (gtk_set_frame_text_value):
* frame-gtk.c (gtk_create_widgets):
* frame-msw.c (mswindows_init_frame_1):
* frame-msw.c (mswindows_set_title_from_ibyte):
* frame-msw.c (msprinter_init_frame_3):
* frame-x.c (x_set_frame_text_value):
* frame-x.c (x_set_frame_properties):
* frame-x.c (start_drag_internal_1):
* frame-x.c (x_cde_transfer_callback):
* frame-x.c (x_create_widgets):
* glyphs-eimage.c (my_jpeg_output_message):
* glyphs-eimage.c (jpeg_instantiate):
* glyphs-eimage.c (gif_instantiate):
* glyphs-eimage.c (png_instantiate):
* glyphs-eimage.c (tiff_instantiate):
* glyphs-gtk.c (xbm_instantiate_1):
* glyphs-gtk.c (gtk_xbm_instantiate):
* glyphs-gtk.c (gtk_xpm_instantiate):
* glyphs-gtk.c (gtk_xface_instantiate):
* glyphs-gtk.c (cursor_font_instantiate):
* glyphs-gtk.c (gtk_redisplay_widget):
* glyphs-gtk.c (gtk_widget_instantiate_1):
* glyphs-gtk.c (gtk_add_tab_item):
* glyphs-msw.c (mswindows_xpm_instantiate):
* glyphs-msw.c (bmp_instantiate):
* glyphs-msw.c (mswindows_resource_instantiate):
* glyphs-msw.c (xbm_instantiate_1):
* glyphs-msw.c (mswindows_xbm_instantiate):
* glyphs-msw.c (mswindows_xface_instantiate):
* glyphs-msw.c (mswindows_redisplay_widget):
* glyphs-msw.c (mswindows_widget_instantiate):
* glyphs-msw.c (add_tree_item):
* glyphs-msw.c (add_tab_item):
* glyphs-msw.c (mswindows_combo_box_instantiate):
* glyphs-msw.c (mswindows_widget_query_string_geometry):
* glyphs-x.c (x_locate_pixmap_file):
* glyphs-x.c (xbm_instantiate_1):
* glyphs-x.c (x_xbm_instantiate):
* glyphs-x.c (extract_xpm_color_names):
* glyphs-x.c (x_xpm_instantiate):
* glyphs-x.c (x_xface_instantiate):
* glyphs-x.c (autodetect_instantiate):
* glyphs-x.c (safe_XLoadFont):
* glyphs-x.c (cursor_font_instantiate):
* glyphs-x.c (x_redisplay_widget):
* glyphs-x.c (Fchange_subwindow_property):
* glyphs-x.c (x_widget_instantiate):
* glyphs-x.c (x_tab_control_redisplay):
* glyphs.c (pixmap_to_lisp_data):
* gui-x.c (menu_separator_style_and_to_external):
* gui-x.c (add_accel_and_to_external):
* gui-x.c (button_item_to_widget_value):
* hpplay.c (player_error_internal):
* hpplay.c (play_sound_file):
* hpplay.c (play_sound_data):
* intl.c (Fset_current_locale):
* lisp.h:
* menubar-gtk.c (gtk_xemacs_set_accel_keys):
* menubar-msw.c (populate_menu_add_item):
* menubar-msw.c (populate_or_checksum_helper):
* menubar-x.c (menu_item_descriptor_to_widget_value_1):
* nt.c (init_user_info):
* nt.c (get_long_basename):
* nt.c (nt_get_resource):
* nt.c (init_mswindows_environment):
* nt.c (get_cached_volume_information):
* nt.c (mswindows_readdir):
* nt.c (read_unc_volume):
* nt.c (mswindows_stat):
* nt.c (mswindows_getdcwd):
* nt.c (mswindows_executable_type):
* nt.c (Fmswindows_short_file_name):
* ntplay.c (nt_play_sound_file):
* objects-gtk.c:
* objects-gtk.c (gtk_valid_color_name_p):
* objects-gtk.c (gtk_initialize_font_instance):
* objects-gtk.c (gtk_font_list):
* objects-msw.c (font_enum_callback_2):
* objects-msw.c (parse_font_spec):
* objects-x.c (x_parse_nearest_color):
* objects-x.c (x_valid_color_name_p):
* objects-x.c (x_initialize_font_instance):
* objects-x.c (x_font_instance_truename):
* objects-x.c (x_font_list):
* objects-xlike-inc.c (XFUN):
* objects-xlike-inc.c (xft_find_charset_font):
* process-nt.c (mswindows_report_winsock_error):
* process-nt.c (nt_create_process):
* process-nt.c (get_internet_address):
* process-nt.c (nt_open_network_stream):
* process-unix.c:
* process-unix.c (allocate_pty):
* process-unix.c (get_internet_address):
* process-unix.c (unix_canonicalize_host_name):
* process-unix.c (unix_open_network_stream):
* realpath.c:
* select-common.h (lisp_data_to_selection_data):
* select-gtk.c (symbol_to_gtk_atom):
* select-gtk.c (atom_to_symbol):
* select-msw.c (symbol_to_ms_cf):
* select-msw.c (mswindows_register_selection_data_type):
* select-x.c (symbol_to_x_atom):
* select-x.c (x_atom_to_symbol):
* select-x.c (hack_motif_clipboard_selection):
* select-x.c (Fx_store_cutbuffer_internal):
* sound.c (Fplay_sound_file):
* sound.c (Fplay_sound):
* sound.h (sound_perror):
* sysdep.c:
* sysdep.c (qxe_allocating_getcwd):
* sysdep.c (qxe_execve):
* sysdep.c (copy_in_passwd):
* sysdep.c (qxe_getpwnam):
* sysdep.c (qxe_ctime):
* sysdll.c (dll_open):
* sysdll.c (dll_function):
* sysdll.c (dll_variable):
* sysdll.c (search_linked_libs):
* sysdll.c (dll_error):
* sysfile.h:
* sysfile.h (PATHNAME_CONVERT_OUT_TSTR):
* sysfile.h (PATHNAME_CONVERT_OUT_UTF_8):
* sysfile.h (PATHNAME_CONVERT_OUT):
* sysfile.h (LISP_PATHNAME_CONVERT_OUT):
* syswindows.h (ITEXT_TO_TSTR):
* syswindows.h (LOCAL_FILE_FORMAT_TO_TSTR):
* syswindows.h (TSTR_TO_LOCAL_FILE_FORMAT):
* syswindows.h (LOCAL_FILE_FORMAT_TO_INTERNAL_MSWIN):
* syswindows.h (LISP_LOCAL_FILE_FORMAT_MAYBE_URL_TO_TSTR):
* text.h:
* text.h (eicpy_ext_len):
* text.h (enum new_dfc_src_type):
* text.h (EXTERNAL_TO_ITEXT):
* text.h (GET_STRERROR):
* tooltalk.c (check_status):
* tooltalk.c (Fadd_tooltalk_message_arg):
* tooltalk.c (Fadd_tooltalk_pattern_attribute):
* tooltalk.c (Fadd_tooltalk_pattern_arg):
* win32.c (tstr_to_local_file_format):
* win32.c (mswindows_lisp_error_1):
* win32.c (mswindows_report_process_error):
* win32.c (Fmswindows_shell_execute):
* win32.c (mswindows_read_link_1):
Changes involving external/internal format conversion,
mostly code cleanup and renaming.
1. Eliminate the previous macros like LISP_STRING_TO_EXTERNAL
that stored its result in a parameter. The new version of
LISP_STRING_TO_EXTERNAL returns its result through the
return value, same as the previous NEW_LISP_STRING_TO_EXTERNAL.
Use the new-style macros throughout the code.
2. Rename C_STRING_TO_EXTERNAL and friends to ITEXT_TO_EXTERNAL,
in keeping with overall naming rationalization involving
Itext and related types.
Macros involved in previous two:
EXTERNAL_TO_C_STRING -> EXTERNAL_TO_ITEXT
EXTERNAL_TO_C_STRING_MALLOC -> EXTERNAL_TO_ITEXT_MALLOC
SIZED_EXTERNAL_TO_C_STRING -> SIZED_EXTERNAL_TO_ITEXT
SIZED_EXTERNAL_TO_C_STRING_MALLOC -> SIZED_EXTERNAL_TO_ITEXT_MALLOC
C_STRING_TO_EXTERNAL -> ITEXT_TO_EXTERNAL
C_STRING_TO_EXTERNAL_MALLOC -> ITEXT_TO_EXTERNAL_MALLOC
LISP_STRING_TO_EXTERNAL
LISP_STRING_TO_EXTERNAL_MALLOC
LISP_STRING_TO_TSTR
C_STRING_TO_TSTR -> ITEXT_TO_TSTR
TSTR_TO_C_STRING -> TSTR_TO_ITEXT
The following four still return their values through parameters,
since they have more than one value to return:
C_STRING_TO_SIZED_EXTERNAL -> ITEXT_TO_SIZED_EXTERNAL
LISP_STRING_TO_SIZED_EXTERNAL
C_STRING_TO_SIZED_EXTERNAL_MALLOC -> ITEXT_TO_SIZED_EXTERNAL_MALLOC
LISP_STRING_TO_SIZED_EXTERNAL_MALLOC
Sometimes additional casts had to be inserted, since the old
macros played strange games and completely defeated the type system
of the store params.
3. Rewrite many places where direct calls to TO_EXTERNAL_FORMAT
occurred with calls to one of the convenience macros listed above,
or to make_extstring().
4. Eliminate SIZED_C_STRING macros (they were hardly used, anyway)
and use a direct call to TO_EXTERNAL_FORMAT or TO_INTERNAL_FORMAT.
4. Use LISP_PATHNAME_CONVERT_OUT in many places instead of something
like LISP_STRING_TO_EXTERNAL(..., Qfile_name).
5. Eliminate some temporary variables that are no longer necessary
now that we return a value rather than storing it into a variable.
6. Some Mule-izing in database.c.
7. Error functions:
-- A bit of code cleanup in maybe_signal_error_1.
-- Eliminate report_file_type_error; it's just an alias for
signal_error_2 with params in a different order.
-- Fix some places in the hostname-handling code that directly
inserted externally-retrieved error strings into the
supposed ASCII "reason" param instead of doing the right thing
and sticking text descriptive of what was going on in "reason"
and putting the external message in a frob.
8. Use Ascbyte instead of CIbyte in process-unix.c and maybe one
or two other places.
9. Some code cleanup in copy_in_passwd() in sysdep.c.
10. Fix a real bug due to accidental variable shadowing in
tstr_to_local_file_format() in win32.c.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Fri, 05 Feb 2010 11:02:24 -0600 |
parents | 49316578f12d |
children | 308d34e9f07d |
rev | line source |
---|---|
442 | 1 /* I-connector utility |
2 Copyright (C) 2000 Kirill M. Katsnelson | |
1346 | 3 Copyright (C) 2002, 2003 Ben Wing. |
442 | 4 |
5 This file is part of XEmacs. | |
6 | |
7 XEmacs is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published by the | |
9 Free Software Foundation; either version 2, or (at your option) any | |
10 later version. | |
11 | |
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with XEmacs; see the file COPYING. If not, write to | |
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 Boston, MA 02111-1307, USA. */ | |
21 | |
22 /* When run with an argument, i treats it as a command line, and pipes | |
23 command stdin, stdout and stderr to its own respective streams. How | |
24 silly it should sound, but windowed program in Win32 cannot do output | |
25 to the console from which it has been started, and should be run using | |
26 this utility. | |
27 | |
28 This utility is for running [tx]emacs as part of make process so that | |
29 its output goes to the same console as the rest of the make output | |
30 does. It can be used also when xemacs should be run as a batch | |
31 command ina script, especially when its standart output should be | |
32 obtained programmatically. */ | |
33 | |
2993 | 34 #ifdef HAVE_CONFIG_H |
35 # include <config.h> | |
36 #endif | |
37 | |
442 | 38 #include <windows.h> |
39 #include <stdio.h> | |
40 #include <string.h> | |
41 #include <tchar.h> | |
42 | |
43 typedef struct | |
44 { | |
45 HANDLE source; | |
46 HANDLE drain; | |
47 } I_connector; | |
48 | |
49 /* | |
50 * Make new handle as that pointed to by PH but | |
51 * inheritable, substitute PH with it, and close the | |
52 * original one | |
53 */ | |
54 static void | |
55 make_inheritable (HANDLE* ph) | |
56 { | |
57 HANDLE htmp; | |
58 DuplicateHandle (GetCurrentProcess(), *ph, GetCurrentProcess(), &htmp, | |
59 0, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
60 *ph = htmp; | |
61 } | |
62 | |
63 /* | |
64 * Worker thread proc. Reads source, pumps into drain, | |
65 * till either clogs. | |
66 */ | |
67 static DWORD CALLBACK | |
68 pump (LPVOID pv_i) | |
69 { | |
70 I_connector* pi = (I_connector*) pv_i; | |
71 BYTE buffer [256]; | |
72 DWORD really_read, unused; | |
73 | |
2426 | 74 /* I said: |
75 | |
76 [[ The docs for ReadFile claim: | |
1346 | 77 |
78 The ReadFile function returns when one of the following is true: a write | |
79 operation completes on the write end of the pipe, the number of bytes | |
80 requested has been read, or an error occurs. | |
81 | |
82 But this is just not true. ReadFile never seems to block, and unless we | |
2426 | 83 Sleep(), we will chew up all the CPU time. --ben ]] |
84 | |
85 But in fact | |
86 | |
87 [a] this does not appear to be the case any more [maybe a temporary | |
88 bug in some versions of Win2000?] | |
89 [b] it causes data lossage. [#### Why should this be? Seems extremely | |
90 fishy. I tried commenting out the calls to close the standard | |
91 handles at the bottom of the program, but it made no difference. | |
92 Would we need some kind of additional handshaking? If we get | |
93 data loss with the sleep, then we are a race condition waiting | |
94 to happen. */ | |
442 | 95 while (ReadFile (pi->source, buffer, sizeof (buffer), &really_read, NULL) && |
96 WriteFile (pi->drain, buffer, really_read, &unused, NULL)) | |
2426 | 97 /* Sleep (100) */ ; |
442 | 98 |
99 return 0; | |
100 } | |
101 | |
102 /* | |
103 * Launch a pump for the given I-connector | |
104 */ | |
105 static void | |
106 start_pump (I_connector* pi) | |
107 { | |
108 DWORD unused; | |
109 HANDLE h_thread = CreateThread (NULL, 0, pump, (void*)pi, 0, &unused); | |
110 CloseHandle (h_thread); | |
111 } | |
112 | |
826 | 113 static HANDLE external_event; |
114 | |
115 static BOOL | |
116 ctrl_c_handler (unsigned long type) | |
117 { | |
118 SetEvent (external_event); | |
119 return FALSE; | |
120 } | |
121 | |
122 /* Skip over the executable name in the given command line. Correctly | |
123 handles quotes in the name. Return NULL upon error. If | |
124 REQUIRE_FOLLOWING is non-zero, it's an error if no argument follows the | |
125 executable name. */ | |
126 | |
442 | 127 static LPTSTR |
826 | 128 skip_executable_name (LPTSTR cl, int require_following) |
442 | 129 { |
130 int ix; | |
131 | |
132 while (1) | |
133 { | |
134 ix = _tcscspn (cl, _T(" \t\"")); | |
135 if (cl[ix] == '\"') | |
136 { | |
137 cl = _tcschr (cl + ix + 1, '\"'); | |
138 if (cl == NULL) | |
139 return NULL; /* Unmatched quote */ | |
140 cl++; | |
141 } | |
142 else | |
143 { | |
144 cl += ix; | |
145 cl += _tcsspn (cl, _T(" \t")); | |
826 | 146 if (!require_following) |
147 return cl; | |
442 | 148 return *cl ? cl : NULL; |
149 } | |
150 } | |
151 } | |
152 | |
153 /* | |
154 * Brew coffee and bring snickers | |
155 */ | |
156 void | |
157 usage (void) | |
158 { | |
159 fprintf (stderr, | |
160 "\n" | |
161 "usage: i command\n" | |
162 "i executes the command and reroutes its standard handles to the calling\n" | |
163 "console. Good for seeing output of GUI programs that use standard output." | |
164 "\n"); | |
165 } | |
166 | |
167 int | |
168 main (void) | |
169 { | |
170 STARTUPINFO si; | |
171 PROCESS_INFORMATION pi; | |
172 I_connector I_in, I_out, I_err; | |
173 DWORD exit_code; | |
826 | 174 LPTSTR command = skip_executable_name (GetCommandLine (), 1); |
175 | |
442 | 176 if (command == NULL) |
177 { | |
178 usage (); | |
179 return 1; | |
180 } | |
181 | |
182 ZeroMemory (&si, sizeof (si)); | |
183 si.dwFlags = STARTF_USESTDHANDLES; | |
184 | |
185 I_in.source = GetStdHandle (STD_INPUT_HANDLE); | |
186 CreatePipe (&si.hStdInput, &I_in.drain, NULL, 0); | |
187 make_inheritable (&si.hStdInput); | |
188 | |
189 I_out.drain = GetStdHandle (STD_OUTPUT_HANDLE); | |
190 CreatePipe (&I_out.source, &si.hStdOutput, NULL, 0); | |
191 make_inheritable (&si.hStdOutput); | |
192 | |
193 I_err.drain = GetStdHandle (STD_ERROR_HANDLE); | |
194 CreatePipe (&I_err.source, &si.hStdError, NULL, 0); | |
195 make_inheritable (&si.hStdError); | |
196 | |
826 | 197 { |
198 SECURITY_ATTRIBUTES sa; | |
199 LPTSTR new_command = | |
200 (LPTSTR) malloc (666 + sizeof (TCHAR) * _tcslen (command)); | |
201 LPTSTR past_exe; | |
202 | |
203 if (!new_command) | |
204 { | |
205 _ftprintf (stderr, _T ("Out of memory when launching `%s'\n"), | |
206 command); | |
207 return 2; | |
208 } | |
209 | |
210 past_exe = skip_executable_name (command, 0); | |
211 if (!past_exe) | |
212 { | |
213 usage (); | |
214 return 1; | |
215 } | |
216 | |
217 /* Since XEmacs isn't a console application, it can't easily be | |
218 terminated using ^C. Therefore, we set up a communication path with | |
219 it so that when a ^C is sent to us (using GenerateConsoleCtrlEvent), | |
220 we in turn signals it to commit suicide. (This is cleaner than using | |
221 TerminateProcess()). This makes (e.g.) the "Stop Build" command | |
222 from VC++ correctly terminate XEmacs. | |
223 | |
224 #### This will cause problems if i.exe is used for commands other | |
225 than XEmacs. We need to make behavior this a command-line | |
226 option. */ | |
442 | 227 |
826 | 228 /* Create the event as inheritable so that we can use it to communicate |
229 with the child process */ | |
230 sa.nLength = sizeof (sa); | |
231 sa.bInheritHandle = TRUE; | |
232 sa.lpSecurityDescriptor = NULL; | |
233 external_event = CreateEvent (&sa, FALSE, FALSE, NULL); | |
234 if (!external_event) | |
235 { | |
236 _ftprintf (stderr, _T ("Error %d creating signal event for `%s'\n"), | |
237 GetLastError (), command); | |
238 return 2; | |
239 } | |
240 | |
241 SetConsoleCtrlHandler ((PHANDLER_ROUTINE) ctrl_c_handler, TRUE); | |
242 _tcsncpy (new_command, command, past_exe - command); | |
243 _stprintf (new_command + (past_exe - command), | |
244 /* start with space in case no args past command name */ | |
245 " -mswindows-termination-handle %d ", (long) external_event); | |
246 _tcscat (new_command, past_exe); | |
247 | |
248 if (CreateProcess (NULL, new_command, NULL, NULL, TRUE, 0, | |
249 NULL, NULL, &si, &pi) == 0) | |
250 { | |
251 _ftprintf (stderr, _T("Error %d launching `%s'\n"), | |
252 GetLastError (), command); | |
253 return 2; | |
254 } | |
255 | |
256 CloseHandle (pi.hThread); | |
257 } | |
258 | |
442 | 259 |
260 /* Start pump in each I-connector */ | |
261 start_pump (&I_in); | |
262 start_pump (&I_out); | |
263 start_pump (&I_err); | |
264 | |
265 /* Wait for the process to complete */ | |
266 WaitForSingleObject (pi.hProcess, INFINITE); | |
267 GetExitCodeProcess (pi.hProcess, &exit_code); | |
268 CloseHandle (pi.hProcess); | |
269 | |
270 /* Make pump threads eventually die out. Looks rude, I agree */ | |
271 CloseHandle (GetStdHandle (STD_INPUT_HANDLE)); | |
272 CloseHandle (GetStdHandle (STD_OUTPUT_HANDLE)); | |
273 CloseHandle (GetStdHandle (STD_ERROR_HANDLE)); | |
274 | |
275 return exit_code; | |
276 } |