CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/external/serialport/serialport.c
Views: 11701
1
/* Ruby/SerialPort $Id: serialport.c,v 1.1.1.1 2004/05/25 20:41:09 vjt Exp $
2
* Guillaume Pierronnet <[email protected]>
3
* Alan Stern <[email protected]>
4
*
5
* This code is hereby licensed for public consumption under either the
6
* GNU GPL v2 or greater.
7
*
8
* You should have received a copy of the GNU General Public License
9
* along with this program; if not, write to the Free Software
10
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11
*
12
* For documentation on serial programming, see the excellent:
13
* "Serial Programming Guide for POSIX Operating Systems"
14
* written Michael R. Sweet.
15
* http://www.easysw.com/~mike/serial/
16
*/
17
18
#define VERSION "0.6.1-msf"
19
20
#include <ruby.h> /* ruby inclusion */
21
#include <rubyio.h> /* ruby io inclusion */
22
23
struct modem_params {
24
int data_rate;
25
int data_bits;
26
int stop_bits;
27
int parity;
28
};
29
30
struct line_signals {
31
int rts;
32
int dtr;
33
int cts;
34
int dsr;
35
int dcd;
36
int ri;
37
};
38
39
VALUE cSerialPort; /* serial port class */
40
41
static VALUE sBaud, sDataBits, sStopBits, sParity; /* strings */
42
static VALUE sRts, sDtr, sCts, sDsr, sDcd, sRi;
43
44
45
#if defined(mswin) || defined(bccwin)
46
47
48
#include <stdio.h> /* Standard input/output definitions */
49
#include <io.h> /* Low-level I/O definitions */
50
#include <fcntl.h> /* File control definitions */
51
#include <windows.h> /* Windows standard function definitions */
52
53
#define NONE 0
54
#define HARD 1
55
#define SOFT 2
56
57
#define SPACE SPACEPARITY
58
#define MARK MARKPARITY
59
#define EVEN EVENPARITY
60
#define ODD ODDPARITY
61
62
static char sGetCommState[] = "GetCommState";
63
static char sSetCommState[] = "SetCommState";
64
static char sGetCommTimeouts[] = "GetCommTimeouts";
65
static char sSetCommTimeouts[] = "SetCommTimeouts";
66
67
68
static HANDLE sp_get_handle(obj)
69
VALUE obj;
70
{
71
OpenFile *fptr;
72
73
GetOpenFile(obj, fptr);
74
return (HANDLE) _get_osfhandle(fileno(fptr->f));
75
}
76
77
static VALUE sp_create(class, _port)
78
VALUE class, _port;
79
{
80
OpenFile *fp;
81
int fd;
82
HANDLE fh;
83
int num_port;
84
char *port;
85
char *ports[] = {
86
"COM1", "COM2", "COM3", "COM4",
87
"COM5", "COM6", "COM7", "COM8"
88
};
89
DCB dcb;
90
91
NEWOBJ(sp, struct RFile);
92
rb_secure(4);
93
OBJSETUP(sp, class, T_FILE);
94
MakeOpenFile(sp, fp);
95
96
switch(TYPE(_port)) {
97
case T_FIXNUM:
98
num_port = FIX2INT(_port);
99
if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0]))
100
rb_raise(rb_eArgError, "illegal port number");
101
port = ports[num_port];
102
break;
103
104
case T_STRING:
105
Check_SafeStr(_port);
106
port = RSTRING(_port)->ptr;
107
break;
108
109
default:
110
rb_raise(rb_eTypeError, "wrong argument type");
111
break;
112
}
113
114
fd = open(port, O_BINARY | O_RDWR);
115
if (fd == -1)
116
rb_sys_fail(port);
117
fh = (HANDLE) _get_osfhandle(fd);
118
if (SetupComm(fh, 1024, 1024) == 0) {
119
close(fd);
120
rb_raise(rb_eArgError, "not a serial port");
121
}
122
123
dcb.DCBlength = sizeof(dcb);
124
if (GetCommState(fh, &dcb) == 0) {
125
close(fd);
126
rb_sys_fail(sGetCommState);
127
}
128
dcb.fBinary = TRUE;
129
dcb.fParity = FALSE;
130
dcb.fOutxDsrFlow = FALSE;
131
dcb.fDtrControl = DTR_CONTROL_ENABLE;
132
dcb.fDsrSensitivity = FALSE;
133
dcb.fTXContinueOnXoff = FALSE;
134
dcb.fErrorChar = FALSE;
135
dcb.fNull = FALSE;
136
dcb.fAbortOnError = FALSE;
137
dcb.XonChar = 17;
138
dcb.XoffChar = 19;
139
if (SetCommState(fh, &dcb) == 0) {
140
close(fd);
141
rb_sys_fail(sSetCommState);
142
}
143
144
fp->f = rb_fdopen(fd, "rb+");
145
fp->mode = FMODE_READWRITE | FMODE_BINMODE | FMODE_SYNC;
146
return (VALUE) sp;
147
}
148
149
static VALUE sp_set_modem_params(argc, argv, self)
150
int argc;
151
VALUE *argv, self;
152
{
153
HANDLE fh;
154
DCB dcb;
155
VALUE _data_rate = 0, _data_bits = 0, _parity = NONE, _stop_bits = 0;
156
int use_hash = 0;
157
int data_rate, data_bits, parity;
158
159
if (argc == 0)
160
return self;
161
if (argc == 1 && T_HASH == TYPE(argv[0])) {
162
use_hash = 1;
163
_data_rate = rb_hash_aref(argv[0], sBaud);
164
_data_bits = rb_hash_aref(argv[0], sDataBits);
165
_stop_bits = rb_hash_aref(argv[0], sStopBits);
166
_parity = rb_hash_aref(argv[0], sParity);
167
}
168
169
fh = sp_get_handle(self);
170
dcb.DCBlength = sizeof(dcb);
171
if (GetCommState(fh, &dcb) == 0)
172
rb_sys_fail(sGetCommState);
173
174
if (!use_hash)
175
_data_rate = argv[0];
176
if (NIL_P(_data_rate))
177
goto SkipDataRate;
178
Check_Type(_data_rate, T_FIXNUM);
179
180
data_rate = FIX2INT(_data_rate);
181
switch (data_rate) {
182
case 110:
183
case 300:
184
case 600:
185
case 1200:
186
case 2400:
187
case 4800:
188
case 9600:
189
case 14400:
190
case 19200:
191
case 38400:
192
case 56000:
193
case 57600:
194
case 115200:
195
case 128000:
196
case 256000:
197
dcb.BaudRate = data_rate;
198
break;
199
200
default:
201
rb_raise(rb_eArgError, "unknown baud rate");
202
break;
203
}
204
SkipDataRate:
205
206
if (!use_hash)
207
_data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));
208
if (NIL_P(_data_bits))
209
goto SkipDataBits;
210
Check_Type(_data_bits, T_FIXNUM);
211
212
data_bits = FIX2INT(_data_bits);
213
if (4 <= data_bits && data_bits <= 8)
214
dcb.ByteSize = data_bits;
215
else
216
rb_raise(rb_eArgError, "unknown character size");
217
SkipDataBits:
218
219
if (!use_hash)
220
_stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));
221
if (NIL_P(_stop_bits))
222
goto SkipStopBits;
223
Check_Type(_stop_bits, T_FIXNUM);
224
225
switch (FIX2INT(_stop_bits)) {
226
case 1:
227
dcb.StopBits = ONESTOPBIT;
228
break;
229
case 2:
230
dcb.StopBits = TWOSTOPBITS;
231
break;
232
default:
233
rb_raise(rb_eArgError, "unknown number of stop bits");
234
break;
235
}
236
SkipStopBits:
237
238
if (!use_hash)
239
_parity = (argc >= 4 ? argv[3] : (dcb.ByteSize == 8 ?
240
INT2FIX(NOPARITY) : INT2FIX(EVENPARITY)));
241
if (NIL_P(_parity))
242
goto SkipParity;
243
Check_Type(_parity, T_FIXNUM);
244
245
parity = FIX2INT(_parity);
246
switch (parity) {
247
case EVENPARITY:
248
case ODDPARITY:
249
case MARKPARITY:
250
case SPACEPARITY:
251
case NOPARITY:
252
dcb.Parity = parity;
253
break;
254
255
default:
256
rb_raise(rb_eArgError, "unknown parity");
257
break;
258
}
259
SkipParity:
260
261
if (SetCommState(fh, &dcb) == 0)
262
rb_sys_fail(sSetCommState);
263
return self;
264
}
265
266
static void get_modem_params(self, mp)
267
VALUE self;
268
struct modem_params *mp;
269
{
270
HANDLE fh;
271
DCB dcb;
272
273
fh = sp_get_handle(self);
274
dcb.DCBlength = sizeof(dcb);
275
if (GetCommState(fh, &dcb) == 0)
276
rb_sys_fail(sGetCommState);
277
278
mp->data_rate = dcb.BaudRate;
279
mp->data_bits = dcb.ByteSize;
280
mp->stop_bits = (dcb.StopBits == ONESTOPBIT ? 1 : 2);
281
mp->parity = dcb.Parity;
282
}
283
284
static VALUE sp_set_flow_control(self, val)
285
VALUE self, val;
286
{
287
HANDLE fh;
288
int flowc;
289
DCB dcb;
290
291
Check_Type(val, T_FIXNUM);
292
293
fh = sp_get_handle(self);
294
dcb.DCBlength = sizeof(dcb);
295
if (GetCommState(fh, &dcb) == 0)
296
rb_sys_fail(sGetCommState);
297
298
flowc = FIX2INT(val);
299
if (flowc & HARD) {
300
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
301
dcb.fOutxCtsFlow = TRUE;
302
} else {
303
dcb.fRtsControl = RTS_CONTROL_ENABLE;
304
dcb.fOutxCtsFlow = FALSE;
305
}
306
if (flowc & SOFT)
307
dcb.fOutX = dcb.fInX = TRUE;
308
else
309
dcb.fOutX = dcb.fInX = FALSE;
310
311
if (SetCommState(fh, &dcb) == 0)
312
rb_sys_fail(sSetCommState);
313
return self;
314
}
315
316
static VALUE sp_get_flow_control(self)
317
VALUE self;
318
{
319
HANDLE fh;
320
int ret;
321
DCB dcb;
322
323
fh = sp_get_handle(self);
324
dcb.DCBlength = sizeof(dcb);
325
if (GetCommState(fh, &dcb) == 0)
326
rb_sys_fail(sGetCommState);
327
328
ret = 0;
329
if (dcb.fOutxCtsFlow)
330
ret += HARD;
331
if (dcb.fOutX)
332
ret += SOFT;
333
334
return INT2FIX(ret);
335
}
336
337
static VALUE sp_set_input_type(self, val)
338
{
339
rb_notimplement();
340
return self;
341
}
342
343
static VALUE sp_get_input_type(self)
344
{
345
rb_notimplement();
346
return self;
347
}
348
349
static VALUE sp_set_output_type(self, val)
350
{
351
rb_notimplement();
352
return self;
353
}
354
355
static VALUE sp_get_output_type(self)
356
{
357
rb_notimplement();
358
return self;
359
}
360
361
static VALUE sp_set_nonblock(self, val)
362
{
363
rb_notimplement();
364
return self;
365
}
366
367
static VALUE sp_get_nonblock(self)
368
{
369
rb_notimplement();
370
return self;
371
}
372
373
static VALUE sp_set_read_timeout(self, val)
374
VALUE self, val;
375
{
376
int timeout;
377
HANDLE fh;
378
COMMTIMEOUTS ctout;
379
380
Check_Type(val, T_FIXNUM);
381
timeout = FIX2INT(val);
382
383
fh = sp_get_handle(self);
384
if (GetCommTimeouts(fh, &ctout) == 0)
385
rb_sys_fail(sGetCommTimeouts);
386
387
if (timeout < 0) {
388
ctout.ReadIntervalTimeout = MAXDWORD;
389
ctout.ReadTotalTimeoutMultiplier = 0;
390
ctout.ReadTotalTimeoutConstant = 0;
391
} else if (timeout == 0) {
392
ctout.ReadIntervalTimeout = MAXDWORD;
393
ctout.ReadTotalTimeoutMultiplier = MAXDWORD;
394
ctout.ReadTotalTimeoutConstant = MAXDWORD - 1;
395
} else {
396
ctout.ReadIntervalTimeout = timeout;
397
ctout.ReadTotalTimeoutMultiplier = 0;
398
ctout.ReadTotalTimeoutConstant = timeout;
399
}
400
401
if (SetCommTimeouts(fh, &ctout) == 0)
402
rb_sys_fail(sSetCommTimeouts);
403
return self;
404
}
405
406
static VALUE sp_get_read_timeout(self)
407
VALUE self;
408
{
409
HANDLE fh;
410
COMMTIMEOUTS ctout;
411
412
fh = sp_get_handle(self);
413
if (GetCommTimeouts(fh, &ctout) == 0)
414
rb_sys_fail(sGetCommTimeouts);
415
switch (ctout.ReadTotalTimeoutConstant) {
416
case 0:
417
return INT2FIX(-1);
418
case MAXDWORD:
419
return INT2FIX(0);
420
}
421
return INT2FIX(ctout.ReadTotalTimeoutConstant);
422
}
423
424
static VALUE sp_set_write_timeout(self, val)
425
VALUE self, val;
426
{
427
int timeout;
428
HANDLE fh;
429
COMMTIMEOUTS ctout;
430
431
Check_Type(val, T_FIXNUM);
432
timeout = FIX2INT(val);
433
434
fh = sp_get_handle(self);
435
if (GetCommTimeouts(fh, &ctout) == 0)
436
rb_sys_fail(sGetCommTimeouts);
437
438
if (timeout <= 0) {
439
ctout.WriteTotalTimeoutMultiplier = 0;
440
ctout.WriteTotalTimeoutConstant = 0;
441
} else {
442
ctout.WriteTotalTimeoutMultiplier = timeout;
443
ctout.WriteTotalTimeoutConstant = 0;
444
}
445
446
if (SetCommTimeouts(fh, &ctout) == 0)
447
rb_sys_fail(sSetCommTimeouts);
448
return self;
449
}
450
451
static VALUE sp_get_write_timeout(self)
452
VALUE self;
453
{
454
HANDLE fh;
455
COMMTIMEOUTS ctout;
456
457
fh = sp_get_handle(self);
458
if (GetCommTimeouts(fh, &ctout) == 0)
459
rb_sys_fail(sGetCommTimeouts);
460
return INT2FIX(ctout.WriteTotalTimeoutMultiplier);
461
}
462
463
static void delay_ms(time)
464
int time;
465
{
466
HANDLE ev;
467
468
ev = CreateEvent(NULL, FALSE, FALSE, NULL);
469
if (!ev)
470
rb_sys_fail("CreateEvent");
471
if (WaitForSingleObject(ev, time) == WAIT_FAILED)
472
rb_sys_fail("WaitForSingleObject");
473
CloseHandle(ev);
474
}
475
476
static VALUE sp_break(self, time)
477
VALUE self, time;
478
{
479
HANDLE fh;
480
481
Check_Type(time, T_FIXNUM);
482
483
fh = sp_get_handle(self);
484
if (SetCommBreak(fh) == 0)
485
rb_sys_fail("SetCommBreak");
486
delay_ms(FIX2INT(time) * 100);
487
ClearCommBreak(fh);
488
return Qnil;
489
}
490
491
static void get_line_signals(obj, ls)
492
VALUE obj;
493
struct line_signals *ls;
494
{
495
HANDLE fh;
496
int status;
497
498
fh = sp_get_handle(obj);
499
if (GetCommModemStatus(fh, &status) == 0)
500
rb_sys_fail("GetCommModemStatus");
501
502
ls->cts = (status & MS_CTS_ON ? 1 : 0);
503
ls->dsr = (status & MS_DSR_ON ? 1 : 0);
504
ls->dcd = (status & MS_RLSD_ON ? 1 : 0);
505
ls->ri = (status & MS_RING_ON ? 1 : 0);
506
}
507
508
static VALUE set_signal(obj, val, sigoff, sigon)
509
VALUE obj,val;
510
int sigoff, sigon;
511
{
512
HANDLE fh;
513
int set, sig;
514
515
Check_Type(val, T_FIXNUM);
516
fh = sp_get_handle(obj);
517
518
set = FIX2INT(val);
519
if (set == 0)
520
sig = sigoff;
521
else if (set == 1)
522
sig = sigon;
523
else
524
rb_raise(rb_eArgError, "invalid value");
525
526
if (EscapeCommFunction(fh, sig) == 0)
527
rb_sys_fail("EscapeCommFunction");
528
return obj;
529
}
530
531
static VALUE sp_set_rts(self, val)
532
VALUE self, val;
533
{
534
return set_signal(self, val, CLRRTS, SETRTS);
535
}
536
537
static VALUE sp_set_dtr(self, val)
538
VALUE self, val;
539
{
540
return set_signal(self, val, CLRDTR, SETDTR);
541
}
542
543
static VALUE sp_get_rts(self)
544
VALUE self;
545
{
546
rb_notimplement();
547
return self;
548
}
549
550
static VALUE sp_get_dtr(self)
551
VALUE self;
552
{
553
rb_notimplement();
554
return self;
555
}
556
557
558
#else /* defined(mswin) || defined(bccwin) */
559
560
561
#include <stdio.h> /* Standard input/output definitions */
562
#include <unistd.h> /* UNIX standard function definitions */
563
#include <fcntl.h> /* File control definitions */
564
#include <errno.h> /* Error number definitions */
565
#include <termios.h> /* POSIX terminal control definitions */
566
#include <sys/ioctl.h>
567
568
#ifdef CRTSCTS
569
#define HAVE_FLOWCONTROL_HARD 1
570
#else
571
#undef HAVE_FLOWCONTROL_HARD
572
#endif
573
574
#define NONE 0
575
#define HARD 1
576
#define SOFT 2
577
578
#define SPACE 0
579
#define MARK 0
580
#define EVEN 1
581
#define ODD 2
582
583
#define PROCESSED 1
584
#define RAW 2
585
586
static char sTcgetattr[] = "tcgetattr";
587
static char sTcsetattr[] = "tcsetattr";
588
static char sIoctl[] = "ioctl";
589
static char sFcntl[] = "fcntl";
590
591
592
static int sp_get_fd(obj)
593
VALUE obj;
594
{
595
OpenFile *fptr;
596
597
GetOpenFile(obj, fptr);
598
return (fileno(fptr->f));
599
}
600
601
static VALUE sp_create(class, _port)
602
VALUE class, _port;
603
{
604
OpenFile *fp;
605
int fd;
606
int num_port;
607
char *port;
608
char *ports[] = {
609
#if defined(linux) || defined(cygwin)
610
"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3",
611
"/dev/ttyS4", "/dev/ttyS5", "/dev/ttyS6", "/dev/ttyS7"
612
#elif defined(freebsd) || defined(netbsd) || defined(openbsd)
613
"/dev/cuaa0", "/dev/cuaa1", "/dev/cuaa2", "/dev/cuaa3",
614
"/dev/cuaa4", "/dev/cuaa5", "/dev/cuaa6", "/dev/cuaa7"
615
#elif defined(solaris)
616
"/dev/ttya", "/dev/ttyb", "/dev/ttyc", "/dev/ttyd",
617
"/dev/ttye", "/dev/ttyf", "/dev/ttyg", "/dev/ttyh"
618
#elif defined(aix)
619
"/dev/tty0", "/dev/tty1", "/dev/tty2", "/dev/tty3",
620
"/dev/tty4", "/dev/tty5", "/dev/tty6", "/dev/tty7"
621
#elif defined(irix)
622
"/dev/ttyf1", "/dev/ttyf2", "/dev/ttyf3", "/dev/ttyf4",
623
"/dev/ttyf5", "/dev/ttyf6", "/dev/ttyf7", "/dev/ttyf8"
624
#endif
625
};
626
struct termios params;
627
628
NEWOBJ(sp, struct RFile);
629
rb_secure(4);
630
OBJSETUP(sp, class, T_FILE);
631
MakeOpenFile((VALUE)sp, fp);
632
633
switch(TYPE(_port)) {
634
case T_FIXNUM:
635
num_port = FIX2INT(_port);
636
if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0]))
637
rb_raise(rb_eArgError, "illegal port number");
638
port = ports[num_port];
639
break;
640
641
case T_STRING:
642
Check_SafeStr(_port);
643
port = RSTRING(_port)->ptr;
644
break;
645
646
default:
647
rb_raise(rb_eTypeError, "wrong argument type");
648
break;
649
}
650
651
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
652
if (fd == -1)
653
rb_sys_fail(port);
654
if (!isatty(fd)) {
655
close(fd);
656
rb_raise(rb_eArgError, "not a serial port");
657
}
658
659
if (tcgetattr(fd, &params) == -1) {
660
close(fd);
661
rb_sys_fail(sTcgetattr);
662
}
663
params.c_oflag = 0;
664
params.c_lflag = 0;
665
params.c_iflag &= (IXON | IXOFF | IXANY);
666
params.c_cflag |= CLOCAL | CREAD;
667
params.c_cflag &= ~HUPCL;
668
if (tcsetattr(fd, TCSANOW, &params) == -1) {
669
close(fd);
670
rb_sys_fail(sTcsetattr);
671
}
672
673
fp->f = rb_fdopen(fd, "r+");
674
fp->mode = FMODE_READWRITE | FMODE_SYNC;
675
return (VALUE) sp;
676
}
677
678
static VALUE sp_set_modem_params(argc, argv, self)
679
int argc;
680
VALUE *argv, self;
681
{
682
int fd;
683
struct termios params;
684
VALUE _data_rate = 0, _data_bits = 0, _parity = NONE, _stop_bits = 0;
685
int use_hash = 0;
686
int data_rate, data_bits;
687
688
if (argc == 0)
689
return self;
690
if (argc == 1 && T_HASH == TYPE(argv[0])) {
691
use_hash = 1;
692
_data_rate = rb_hash_aref(argv[0], sBaud);
693
_data_bits = rb_hash_aref(argv[0], sDataBits);
694
_stop_bits = rb_hash_aref(argv[0], sStopBits);
695
_parity = rb_hash_aref(argv[0], sParity);
696
}
697
698
fd = sp_get_fd(self);
699
if (tcgetattr(fd, &params) == -1)
700
rb_sys_fail(sTcgetattr);
701
702
if (!use_hash)
703
_data_rate = argv[0];
704
if (NIL_P(_data_rate))
705
goto SkipDataRate;
706
Check_Type(_data_rate, T_FIXNUM);
707
708
switch(FIX2INT(_data_rate)) {
709
case 50: data_rate = B50; break;
710
case 75: data_rate = B75; break;
711
case 110: data_rate = B110; break;
712
case 134: data_rate = B134; break;
713
case 150: data_rate = B150; break;
714
case 200: data_rate = B200; break;
715
case 300: data_rate = B300; break;
716
case 600: data_rate = B600; break;
717
case 1200: data_rate = B1200; break;
718
case 1800: data_rate = B1800; break;
719
case 2400: data_rate = B2400; break;
720
case 4800: data_rate = B4800; break;
721
case 9600: data_rate = B9600; break;
722
case 19200: data_rate = B19200; break;
723
case 38400: data_rate = B38400; break;
724
#ifdef B57600
725
case 57600: data_rate = B57600; break;
726
#endif
727
#ifdef B76800
728
case 76800: data_rate = B76800; break;
729
#endif
730
#ifdef B115200
731
case 115200: data_rate = B115200; break;
732
#endif
733
#ifdef B230400
734
case 230400: data_rate = B230400; break;
735
#endif
736
737
default:
738
rb_raise(rb_eArgError, "unknown baud rate");
739
break;
740
}
741
cfsetispeed(&params, data_rate);
742
cfsetospeed(&params, data_rate);
743
SkipDataRate:
744
745
if (!use_hash)
746
_data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));
747
if (NIL_P(_data_bits))
748
goto SkipDataBits;
749
Check_Type(_data_bits, T_FIXNUM);
750
751
switch(FIX2INT(_data_bits)) {
752
case 5:
753
data_bits = CS5;
754
break;
755
case 6:
756
data_bits = CS6;
757
break;
758
case 7:
759
data_bits = CS7;
760
break;
761
case 8:
762
data_bits = CS8;
763
break;
764
default:
765
rb_raise(rb_eArgError, "unknown character size");
766
break;
767
}
768
params.c_cflag &= ~CSIZE;
769
params.c_cflag |= data_bits;
770
SkipDataBits:
771
772
if (!use_hash)
773
_stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));
774
if (NIL_P(_stop_bits))
775
goto SkipStopBits;
776
Check_Type(_stop_bits, T_FIXNUM);
777
778
switch(FIX2INT(_stop_bits)) {
779
case 1:
780
params.c_cflag &= ~CSTOPB;
781
break;
782
case 2:
783
params.c_cflag |= CSTOPB;
784
break;
785
default:
786
rb_raise(rb_eArgError, "unknown number of stop bits");
787
break;
788
}
789
SkipStopBits:
790
791
if (!use_hash)
792
_parity = (argc >= 4 ? argv[3] : ((params.c_cflag & CSIZE) == CS8 ?
793
INT2FIX(NONE) : INT2FIX(EVEN)));
794
if (NIL_P(_parity))
795
goto SkipParity;
796
Check_Type(_parity, T_FIXNUM);
797
798
switch(FIX2INT(_parity)) {
799
case EVEN:
800
params.c_cflag |= PARENB;
801
params.c_cflag &= ~PARODD;
802
break;
803
804
case ODD:
805
params.c_cflag |= PARENB;
806
params.c_cflag |= PARODD;
807
break;
808
809
case NONE:
810
params.c_cflag &= ~PARENB;
811
break;
812
813
default:
814
rb_raise(rb_eArgError, "unknown parity");
815
break;
816
}
817
SkipParity:
818
819
if (tcsetattr(fd, TCSANOW, &params) == -1)
820
rb_sys_fail(sTcsetattr);
821
return self;
822
}
823
824
static void get_modem_params(self, mp)
825
VALUE self;
826
struct modem_params *mp;
827
{
828
int fd;
829
struct termios params;
830
831
fd = sp_get_fd(self);
832
if (tcgetattr(fd, &params) == -1)
833
rb_sys_fail(sTcgetattr);
834
835
switch (cfgetospeed(&params)) {
836
case B50: mp->data_rate = 50; break;
837
case B75: mp->data_rate = 75; break;
838
case B110: mp->data_rate = 110; break;
839
case B134: mp->data_rate = 134; break;
840
case B150: mp->data_rate = 150; break;
841
case B200: mp->data_rate = 200; break;
842
case B300: mp->data_rate = 300; break;
843
case B600: mp->data_rate = 600; break;
844
case B1200: mp->data_rate = 1200; break;
845
case B1800: mp->data_rate = 1800; break;
846
case B2400: mp->data_rate = 2400; break;
847
case B4800: mp->data_rate = 4800; break;
848
case B9600: mp->data_rate = 9600; break;
849
case B19200: mp->data_rate = 19200; break;
850
case B38400: mp->data_rate = 38400; break;
851
#ifdef B57600
852
case B57600: mp->data_rate = 57600; break;
853
#endif
854
#ifdef B76800
855
case B76800: mp->data_rate = 76800; break;
856
#endif
857
#ifdef B115200
858
case B115200: mp->data_rate = 115200; break;
859
#endif
860
#ifdef B230400
861
case B230400: mp->data_rate = 230400; break;
862
#endif
863
}
864
865
switch(params.c_cflag & CSIZE) {
866
case CS5:
867
mp->data_bits = 5;
868
break;
869
case CS6:
870
mp->data_bits = 6;
871
break;
872
case CS7:
873
mp->data_bits = 7;
874
break;
875
case CS8:
876
mp->data_bits = 8;
877
break;
878
default:
879
mp->data_bits = 0;
880
break;
881
}
882
883
mp->stop_bits = (params.c_cflag & CSTOPB ? 2 : 1);
884
885
if (!(params.c_cflag & PARENB))
886
mp->parity = NONE;
887
else if (params.c_cflag & PARODD)
888
mp->parity = ODD;
889
else
890
mp->parity = EVEN;
891
}
892
893
static VALUE sp_set_flow_control(self, val)
894
VALUE self, val;
895
{
896
int fd;
897
int flowc;
898
struct termios params;
899
900
Check_Type(val, T_FIXNUM);
901
902
fd = sp_get_fd(self);
903
if (tcgetattr(fd, &params) == -1)
904
rb_sys_fail(sTcgetattr);
905
906
flowc = FIX2INT(val);
907
if (flowc & HARD)
908
#ifdef HAVE_FLOWCONTROL_HARD
909
params.c_cflag |= CRTSCTS;
910
else
911
params.c_cflag &= ~CRTSCTS;
912
#else
913
rb_raise(rb_eIOError, "Hardware flow control not supported");
914
#endif
915
if (flowc & SOFT)
916
params.c_iflag |= (IXON | IXOFF | IXANY);
917
else
918
params.c_iflag &= ~(IXON | IXOFF | IXANY);
919
920
if (tcsetattr(fd, TCSANOW, &params) == -1)
921
rb_sys_fail(sTcsetattr);
922
return self;
923
}
924
925
static VALUE sp_get_flow_control(self)
926
VALUE self;
927
{
928
int ret;
929
int fd;
930
struct termios params;
931
932
fd = sp_get_fd(self);
933
if (tcgetattr(fd, &params) == -1)
934
rb_sys_fail(sTcgetattr);
935
936
ret = 0;
937
#ifdef HAVE_FLOWCONTROL_HARD
938
if (params.c_cflag & CRTSCTS)
939
ret += HARD;
940
#endif
941
if (params.c_iflag & (IXON | IXOFF | IXANY))
942
ret += SOFT;
943
944
return INT2FIX(ret);
945
}
946
947
static VALUE sp_set_input_type(self, val)
948
VALUE self, val;
949
{
950
int fd;
951
int type;
952
struct termios params;
953
954
Check_Type(val, T_FIXNUM);
955
956
fd = sp_get_fd(self);
957
if (tcgetattr(fd, &params) == -1)
958
rb_sys_fail(sTcgetattr);
959
960
type = FIX2INT(val);
961
if (type == PROCESSED)
962
params.c_lflag |= ICANON;
963
else
964
params.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
965
966
if (tcsetattr(fd, TCSANOW, &params) == -1)
967
rb_sys_fail(sTcsetattr);
968
969
return self;
970
}
971
972
static VALUE sp_get_input_type(self)
973
VALUE self;
974
{
975
int ret;
976
int fd;
977
struct termios params;
978
979
fd = sp_get_fd(self);
980
if (tcgetattr(fd, &params) == -1)
981
rb_sys_fail(sTcgetattr);
982
983
ret = 0;
984
if (params.c_lflag & ICANON)
985
ret = PROCESSED;
986
else
987
ret = RAW;
988
989
return INT2FIX(ret);
990
}
991
992
static VALUE sp_set_output_type(self, val)
993
VALUE self, val;
994
{
995
int fd;
996
int type;
997
struct termios params;
998
999
Check_Type(val, T_FIXNUM);
1000
1001
fd = sp_get_fd(self);
1002
if (tcgetattr(fd, &params) == -1)
1003
rb_sys_fail(sTcgetattr);
1004
1005
type = FIX2INT(val);
1006
if (type == PROCESSED)
1007
params.c_oflag |= OPOST;
1008
else
1009
params.c_oflag &= ~OPOST;
1010
1011
if (tcsetattr(fd, TCSANOW, &params) == -1)
1012
rb_sys_fail(sTcsetattr);
1013
1014
return self;
1015
}
1016
1017
static VALUE sp_get_output_type(self)
1018
VALUE self;
1019
{
1020
int ret;
1021
int fd;
1022
struct termios params;
1023
1024
fd = sp_get_fd(self);
1025
if (tcgetattr(fd, &params) == -1)
1026
rb_sys_fail(sTcgetattr);
1027
1028
ret = 0;
1029
if (params.c_oflag & OPOST)
1030
ret = PROCESSED;
1031
else
1032
ret = RAW;
1033
1034
return INT2FIX(ret);
1035
}
1036
1037
static VALUE sp_set_nonblock(self, val)
1038
VALUE self, val;
1039
{
1040
int fd;
1041
int flags;
1042
1043
fd = sp_get_fd(self);
1044
1045
flags = fcntl(fd, F_GETFL, 0);
1046
if(flags == -1)
1047
rb_sys_fail(sFcntl);
1048
1049
if (val == Qtrue) {
1050
if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
1051
rb_sys_fail(sFcntl);
1052
}
1053
else if (val == Qfalse) {
1054
if(fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1)
1055
rb_sys_fail(sFcntl);
1056
}
1057
else
1058
rb_raise(rb_eArgError, "invalid value");
1059
1060
return self;
1061
}
1062
1063
static VALUE sp_get_nonblock(self)
1064
VALUE self;
1065
{
1066
int fd;
1067
int flags;
1068
1069
fd = sp_get_fd(self);
1070
flags = fcntl(fd, F_GETFL, 0);
1071
if(flags == -1)
1072
rb_sys_fail(sFcntl);
1073
1074
return (flags & O_NONBLOCK) ? Qtrue : Qfalse;
1075
}
1076
1077
static VALUE sp_set_read_timeout(self, val)
1078
VALUE self, val;
1079
{
1080
int timeout;
1081
int fd;
1082
struct termios params;
1083
1084
Check_Type(val, T_FIXNUM);
1085
timeout = FIX2INT(val);
1086
1087
fd = sp_get_fd(self);
1088
if (tcgetattr(fd, &params) == -1)
1089
rb_sys_fail(sTcgetattr);
1090
1091
if (timeout < 0) {
1092
params.c_cc[VTIME] = 0;
1093
params.c_cc[VMIN] = 0;
1094
} else if (timeout == 0) {
1095
params.c_cc[VTIME] = 0;
1096
params.c_cc[VMIN] = 1;
1097
} else {
1098
params.c_cc[VTIME] = (timeout + 50) / 100;
1099
params.c_cc[VMIN] = 0;
1100
}
1101
1102
if (tcsetattr(fd, TCSANOW, &params) == -1)
1103
rb_sys_fail(sTcsetattr);
1104
return self;
1105
}
1106
1107
static VALUE sp_get_read_timeout(self)
1108
VALUE self;
1109
{
1110
int fd;
1111
struct termios params;
1112
1113
fd = sp_get_fd(self);
1114
if (tcgetattr(fd, &params) == -1)
1115
rb_sys_fail(sTcgetattr);
1116
if (params.c_cc[VTIME] == 0 && params.c_cc[VMIN] == 0)
1117
return INT2FIX(-1);
1118
return INT2FIX(params.c_cc[VTIME] * 100);
1119
}
1120
1121
static VALUE sp_set_write_timeout(self, val)
1122
VALUE self, val;
1123
{
1124
rb_notimplement();
1125
return self;
1126
}
1127
1128
static VALUE sp_get_write_timeout(self)
1129
VALUE self;
1130
{
1131
rb_notimplement();
1132
return self;
1133
}
1134
1135
static VALUE sp_break(self, time)
1136
VALUE self, time;
1137
{
1138
int fd;
1139
1140
Check_Type(time, T_FIXNUM);
1141
1142
fd = sp_get_fd(self);
1143
if (tcsendbreak(fd, FIX2INT(time) / 3) == -1)
1144
rb_sys_fail("tcsendbreak");
1145
return Qnil;
1146
}
1147
1148
static void get_line_signals(obj, ls)
1149
VALUE obj;
1150
struct line_signals *ls;
1151
{
1152
int fd, status;
1153
1154
fd = sp_get_fd(obj);
1155
if (ioctl(fd, TIOCMGET, &status) == -1)
1156
rb_sys_fail(sIoctl);
1157
1158
ls->rts = (status & TIOCM_RTS ? 1 : 0);
1159
ls->dtr = (status & TIOCM_DTR ? 1 : 0);
1160
ls->cts = (status & TIOCM_CTS ? 1 : 0);
1161
ls->dsr = (status & TIOCM_DSR ? 1 : 0);
1162
ls->dcd = (status & TIOCM_CD ? 1 : 0);
1163
ls->ri = (status & TIOCM_RI ? 1 : 0);
1164
}
1165
1166
static VALUE set_signal(obj, val, sig)
1167
VALUE obj,val;
1168
int sig;
1169
{
1170
int status;
1171
int fd;
1172
int set;
1173
1174
Check_Type(val, T_FIXNUM);
1175
fd = sp_get_fd(obj);
1176
if (ioctl(fd, TIOCMGET, &status) == -1)
1177
rb_sys_fail(sIoctl);
1178
1179
set = FIX2INT(val);
1180
if (set == 0)
1181
status &= ~sig;
1182
else if (set == 1)
1183
status |= sig;
1184
else
1185
rb_raise(rb_eArgError, "invalid value");
1186
1187
if (ioctl(fd, TIOCMSET, &status) == -1)
1188
rb_sys_fail(sIoctl);
1189
return obj;
1190
}
1191
1192
static VALUE sp_set_rts(self, val)
1193
VALUE self, val;
1194
{
1195
return set_signal(self, val, TIOCM_RTS);
1196
}
1197
1198
static VALUE sp_set_dtr(self, val)
1199
VALUE self, val;
1200
{
1201
return set_signal(self, val, TIOCM_DTR);
1202
}
1203
1204
static VALUE sp_get_rts(self)
1205
VALUE self;
1206
{
1207
struct line_signals ls;
1208
1209
get_line_signals(self, &ls);
1210
return INT2FIX(ls.rts);
1211
}
1212
1213
static VALUE sp_get_dtr(self)
1214
VALUE self;
1215
{
1216
struct line_signals ls;
1217
1218
get_line_signals(self, &ls);
1219
return INT2FIX(ls.dtr);
1220
}
1221
1222
1223
#endif /* defined(mswin) || defined(bccwin) */
1224
1225
1226
static VALUE sp_set_data_rate(self, data_rate)
1227
VALUE self, data_rate;
1228
{
1229
VALUE argv[4];
1230
1231
argv[0] = data_rate;
1232
argv[1] = argv[2] = argv[3] = Qnil;
1233
return sp_set_modem_params(4, argv, self);
1234
}
1235
1236
static VALUE sp_set_data_bits(self, data_bits)
1237
VALUE self, data_bits;
1238
{
1239
VALUE argv[4];
1240
1241
argv[1] = data_bits;
1242
argv[0] = argv[2] = argv[3] = Qnil;
1243
return sp_set_modem_params(4, argv, self);
1244
}
1245
1246
static VALUE sp_set_stop_bits(self, stop_bits)
1247
VALUE self, stop_bits;
1248
{
1249
VALUE argv[4];
1250
1251
argv[2] = stop_bits;
1252
argv[0] = argv[1] = argv[3] = Qnil;
1253
return sp_set_modem_params(4, argv, self);
1254
}
1255
1256
static VALUE sp_set_parity(self, parity)
1257
VALUE self, parity;
1258
{
1259
VALUE argv[4];
1260
1261
argv[3] = parity;
1262
argv[0] = argv[1] = argv[2] = Qnil;
1263
return sp_set_modem_params(4, argv, self);
1264
}
1265
1266
static VALUE sp_get_data_rate(self)
1267
VALUE self;
1268
{
1269
struct modem_params mp;
1270
1271
get_modem_params(self, &mp);
1272
return INT2FIX(mp.data_rate);
1273
}
1274
1275
static VALUE sp_get_data_bits(self)
1276
VALUE self;
1277
{
1278
struct modem_params mp;
1279
1280
get_modem_params(self, &mp);
1281
return INT2FIX(mp.data_bits);
1282
}
1283
1284
static VALUE sp_get_stop_bits(self)
1285
VALUE self;
1286
{
1287
struct modem_params mp;
1288
1289
get_modem_params(self, &mp);
1290
return INT2FIX(mp.stop_bits);
1291
}
1292
1293
static VALUE sp_get_parity(self)
1294
VALUE self;
1295
{
1296
struct modem_params mp;
1297
1298
get_modem_params(self, &mp);
1299
return INT2FIX(mp.parity);
1300
}
1301
1302
static VALUE sp_get_modem_params(self)
1303
VALUE self;
1304
{
1305
struct modem_params mp;
1306
VALUE hash;
1307
1308
get_modem_params(self, &mp);
1309
hash = rb_hash_new();
1310
rb_hash_aset(hash, sBaud, INT2FIX(mp.data_rate));
1311
rb_hash_aset(hash, sDataBits, INT2FIX(mp.data_bits));
1312
rb_hash_aset(hash, sStopBits, INT2FIX(mp.stop_bits));
1313
rb_hash_aset(hash, sParity, INT2FIX(mp.parity));
1314
return hash;
1315
}
1316
1317
static VALUE sp_get_cts(self)
1318
VALUE self;
1319
{
1320
struct line_signals ls;
1321
1322
get_line_signals(self, &ls);
1323
return INT2FIX(ls.cts);
1324
}
1325
1326
static VALUE sp_get_dsr(self)
1327
VALUE self;
1328
{
1329
struct line_signals ls;
1330
1331
get_line_signals(self, &ls);
1332
return INT2FIX(ls.dsr);
1333
}
1334
1335
static VALUE sp_get_dcd(self)
1336
VALUE self;
1337
{
1338
struct line_signals ls;
1339
1340
get_line_signals(self, &ls);
1341
return INT2FIX(ls.dcd);
1342
}
1343
1344
static VALUE sp_get_ri(self)
1345
VALUE self;
1346
{
1347
struct line_signals ls;
1348
1349
get_line_signals(self, &ls);
1350
return INT2FIX(ls.ri);
1351
}
1352
1353
static VALUE
1354
sp_signals(self)
1355
VALUE self;
1356
{
1357
struct line_signals ls;
1358
VALUE hash;
1359
1360
get_line_signals(self, &ls);
1361
hash = rb_hash_new();
1362
#if !(defined(mswin) || defined(bccwin))
1363
rb_hash_aset(hash, sRts, INT2FIX(ls.rts));
1364
rb_hash_aset(hash, sDtr, INT2FIX(ls.dtr));
1365
#endif
1366
rb_hash_aset(hash, sCts, INT2FIX(ls.cts));
1367
rb_hash_aset(hash, sDsr, INT2FIX(ls.dsr));
1368
rb_hash_aset(hash, sDcd, INT2FIX(ls.dcd));
1369
rb_hash_aset(hash, sRi, INT2FIX(ls.ri));
1370
return hash;
1371
}
1372
1373
void Init_serialport() {
1374
sBaud = rb_str_new2("baud");
1375
sDataBits = rb_str_new2("data_bits");
1376
sStopBits = rb_str_new2("stop_bits");
1377
sParity = rb_str_new2("parity");
1378
sRts = rb_str_new2("rts");
1379
sDtr = rb_str_new2("dtr");
1380
sCts = rb_str_new2("cts");
1381
sDsr = rb_str_new2("dsr");
1382
sDcd = rb_str_new2("dcd");
1383
sRi = rb_str_new2("ri");
1384
1385
rb_gc_register_address(&sBaud);
1386
rb_gc_register_address(&sDataBits);
1387
rb_gc_register_address(&sStopBits);
1388
rb_gc_register_address(&sParity);
1389
rb_gc_register_address(&sRts);
1390
rb_gc_register_address(&sDtr);
1391
rb_gc_register_address(&sCts);
1392
rb_gc_register_address(&sDsr);
1393
rb_gc_register_address(&sDcd);
1394
rb_gc_register_address(&sRi);
1395
1396
cSerialPort = rb_define_class("SerialPort", rb_cIO);
1397
rb_define_singleton_method(cSerialPort, "create", sp_create, 1);
1398
1399
rb_define_method(cSerialPort, "get_modem_params", sp_get_modem_params, 0);
1400
rb_define_method(cSerialPort, "set_modem_params", sp_set_modem_params, -1);
1401
rb_define_method(cSerialPort, "modem_params", sp_get_modem_params, 0);
1402
rb_define_method(cSerialPort, "modem_params=", sp_set_modem_params, -1);
1403
rb_define_method(cSerialPort, "baud", sp_get_data_rate, 0);
1404
rb_define_method(cSerialPort, "baud=", sp_set_data_rate, 1);
1405
rb_define_method(cSerialPort, "data_bits", sp_get_data_bits, 0);
1406
rb_define_method(cSerialPort, "data_bits=", sp_set_data_bits, 1);
1407
rb_define_method(cSerialPort, "stop_bits", sp_get_stop_bits, 0);
1408
rb_define_method(cSerialPort, "stop_bits=", sp_set_stop_bits, 1);
1409
rb_define_method(cSerialPort, "parity", sp_get_parity, 0);
1410
rb_define_method(cSerialPort, "parity=", sp_set_parity, 1);
1411
1412
rb_define_method(cSerialPort, "flow_control=", sp_set_flow_control, 1);
1413
rb_define_method(cSerialPort, "flow_control", sp_get_flow_control, 0);
1414
rb_define_method(cSerialPort, "input_type=", sp_set_input_type, 1);
1415
rb_define_method(cSerialPort, "input_type", sp_get_input_type, 0);
1416
rb_define_method(cSerialPort, "output_type=", sp_set_output_type, 1);
1417
rb_define_method(cSerialPort, "output_type", sp_get_output_type, 0);
1418
1419
rb_define_method(cSerialPort, "nonblock=", sp_set_nonblock, 1);
1420
rb_define_method(cSerialPort, "nonblock", sp_get_nonblock, 0);
1421
1422
rb_define_method(cSerialPort, "read_timeout", sp_get_read_timeout, 0);
1423
rb_define_method(cSerialPort, "read_timeout=", sp_set_read_timeout, 1);
1424
rb_define_method(cSerialPort, "write_timeout", sp_get_write_timeout, 0);
1425
rb_define_method(cSerialPort, "write_timeout=", sp_set_write_timeout, 1);
1426
1427
rb_define_method(cSerialPort, "break", sp_break, 1);
1428
1429
rb_define_method(cSerialPort, "signals", sp_signals, 0);
1430
rb_define_method(cSerialPort, "get_signals", sp_signals, 0);
1431
rb_define_method(cSerialPort, "rts", sp_get_rts, 0);
1432
rb_define_method(cSerialPort, "rts=", sp_set_rts, 1);
1433
rb_define_method(cSerialPort, "dtr", sp_get_dtr, 0);
1434
rb_define_method(cSerialPort, "dtr=", sp_set_dtr, 1);
1435
rb_define_method(cSerialPort, "cts", sp_get_cts, 0);
1436
rb_define_method(cSerialPort, "dsr", sp_get_dsr, 0);
1437
rb_define_method(cSerialPort, "dcd", sp_get_dcd, 0);
1438
rb_define_method(cSerialPort, "ri", sp_get_ri, 0);
1439
1440
rb_define_const(cSerialPort, "NONE", INT2FIX(NONE));
1441
rb_define_const(cSerialPort, "HARD", INT2FIX(HARD));
1442
rb_define_const(cSerialPort, "SOFT", INT2FIX(SOFT));
1443
1444
rb_define_const(cSerialPort, "SPACE", INT2FIX(SPACE));
1445
rb_define_const(cSerialPort, "MARK", INT2FIX(MARK));
1446
rb_define_const(cSerialPort, "EVEN", INT2FIX(EVEN));
1447
rb_define_const(cSerialPort, "ODD", INT2FIX(ODD));
1448
1449
rb_define_const(cSerialPort, "PROCESSED", INT2FIX(PROCESSED));
1450
rb_define_const(cSerialPort, "RAW", INT2FIX(RAW));
1451
1452
rb_define_const(cSerialPort, "VERSION", rb_str_new2(VERSION));
1453
1454
/* The following definitions are more easily carried out in Ruby */
1455
rb_eval_string(
1456
"class SerialPort\n"
1457
1458
"def self.new(port, *params)\n"
1459
"sp = create(port)\n"
1460
"begin\n"
1461
"sp.set_modem_params(*params)\n"
1462
"rescue\n"
1463
"sp.close\n"
1464
"raise\n"
1465
"end\n"
1466
"return sp\n"
1467
"end\n"
1468
1469
"def self.open(port, *params)\n"
1470
"sp = create(port)\n"
1471
"begin\n"
1472
"sp.set_modem_params(*params)\n"
1473
"if (block_given?)\n"
1474
"yield sp\n"
1475
"sp.close\n"
1476
"return nil\n"
1477
"end\n"
1478
"rescue\n"
1479
"sp.close\n"
1480
"raise\n"
1481
"end\n"
1482
"return sp\n"
1483
"end\n"
1484
1485
"end\n"
1486
);
1487
}
1488
1489