* bcache.c, bcache.h: New files to implement a byte cache.
[deliverable/binutils-gdb.git] / gdb / serial.c
1 /* Generic serial interface routines
2 Copyright 1992, 1993, 1996 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19
20 #include "defs.h"
21 #include "serial.h"
22 #include "gdb_string.h"
23 #include "gdbcmd.h"
24
25 /* Linked list of serial I/O handlers */
26
27 static struct serial_ops *serial_ops_list = NULL;
28
29 /* This is the last serial stream opened. Used by connect command. */
30
31 static serial_t last_serial_opened = NULL;
32
33 /* Pointer to list of scb's. */
34
35 static serial_t scb_base;
36
37 /* Non-NULL gives filename which contains a recording of the remote session,
38 suitable for playback by gdbserver. */
39
40 char *serial_logfile = NULL;
41 FILE *serial_logfp = NULL;
42
43 \f
44 static int serial_reading = 0;
45 static int serial_writing = 0;
46
47 void
48 serial_log_command (cmd)
49 const char *cmd;
50 {
51 if (serial_reading || serial_writing)
52 {
53 fputc_unfiltered ('\n', serial_logfp);
54 serial_reading = 0;
55 serial_writing = 0;
56 }
57 fprintf_unfiltered (serial_logfp, "c %s\n", cmd);
58 /* Make sure that the log file is as up-to-date as possible,
59 in case we are getting ready to dump core or something. */
60 fflush (serial_logfp);
61 }
62
63 static void
64 serial_logchar (ch)
65 int ch;
66 {
67 switch (ch)
68 {
69 case '\\': fputs_unfiltered ("\\\\", serial_logfp); break;
70 case '\b': fputs_unfiltered ("\\b", serial_logfp); break;
71 case '\f': fputs_unfiltered ("\\f", serial_logfp); break;
72 case '\n': fputs_unfiltered ("\\n", serial_logfp); break;
73 case '\r': fputs_unfiltered ("\\r", serial_logfp); break;
74 case '\t': fputs_unfiltered ("\\t", serial_logfp); break;
75 case '\v': fputs_unfiltered ("\\v", serial_logfp); break;
76 default: fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break;
77 }
78 }
79
80 int
81 serial_write (scb, str, len)
82 serial_t scb;
83 const char *str;
84 int len;
85 {
86 int count;
87
88 if (serial_logfp != NULL)
89 {
90 if (serial_reading)
91 {
92 fputc_unfiltered ('\n', serial_logfp);
93 serial_reading = 0;
94 }
95 if (!serial_writing)
96 {
97 serial_logchar ('w');
98 serial_logchar (' ');
99 serial_writing = 1;
100 }
101 for (count = 0; count < len; count++)
102 {
103 serial_logchar (str[count]);
104 }
105 /* Make sure that the log file is as up-to-date as possible,
106 in case we are getting ready to dump core or something. */
107 fflush (serial_logfp);
108 }
109 return (scb -> ops -> write (scb, str, len));
110 }
111
112 int
113 serial_readchar (scb, timeout)
114 serial_t scb;
115 int timeout;
116 {
117 int ch;
118
119 ch = scb -> ops -> readchar (scb, timeout);
120 if (serial_logfp != NULL)
121 {
122 if (serial_writing)
123 {
124 fputc_unfiltered ('\n', serial_logfp);
125 serial_writing = 0;
126 }
127 if (!serial_reading)
128 {
129 serial_logchar ('r');
130 serial_logchar (' ');
131 serial_reading = 1;
132 }
133 serial_logchar (ch);
134 /* Make sure that the log file is as up-to-date as possible,
135 in case we are getting ready to dump core or something. */
136 fflush (serial_logfp);
137 }
138 return (ch);
139 }
140
141 static struct serial_ops *
142 serial_interface_lookup (name)
143 char *name;
144 {
145 struct serial_ops *ops;
146
147 for (ops = serial_ops_list; ops; ops = ops->next)
148 if (strcmp (name, ops->name) == 0)
149 return ops;
150
151 return NULL;
152 }
153
154 void
155 serial_add_interface(optable)
156 struct serial_ops *optable;
157 {
158 optable->next = serial_ops_list;
159 serial_ops_list = optable;
160 }
161
162 /* Open up a device or a network socket, depending upon the syntax of NAME. */
163
164 serial_t
165 serial_open (name)
166 const char *name;
167 {
168 serial_t scb;
169 struct serial_ops *ops;
170
171 for (scb = scb_base; scb; scb = scb->next)
172 if (scb->name && strcmp (scb->name, name) == 0)
173 {
174 scb->refcnt++;
175 return scb;
176 }
177
178 if (strcmp (name, "pc") == 0)
179 ops = serial_interface_lookup ("pc");
180 else if (strchr (name, ':'))
181 ops = serial_interface_lookup ("tcp");
182 else if (strncmp (name, "lpt", 3) == 0)
183 ops = serial_interface_lookup ("parallel");
184 else
185 ops = serial_interface_lookup ("hardwire");
186
187 if (!ops)
188 return NULL;
189
190 scb = (serial_t)xmalloc (sizeof (struct _serial_t));
191
192 scb->ops = ops;
193
194 scb->bufcnt = 0;
195 scb->bufp = scb->buf;
196
197 if (scb->ops->open(scb, name))
198 {
199 free (scb);
200 return NULL;
201 }
202
203 scb->name = strsave (name);
204 scb->next = scb_base;
205 scb->refcnt = 1;
206 scb_base = scb;
207
208 last_serial_opened = scb;
209
210 if (serial_logfile != NULL)
211 {
212 serial_logfp = fopen (serial_logfile, "w");
213 if (serial_logfp == NULL)
214 {
215 perror_with_name (serial_logfile);
216 }
217 }
218
219 return scb;
220 }
221
222 serial_t
223 serial_fdopen (fd)
224 const int fd;
225 {
226 serial_t scb;
227 struct serial_ops *ops;
228
229 for (scb = scb_base; scb; scb = scb->next)
230 if (scb->fd == fd)
231 {
232 scb->refcnt++;
233 return scb;
234 }
235
236 ops = serial_interface_lookup ("hardwire");
237
238 if (!ops)
239 return NULL;
240
241 scb = (serial_t)xmalloc (sizeof (struct _serial_t));
242
243 scb->ops = ops;
244
245 scb->bufcnt = 0;
246 scb->bufp = scb->buf;
247
248 scb->fd = fd;
249
250 scb->name = NULL;
251 scb->next = scb_base;
252 scb->refcnt = 1;
253 scb_base = scb;
254
255 last_serial_opened = scb;
256
257 return scb;
258 }
259
260 void
261 serial_close(scb, really_close)
262 serial_t scb;
263 int really_close;
264 {
265 serial_t tmp_scb;
266
267 last_serial_opened = NULL;
268
269 if (serial_logfp)
270 {
271 if (serial_reading || serial_writing)
272 {
273 fputc_unfiltered ('\n', serial_logfp);
274 serial_reading = 0;
275 serial_writing = 0;
276 }
277 fclose (serial_logfp);
278 serial_logfp = NULL;
279 }
280
281 /* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you
282 should fix your code instead. */
283
284 if (!scb)
285 return;
286
287 scb->refcnt--;
288 if (scb->refcnt > 0)
289 return;
290
291 if (really_close)
292 scb->ops->close (scb);
293
294 if (scb->name)
295 free (scb->name);
296
297 if (scb_base == scb)
298 scb_base = scb_base->next;
299 else
300 for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
301 {
302 if (tmp_scb->next != scb)
303 continue;
304
305 tmp_scb->next = tmp_scb->next->next;
306 break;
307 }
308
309 free(scb);
310 }
311
312 #if 0
313 /*
314 The connect command is #if 0 because I hadn't thought of an elegant
315 way to wait for I/O on two serial_t's simultaneously. Two solutions
316 came to mind:
317
318 1) Fork, and have have one fork handle the to user direction,
319 and have the other hand the to target direction. This
320 obviously won't cut it for MSDOS.
321
322 2) Use something like select. This assumes that stdin and
323 the target side can both be waited on via the same
324 mechanism. This may not be true for DOS, if GDB is
325 talking to the target via a TCP socket.
326 -grossman, 8 Jun 93
327 */
328
329 /* Connect the user directly to the remote system. This command acts just like
330 the 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
331
332 static serial_t tty_desc; /* Controlling terminal */
333
334 static void
335 cleanup_tty(ttystate)
336 serial_ttystate ttystate;
337 {
338 printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
339 SERIAL_SET_TTY_STATE (tty_desc, ttystate);
340 free (ttystate);
341 SERIAL_CLOSE (tty_desc);
342 }
343
344 static void
345 connect_command (args, fromtty)
346 char *args;
347 int fromtty;
348 {
349 int c;
350 char cur_esc = 0;
351 serial_ttystate ttystate;
352 serial_t port_desc; /* TTY port */
353
354 dont_repeat();
355
356 if (args)
357 fprintf_unfiltered(gdb_stderr, "This command takes no args. They have been ignored.\n");
358
359 printf_unfiltered("[Entering connect mode. Use ~. or ~^D to escape]\n");
360
361 tty_desc = SERIAL_FDOPEN (0);
362 port_desc = last_serial_opened;
363
364 ttystate = SERIAL_GET_TTY_STATE (tty_desc);
365
366 SERIAL_RAW (tty_desc);
367 SERIAL_RAW (port_desc);
368
369 make_cleanup (cleanup_tty, ttystate);
370
371 while (1)
372 {
373 int mask;
374
375 mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
376
377 if (mask & 2)
378 { /* tty input */
379 char cx;
380
381 while (1)
382 {
383 c = SERIAL_READCHAR(tty_desc, 0);
384
385 if (c == SERIAL_TIMEOUT)
386 break;
387
388 if (c < 0)
389 perror_with_name("connect");
390
391 cx = c;
392 SERIAL_WRITE(port_desc, &cx, 1);
393
394 switch (cur_esc)
395 {
396 case 0:
397 if (c == '\r')
398 cur_esc = c;
399 break;
400 case '\r':
401 if (c == '~')
402 cur_esc = c;
403 else
404 cur_esc = 0;
405 break;
406 case '~':
407 if (c == '.' || c == '\004')
408 return;
409 else
410 cur_esc = 0;
411 }
412 }
413 }
414
415 if (mask & 1)
416 { /* Port input */
417 char cx;
418
419 while (1)
420 {
421 c = SERIAL_READCHAR(port_desc, 0);
422
423 if (c == SERIAL_TIMEOUT)
424 break;
425
426 if (c < 0)
427 perror_with_name("connect");
428
429 cx = c;
430
431 SERIAL_WRITE(tty_desc, &cx, 1);
432 }
433 }
434 }
435 }
436 #endif /* 0 */
437
438 /* VARARGS */
439 void
440 #ifdef ANSI_PROTOTYPES
441 serial_printf (serial_t desc, const char *format, ...)
442 #else
443 serial_printf (va_alist)
444 va_dcl
445 #endif
446 {
447 va_list args;
448 char *buf;
449 #ifdef ANSI_PROTOTYPES
450 va_start (args, format);
451 #else
452 serial_t desc;
453 char *format;
454
455 va_start (args);
456 desc = va_arg (args, serial_t);
457 format = va_arg (args, char *);
458 #endif
459
460 vasprintf (&buf, format, args);
461 SERIAL_WRITE (desc, buf, strlen (buf));
462
463 free (buf);
464 va_end (args);
465 }
466
467 void
468 _initialize_serial ()
469 {
470 #if 0
471 add_com ("connect", class_obscure, connect_command,
472 "Connect the terminal directly up to the command monitor.\n\
473 Use <CR>~. or <CR>~^D to break out.");
474 #endif /* 0 */
475
476 add_show_from_set (add_set_cmd ("remotelogfile", no_class,
477 var_filename, (char *)&serial_logfile,
478 "Set filename for remote session recording.\n\
479 This file is used to record the remote session for future playback\n\
480 by gdbserver.", &setlist),
481 &showlist);
482
483 }
This page took 0.046545 seconds and 4 git commands to generate.