This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / readline / examples / rl-fgets.c
1 /*
2 Date: Tue, 16 Mar 2004 19:38:40 -0800
3 From: Harold Levy <Harold.Levy@synopsys.com>
4 Subject: fgets(stdin) --> readline() redirector
5 To: chet@po.cwru.edu
6
7 Hi Chet,
8
9 Here is something you may find useful enough to include in the readline
10 distribution. It is a shared library that redirects calls to fgets(stdin)
11 to readline() via LD_PRELOAD, and it supports a custom prompt and list of
12 command names. Many people have asked me for this file, so I thought I'd
13 pass it your way in hope of just including it with readline to begin with.
14
15 Best Regards,
16
17 -Harold
18 */
19
20 /******************************************************************************
21 *******************************************************************************
22
23 FILE NAME: fgets.c TARGET: libfgets.so
24 AUTHOR: Harold Levy VERSION: 1.0
25 hlevy@synopsys.com
26
27 ABSTRACT: Customize fgets() behavior via LD_PRELOAD in the following ways:
28
29 -- If fgets(stdin) is called, redirect to GNU readline() to obtain
30 command-line editing, file-name completion, history, etc.
31
32 -- A list of commands for command-name completion can be configured by
33 setting the environment-variable FGETS_COMMAND_FILE to a file containing
34 the list of commands to be used.
35
36 -- Command-line editing with readline() works best when the prompt string
37 is known; you can set this with the FGETS_PROMPT environment variable.
38
39 -- There special strings that libfgets will interpret as internal commands:
40
41 _fgets_reset_ reset the command list
42
43 _fgets_dump_ dump status
44
45 _fgets_debug_ toggle debug messages
46
47 HOW TO BUILD: Here are examples of how to build libfgets.so on various
48 platforms; you will have to add -I and -L flags to configure access to
49 the readline header and library files.
50
51 (32-bit builds with gcc)
52 AIX: gcc -fPIC fgets.c -shared -o libfgets.so -lc -ldl -lreadline -ltermcap
53 HP-UX: gcc -fPIC fgets.c -shared -o libfgets.so -lc -ldld -lreadline
54 Linux: gcc -fPIC fgets.c -shared -o libfgets.so -lc -ldl -lreadline
55 SunOS: gcc -fPIC fgets.c -shared -o libfgets.so -lc -ldl -lgen -lreadline
56
57 (64-bit builds without gcc)
58 SunOS: SUNWspro/bin/cc -D_LARGEFILE64_SOURCE=1 -xtarget=ultra -xarch=v9 \
59 -KPIC fgets.c -Bdynamic -lc -ldl -lgen -ltermcap -lreadline
60
61 HOW TO USE: Different operating systems have different levels of support
62 for the LD_PRELOAD concept. The generic method for 32-bit platforms is to
63 put libtermcap.so, libfgets.so, and libreadline.so (with absolute paths)
64 in the LD_PRELOAD environment variable, and to put their parent directories
65 in the LD_LIBRARY_PATH environment variable. Unfortunately there is no
66 generic method for 64-bit platforms; e.g. for 64-bit SunOS, you would have
67 to build both 32-bit and 64-bit libfgets and libreadline libraries, and
68 use the LD_FLAGS_32 and LD_FLAGS_64 environment variables with preload and
69 library_path configurations (a mix of 32-bit and 64-bit calls are made under
70 64-bit SunOS).
71
72 EXAMPLE WRAPPER: Here is an example shell script wrapper around the
73 program "foo" that uses fgets() for command-line input:
74
75 #!/bin/csh
76 #### replace this with the libtermcap.so directory:
77 set dir1 = "/usr/lib"
78 #### replace this with the libfgets.so directory:
79 set dir2 = "/usr/fgets"
80 #### replace this with the libreadline.so directory:
81 set dir3 = "/usr/local/lib"
82 set lib1 = "${dir1}/libtermcap.so"
83 set lib2 = "${dir2}/libfgets.so"
84 set lib3 = "${dir3}/libreadline.so"
85 if ( "${?LD_PRELOAD}" ) then
86 setenv LD_PRELOAD "${lib1}:${lib2}:${lib3}:${LD_PRELOAD}"
87 else
88 setenv LD_PRELOAD "${lib1}:${lib2}:${lib3}"
89 endif
90 if ( "${?LD_LIBRARY_PATH}" ) then
91 setenv LD_LIBRARY_PATH "${dir1}:${dir2}:${dir3}:${LD_LIBRARY_PATH}"
92 else
93 setenv LD_LIBRARY_PATH "${dir1}:${dir2}:${dir3}"
94 endif
95 setenv FGETS_COMMAND_FILE "${dir2}/foo.commands"
96 setenv FGETS_PROMPT "foo> "
97 exec "foo" $*
98
99 Copyright (C)©2003-2004 Harold Levy.
100
101 This code links to the GNU readline library, and as such is bound by the
102 terms of the GNU General Public License as published by the Free Software
103 Foundation, either version 2 or (at your option) any later version.
104
105 The GNU General Public License is often shipped with GNU software, and is
106 generally kept in a file called COPYING or LICENSE. If you do not have a
107 copy of the license, write to the Free Software Foundation, 59 Temple Place,
108 Suite 330, Boston, MA 02111 USA.
109
110 This program is distributed in the hope that it will be useful, but WITHOUT
111 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
112 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
113 details.
114
115 *******************************************************************************
116 ******************************************************************************/
117
118
119 \f
120 #include <dlfcn.h>
121 #include <stdio.h>
122 #include <strings.h>
123 #include <stdlib.h>
124 #include <unistd.h>
125
126 #include <readline/readline.h>
127 #include <readline/history.h>
128
129
130 \f
131 /* for dynamically connecting to the native fgets() */
132 #if defined(RTLD_NEXT)
133 #define REAL_LIBC RTLD_NEXT
134 #else
135 #define REAL_LIBC ((void *) -1L)
136 #endif
137 typedef char * ( * fgets_t ) ( char * s, int n, FILE * stream ) ;
138
139
140 \f
141 /* private data */
142 /* -- writeable data is stored in the shared library's data segment
143 -- every process that uses the shared library gets a private memory copy of
144 its entire data segment
145 -- static data in the shared library is not copied to the application
146 -- only read-only (i.e. 'const') data is stored in the shared library's
147 text segment
148 */
149 static char ** my_fgets_names = NULL ;
150 static int my_fgets_number_of_names = 0 ;
151 static int my_fgets_debug_flag = 0 ;
152
153
154 \f
155 /* invoked with _fgets_reset_ */
156 static void
157 my_fgets_reset (
158 void
159 ) {
160 if ( my_fgets_names && (my_fgets_number_of_names > 0) ) {
161 int i ;
162 if ( my_fgets_debug_flag ) {
163 printf ( "libfgets: removing command list\n" ) ;
164 }
165 for ( i = 0 ; i < my_fgets_number_of_names ; i ++ ) {
166 if ( my_fgets_names[i] ) free ( my_fgets_names[i] ) ;
167 }
168 free ( my_fgets_names ) ;
169 }
170 my_fgets_names = NULL ;
171 my_fgets_number_of_names = 0 ;
172 }
173
174
175 \f
176 /* invoked with _fgets_dump_ */
177 static void
178 my_fgets_dump (
179 void
180 ) {
181 char * s ;
182 printf ( "\n" ) ;
183 s = getenv ( "FGETS_PROMPT" ) ;
184 printf ( "FGETS_PROMPT = %s\n", s ? s : "" ) ;
185 s = getenv ( "FGETS_COMMAND_FILE" ) ;
186 printf ( "FGETS_COMMAND_FILE = %s\n", s ? s : "" ) ;
187 printf ( "debug flag = %d\n", my_fgets_debug_flag ) ;
188 printf ( "#commands = %d\n", my_fgets_number_of_names ) ;
189 if ( my_fgets_debug_flag ) {
190 if ( my_fgets_names && (my_fgets_number_of_names > 0) ) {
191 int i ;
192 for ( i = 0 ; i < my_fgets_number_of_names ; i ++ ) {
193 printf ( "%s\n", my_fgets_names[i] ) ;
194 }
195 }
196 }
197 printf ( "\n" ) ;
198 }
199
200
201 \f
202 /* invoked with _fgets_debug_ */
203 static void
204 my_fgets_debug_toggle (
205 void
206 ) {
207 my_fgets_debug_flag = my_fgets_debug_flag ? 0 : 1 ;
208 if ( my_fgets_debug_flag ) {
209 printf ( "libfgets: debug flag = %d\n", my_fgets_debug_flag ) ;
210 }
211 }
212
213
214 \f
215 /* read the command list if needed, return the i-th name */
216 static char *
217 my_fgets_lookup (
218 int index
219 ) {
220 if ( (! my_fgets_names) || (! my_fgets_number_of_names) ) {
221 char * fname ;
222 FILE * fp ;
223 fgets_t _fgets ;
224 int i ;
225 char buf1[256], buf2[256] ;
226 fname = getenv ( "FGETS_COMMAND_FILE" ) ;
227 if ( ! fname ) {
228 if ( my_fgets_debug_flag ) {
229 printf ( "libfgets: empty or unset FGETS_COMMAND_FILE\n" ) ;
230 }
231 return NULL ;
232 }
233 fp = fopen ( fname, "r" ) ;
234 if ( ! fp ) {
235 if ( my_fgets_debug_flag ) {
236 printf ( "libfgets: cannot open '%s' for reading\n", fname ) ;
237 }
238 return NULL ;
239 }
240 _fgets = (fgets_t) dlsym ( REAL_LIBC, "fgets" ) ;
241 if ( ! _fgets ) {
242 fprintf ( stderr,
243 "libfgets: failed to dynamically link to native fgets()\n"
244 ) ;
245 return NULL ;
246 }
247 for ( i = 0 ; _fgets(buf1,255,fp) ; i ++ ) ;
248 if ( ! i ) { fclose(fp) ; return NULL ; }
249 my_fgets_names = (char**) calloc ( i, sizeof(char*) ) ;
250 rewind ( fp ) ;
251 i = 0 ;
252 while ( _fgets(buf1,255,fp) ) {
253 buf1[255] = 0 ;
254 if ( 1 == sscanf(buf1,"%s",buf2) ) {
255 my_fgets_names[i] = strdup(buf2) ;
256 i ++ ;
257 }
258 }
259 fclose ( fp ) ;
260 my_fgets_number_of_names = i ;
261 if ( my_fgets_debug_flag ) {
262 printf ( "libfgets: successfully read %d commands\n", i ) ;
263 }
264 }
265 if ( index < my_fgets_number_of_names ) {
266 return my_fgets_names[index] ;
267 } else {
268 return NULL ;
269 }
270 }
271
272
273 \f
274 /* generate a list of partial name matches for readline() */
275 static char *
276 my_fgets_generator (
277 const char * text,
278 int state
279 )
280 {
281 static int list_index, len ;
282 char * name ;
283 if ( ! state ) {
284 list_index = 0 ;
285 len = strlen ( text ) ;
286 }
287 while ( ( name = my_fgets_lookup(list_index) ) ) {
288 list_index ++ ;
289 if ( ! strncmp ( name, text, len ) ) {
290 return ( strdup ( name ) ) ;
291 }
292 }
293 return ( NULL ) ;
294 }
295
296
297 \f
298 /* partial name completion callback for readline() */
299 static char **
300 my_fgets_completion (
301 const char * text,
302 int start,
303 int end
304 )
305 {
306 char ** matches ;
307 matches = NULL ;
308 if ( ! start ) {
309 matches = rl_completion_matches ( text, my_fgets_generator ) ;
310 }
311 return ( matches ) ;
312 }
313
314
315 \f
316 /* fgets() intercept */
317 char *
318 fgets (
319 char * s,
320 int n,
321 FILE * stream
322 )
323 {
324 if ( ! s ) return NULL ;
325 if ( stream == stdin ) {
326 char * prompt ;
327 char * my_fgets_line ;
328 rl_already_prompted = 1 ;
329 rl_attempted_completion_function = my_fgets_completion ;
330 rl_catch_signals = 1 ;
331 rl_catch_sigwinch = 1 ;
332 rl_set_signals () ;
333 prompt = getenv ( "FGETS_PROMPT" ) ;
334 for (
335 my_fgets_line = 0 ; ! my_fgets_line ; my_fgets_line=readline(prompt)
336 ) ;
337 if ( ! strncmp(my_fgets_line, "_fgets_reset_", 13) ) {
338 my_fgets_reset () ;
339 free ( my_fgets_line ) ;
340 strcpy ( s, "\n" ) ;
341 return ( s ) ;
342 }
343 if ( ! strncmp(my_fgets_line, "_fgets_dump_", 12) ) {
344 my_fgets_dump () ;
345 free ( my_fgets_line ) ;
346 strcpy ( s, "\n" ) ;
347 return ( s ) ;
348 }
349 if ( ! strncmp(my_fgets_line, "_fgets_debug_", 13) ) {
350 my_fgets_debug_toggle () ;
351 free ( my_fgets_line ) ;
352 strcpy ( s, "\n" ) ;
353 return ( s ) ;
354 }
355 (void) strncpy ( s, my_fgets_line, n-1 ) ;
356 (void) strcat ( s, "\n" ) ;
357 if ( *my_fgets_line ) add_history ( my_fgets_line ) ;
358 free ( my_fgets_line ) ;
359 return ( s ) ;
360 } else {
361 static fgets_t _fgets ;
362 _fgets = (fgets_t) dlsym ( REAL_LIBC, "fgets" ) ;
363 if ( ! _fgets ) {
364 fprintf ( stderr,
365 "libfgets: failed to dynamically link to native fgets()\n"
366 ) ;
367 strcpy ( s, "\n" ) ;
368 return ( s ) ;
369 }
370 return (
371 _fgets ( s, n, stream )
372 ) ;
373 }
374 }
This page took 0.038343 seconds and 5 git commands to generate.