diff options
Diffstat (limited to 'apps/plugins/pdbox/PDa/extra/shell.c')
-rw-r--r-- | apps/plugins/pdbox/PDa/extra/shell.c | 624 |
1 files changed, 624 insertions, 0 deletions
diff --git a/apps/plugins/pdbox/PDa/extra/shell.c b/apps/plugins/pdbox/PDa/extra/shell.c new file mode 100644 index 0000000000..a0b6cef5b5 --- /dev/null +++ b/apps/plugins/pdbox/PDa/extra/shell.c | |||
@@ -0,0 +1,624 @@ | |||
1 | /* (C) Guenter Geiger <geiger@epy.co.at> */ | ||
2 | |||
3 | #include "m_pd.h" | ||
4 | #ifdef NT | ||
5 | #pragma warning( disable : 4244 ) | ||
6 | #pragma warning( disable : 4305 ) | ||
7 | #endif | ||
8 | |||
9 | #include <unistd.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <stdio.h> | ||
13 | #include <sys/types.h> | ||
14 | #include <sys/wait.h> | ||
15 | #include <signal.h> | ||
16 | #include <sched.h> | ||
17 | |||
18 | void sys_rmpollfn(int fd); | ||
19 | void sys_addpollfn(int fd, void* fn, void *ptr); | ||
20 | |||
21 | /* ------------------------ shell ----------------------------- */ | ||
22 | |||
23 | #define INBUFSIZE 1024 | ||
24 | |||
25 | static t_class *shell_class; | ||
26 | |||
27 | |||
28 | static void drop_priority(void) | ||
29 | { | ||
30 | #ifdef _POSIX_PRIORITY_SCHEDULING | ||
31 | struct sched_param par; | ||
32 | int p1 ,p2, p3; | ||
33 | par.sched_priority = 0; | ||
34 | sched_setscheduler(0,SCHED_OTHER,&par); | ||
35 | #endif | ||
36 | } | ||
37 | |||
38 | |||
39 | typedef struct _shell | ||
40 | { | ||
41 | t_object x_obj; | ||
42 | int x_echo; | ||
43 | char *sr_inbuf; | ||
44 | int sr_inhead; | ||
45 | int sr_intail; | ||
46 | void* x_binbuf; | ||
47 | int fdpipe[2]; | ||
48 | int fdinpipe[2]; | ||
49 | int pid; | ||
50 | int x_del; | ||
51 | t_outlet* x_done; | ||
52 | t_clock* x_clock; | ||
53 | } t_shell; | ||
54 | |||
55 | static int shell_pid; | ||
56 | |||
57 | |||
58 | void shell_cleanup(t_shell* x) | ||
59 | { | ||
60 | sys_rmpollfn(x->fdpipe[0]); | ||
61 | |||
62 | if (x->fdpipe[0]>0) close(x->fdpipe[0]); | ||
63 | if (x->fdpipe[1]>0) close(x->fdpipe[1]); | ||
64 | if (x->fdinpipe[0]>0) close(x->fdinpipe[0]); | ||
65 | if (x->fdinpipe[1]>0) close(x->fdinpipe[1]); | ||
66 | |||
67 | x->fdpipe[0] = -1; | ||
68 | x->fdpipe[1] = -1; | ||
69 | x->fdinpipe[0] = -1; | ||
70 | x->fdinpipe[1] = -1; | ||
71 | clock_unset(x->x_clock); | ||
72 | } | ||
73 | |||
74 | void shell_check(t_shell* x) | ||
75 | { | ||
76 | int ret; | ||
77 | int status; | ||
78 | ret = waitpid(x->pid,&status,WNOHANG); | ||
79 | if (ret == x->pid) { | ||
80 | shell_cleanup(x); | ||
81 | if (WIFEXITED(status)) { | ||
82 | outlet_float(x->x_done,WEXITSTATUS(status)); | ||
83 | } | ||
84 | else outlet_float(x->x_done,0); | ||
85 | } | ||
86 | else { | ||
87 | if (x->x_del < 100) x->x_del+=2; /* increment poll times */ | ||
88 | clock_delay(x->x_clock,x->x_del); | ||
89 | } | ||
90 | } | ||
91 | |||
92 | |||
93 | void shell_bang(t_shell *x) | ||
94 | { | ||
95 | post("bang"); | ||
96 | } | ||
97 | |||
98 | /* snippet from pd's code */ | ||
99 | static void shell_doit(void *z, t_binbuf *b) | ||
100 | { | ||
101 | t_shell *x = (t_shell *)z; | ||
102 | int msg, natom = binbuf_getnatom(b); | ||
103 | t_atom *at = binbuf_getvec(b); | ||
104 | |||
105 | for (msg = 0; msg < natom;) | ||
106 | { | ||
107 | int emsg; | ||
108 | for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA | ||
109 | && at[emsg].a_type != A_SEMI; emsg++) | ||
110 | ; | ||
111 | if (emsg > msg) | ||
112 | { | ||
113 | int i; | ||
114 | for (i = msg; i < emsg; i++) | ||
115 | if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) | ||
116 | { | ||
117 | pd_error(x, "netreceive: got dollar sign in message"); | ||
118 | goto nodice; | ||
119 | } | ||
120 | if (at[msg].a_type == A_FLOAT) | ||
121 | { | ||
122 | if (emsg > msg + 1) | ||
123 | outlet_list(x->x_obj.ob_outlet, 0, emsg-msg, at + msg); | ||
124 | else outlet_float(x->x_obj.ob_outlet, at[msg].a_w.w_float); | ||
125 | } | ||
126 | else if (at[msg].a_type == A_SYMBOL) | ||
127 | outlet_anything(x->x_obj.ob_outlet, at[msg].a_w.w_symbol, | ||
128 | emsg-msg-1, at + msg + 1); | ||
129 | } | ||
130 | nodice: | ||
131 | msg = emsg + 1; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | |||
136 | void shell_read(t_shell *x, int fd) | ||
137 | { | ||
138 | char buf[INBUFSIZE]; | ||
139 | t_binbuf* bbuf = binbuf_new(); | ||
140 | int i; | ||
141 | int readto = | ||
142 | (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); | ||
143 | int ret; | ||
144 | |||
145 | ret = read(fd, buf,INBUFSIZE-1); | ||
146 | buf[ret] = '\0'; | ||
147 | |||
148 | for (i=0;i<ret;i++) | ||
149 | if (buf[i] == '\n') buf[i] = ';'; | ||
150 | if (ret < 0) | ||
151 | { | ||
152 | error("shell: pipe read error"); | ||
153 | sys_rmpollfn(fd); | ||
154 | x->fdpipe[0] = -1; | ||
155 | close(fd); | ||
156 | return; | ||
157 | } | ||
158 | else if (ret == 0) | ||
159 | { | ||
160 | post("EOF on socket %d\n", fd); | ||
161 | sys_rmpollfn(fd); | ||
162 | x->fdpipe[0] = -1; | ||
163 | close(fd); | ||
164 | return; | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | int natom; | ||
169 | t_atom *at; | ||
170 | binbuf_text(bbuf, buf, strlen(buf)); | ||
171 | |||
172 | natom = binbuf_getnatom(bbuf); | ||
173 | at = binbuf_getvec(bbuf); | ||
174 | shell_doit(x,bbuf); | ||
175 | } | ||
176 | binbuf_free(bbuf); | ||
177 | } | ||
178 | |||
179 | |||
180 | static void shell_send(t_shell *x, t_symbol *s,int ac, t_atom *at) | ||
181 | { | ||
182 | int i; | ||
183 | char tmp[MAXPDSTRING]; | ||
184 | int size = 0; | ||
185 | |||
186 | if (x->fdinpipe[0] == -1) return; /* nothing to send to */ | ||
187 | |||
188 | for (i=0;i<ac;i++) { | ||
189 | atom_string(at,tmp+size,MAXPDSTRING - size); | ||
190 | at++; | ||
191 | size=strlen(tmp); | ||
192 | tmp[size++] = ' '; | ||
193 | } | ||
194 | tmp[size-1] = '\0'; | ||
195 | post("sending %s",tmp); | ||
196 | write(x->fdinpipe[0],tmp,strlen(tmp)); | ||
197 | } | ||
198 | |||
199 | static void shell_anything(t_shell *x, t_symbol *s, int ac, t_atom *at) | ||
200 | { | ||
201 | int i; | ||
202 | char* argv[20]; | ||
203 | t_symbol* sym; | ||
204 | |||
205 | if (!strcmp(s->s_name,"send")) { | ||
206 | post("send"); | ||
207 | shell_send(x,s,ac,at); | ||
208 | return; | ||
209 | } | ||
210 | |||
211 | argv[0] = s->s_name; | ||
212 | |||
213 | if (x->fdpipe[0] != -1) { | ||
214 | post("shell: old process still running"); | ||
215 | kill(x->pid,SIGKILL); | ||
216 | shell_cleanup(x); | ||
217 | } | ||
218 | |||
219 | |||
220 | if (pipe(x->fdpipe) < 0) { | ||
221 | error("unable to create pipe"); | ||
222 | return; | ||
223 | } | ||
224 | |||
225 | if (pipe(x->fdinpipe) < 0) { | ||
226 | error("unable to create input pipe"); | ||
227 | return; | ||
228 | } | ||
229 | |||
230 | |||
231 | sys_addpollfn(x->fdpipe[0],shell_read,x); | ||
232 | |||
233 | if (!(x->pid = fork())) { | ||
234 | int status; | ||
235 | char* cmd = getbytes(1024); | ||
236 | char* tcmd = getbytes(1024); | ||
237 | strcpy(cmd,s->s_name); | ||
238 | |||
239 | #if 0 | ||
240 | for (i=1;i<=ac;i++) { | ||
241 | argv[i] = getbytes(255); | ||
242 | atom_string(at,argv[i],255); | ||
243 | /* post("argument %s",argv[i]); */ | ||
244 | at++; | ||
245 | } | ||
246 | argv[i] = 0; | ||
247 | #endif | ||
248 | for (i=1;i<=ac;i++) { | ||
249 | atom_string(at,tcmd,255); | ||
250 | strcat(cmd," "); | ||
251 | strcat(cmd,tcmd); | ||
252 | at++; | ||
253 | } | ||
254 | |||
255 | |||
256 | /* reassign stdout */ | ||
257 | dup2(x->fdpipe[1],1); | ||
258 | dup2(x->fdinpipe[1],0); | ||
259 | |||
260 | /* drop privileges */ | ||
261 | drop_priority(); | ||
262 | seteuid(getuid()); /* lose setuid priveliges */ | ||
263 | |||
264 | post("executing %s",cmd); | ||
265 | system(cmd); | ||
266 | // execvp(s->s_name,argv); | ||
267 | exit(0); | ||
268 | } | ||
269 | x->x_del = 4; | ||
270 | clock_delay(x->x_clock,x->x_del); | ||
271 | |||
272 | if (x->x_echo) | ||
273 | outlet_anything(x->x_obj.ob_outlet, s, ac, at); | ||
274 | } | ||
275 | |||
276 | |||
277 | |||
278 | void shell_free(t_shell* x) | ||
279 | { | ||
280 | binbuf_free(x->x_binbuf); | ||
281 | } | ||
282 | |||
283 | static void *shell_new(void) | ||
284 | { | ||
285 | t_shell *x = (t_shell *)pd_new(shell_class); | ||
286 | |||
287 | x->x_echo = 0; | ||
288 | x->fdpipe[0] = -1; | ||
289 | x->fdpipe[1] = -1; | ||
290 | x->fdinpipe[0] = -1; | ||
291 | x->fdinpipe[1] = -1; | ||
292 | |||
293 | x->sr_inhead = x->sr_intail = 0; | ||
294 | if (!(x->sr_inbuf = (char*) malloc(INBUFSIZE))) bug("t_shell");; | ||
295 | |||
296 | x->x_binbuf = binbuf_new(); | ||
297 | |||
298 | outlet_new(&x->x_obj, &s_list); | ||
299 | x->x_done = outlet_new(&x->x_obj, &s_bang); | ||
300 | x->x_clock = clock_new(x, (t_method) shell_check); | ||
301 | return (x); | ||
302 | } | ||
303 | |||
304 | void shell_setup(void) | ||
305 | { | ||
306 | shell_class = class_new(gensym("shell"), (t_newmethod)shell_new, | ||
307 | (t_method)shell_free,sizeof(t_shell), 0,0); | ||
308 | class_addbang(shell_class,shell_bang); | ||
309 | class_addanything(shell_class, shell_anything); | ||
310 | } | ||
311 | |||
312 | |||
313 | /* (C) Guenter Geiger <geiger@epy.co.at> */ | ||
314 | |||
315 | #include "m_pd.h" | ||
316 | #ifdef NT | ||
317 | #pragma warning( disable : 4244 ) | ||
318 | #pragma warning( disable : 4305 ) | ||
319 | #endif | ||
320 | |||
321 | #include <unistd.h> | ||
322 | #include <stdlib.h> | ||
323 | #include <string.h> | ||
324 | #include <stdio.h> | ||
325 | #include <sys/types.h> | ||
326 | #include <sys/wait.h> | ||
327 | #include <signal.h> | ||
328 | #include <sched.h> | ||
329 | |||
330 | void sys_rmpollfn(int fd); | ||
331 | void sys_addpollfn(int fd, void* fn, void *ptr); | ||
332 | |||
333 | /* ------------------------ shell ----------------------------- */ | ||
334 | |||
335 | #define INBUFSIZE 1024 | ||
336 | |||
337 | static t_class *shell_class; | ||
338 | |||
339 | |||
340 | static void drop_priority(void) | ||
341 | { | ||
342 | #ifdef _POSIX_PRIORITY_SCHEDULING | ||
343 | struct sched_param par; | ||
344 | int p1 ,p2, p3; | ||
345 | par.sched_priority = 0; | ||
346 | sched_setscheduler(0,SCHED_OTHER,&par); | ||
347 | #endif | ||
348 | } | ||
349 | |||
350 | |||
351 | typedef struct _shell | ||
352 | { | ||
353 | t_object x_obj; | ||
354 | int x_echo; | ||
355 | char *sr_inbuf; | ||
356 | int sr_inhead; | ||
357 | int sr_intail; | ||
358 | void* x_binbuf; | ||
359 | int fdpipe[2]; | ||
360 | int fdinpipe[2]; | ||
361 | int pid; | ||
362 | int x_del; | ||
363 | t_outlet* x_done; | ||
364 | t_clock* x_clock; | ||
365 | } t_shell; | ||
366 | |||
367 | static int shell_pid; | ||
368 | |||
369 | |||
370 | void shell_cleanup(t_shell* x) | ||
371 | { | ||
372 | sys_rmpollfn(x->fdpipe[0]); | ||
373 | |||
374 | if (x->fdpipe[0]>0) close(x->fdpipe[0]); | ||
375 | if (x->fdpipe[1]>0) close(x->fdpipe[1]); | ||
376 | if (x->fdinpipe[0]>0) close(x->fdinpipe[0]); | ||
377 | if (x->fdinpipe[1]>0) close(x->fdinpipe[1]); | ||
378 | |||
379 | x->fdpipe[0] = -1; | ||
380 | x->fdpipe[1] = -1; | ||
381 | x->fdinpipe[0] = -1; | ||
382 | x->fdinpipe[1] = -1; | ||
383 | clock_unset(x->x_clock); | ||
384 | } | ||
385 | |||
386 | void shell_check(t_shell* x) | ||
387 | { | ||
388 | int ret; | ||
389 | int status; | ||
390 | ret = waitpid(x->pid,&status,WNOHANG); | ||
391 | if (ret == x->pid) { | ||
392 | shell_cleanup(x); | ||
393 | if (WIFEXITED(status)) { | ||
394 | outlet_float(x->x_done,WEXITSTATUS(status)); | ||
395 | } | ||
396 | else outlet_float(x->x_done,0); | ||
397 | } | ||
398 | else { | ||
399 | if (x->x_del < 100) x->x_del+=2; /* increment poll times */ | ||
400 | clock_delay(x->x_clock,x->x_del); | ||
401 | } | ||
402 | } | ||
403 | |||
404 | |||
405 | void shell_bang(t_shell *x) | ||
406 | { | ||
407 | post("bang"); | ||
408 | } | ||
409 | |||
410 | /* snippet from pd's code */ | ||
411 | static void shell_doit(void *z, t_binbuf *b) | ||
412 | { | ||
413 | t_shell *x = (t_shell *)z; | ||
414 | int msg, natom = binbuf_getnatom(b); | ||
415 | t_atom *at = binbuf_getvec(b); | ||
416 | |||
417 | for (msg = 0; msg < natom;) | ||
418 | { | ||
419 | int emsg; | ||
420 | for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA | ||
421 | && at[emsg].a_type != A_SEMI; emsg++) | ||
422 | ; | ||
423 | if (emsg > msg) | ||
424 | { | ||
425 | int i; | ||
426 | for (i = msg; i < emsg; i++) | ||
427 | if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM) | ||
428 | { | ||
429 | pd_error(x, "netreceive: got dollar sign in message"); | ||
430 | goto nodice; | ||
431 | } | ||
432 | if (at[msg].a_type == A_FLOAT) | ||
433 | { | ||
434 | if (emsg > msg + 1) | ||
435 | outlet_list(x->x_obj.ob_outlet, 0, emsg-msg, at + msg); | ||
436 | else outlet_float(x->x_obj.ob_outlet, at[msg].a_w.w_float); | ||
437 | } | ||
438 | else if (at[msg].a_type == A_SYMBOL) | ||
439 | outlet_anything(x->x_obj.ob_outlet, at[msg].a_w.w_symbol, | ||
440 | emsg-msg-1, at + msg + 1); | ||
441 | } | ||
442 | nodice: | ||
443 | msg = emsg + 1; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | |||
448 | void shell_read(t_shell *x, int fd) | ||
449 | { | ||
450 | char buf[INBUFSIZE]; | ||
451 | t_binbuf* bbuf = binbuf_new(); | ||
452 | int i; | ||
453 | int readto = | ||
454 | (x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1); | ||
455 | int ret; | ||
456 | |||
457 | ret = read(fd, buf,INBUFSIZE-1); | ||
458 | buf[ret] = '\0'; | ||
459 | |||
460 | for (i=0;i<ret;i++) | ||
461 | if (buf[i] == '\n') buf[i] = ';'; | ||
462 | if (ret < 0) | ||
463 | { | ||
464 | error("shell: pipe read error"); | ||
465 | sys_rmpollfn(fd); | ||
466 | x->fdpipe[0] = -1; | ||
467 | close(fd); | ||
468 | return; | ||
469 | } | ||
470 | else if (ret == 0) | ||
471 | { | ||
472 | post("EOF on socket %d\n", fd); | ||
473 | sys_rmpollfn(fd); | ||
474 | x->fdpipe[0] = -1; | ||
475 | close(fd); | ||
476 | return; | ||
477 | } | ||
478 | else | ||
479 | { | ||
480 | int natom; | ||
481 | t_atom *at; | ||
482 | binbuf_text(bbuf, buf, strlen(buf)); | ||
483 | |||
484 | natom = binbuf_getnatom(bbuf); | ||
485 | at = binbuf_getvec(bbuf); | ||
486 | shell_doit(x,bbuf); | ||
487 | } | ||
488 | binbuf_free(bbuf); | ||
489 | } | ||
490 | |||
491 | |||
492 | static void shell_send(t_shell *x, t_symbol *s,int ac, t_atom *at) | ||
493 | { | ||
494 | int i; | ||
495 | char tmp[MAXPDSTRING]; | ||
496 | int size = 0; | ||
497 | |||
498 | if (x->fdinpipe[0] == -1) return; /* nothing to send to */ | ||
499 | |||
500 | for (i=0;i<ac;i++) { | ||
501 | atom_string(at,tmp+size,MAXPDSTRING - size); | ||
502 | at++; | ||
503 | size=strlen(tmp); | ||
504 | tmp[size++] = ' '; | ||
505 | } | ||
506 | tmp[size-1] = '\0'; | ||
507 | post("sending %s",tmp); | ||
508 | write(x->fdinpipe[0],tmp,strlen(tmp)); | ||
509 | } | ||
510 | |||
511 | static void shell_anything(t_shell *x, t_symbol *s, int ac, t_atom *at) | ||
512 | { | ||
513 | int i; | ||
514 | char* argv[20]; | ||
515 | t_symbol* sym; | ||
516 | |||
517 | if (!strcmp(s->s_name,"send")) { | ||
518 | post("send"); | ||
519 | shell_send(x,s,ac,at); | ||
520 | return; | ||
521 | } | ||
522 | |||
523 | argv[0] = s->s_name; | ||
524 | |||
525 | if (x->fdpipe[0] != -1) { | ||
526 | post("shell: old process still running"); | ||
527 | kill(x->pid,SIGKILL); | ||
528 | shell_cleanup(x); | ||
529 | } | ||
530 | |||
531 | |||
532 | if (pipe(x->fdpipe) < 0) { | ||
533 | error("unable to create pipe"); | ||
534 | return; | ||
535 | } | ||
536 | |||
537 | if (pipe(x->fdinpipe) < 0) { | ||
538 | error("unable to create input pipe"); | ||
539 | return; | ||
540 | } | ||
541 | |||
542 | |||
543 | sys_addpollfn(x->fdpipe[0],shell_read,x); | ||
544 | |||
545 | if (!(x->pid = fork())) { | ||
546 | int status; | ||
547 | char* cmd = getbytes(1024); | ||
548 | char* tcmd = getbytes(1024); | ||
549 | strcpy(cmd,s->s_name); | ||
550 | |||
551 | #if 0 | ||
552 | for (i=1;i<=ac;i++) { | ||
553 | argv[i] = getbytes(255); | ||
554 | atom_string(at,argv[i],255); | ||
555 | /* post("argument %s",argv[i]); */ | ||
556 | at++; | ||
557 | } | ||
558 | argv[i] = 0; | ||
559 | #endif | ||
560 | for (i=1;i<=ac;i++) { | ||
561 | atom_string(at,tcmd,255); | ||
562 | strcat(cmd," "); | ||
563 | strcat(cmd,tcmd); | ||
564 | at++; | ||
565 | } | ||
566 | |||
567 | |||
568 | /* reassign stdout */ | ||
569 | dup2(x->fdpipe[1],1); | ||
570 | dup2(x->fdinpipe[1],0); | ||
571 | |||
572 | /* drop privileges */ | ||
573 | drop_priority(); | ||
574 | seteuid(getuid()); /* lose setuid priveliges */ | ||
575 | |||
576 | post("executing %s",cmd); | ||
577 | system(cmd); | ||
578 | // execvp(s->s_name,argv); | ||
579 | exit(0); | ||
580 | } | ||
581 | x->x_del = 4; | ||
582 | clock_delay(x->x_clock,x->x_del); | ||
583 | |||
584 | if (x->x_echo) | ||
585 | outlet_anything(x->x_obj.ob_outlet, s, ac, at); | ||
586 | } | ||
587 | |||
588 | |||
589 | |||
590 | void shell_free(t_shell* x) | ||
591 | { | ||
592 | binbuf_free(x->x_binbuf); | ||
593 | } | ||
594 | |||
595 | static void *shell_new(void) | ||
596 | { | ||
597 | t_shell *x = (t_shell *)pd_new(shell_class); | ||
598 | |||
599 | x->x_echo = 0; | ||
600 | x->fdpipe[0] = -1; | ||
601 | x->fdpipe[1] = -1; | ||
602 | x->fdinpipe[0] = -1; | ||
603 | x->fdinpipe[1] = -1; | ||
604 | |||
605 | x->sr_inhead = x->sr_intail = 0; | ||
606 | if (!(x->sr_inbuf = (char*) malloc(INBUFSIZE))) bug("t_shell");; | ||
607 | |||
608 | x->x_binbuf = binbuf_new(); | ||
609 | |||
610 | outlet_new(&x->x_obj, &s_list); | ||
611 | x->x_done = outlet_new(&x->x_obj, &s_bang); | ||
612 | x->x_clock = clock_new(x, (t_method) shell_check); | ||
613 | return (x); | ||
614 | } | ||
615 | |||
616 | void shell_setup(void) | ||
617 | { | ||
618 | shell_class = class_new(gensym("shell"), (t_newmethod)shell_new, | ||
619 | (t_method)shell_free,sizeof(t_shell), 0,0); | ||
620 | class_addbang(shell_class,shell_bang); | ||
621 | class_addanything(shell_class, shell_anything); | ||
622 | } | ||
623 | |||
624 | |||