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