bringing SDL 1.2.14 from vendor into the main branch
[AROS-Contrib.git] / regina / extstack.c
blobcd14205efae3539f2740eb6fc8eb9262b13a8053
1 #ifndef lint
2 static char *RCSid = "$Id$";
3 #endif
5 /*
6 * The Regina Rexx Interpreter
7 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "rexx.h"
26 #ifdef EXTERNAL_TO_REGINA
27 # include <assert.h>
28 /* tmpstr_of must be defined before the inclusion of extstack.h since it
29 * redefines tsd_t (grrr) */
30 volatile char *tmpstr_of( tsd_t *TSD, const streng *input )
32 /* even exiterror isn't permitted at this point. */
33 assert(0); /* hint while debugging */
34 return((volatile char *) input->value);
36 #endif
39 #if defined(WIN32)
40 # if defined(_MSC_VER)
41 # if _MSC_VER >= 1100
42 /* Stupid MSC can't compile own headers without warning at least in VC 5.0 */
43 # pragma warning(disable: 4115 4201 4214)
44 # endif
45 # include <windows.h>
46 # if _MSC_VER >= 1100
47 # pragma warning(default: 4115 4201 4214)
48 # endif
49 # else
50 # include <windows.h>
51 # endif
52 # include <io.h>
53 #else
54 # ifdef HAVE_SYS_SOCKET_H
55 # include <sys/socket.h>
56 # endif
57 # ifdef HAVE_NETINET_IN_H
58 # include <netinet/in.h>
59 # endif
60 # ifdef HAVE_SYS_SELECT_H
61 # include <sys/select.h>
62 # endif
63 # ifdef HAVE_NETDB_H
64 # include <netdb.h>
65 # endif
66 # ifdef HAVE_ARPA_INET_H
67 # include <arpa/inet.h>
68 # endif
69 #endif
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <assert.h>
75 #include <ctype.h>
76 #include <stdarg.h>
78 #include "extstack.h"
80 #ifndef NDEBUG
81 # define DEBUGDUMP(x) {x;}
82 #else
83 # define DEBUGDUMP(x) {}
84 #endif
86 void showerror( int err, int suberr, char *tmpl, ...)
88 va_list argptr;
89 if ( suberr )
90 fprintf( stderr, "Error:%d.%d - ", err, suberr );
91 else
92 fprintf( stderr, "Error:%d - ", err );
93 va_start( argptr, tmpl );
94 vfprintf( stderr, tmpl, argptr );
95 va_end( argptr );
96 fprintf( stderr, "\n" );
99 int init_external_queue( const tsd_t *TSD )
101 int rc=0;
102 #ifdef WIN32
103 WORD wsver = (WORD)MAKEWORD(1,1);
104 WSADATA wsaData;
105 if ( WSAStartup( wsver, &wsaData ) != 0 )
107 /* TSD can be NULL when called from rxqueue or rxstack */
108 if ( TSD == NULL || TSD->called_from_saa )
109 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_NO_WINSOCK, ERR_RXSTACK_NO_WINSOCK_TMPL, WSAGetLastError() );
110 else
111 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_NO_WINSOCK, WSAGetLastError() );
112 rc = 1;
114 #else
115 TSD = TSD; /* keep compiler happy */
116 #endif
117 return rc;
120 void term_external_queue( void )
122 #ifdef WIN32
123 WSACleanup();
124 #endif
127 int get_default_port_number( void )
129 int portno;
130 char *port = getenv("RXSTACK");
131 if ( port == NULL )
133 portno = RXSOCKET;
135 else
137 portno = atoi(port);
140 return portno;
143 int get_length_from_header( const tsd_t *TSD, streng *header )
145 int length=0;
146 streng *result=NULL;
148 result = MAKESTRENG( RXSTACK_HEADER_SIZE - 1 );
149 if ( result )
151 result->len = RXSTACK_HEADER_SIZE - 1;
152 memcpy( result->value, header->value+1, RXSTACK_HEADER_SIZE-1 );
153 DEBUGDUMP(printf("Hex value: %s\n", result->value););
154 length = REXX_X2D( result );
155 DROPSTRENG( result );
157 return length;
160 #if !defined(NO_EXTERNAL_QUEUES)
162 int get_default_server_address( void )
164 return inet_addr( "127.0.0.1" );
167 int connect_to_rxstack( tsd_t *TSD, int portno, streng *server_name, int server_address )
169 struct sockaddr_in server;
170 int sock;
172 * Connect to external rxstack process/daemon/service
174 memset( &server, 0, sizeof(server) );
175 server.sin_family = AF_INET;
176 server.sin_addr.s_addr = server_address;
177 server.sin_port = htons((unsigned short) portno);
179 sock = socket( AF_INET, SOCK_STREAM, 0 );
180 if ( sock < 0 )
181 return sock;
182 if ( connect( sock, (struct sockaddr *)&server, sizeof(server) ) < 0 )
184 /* TSD can be NULL when called from rxqueue or rxstack */
185 if ( TSD == NULL || TSD->called_from_saa )
186 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_CANT_CONNECT, ERR_RXSTACK_CANT_CONNECT_TMPL, server_name->value, portno, strerror ( errno ) );
187 else
188 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_CANT_CONNECT, tmpstr_of( (void *) TSD, server_name), portno, strerror ( errno ) );
189 return -1;
191 return sock;
193 #endif
195 #if !defined(NO_EXTERNAL_QUEUES)
196 int disconnect_from_rxstack( const tsd_t *TSD, int sock )
198 int rc;
200 DEBUGDUMP(printf("Diconnecting from socket %d\n", sock ););
201 rc = send_command_to_rxstack( TSD, sock, RXSTACK_EXIT_STR, NULL, 0 );
202 close( sock );
203 return rc;
205 #endif
207 #if !defined(NO_EXTERNAL_QUEUES)
208 int send_command_to_rxstack( const tsd_t *TSD, int sock, char *action, char *str, int len )
210 streng *qlen, *header;
211 int rc=-1;
213 DEBUGDUMP(printf("Sending to %d Action: %s <%s> Len:%d\n", sock, action, (str) ? str : "", len););
214 qlen = REXX_D2X( len );
215 if ( qlen )
217 header = REXX_RIGHT( qlen, RXSTACK_HEADER_SIZE, '0');
218 DROPSTRENG( qlen );
219 if ( header )
221 header->value[0] = action[0];
222 rc = send( sock, PSTRENGVAL(header), PSTRENGLEN(header), 0 );
223 DEBUGDUMP(printf("Send length: %s(%d) rc %d\n", PSTRENGVAL(header),PSTRENGLEN(header),rc););
224 if ( str && rc != -1 )
226 rc = send( sock, str, len, 0 );
227 DEBUGDUMP(printf("Send str length: %d\n", rc););
229 DROPSTRENG( header );
232 return rc;
234 #endif
236 #if !defined(NO_EXTERNAL_QUEUES)
237 streng *read_result_from_rxstack( const tsd_t *TSD, int sock, int result_size )
240 * Creates a streng of length 'result_size' and if non-zero,
241 * reads this many characters from the socket.
242 * The caller MUST DROPSTRENG this streng.
244 streng *result;
245 int rc;
247 result = MAKESTRENG( result_size );
248 if ( result )
250 result->len = result_size;
251 if ( result_size )
253 rc = recv( sock, PSTRENGVAL(result), PSTRENGLEN(result), 0 );
254 DEBUGDUMP(printf("Recv result: %s(%d) length: %d\n", PSTRENGVAL(result),PSTRENGLEN(result), rc););
257 return result;
259 #endif
261 #if !defined(NO_EXTERNAL_QUEUES)
262 int parse_queue( tsd_t *TSD, streng *queue, streng **server_name, int *server_address, int *portno )
265 * Validate the queue name. Format is [queue][@host[:port]]
267 int num_colons=0,num_ats=0,num_dots=0,i,colon_pos=-1,at_pos=-1;
268 char *tmp_server=NULL,*tmp_port=NULL;
269 int len=PSTRENGLEN( queue );
270 struct hostent *host;
271 struct in_addr *ptr;
274 * Find the optional '@' and ':'...
276 for ( i = 0; i < len; i++ )
278 if ( queue->value[i] == '@' )
280 num_ats++;
281 at_pos = i;
282 tmp_server = queue->value+at_pos+1;
283 queue->value[at_pos] = '\0';
285 else if ( queue->value[i] == ':' )
287 num_colons++;
288 colon_pos = i;
289 tmp_port = queue->value+colon_pos+1;
290 queue->value[colon_pos] = '\0';
293 if ( num_colons > 1
294 || num_ats > 1
295 || ( num_colons == 1
296 && num_ats == 1
297 && at_pos > colon_pos ) )
299 /* TSD can be NULL when called from rxqueue or rxstack */
300 if ( TSD == NULL || TSD->called_from_saa )
301 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INVALID_QUEUE, ERR_RXSTACK_INVALID_QUEUE_TMPL, queue->value );
302 else
303 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INVALID_QUEUE, tmpstr_of( (void *) TSD, queue ) );
304 return 1;
307 * Sort out the port number portion...
309 if ( num_colons == 1 )
311 *portno = atoi( tmp_port );
312 queue->len = colon_pos;
314 else
316 *portno = get_default_port_number();
318 DEBUGDUMP(printf("port <%d>\n", *portno ););
320 * Sort out server_name portion...
322 if ( num_ats == 1 )
325 * Get the length of the server portion of the specified queue
326 * If 3 dots, we have an IP address for the server address and queue name
328 len = strlen( tmp_server );
329 for( i = 0, num_dots = 0; i < len; i++ )
331 if ( tmp_server[i] == '.' )
332 num_dots++;
334 if ( num_dots == 0 )
336 host = gethostbyname( tmp_server );
337 if ( host )
339 ptr = (struct in_addr *)host->h_addr;
340 *server_address = ptr->s_addr;
341 *server_name = MAKESTRENG( len+1 );
342 if ( *server_name == NULL )
344 /* TSD can be NULL when called from rxqueue or rxstack */
345 if ( TSD == NULL || TSD->called_from_saa )
346 showerror( ERR_STORAGE_EXHAUSTED, 0, ERR_STORAGE_EXHAUSTED_TMPL );
347 else
348 exiterror( ERR_STORAGE_EXHAUSTED, 0 );
349 return 1;
351 (*server_name)->len = len;
352 memcpy( (*server_name)->value, tmp_server, len );
353 (*server_name)->value[len] = '\0';
355 else
357 /* TSD can be NULL when called from rxqueue or rxstack */
358 if ( TSD == NULL || TSD->called_from_saa )
359 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_NO_IP, ERR_RXSTACK_NO_IP_TMPL, tmp_server );
360 else
361 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_NO_IP, tmp_server );
362 return 1;
365 else if ( num_dots == 3 )
367 *server_address = inet_addr( tmp_server );
368 *server_name = MAKESTRENG( len+1 );
369 if ( *server_name == NULL )
371 /* TSD can be NULL when called from rxqueue or rxstack */
372 if ( TSD == NULL || TSD->called_from_saa )
373 showerror( ERR_STORAGE_EXHAUSTED, 0, ERR_STORAGE_EXHAUSTED_TMPL );
374 else
375 exiterror( ERR_STORAGE_EXHAUSTED, 0 );
376 return 1;
378 (*server_name)->len = len;
379 memcpy( (*server_name)->value, tmp_server, len );
380 (*server_name)->value[len] = '\0';
382 else
384 /* TSD can be NULL when called from rxqueue or rxstack */
385 if ( TSD == NULL || TSD->called_from_saa )
386 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INVALID_SERVER, ERR_RXSTACK_INVALID_SERVER_TMPL, tmp_server );
387 else
388 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INVALID_SERVER, tmp_server );
389 return 1;
391 queue->len = at_pos;
393 else
395 *server_address = inet_addr("127.0.0.1");
396 *server_name = MAKESTRENG( 10 );
397 if ( *server_name == NULL )
399 /* TSD can be NULL when called from rxqueue or rxstack */
400 if ( TSD == NULL || TSD->called_from_saa )
401 showerror( ERR_STORAGE_EXHAUSTED, 0, ERR_STORAGE_EXHAUSTED_TMPL );
402 else
403 exiterror( ERR_STORAGE_EXHAUSTED, 0 );
404 return 1;
406 (*server_name)->len = 10;
407 memcpy( (*server_name)->value, "127.0.0.1", 9 );
408 (*server_name)->value[9] = '\0';
410 DEBUGDUMP(printf("server <%s>\n", (*server_name)->value ););
411 return 0;
413 #endif
415 int delete_queue_from_rxstack( const tsd_t *TSD, int sock, streng *queue_name )
417 int rc;
418 streng *result;
420 rc = send_command_to_rxstack( TSD, sock, RXSTACK_DELETE_QUEUE_STR, PSTRENGVAL( queue_name ), PSTRENGLEN( queue_name ) );
421 if ( rc != -1 )
423 result = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
424 if ( result )
426 rc = result->value[0]-'0';
427 DROPSTRENG( result );
430 return rc;
433 int timeout_queue_on_rxstack( const tsd_t *TSD, int sock, long timeout )
435 int rc=0;
436 streng *result,*qtimeout, *hex_timeout;
438 qtimeout = REXX_D2X( timeout );
439 if ( qtimeout )
441 hex_timeout = REXX_RIGHT( qtimeout, RXSTACK_TIMEOUT_SIZE, '0');
442 DROPSTRENG( qtimeout );
443 if ( hex_timeout )
445 DEBUGDUMP(printf("Send timeout: %s(%d) rc %d\n", PSTRENGVAL(hex_timeout),PSTRENGLEN(hex_timeout),rc););
446 rc = send_command_to_rxstack( TSD, sock, RXSTACK_TIMEOUT_QUEUE_STR, PSTRENGVAL(hex_timeout), PSTRENGLEN(hex_timeout) );
447 DROPSTRENG( hex_timeout );
448 if ( rc != -1 )
450 result = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
451 if ( result )
453 rc = result->value[0]-'0';
454 DROPSTRENG( result );
459 return rc;
462 int get_number_in_queue_from_rxstack( const tsd_t *TSD, int sock )
464 int rc,length=0;
465 streng *header;
467 rc = send_command_to_rxstack( TSD, sock, RXSTACK_NUMBER_IN_QUEUE_STR, NULL, 0 );
468 if ( rc != -1 )
470 header = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
471 if ( header )
473 rc = header->value[0]-'0';
474 if ( rc == 0 )
477 * now get the length from the header
479 DEBUGDUMP(printf("before get_length_from_header: %s\n", header->value););
480 length = get_length_from_header( TSD, header );
482 else
484 /* TSD can be NULL when called from rxqueue or rxstack */
485 if ( TSD == NULL || TSD->called_from_saa )
486 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, ERR_RXSTACK_INTERNAL_TMPL, rc, "Getting number in queue" );
487 else
488 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, rc, "Getting number in queue" );
490 DROPSTRENG( header );
493 return length;
496 int get_queue_from_rxstack( const tsd_t *TSD, int sock, streng **result )
498 int rc,length;
499 streng *header;
501 rc = send_command_to_rxstack( TSD, sock, RXSTACK_GET_QUEUE_STR, NULL, 0 );
502 if ( rc != -1 )
504 header = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
505 if ( header )
507 rc = header->value[0]-'0';
508 if ( rc == 0 )
511 * now get the length from the header and get that many characters...
513 length = get_length_from_header( TSD, header );
514 *result = read_result_from_rxstack( TSD, sock, length );
516 else
518 /* TSD can be NULL when called from rxqueue or rxstack */
519 if ( TSD == NULL || TSD->called_from_saa )
520 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, ERR_RXSTACK_INTERNAL_TMPL, rc, "Getting queue from stack" );
521 else
522 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, rc, "Getting queue from stack" );
524 DROPSTRENG( header );
527 return rc;
530 int get_line_from_rxstack( const tsd_t *TSD, int sock, streng **result )
532 int rc,length;
533 streng *header;
535 rc = send_command_to_rxstack( TSD, sock, RXSTACK_PULL_STR, NULL, 0 );
536 if ( rc != -1 )
538 header = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
539 if ( header )
541 rc = header->value[0]-'0';
542 if ( rc == 0 )
545 * now get the length from the header and get that many characters...
547 length = get_length_from_header( TSD, header );
548 *result = read_result_from_rxstack( TSD, sock, length );
550 else if ( rc == 1 || rc == 4 )
553 * queue is empty - return a NULL
555 *result = NULL;
557 else
559 /* TSD can be NULL when called from rxqueue or rxstack */
560 if ( TSD == NULL || TSD->called_from_saa )
561 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, ERR_RXSTACK_INTERNAL_TMPL, rc, "Getting line from queue" );
562 else
563 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, rc, "Getting line from queue" );
565 DROPSTRENG( header );
568 return rc;
571 int create_queue_on_rxstack( const tsd_t *TSD, int sock, streng *queue, streng **result )
573 int rc,length;
574 streng *header;
576 rc = send_command_to_rxstack( TSD, sock, RXSTACK_CREATE_QUEUE_STR, (queue) ? PSTRENGVAL( queue ) : NULL, (queue) ? PSTRENGLEN( queue ) : 0 );
577 if ( rc != -1 )
579 header = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
580 if ( header )
582 rc = header->value[0]-'0';
583 if ( rc == 0 )
586 * the requested queue name was created, so put the input
587 * value into the result
589 *result = MAKESTRENG( PSTRENGLEN( queue ) );
590 if ( *result == NULL )
592 /* TSD can be NULL when called from rxqueue or rxstack */
593 if ( TSD == NULL || TSD->called_from_saa )
594 showerror( ERR_STORAGE_EXHAUSTED, 0, ERR_STORAGE_EXHAUSTED_TMPL );
595 else
596 exiterror( ERR_STORAGE_EXHAUSTED, 0 );
598 else
600 (*result)->len = PSTRENGLEN( queue );
601 memcpy( (*result)->value, PSTRENGVAL( queue ), PSTRENGLEN( queue ) );
604 else if ( rc == 1 )
607 * now get the length from the header and get that many characters...
609 length = get_length_from_header( TSD, header );
610 *result = read_result_from_rxstack( TSD, sock, length );
612 else
614 /* TSD can be NULL when called from rxqueue or rxstack */
615 if ( TSD == NULL || TSD->called_from_saa )
616 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, ERR_RXSTACK_INTERNAL_TMPL, rc, "Creating queue" );
617 else
618 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, rc, "Creating queue" );
620 DROPSTRENG( header );
623 return rc;
626 int set_queue_in_rxstack( const tsd_t *TSD, int sock, streng *queue_name, streng **result )
628 int rc,length;
629 streng *header;
631 rc = send_command_to_rxstack( TSD, sock, RXSTACK_SET_QUEUE_STR, PSTRENGVAL( queue_name ), PSTRENGLEN( queue_name ) );
632 if ( rc != -1 )
634 header = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
635 if ( header )
637 rc = header->value[0]-'0';
638 if ( rc == 0 )
641 * now get the length from the header and get that many characters...
643 length = get_length_from_header( TSD, header );
644 *result = read_result_from_rxstack( TSD, sock, length );
646 else
648 /* TSD can be NULL when called from rxqueue or rxstack */
649 if ( TSD == NULL || TSD->called_from_saa )
650 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, ERR_RXSTACK_INTERNAL_TMPL, rc, "Setting quueue" );
651 else
652 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, rc, "Setting quueue" );
654 DROPSTRENG( header );
657 return rc;
660 int queue_line_fifo_to_rxstack( const tsd_t *TSD, int sock, streng *line )
662 int rc;
663 streng *header;
665 rc = send_command_to_rxstack( TSD, sock, RXSTACK_QUEUE_FIFO_STR, PSTRENGVAL( line ), PSTRENGLEN( line ) );
666 if ( rc != -1 )
668 header = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
669 if ( header )
671 rc = header->value[0]-'0';
672 if ( rc != 0 )
674 /* TSD can be NULL when called from rxqueue or rxstack */
675 if ( TSD == NULL || TSD->called_from_saa )
676 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, ERR_RXSTACK_INTERNAL_TMPL, rc, "Queueing line" );
677 else
678 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, rc, "Queueing line" );
680 DROPSTRENG( header );
683 return rc;
686 int queue_line_lifo_to_rxstack( const tsd_t *TSD, int sock, streng *line )
688 int rc;
689 streng *header;
691 rc = send_command_to_rxstack( TSD, sock, RXSTACK_QUEUE_LIFO_STR, PSTRENGVAL( line ), PSTRENGLEN( line ) );
692 if ( rc != -1 )
694 header = read_result_from_rxstack( TSD, sock, RXSTACK_HEADER_SIZE );
695 if ( header )
697 rc = header->value[0]-'0';
698 if ( rc != 0 )
700 /* TSD can be NULL when called from rxqueue or rxstack */
701 if ( TSD == NULL || TSD->called_from_saa )
702 showerror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, ERR_RXSTACK_INTERNAL_TMPL, rc, "Queueing line" );
703 else
704 exiterror( ERR_EXTERNAL_QUEUE, ERR_RXSTACK_INTERNAL, rc, "Queueing line" );
706 DROPSTRENG( header );
709 return rc;