* monitor.c (monitor_load_srec monitor_make_srec): Move all
[external/binutils.git] / gdb / serial.c
1 /* Generic serial interface routines
2    Copyright 1992, 1993 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
24 /* Linked list of serial I/O handlers */
25
26 static struct serial_ops *serial_ops_list = NULL;
27
28 /* This is the last serial stream opened.  Used by connect command. */
29
30 static serial_t last_serial_opened = NULL;
31
32 /* Pointer to list of scb's. */
33
34 static serial_t scb_base;
35
36 static struct serial_ops *
37 serial_interface_lookup (name)
38      char *name;
39 {
40   struct serial_ops *ops;
41
42   for (ops = serial_ops_list; ops; ops = ops->next)
43     if (strcmp (name, ops->name) == 0)
44       return ops;
45
46   return NULL;
47 }
48
49 void
50 serial_add_interface(optable)
51      struct serial_ops *optable;
52 {
53   optable->next = serial_ops_list;
54   serial_ops_list = optable;
55 }
56
57 /* Open up a device or a network socket, depending upon the syntax of NAME. */
58
59 serial_t
60 serial_open (name)
61      const char *name;
62 {
63   serial_t scb;
64   struct serial_ops *ops;
65
66   for (scb = scb_base; scb; scb = scb->next)
67     if (scb->name && strcmp (scb->name, name) == 0)
68       {
69         scb->refcnt++;
70         return scb;
71       }
72
73   if (strcmp (name, "pc") == 0)
74     ops = serial_interface_lookup ("pc");
75   else if (strchr (name, ':'))
76     ops = serial_interface_lookup ("tcp");
77   else
78     ops = serial_interface_lookup ("hardwire");
79
80   if (!ops)
81     return NULL;
82
83   scb = (serial_t)xmalloc (sizeof (struct _serial_t));
84
85   scb->ops = ops;
86
87   scb->bufcnt = 0;
88   scb->bufp = scb->buf;
89
90   if (scb->ops->open(scb, name))
91     {
92       free (scb);
93       return NULL;
94     }
95
96   scb->name = strsave (name);
97   scb->next = scb_base;
98   scb->refcnt = 1;
99   scb_base = scb;
100
101   last_serial_opened = scb;
102
103   return scb;
104 }
105
106 serial_t
107 serial_fdopen (fd)
108      const int fd;
109 {
110   serial_t scb;
111   struct serial_ops *ops;
112
113   for (scb = scb_base; scb; scb = scb->next)
114     if (scb->fd == fd)
115       {
116         scb->refcnt++;
117         return scb;
118       }
119
120   ops = serial_interface_lookup ("hardwire");
121
122   if (!ops)
123     return NULL;
124
125   scb = (serial_t)xmalloc (sizeof (struct _serial_t));
126
127   scb->ops = ops;
128
129   scb->bufcnt = 0;
130   scb->bufp = scb->buf;
131
132   scb->fd = fd;
133
134   scb->name = NULL;
135   scb->next = scb_base;
136   scb->refcnt = 1;
137   scb_base = scb;
138
139   last_serial_opened = scb;
140
141   return scb;
142 }
143
144 void
145 serial_close(scb, really_close)
146      serial_t scb;
147      int really_close;
148 {
149   serial_t tmp_scb;
150
151   last_serial_opened = NULL;
152
153 /* This is bogus.  It's not our fault if you pass us a bad scb...!  Rob, you
154    should fix your code instead.  */
155
156   if (!scb)
157     return;
158
159   scb->refcnt--;
160   if (scb->refcnt > 0)
161     return;
162
163   if (really_close)
164     scb->ops->close (scb);
165
166   if (scb->name)
167     free (scb->name);
168
169   if (scb_base == scb)
170     scb_base = scb_base->next;
171   else
172     for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
173       {
174         if (tmp_scb->next != scb)
175           continue;
176
177         tmp_scb->next = tmp_scb->next->next;
178         break;
179       }
180
181   free(scb);
182 }
183
184 #if 0
185 /*
186 The connect command is #if 0 because I hadn't thought of an elegant
187 way to wait for I/O on two serial_t's simultaneously.  Two solutions
188 came to mind:
189
190         1) Fork, and have have one fork handle the to user direction,
191            and have the other hand the to target direction.  This
192            obviously won't cut it for MSDOS.
193
194         2) Use something like select.  This assumes that stdin and
195            the target side can both be waited on via the same
196            mechanism.  This may not be true for DOS, if GDB is
197            talking to the target via a TCP socket.
198 -grossman, 8 Jun 93
199 */
200
201 /* Connect the user directly to the remote system.  This command acts just like
202    the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
203
204 static serial_t tty_desc;               /* Controlling terminal */
205
206 static void
207 cleanup_tty(ttystate)
208      serial_ttystate ttystate;
209 {
210   printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
211   SERIAL_SET_TTY_STATE (tty_desc, ttystate);
212   free (ttystate);
213   SERIAL_CLOSE (tty_desc);
214 }
215
216 static void
217 connect_command (args, fromtty)
218      char       *args;
219      int        fromtty;
220 {
221   int c;
222   char cur_esc = 0;
223   serial_ttystate ttystate;
224   serial_t port_desc;           /* TTY port */
225
226   dont_repeat();
227
228   if (args)
229     fprintf_unfiltered(gdb_stderr, "This command takes no args.  They have been ignored.\n");
230         
231   printf_unfiltered("[Entering connect mode.  Use ~. or ~^D to escape]\n");
232
233   tty_desc = SERIAL_FDOPEN (0);
234   port_desc = last_serial_opened;
235
236   ttystate = SERIAL_GET_TTY_STATE (tty_desc);
237
238   SERIAL_RAW (tty_desc);
239   SERIAL_RAW (port_desc);
240
241   make_cleanup (cleanup_tty, ttystate);
242
243   while (1)
244     {
245       int mask;
246
247       mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
248
249       if (mask & 2)
250         {                       /* tty input */
251           char cx;
252
253           while (1)
254             {
255               c = SERIAL_READCHAR(tty_desc, 0);
256
257               if (c == SERIAL_TIMEOUT)
258                   break;
259
260               if (c < 0)
261                 perror_with_name("connect");
262
263               cx = c;
264               SERIAL_WRITE(port_desc, &cx, 1);
265
266               switch (cur_esc)
267                 {
268                 case 0:
269                   if (c == '\r')
270                     cur_esc = c;
271                   break;
272                 case '\r':
273                   if (c == '~')
274                     cur_esc = c;
275                   else
276                     cur_esc = 0;
277                   break;
278                 case '~':
279                   if (c == '.' || c == '\004')
280                     return;
281                   else
282                     cur_esc = 0;
283                 }
284             }
285         }
286
287       if (mask & 1)
288         {                       /* Port input */
289           char cx;
290
291           while (1)
292             {
293               c = SERIAL_READCHAR(port_desc, 0);
294
295               if (c == SERIAL_TIMEOUT)
296                   break;
297
298               if (c < 0)
299                 perror_with_name("connect");
300
301               cx = c;
302
303               SERIAL_WRITE(tty_desc, &cx, 1);
304             }
305         }
306     }
307 }
308 #endif /* 0 */
309
310 /* VARARGS */
311 void
312 #ifdef ANSI_PROTOTYPES
313 serial_printf (serial_t desc, const char *format, ...)
314 #else
315 serial_printf (va_alist)
316      va_dcl
317 #endif
318 {
319   va_list args;
320   char *buf;
321 #ifdef ANSI_PROTOTYPES
322   va_start (args, format);
323 #else
324   serial_t desc;
325   char *format;
326
327   va_start (args);
328   desc = va_arg (args, serial_t);
329   format = va_arg (args, char *);
330 #endif
331
332   vasprintf (&buf, format, args);
333   SERIAL_WRITE (desc, buf, strlen (buf));
334
335   free (buf);
336   va_end (args);
337 }
338
339 void
340 _initialize_serial ()
341 {
342 #if 0
343   add_com ("connect", class_obscure, connect_command,
344            "Connect the terminal directly up to the command monitor.\n\
345 Use <CR>~. or <CR>~^D to break out.");
346 #endif /* 0 */
347 }