2 * The Regina Rexx Interpreter
3 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Concept of implementation:
22 * In this description, the stack is described as growing upwards
24 * The stack has two pointers to the ends of a double-linked list,
25 * which contains entries consisting of just a pointer to the text (in
26 * a struct streng) in addition to pointers to next and previous
27 * entry. Last box' next, and first box' prev is both NIL. The text
28 * pointer points to the text of that line in the stack.
30 * If the text pointer is NIL, then that box in the stack-structure is
31 * just symbolizing a stack buffer mark. The integer variable
32 * 'buffers' contains the current number of buffermarks in the stack.
33 * A buffer is the lines between two buffermarks. The first buffer mark
34 * (for buffer 0) is not marked, but is implicit the bottom of the
35 * stack. The last buffer is the lines between the uppermost
36 * buffermark and the top of the stack.
38 * Initialy all lines are put in buffer 0. When a new buffer is
39 * created, lines pushed lifo is put on top of that buffer, and lines
40 * queued fifo are put in the bottom of that buffer (i.e. not in the
41 * bottom of buffer 0.) Lines pushed on the stack are 'eaten' and
42 * there must not be any referances to them in other parts of the
43 * program after they have been pushed.
45 * When reading lines from the stack, and all lines in the current
46 * buffer has been read, the buffer-mark will be removed, and lines
47 * are read from the buffer underneath. Lines read from the stack must
48 * be free'ed by the routine that popped them from the stack.
50 * When the whole stack is empty, lines are read from standard input.
52 * Buffer 0 contains the lines between the bottom of the stack, and
53 * the first buffermark on the stack, the first buffer, is the lines
54 * between buffermark 1 and buffer mark 2.
56 * When creating a buffer, the value returned will be the number of
57 * buffermarks in the stack after the new buffermark is created.
58 * When destroying buffers, the parameter given will equal the number
59 * of the lowest buffermark to be destroyed (i.e dropbuf 4) will leave
60 * 3 buffermarks on the stack).
62 * A special variable buf is now part of a stack element. It points to
63 * the last buffer' begin or is NULL for buffer 0.
66 * Overview of internal or temporary queues. Even temporary queues may
67 * contain buffer marks if the content was moved from an internal queue to
69 * The firstbox is equivalent to firstline and lastbox to lastline.
70 * The ends of the double linked list are NULL values. p is short for prev,
71 * n for next. b is short for buf. buf is either NULL or points to the element
72 * which is the next buffer mark.
73 * A buffer mark is a StackLine (SL) with a contents-field of NULL.
75 * -->---------->---------->---------->---------->-+
76 * ^ ^ ^ ^ ^ | NULL NULL
79 * p-SL-n <-> p-SL-n <-> p-SL-n <-> p-SL-n <-> p-SL-n <-> p-SL-n <-> p-SL-n
81 * firstbox Buffer lastbox
84 * READER'S END FIFO'S END
88 * Possible extentions:
89 * o A new 'hard-buffer', that is not removed when a line is popped
90 * from it while it is empty
102 #ifdef HAVE_PROCESS_H
103 # include <process.h>
106 #include "extstack.h"
108 #define NUMBER_QUEUES 100
110 * Queue 0 is SESSION and cannot be added/deleted
113 #define ENSURE_BUFFER(iq) { \
114 /* Ensures that at least one buffer exists for an internal queue. \
116 if ( (iq)->u.i.top == NULL ) \
118 (iq)->u.i.top = (iq)->u.i.bottom = (Buffer *)MallocTSD( sizeof( Buffer ) ) ; \
119 memset( (iq)->u.i.top, 0, sizeof( Buffer ) ) ; \
120 assert( (iq)->u.i.elements == 0 ) ; \
121 assert( (iq)->u.i.buffers == 0 ) ; \
122 (iq)->u.i.elements = 0 ; \
123 (iq)->u.i.buffers = 1 ; \
127 typedef struct { /* stk_tsd: static variables of this module (thread-safe) */
128 #if !defined(NO_EXTERNAL_QUEUES)
132 * The pointer of the current queue points to one of the elements of queue.
134 Queue
*current_queue
;
135 Queue queue
[ NUMBER_QUEUES
] ;
137 * The current queue's name is buffered for a faster access.
139 streng
*current_queue_name
;
141 * runner is needed to create fresh ids.
144 } stk_tsd_t
; /* thread-specific but only needed by this module. see
148 #if !defined(NO_EXTERNAL_QUEUES)
149 static int get_socket_details_and_connect( tsd_t
*TSD
, Queue
*target
);
150 static int save_parse_queue( tsd_t
*TSD
, streng
*queue
, Queue
*q
,
152 static Queue
*open_external( tsd_t
*TSD
, const streng
*queue
, Queue
*q
,
153 int *rc
, int ignore_name
, streng
**basename
);
156 /* init_stacks initializes the module.
157 * Currently, we set up the thread specific data.
158 * The function returns 1 on success, 0 if memory is short.
160 int init_stacks( tsd_t
*TSD
)
164 if (TSD
->stk_tsd
!= NULL
)
167 if ( ( TSD
->stk_tsd
= MallocTSD( sizeof(stk_tsd_t
) ) ) == NULL
)
169 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
170 memset( st
, 0, sizeof(stk_tsd_t
) ); /* correct for all values */
172 * Create the default internal SESSION queue on demand. purge_stacks()
173 * deletes the queuename very often.
175 st
->queue
[0].type
= QisSESSION
;
176 st
->queue
[0].u
.i
.isReal
= 1 ;
177 st
->current_queue
= &st
->queue
[0] ;
181 /* delete_buffer_content deletes the content of a buffer and resets the
182 * buffer to an empty buffer.
184 static void delete_buffer_content( const tsd_t
*TSD
, stk_tsd_t
*st
, Buffer
*b
)
188 /* prepare the deletion and become reentrant in case of exceptions */
190 b
->top
= b
->bottom
= NULL
;
193 while ( p
!= NULL
) {
196 if ( h
->contents
!= NULL
)
197 Free_stringTSD( h
->contents
) ;
202 /* delete_an_internal_queue deletes the content of an internal queue (including
203 * SESSION) resets the queue to "not used" or "empty" in case of "SESSION".
205 static void delete_an_internal_queue( const tsd_t
*TSD
, stk_tsd_t
*st
, Queue
*q
)
211 if ( type
== QisUnused
)
213 assert( ( type
== QisInternal
) || ( type
== QisSESSION
) ) ;
215 /* prepare the deletion and become reentrant in case of exceptions */
218 memset( q
, 0, sizeof( Queue
) ) ;
219 q
->type
= ( type
== QisSESSION
) ? QisSESSION
: QisUnused
;
221 /* delete the name and all content buffers */
223 Free_stringTSD( n
) ;
224 while ( p
!= NULL
) {
227 delete_buffer_content( TSD
, st
, h
) ;
232 /* delete_a_temp_queue cleans up one of the internal stacks by freeing its
233 * content. The queue is reset to "not used".
235 static void delete_a_temp_queue( const tsd_t
*TSD
, stk_tsd_t
*st
, Queue
*q
)
239 if ( q
->type
== QisUnused
) /* happens very often */
241 assert( q
->type
== QisTemp
) ;
243 /* prepare the deletion and become reentrant in case of exceptions */
245 memset( q
, 0, sizeof( Queue
) ) ;
246 q
->type
= QisUnused
;
248 delete_buffer_content( TSD
, st
, &b
) ;
251 #if !defined(NO_EXTERNAL_QUEUES)
252 /* delete_an_external_queue cleans up one of the external stacks by
253 * disconnecting from the server.
255 static void delete_an_external_queue( const tsd_t
*TSD
, stk_tsd_t
*st
, Queue
*q
)
259 if ( q
->type
== QisUnused
)
261 assert( q
->type
== QisExternal
) ;
263 /* prepare the deletion and become reentrant in case of exceptions */
265 memset( q
, 0, sizeof( Queue
) ) ;
266 q
->type
= QisUnused
;
268 disconnect_from_rxstack( TSD
, &b
) ;
272 /* delete_a_queue cleans up any queue by purging or disconnecting. */
273 static void delete_a_queue( const tsd_t
*TSD
, stk_tsd_t
*st
, Queue
*q
)
278 delete_a_temp_queue( TSD
, st
, q
) ;
283 delete_an_internal_queue( TSD
, st
, q
) ;
286 #if !defined(NO_EXTERNAL_QUEUES)
288 delete_an_external_queue( TSD
, st
, q
) ;
293 assert( q
->type
== QisUnused
) ;
298 * This routine clears all the internal queues we have made
299 * and if we have a connection to rxstack, disconnects from it
301 void purge_stacks( const tsd_t
*TSD
)
306 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
307 for ( i
= 0; i
< NUMBER_QUEUES
; i
++ )
308 delete_a_queue( TSD
, st
, &st
->queue
[i
] );
309 st
->current_queue
= &st
->queue
[0];
310 if ( st
->current_queue_name
!= NULL
)
311 Free_stringTSD( st
->current_queue_name
);
312 st
->current_queue_name
= NULL
;
315 static void SetSessionName( const tsd_t
*TSD
, stk_tsd_t
*st
)
317 Queue
*q
= &st
->queue
[0];
319 assert( q
->type
== QisSESSION
) ;
320 if ( q
->u
.i
.name
== NULL
)
322 q
->u
.i
.name
= Str_creTSD( "SESSION" ) ;
324 st
->current_queue_name
= Str_dupTSD( q
->u
.i
.name
);
329 * Find the named internal queue - case insensitive
331 static Queue
*find_queue( const tsd_t
*TSD
, stk_tsd_t
*st
, const streng
*queue_name
)
335 if ( st
->queue
[0].u
.i
.name
== NULL
)
336 SetSessionName( TSD
, st
) ;
337 for ( i
= 0; i
< NUMBER_QUEUES
; i
++ ) /* inefficient !! */
339 if ( ( st
->queue
[i
].type
!= QisInternal
)
340 && ( st
->queue
[i
].type
!= QisSESSION
) )
343 if ( Str_ccmp( st
->queue
[i
].u
.i
.name
, queue_name
) == 0 )
344 return &st
->queue
[i
] ;
349 /* This function creates a new queue.
350 * The returned queue's type must be overwritten.
352 Queue
*find_free_slot( const tsd_t
*TSD
)
355 stk_tsd_t
*st
= (stk_tsd_t
*)TSD
->stk_tsd
;
357 for ( i
= 1; i
< NUMBER_QUEUES
; i
++ ) /* never ever select SESSION */
359 if ( st
->queue
[i
].type
== QisUnused
)
360 return &st
->queue
[i
] ;
362 if ( !TSD
->called_from_saa
)
363 exiterror( ERR_STORAGE_EXHAUSTED
, 0 ); /* message not very helpful */
368 * Glues the content of the temporary stack src to the top buffer of
369 * dst which must not be temporary. is_fifo controls the position of
370 * the glue. is_fifo should reflect the type of insertion in the
372 * src is destroyed at the end of the operation.
374 void flush_stack( const tsd_t
*TSD
, Queue
*src
, Queue
*dst
, int is_fifo
)
376 #if !defined( NO_EXTERNAL_QUEUES )
381 if ( src
== NULL
) /* no temporary stack? may happen */
383 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
385 * I think this is never used. Let's verify it. Florian, 06.01.2005
387 fprintf( stderr
, "Regina internal error detected in %s, line %u.\n"
388 "Please, send an email to M.Hessling@qut.edu.au.\n",
389 __FILE__
, __LINE__
);
391 assert( src
->type
== QisTemp
) ;
392 assert( dst
->type
== QisSESSION
393 || dst
->type
== QisInternal
394 || dst
->type
== QisExternal
) ;
395 if ( src
->u
.t
.top
== NULL
)
397 /* nothing in temporary stack to flush */
398 assert( src
->u
.t
.bottom
== NULL
) ;
402 #if !defined(NO_EXTERNAL_QUEUES)
403 if ( dst
->type
== QisExternal
)
405 for ( ptr
= src
->u
.t
.top
; ptr
!= NULL
; )
409 queue_line_fifo_to_rxstack( TSD
, dst
->u
.e
.socket
, ptr
->contents
) ;
413 queue_line_lifo_to_rxstack( TSD
, dst
->u
.e
.socket
, ptr
->contents
) ;
418 Free_stringTSD( h
->contents
) ;
421 src
->u
.t
.top
= src
->u
.t
.bottom
= NULL
; /* allow safe cleanup */
422 delete_a_temp_queue( TSD
, st
, src
) ;
427 /* dst->type is QisSESSION or QisInternal, stack it either fifo or lifo */
428 ENSURE_BUFFER( dst
) ;
430 dst
->u
.i
.elements
+= src
->u
.t
.elements
;
433 GLUE_BUFFER2( &src
->u
.t
, dst
->u
.i
.top
); /* begin of newest buffer */
437 GLUE_BUFFER1( dst
->u
.i
.top
, &src
->u
.t
);
439 delete_a_temp_queue( TSD
, st
, src
) ;
443 * stack_to_line converts the content of the temporary stack to one blank
445 * An empty string is returned if nothing is in the queue.
447 streng
*stack_to_line( const tsd_t
*TSD
, Queue
*q
)
455 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
457 if (q
->type
== QisUnused
)
458 return(nullstringptr());
460 assert( q
->type
== QisTemp
) ;
462 if ( q
->u
.t
.top
== NULL
)
464 /* nothing in temporary stack to flush */
465 assert( q
->u
.t
.bottom
== NULL
) ;
466 delete_a_temp_queue( TSD
, st
, q
) ;
467 return(nullstringptr());
470 /* first, count the needed string length. */
471 for ( ptr
= q
->u
.t
.top
; ptr
!= NULL
; ptr
=ptr
->lower
)
473 size
+= Str_len(ptr
->contents
) + 1 ; /* blank is delimiter */
476 retval
= Str_makeTSD( size
) ;
477 dest
= retval
->value
;
479 for ( ptr
= q
->u
.t
.top
; ptr
!= NULL
; )
481 memcpy( dest
, ptr
->contents
->value
, Str_len( ptr
->contents
) ) ;
482 dest
+= Str_len( ptr
->contents
) ;
487 Free_stringTSD( h
->contents
) ;
491 /* strip any blanks at the end of the string. */
492 while ((dest
!= retval
->value
) && (dest
[-1] == ' '))
495 /* finally, terminate the string */
496 *dest
= '\0'; /* DON'T increment dest */
497 Str_len( retval
) = (int)( dest
- retval
->value
) ;
499 /* reset the pointers, to signal that temporary stack is empty */
500 q
->u
.t
.top
= q
->u
.t
.bottom
= NULL
;
501 delete_a_temp_queue( TSD
, st
, q
) ;
506 * The input for a command may be overwritten if both input and output or
507 * input and error are STEM values. A temporary queue is created in this
508 * case to prevent the destruction of an unread value.
509 * fill_input_queue_stem fills up a new queue with a copy of a stems
510 * content. stemname must end with a period and stem0 is the count of lines
512 * OPTIMIZING HINT: The function can be rewritten to access just only the
515 Queue
*fill_input_queue_stem(tsd_t
*TSD
, streng
*stemname
, int stem0
)
517 int i
,stemlen
= Str_len( stemname
) ;
518 streng
*stem
, *newstr
;
520 Queue
*q
= find_free_slot( TSD
) ;
524 stem
= Str_makeTSD(stemlen
+ 1 + 3*sizeof(int));
525 memcpy(stem
->value
, stemname
->value
, stemlen
);
527 for (i
= 1; i
<= stem0
; i
++)
528 { /* Fetch the value: */
529 stem
->len
= stemlen
+ sprintf(stem
->value
+ stemlen
, "%d", i
);
530 newstr
= Str_dupTSD(get_it_anyway_compound(TSD
, stem
));
532 line
= (StackLine
*) MallocTSD( sizeof( StackLine
) ) ;
533 line
->contents
= newstr
;
534 FIFO_LINE( &q
->u
.t
, line
) ;
537 Free_stringTSD(stem
);
542 * The input for a command may be overwritten if both input and output or
543 * input and error are STREAM values. A temporary queue is created in this
544 * case to prevent the destruction of an unread value.
545 * fill_input_queue_stream fills up a new queue with a copy of a streams
546 * content. fileptr must be an opened file stream pointer gotten by
547 * addr_reopen_file() for an input stream.
549 Queue
*fill_input_queue_stream( tsd_t
*TSD
, void *fileptr
)
553 Queue
*q
= find_free_slot( TSD
);
558 { /* Fetch the value: */
559 c
= addr_io_file( TSD
, fileptr
, NULL
);
568 line
= (StackLine
*) MallocTSD( sizeof( StackLine
) );
570 FIFO_LINE( &q
->u
.t
, line
);
577 * use_external checks whether or not an external queue must be processed.
578 * The different reasons why not to do it are checked.
579 * use_external returns either 0, if queue_name is a local queue name or
580 * the current queue is a local queue, or it returns 1 for an external queue
581 * name or if the current queue is external.
583 static int use_external( const tsd_t
*TSD
, const streng
*queue_name
)
585 stk_tsd_t
*st
= (stk_tsd_t
*)TSD
->stk_tsd
;
587 /* A little bit off topic, but purge_stacks() may kill "SESSION" at the
588 * end of RexxStart() and we need a working "SESSION" always. Not deleting
589 * it will produce "errors" with the tracemem feature.
590 * This function is called at top of each relevant function.
592 if ( st
->queue
[0].u
.i
.name
== NULL
)
593 SetSessionName( TSD
, st
);
595 #if defined(NO_EXTERNAL_QUEUES)
597 return 0; /* trivial */
600 if ( !st
->initialized
)
603 * Attention, set the current queue type to default. This may be
604 * either internal or external.
607 init_external_queue( TSD
);
610 if ( get_options_flag( TSD
->currlevel
, EXT_INTERNAL_QUEUES
) )
611 return 0; /* user forces a local queue in every case */
612 if ( ( queue_name
== NULL
) || ( PSTRENGLEN( queue_name
) == 0 ) )
613 return st
->current_queue
->type
== QisExternal
;
615 if ( get_options_flag( TSD
->currlevel
, EXT_QUEUES_301
) == 0 )
618 * A name exists, check it.
620 if ( memchr( queue_name
->value
, '@', Str_len( queue_name
) ) == NULL
)
629 * Returns 1 if we have started using external queues, 0 if we haven't
630 * started using external queues
632 int external_queues_used( const tsd_t
*TSD
)
634 return use_external( TSD
, NULL
) ;
638 * Pushes 'line' onto the REXX stack, lifo, and sets 'lastline' to
639 * point to the new line. The line is put on top of the current
642 * A queue_name is supplied by external reference, only. See IfcAddQueue.
643 * Reuses the current connection if possible.
645 int stack_lifo( tsd_t
*TSD
, streng
*line
, const streng
*queue_name
)
653 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
655 assert( line
!= NULL
) ;
657 if ( !use_external( TSD
, queue_name
) )
661 if ( ( q
= find_queue( TSD
, st
, queue_name
) ) == NULL
)
667 q
= st
->current_queue
;
668 assert( ( q
->type
== QisSESSION
) || ( q
->type
== QisInternal
) ) ;
670 newbox
= (StackLine
*) MallocTSD( sizeof( StackLine
) ) ;
671 newbox
->contents
= line
;
674 LIFO_LINE( b
, newbox
) ;
677 #if !defined(NO_EXTERNAL_QUEUES)
682 if ( ( work
= open_external( TSD
, queue_name
, &q
, &rc
, 0, NULL
) ) == NULL
)
685 if ( ( rc
= queue_line_lifo_to_rxstack( TSD
, work
->u
.e
.socket
, line
) ) == -1 )
687 disconnect_from_rxstack( TSD
, &q
) ;
695 * Puts 'line' on the REXX stack, fifo. This routine is similar to
696 * stack_lifo but the differences are big enough to have a separate
697 * routine. The line is put in the bottom of the current buffer,
698 * that is just above the uppermost buffer mark, or at the bottom
699 * of the stack, if there are no buffer marks.
701 * A queue_name is supplied by external reference, only. See IfcAddQueue.
702 * Reuses the current connection if possible.
704 int stack_fifo( tsd_t
*TSD
, streng
*line
, const streng
*queue_name
)
712 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
714 assert( line
!= NULL
) ;
716 if ( !use_external( TSD
, queue_name
) )
720 if ( ( q
= find_queue( TSD
, st
, queue_name
) ) == NULL
)
726 q
= st
->current_queue
;
727 assert( ( q
->type
== QisSESSION
) || ( q
->type
== QisInternal
) ) ;
729 newbox
= (StackLine
*) MallocTSD( sizeof( StackLine
) ) ;
730 newbox
->contents
= line
;
733 FIFO_LINE( b
, newbox
) ;
736 #if !defined(NO_EXTERNAL_QUEUES)
741 if ( ( work
= open_external( TSD
, queue_name
, &q
, &rc
, 0, NULL
) ) == NULL
)
744 if ( ( rc
= queue_line_fifo_to_rxstack( TSD
, work
->u
.e
.socket
, line
) ) == -1 )
746 disconnect_from_rxstack( TSD
, &q
) ;
754 * Removes one (or several) buffers from the stack. Number must be a
755 * non-negative number giving the number of first buffer from the bottom
756 * which has to be removed. You can pass a number of buffers to destroy
757 * from top of the stack if you supply the negative number of buffers.
759 * Example: Queue has buffers 0, 1, 2, 3, 4 and the number is 3. Then
760 * the buffers 3 and 4 are removed and 2 becomes the current buffer.
761 * If the number is -2 then the top two buffers are destroyed and
762 * 2 becomes the current buffer.
764 * Return values: -2: specified buffer doesn't exist
765 * -1: external queues don't support buffers
766 * others: remaining buffers after success
769 int drop_buffer( const tsd_t
*TSD
, int number
)
775 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
776 curr
= st
->current_queue
;
777 if ( curr
->type
== QisExternal
)
778 exiterror( ERR_EXTERNAL_QUEUE
, 110, "DROPBUF" ) ;
779 assert( ( curr
->type
== QisInternal
) || ( curr
->type
== QisSESSION
) ) ;
781 ENSURE_BUFFER( curr
) ; /* makes things easier */
783 number
= curr
->u
.i
.buffers
+ number
;
785 if ( number
>= (int) curr
->u
.i
.buffers
)
788 for ( b
= curr
->u
.i
.bottom
; ( number
> 0 ) && ( b
!= NULL
); number
-- )
791 assert( b
) ; /* must exist */
792 /* disconnect the buffer sequence marked for deletion */
793 if ( b
== curr
->u
.i
.bottom
)
795 /* preserve en empty buffer */
796 curr
->u
.i
.elements
-= b
->elements
;
797 delete_buffer_content( TSD
, st
, b
) ;
799 curr
->u
.i
.top
= curr
->u
.i
.bottom
;
800 curr
->u
.i
.top
->higher
= NULL
;
804 curr
->u
.i
.top
= b
->lower
;
805 curr
->u
.i
.top
->higher
= NULL
;
808 /* delete each buffer and its content */
809 while ( b
!= NULL
) {
810 curr
->u
.i
.elements
-= b
->elements
;
811 delete_buffer_content( TSD
, st
, b
) ;
816 curr
->u
.i
.buffers
-- ;
819 return curr
->u
.i
.buffers
- 1 ;
824 * Fetches a line from the top of the stack. If the current buffer
825 * does not contain any lines, it is removed and the second current
826 * buffer is search for a line etc. If there isn't any lines in the
827 * stack, a line is read from the standard input.
828 * Reuses the current connection if possible.
830 streng
*popline( tsd_t
*TSD
, const streng
*queue_name
, int *result
, unsigned long waitflag
)
832 streng
*contents
=NULL
;
835 int need_line_from_stdin
=0;
840 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
842 if ( !use_external( TSD
, queue_name
) )
846 if ( ( q
= find_queue( TSD
, st
, queue_name
) ) == NULL
)
850 if ( !TSD
->called_from_saa
)
851 contents
= nullstringptr();
856 q
= st
->current_queue
;
857 assert( ( q
->type
== QisSESSION
) || ( q
->type
== QisInternal
) ) ;
860 while ( ( b
= q
->u
.i
.top
) != NULL
)
862 POP_LINE( b
, line
) ;
869 /* buffer is empty, fetch the next one and drop the empty one
871 q
->u
.i
.top
= b
->lower
;
873 q
->u
.i
.top
->higher
= NULL
; /* fixes bug 1068204 */
879 contents
= line
->contents
;
884 /* q->u.i.top == NULL, too; but bottom's not set */
885 q
->u
.i
.bottom
= NULL
;
886 assert( q
->u
.i
.elements
== 0 ) ;
887 assert( q
->u
.i
.buffers
== 0 ) ;
888 need_line_from_stdin
= 1;
891 #if !defined(NO_EXTERNAL_QUEUES)
896 if ( ( work
= open_external( TSD
, queue_name
, &q
, &rc
, 0, NULL
) ) == NULL
)
903 * waitflag is 0 if called from a Rexx program as [PARSE] PULL, but can be
904 * 1 when called from the Rexx API. We override the waitflag when the current
905 * queue is external and a timeout has been set for the queue
907 if ( work
->u
.e
.timeoutSet
)
909 rc
= get_line_from_rxstack( TSD
, work
->u
.e
.socket
, &contents
, ( waitflag
== 0 ) );
912 case -1: rc
= 100; break;
913 case RXSTACK_ERROR
: rc
= 9; break; /* map generic error to RXQUEUE_NOTREG */
916 disconnect_from_rxstack( TSD
, &q
) ;
917 if ( rc
== RXSTACK_TIMEOUT
)
919 condition_hook( TSD
, SIGNAL_NOTREADY
, 94, 1, -1, NULL
, Str_cre_TSD( TSD
, "Timeout on external queue" ) );
921 if ( ( rc
== RXSTACK_EMPTY
) || ( rc
== RXSTACK_TIMEOUT
) ) /* empty or timeout */
922 need_line_from_stdin
= 1;
926 if ( need_line_from_stdin
)
928 if ( TSD
->called_from_saa
)
930 rc
= 8; /* RXQUEUE_EMPTY */
932 else if ( rc
== RXSTACK_TIMEOUT
)
934 rc
= 8; /* RXQUEUE_EMPTY */
938 int rc2
= HOOK_GO_ON
;
939 if ( TSD
->systeminfo
->hooks
& HOOK_MASK( HOOK_PULL
) )
940 rc2
= hookup_input( TSD
, HOOK_PULL
, &contents
);
942 if ( rc2
== HOOK_GO_ON
)
943 contents
= readkbdline( TSD
);
951 else if ( ( contents
== NULL
) && !TSD
->called_from_saa
)
952 contents
= nullstringptr();
959 * Counts the lines in the stack.
960 * Reuses the current connection if possible.
962 int lines_in_stack( tsd_t
*TSD
, const streng
*queue_name
)
968 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
969 if ( !use_external( TSD
, queue_name
) )
973 if ( ( q
= find_queue( TSD
, st
, queue_name
) ) == NULL
)
979 q
= st
->current_queue
;
980 assert( ( q
->type
== QisSESSION
) || ( q
->type
== QisInternal
) ) ;
982 lines
= q
->u
.i
.elements
;
984 #if !defined(NO_EXTERNAL_QUEUES)
990 if ( ( work
= open_external( TSD
, queue_name
, &q
, &rc
, 0, NULL
) ) == NULL
)
993 lines
= get_number_in_queue_from_rxstack( TSD
, work
->u
.e
.socket
, &rc
);
994 disconnect_from_rxstack( TSD
, &q
) ;
1004 * Marks all chunks of dynamic allocated memory that are allocated
1005 * to the stack subsystem.
1007 static void mark_buffer( const Buffer
*b
)
1011 for ( ptr
= b
->top
; ptr
!= NULL
; ptr
= ptr
->lower
)
1013 markmemory( ptr
, TRC_STACKBOX
) ;
1014 markmemory( ptr
->contents
, TRC_STACKLINE
) ;
1018 void mark_stack( const tsd_t
*TSD
)
1025 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1026 q
= st
->current_queue
;
1027 for ( i
= 0; i
< NUMBER_QUEUES
; i
++ )
1029 switch ( st
->queue
[i
].type
)
1032 assert( st
->queue
[i
].type
) ;
1038 if ( st
->queue
[i
].u
.i
.name
)
1040 markmemory( st
->queue
[i
].u
.i
.name
, TRC_STACKBOX
) ;
1043 for ( b
= st
->queue
[i
].u
.i
.top
; b
!= NULL
; b
= b
->lower
)
1045 markmemory( b
, TRC_STACKBOX
) ;
1051 mark_buffer( &st
->queue
[i
].u
.t
) ;
1055 markmemory( st
->queue
[i
].u
.e
.name
, TRC_STACKBOX
) ;
1064 * Creates a new buffer and returns the number of buffers in the stack
1065 * excluding the zeroth buffer.
1067 int make_buffer( tsd_t
*TSD
)
1073 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1074 q
= st
->current_queue
;
1075 if ( q
->type
== QisExternal
)
1076 exiterror( ERR_EXTERNAL_QUEUE
, 110, "MAKEBUF" ) ;
1077 assert( ( q
->type
== QisSESSION
)
1078 || ( q
->type
== QisInternal
) ) ;
1080 ENSURE_BUFFER( q
) ; /* Possibly create the zeroth buffer */
1082 /* Make a *new* buffer */
1083 b
= (Buffer
*)MallocTSD( sizeof( Buffer
) ) ;
1084 memset( b
, 0, sizeof( Buffer
) ) ;
1086 b
->lower
= q
->u
.i
.top
; /* The zeroth buffer exists */
1087 b
->lower
->higher
= b
;
1091 return q
->u
.i
.buffers
- 1 ;
1096 * Dumps the contents of the stack to standard error. Buffer marks are
1097 * indicated in the printout.
1099 void type_buffer( tsd_t
*TSD
)
1109 if (TSD
->stddump
== NULL
)
1111 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1112 q
= st
->current_queue
;
1113 name
= get_queue( TSD
) ;
1114 fprintf(TSD
->stddump
,"==> Name: %.*s\n", Str_len(name
), name
->value
) ;
1115 fprintf(TSD
->stddump
,"==> Lines: %d\n", lines_in_stack( TSD
, NULL
)) ;
1116 if ( q
->type
== QisExternal
)
1119 assert( ( q
->type
== QisSESSION
) || ( q
->type
== QisInternal
) ) ;
1120 ENSURE_BUFFER( q
) ; /* Possibly create the zeroth buffer */
1121 for ( counter
= q
->u
.i
.buffers
, b
= q
->u
.i
.top
; b
!= NULL
; b
= b
->lower
)
1123 fprintf(TSD
->stddump
,"==> Buffer: %d\n", --counter
) ;
1124 for ( ptr
= b
->top
; ptr
!= NULL
; ptr
= ptr
->lower
)
1126 putc( '"', TSD
->stddump
) ;
1127 stop
= Str_end( ptr
->contents
) ;
1128 for ( cptr
= ptr
->contents
->value
; cptr
< stop
; cptr
++ )
1129 putc( ( rx_isprint( *cptr
) ? ( *cptr
) : '?' ), TSD
->stddump
) ;
1131 putc( '"', TSD
->stddump
) ;
1132 #if defined(DOS) || defined(OS2) || defined(WIN32)
1133 putc( REGINA_CR
, TSD
->stddump
) ;
1135 putc( REGINA_EOL
, TSD
->stddump
) ;
1139 fprintf(TSD
->stddump
,"==> End of Stack\n") ;
1140 fflush(TSD
->stddump
) ;
1143 #if !defined(NO_EXTERNAL_QUEUES)
1145 * The following functions allow interfacing to the external
1146 * queue process; rxstack
1147 * The connection to eq is opened if and only if it isn't opened yet.
1149 static int get_socket_details_and_connect( tsd_t
*TSD
, Queue
*q
)
1153 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1154 assert( q
->type
== QisExternal
) ;
1156 /* Fill in default values. Missing values are rarely used but it may
1159 if ( q
->u
.e
.name
== NULL
)
1160 q
->u
.e
.name
= default_external_name( TSD
) ;
1161 if ( q
->u
.e
.portno
== 0 )
1162 q
->u
.e
.portno
= default_port_number() ;
1163 if ( q
->u
.e
.address
== 0 )
1164 q
->u
.e
.address
= default_external_address() ;
1166 if ( q
->u
.e
.socket
== -1 )
1168 if ( connect_to_rxstack( TSD
, q
) == -1 )
1169 return 100; /* RXQUEUE_NETERROR */
1171 q
->u
.e
.timeoutSet
= 0;
1176 * save_parse_queue wraps parse_queue and exiterrors in case of an error.
1177 * Returns 1 if queue is (probably) different from the current queue, 0 else.
1178 * *q is filled even with a return value of 0.
1179 * A negative return code indicates a RXQUEUE_??? error code which must be
1180 * passed back to the SAA interface immediately.
1181 * Queues are treated as equal if ignore_name is set but host address and port
1182 * numbers are the same.
1184 static int save_parse_queue( tsd_t
*TSD
, streng
*queue
, Queue
*q
,
1187 stk_tsd_t
*st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1191 if ( ( rc
= parse_queue( TSD
, queue
, q
) ) <= 0 )
1194 if ( !ignore_name
&& ( PSTRENGLEN( queue
) != 0 ) )
1196 curr
= st
->current_queue
;
1197 if ( curr
->type
!= QisExternal
)
1199 if ( q
->u
.e
.address
!= curr
->u
.e
.address
)
1201 if ( q
->u
.e
.portno
!= curr
->u
.e
.portno
)
1207 * open_external opens the connection to the external queue will a full
1208 * error checking. NULL is returned on error and *rc describes the
1209 * RXQUEUE_??? error.
1210 * On success the opened queue is returned and *q is set to the old or
1211 * temporary queue. queue is either NULL or describes the new temporary
1213 * Queues are treated as equal if ignore_name is set but host address and port
1214 * numbers are the same. No set_queue_in_rxstack() is called if ignore_name
1216 * *basename is set to the queue's name without the network extension if
1217 * basename != NULL. It must be freed later. *basename may become NULL.
1219 static Queue
*open_external( tsd_t
*TSD
, const streng
*queue
, Queue
*q
,
1220 int *rc
, int ignore_name
, streng
**basename
)
1222 stk_tsd_t
*st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1227 qn
= ( queue
== NULL
) ? NULL
: Str_dupTSD( queue
);
1229 if ( ( h
= save_parse_queue( TSD
, qn
, q
, ignore_name
) ) < 0 )
1232 Free_stringTSD( qn
);
1238 if ( ( h
= get_socket_details_and_connect( TSD
, q
) ) != 0 )
1241 Free_stringTSD( qn
);
1242 disconnect_from_rxstack( TSD
, q
);
1248 if ( ( h
= set_queue_in_rxstack( TSD
, q
->u
.e
.socket
, qn
) ) != 0 )
1251 Free_stringTSD( qn
);
1252 disconnect_from_rxstack( TSD
, q
);
1261 retval
= st
->current_queue
;
1264 if ( basename
!= NULL
)
1266 else if ( qn
!= NULL
)
1267 Free_stringTSD( qn
);
1274 /* SetCurrentQueue set the current queue and makes all the necessary cleanup
1275 * of the "old" current queue.
1276 * new_name is assigned to the current queue's name, the former value is
1279 static streng
*SetCurrentQueue( const tsd_t
*TSD
, stk_tsd_t
*st
, Queue
*q
,
1284 #if !defined( NO_EXTERNAL_QUEUES )
1285 if ( ( st
->current_queue
->type
== QisExternal
)
1286 && ( st
->current_queue
!= q
) )
1287 delete_an_external_queue( TSD
, st
, st
->current_queue
);
1291 st
->current_queue
= q
;
1293 retval
= st
->current_queue_name
;
1294 st
->current_queue_name
= new_name
;
1299 * Create a new queue
1300 * RXQUEUE( 'Create' )
1301 * Reuses the current connection if possible. The newly created current
1302 * queue becomes the current queue.
1304 int create_queue( tsd_t
*TSD
, const streng
*queue_name
, streng
**result
)
1306 streng
*new_queue
= NULL
;
1312 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1313 if ( !use_external( TSD
, queue_name
) )
1315 if ( queue_name
== NULL
)
1318 * Create a unique queue name
1320 sprintf(buf
,"S%d-%ld-%d", (int)getpid(), clock(), st
->runner
++ );
1321 new_queue
= Str_cre_TSD( TSD
, buf
) ;
1325 if ( ( q
= find_queue( TSD
, st
, queue_name
) ) == NULL
)
1328 * No queue of that name, so use it.
1330 new_queue
= Str_dupTSD( queue_name
) ;
1334 if ( q
->type
== QisSESSION
)
1336 if ( !TSD
->called_from_saa
)
1337 exiterror( ERR_EXTERNAL_QUEUE
, ERR_RXSTACK_INTERNAL
, rc
, "Getting queue from stack" );
1342 * If the queue we found is a false queue, we can still
1343 * use the supplied name and the slot
1345 if ( q
->u
.i
.isReal
)
1348 * Create a unique queue name
1350 sprintf(buf
,"S%d-%ld-%d", (int)getpid(), clock(), st
->runner
++ );
1351 new_queue
= Str_cre_TSD( TSD
, buf
) ;
1357 if ( new_queue
!= NULL
) /* new name for a new slot */
1359 q
= find_free_slot( TSD
);
1362 if ( new_queue
!= NULL
)
1363 Free_stringTSD( new_queue
);
1364 return 12; /* RXQUEUE_MEMFAIL */
1366 q
->type
= QisInternal
;
1367 if ( new_queue
== queue_name
) /* need a fresh one */
1368 new_queue
= Str_dupTSD( new_queue
) ;
1369 q
->u
.i
.name
= Str_upper( new_queue
) ;
1371 assert( q
->type
== QisInternal
) ;
1374 * result created here; up to caller to free it
1376 *result
= Str_dupTSD( q
->u
.i
.name
);
1378 #if !defined(NO_EXTERNAL_QUEUES)
1384 if ( ( work
= open_external( TSD
, queue_name
, &q
, &rc
, 1, &base
) ) == NULL
)
1387 if ( ( rc
= create_queue_on_rxstack( TSD
, work
, base
, result
) ) == -1 )
1391 Free_stringTSD( base
);
1392 disconnect_from_rxstack( TSD
, &q
) ;
1400 * RXQUEUE( 'Delete' )
1401 * Reuses the current connection if possible. SESSION becomes the current
1404 int delete_queue( tsd_t
*TSD
, const streng
*queue_name
)
1411 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1412 if ( !use_external( TSD
, queue_name
) )
1414 if ( ( queue_name
== NULL
) || ( PSTRENGLEN( queue_name
) == 0 ) )
1416 if ( ( q
= find_queue( TSD
, st
, queue_name
) ) == NULL
)
1418 if ( q
->type
== QisSESSION
)
1419 return 5 ; /* SESSION can't be deleted */
1420 assert( q
->type
== QisInternal
) ;
1422 * If we found a false queue, return 9
1424 if ( !q
->u
.i
.isReal
)
1427 * Delete the contents of the queue
1428 * and mark it as gone.
1430 delete_an_internal_queue( TSD
, st
, q
);
1431 h
= SetCurrentQueue( TSD
, st
, &st
->queue
[0], Str_creTSD( "SESSION" ) ) ;
1432 Free_stringTSD( h
);
1434 #if !defined(NO_EXTERNAL_QUEUES)
1440 if ( ( work
= open_external( TSD
, queue_name
, &q
, &rc
, 1, &base
) ) == NULL
)
1443 if ( ( base
== NULL
) || ( PSTRENGLEN( base
) == 0 ) )
1446 Free_stringTSD( base
);
1447 if ( TSD
->called_from_saa
)
1449 exiterror( ERR_EXTERNAL_QUEUE
, ERR_RXSTACK_INVALID_QUEUE
, tmpstr_of(TSD
, queue_name
) ) ;
1452 if ( ( rc
= delete_queue_from_rxstack( TSD
, work
->u
.e
.socket
, base
) ) == 0 )
1454 /* This will disconnect the current external queue if needed */
1455 h
= SetCurrentQueue( TSD
, st
, &st
->queue
[0], Str_creTSD( "SESSION" ) );
1456 Free_stringTSD( h
);
1460 Free_stringTSD( base
);
1461 disconnect_from_rxstack( TSD
, &q
) ;
1471 * Set timeout for queue
1472 * RXQUEUE( 'Timeout' )
1473 * Do not reuse the current connection. A different external queue name
1474 * leads to an expensive NOP.
1475 * Timeout only valid for external queues.
1477 int timeout_queue( tsd_t
*TSD
, const streng
*timeout
, const streng
*queue_name
)
1481 if ( !use_external( TSD
, queue_name
) )
1483 exiterror( ERR_EXTERNAL_QUEUE
, 111, "TIMEOUT" ) ;
1485 #if !defined(NO_EXTERNAL_QUEUES)
1491 if ( ( work
= open_external( TSD
, queue_name
, &q
, &rc
, 1, NULL
) ) == NULL
)
1494 * Convert incoming streng to positive (or zero) integer
1496 val
= streng_to_int( TSD
, timeout
, &err
) ;
1497 if ( ( val
< 0 ) || err
)
1499 disconnect_from_rxstack( TSD
, &q
) ;
1500 exiterror( ERR_INCORRECT_CALL
, 930, 999999999, tmpstr_of( TSD
, timeout
) );
1503 * Indicate that this queue has a timeout
1505 work
->u
.e
.timeoutSet
= 1;
1506 rc
= timeout_queue_on_rxstack( TSD
, work
->u
.e
.socket
, val
);
1507 disconnect_from_rxstack( TSD
, &q
) ;
1514 * Return the name of the current queue. The value is silently nul terminated.
1516 * Returns queue name even if it is a false queue
1518 streng
*get_queue( tsd_t
*TSD
)
1525 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1526 if ( st
->queue
[0].u
.i
.name
== NULL
)
1527 SetSessionName( TSD
, st
) ;
1529 assert( st
->current_queue_name
!= NULL
);
1531 l
= Str_len( st
->current_queue_name
);
1532 result
= Str_makeTSD( l
+ 1 );
1533 p
= Str_val( result
);
1534 memcpy( p
, Str_val( st
->current_queue_name
), l
);
1536 Str_len( result
) = l
;
1542 * Return the name and length of the current queue in argument pointers. No
1545 void fill_queue_name( const tsd_t
*TSD
, int *len
, char **name
)
1549 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1550 if ( st
->queue
[0].u
.i
.name
== NULL
)
1551 SetSessionName( TSD
, st
) ;
1553 assert( st
->current_queue_name
!= NULL
);
1555 *len
= Str_len( st
->current_queue_name
);
1556 *name
= Str_val( st
->current_queue_name
);
1560 * Set the current queue
1562 * Object Rexx allows the queue to be set to an unknown queue
1563 * This is stupid; the user should be told its not valid, and
1564 * return an empty string.
1565 * But we validly set the false queue :-(
1566 * Reuses the current connection if possible.
1568 streng
*set_queue( tsd_t
*TSD
, const streng
*queue_name
)
1573 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1574 if ( !use_external( TSD
, queue_name
) )
1576 if ( ( q
= find_queue( TSD
, st
, queue_name
) ) == NULL
)
1579 * We didn't find a real or a false queue, so create
1582 q
= find_free_slot( TSD
);
1583 q
->type
= QisInternal
;
1584 q
->u
.i
.name
= Str_upper( Str_dupTSD( queue_name
) ) ;
1585 q
->u
.i
.isReal
= 0 ; /* false queue */
1587 assert( ( q
->type
== QisSESSION
) || ( q
->type
== QisInternal
) ) ;
1588 return SetCurrentQueue( TSD
, st
, q
, Str_dupTSD( q
->u
.i
.name
) );
1590 #if !defined(NO_EXTERNAL_QUEUES)
1594 streng
*base
, *result
;
1597 if ( ( work
= open_external( TSD
, queue_name
, &q
, &rc
, 1, &base
) ) == NULL
)
1598 exiterror( ERR_EXTERNAL_QUEUE
, ERR_RXSTACK_INTERNAL
, rc
, "Setting queue from stack" );
1600 if ( ( base
== NULL
) || ( PSTRENGLEN( base
) == 0 ) )
1603 Free_stringTSD( base
);
1604 disconnect_from_rxstack( TSD
, &q
) ;
1605 assert( !TSD
->called_from_saa
);
1606 exiterror( ERR_EXTERNAL_QUEUE
, ERR_RXSTACK_INVALID_QUEUE
, tmpstr_of(TSD
, queue_name
) ) ;
1608 if ( ( rc
= set_queue_in_rxstack( TSD
, work
->u
.e
.socket
, base
) ) == 0 )
1610 Free_stringTSD( base
);
1611 if ( ( rc
= get_queue_from_rxstack( TSD
, work
, &result
) ) != 0 )
1613 disconnect_from_rxstack( TSD
, &q
);
1614 assert( !TSD
->called_from_saa
);
1615 exiterror( ERR_EXTERNAL_QUEUE
, ERR_RXSTACK_INTERNAL
, rc
, "Getting queue back from stack" );
1619 work
= find_free_slot( TSD
);
1622 return SetCurrentQueue( TSD
, st
, work
, result
);
1624 Free_stringTSD( base
);
1625 disconnect_from_rxstack( TSD
, &q
) ;
1626 assert( !TSD
->called_from_saa
);
1627 exiterror( ERR_EXTERNAL_QUEUE
, ERR_RXSTACK_INTERNAL
, rc
, "Setting queue from stack" );
1633 Queue
*addr_reopen_queue( tsd_t
*TSD
, const streng
*queuename
, char code
)
1634 /* This is the open routine for the ADDRESS WITH-redirection. queuename is
1635 * the name of the queue. code is either 'r' for "READ",
1636 * 'A' for "WRITE APPEND", 'R' for "WRITE REPLACE".
1637 * The queue named queuename will be (re)opened in all cases.
1638 * In case of REPLACE the queue's content must be purged later by
1640 * A structure for queues is returned and should be used for calls
1642 * The return value *may* be NULL in case of an error. A NOTREADY condition
1643 * may have been raised in this case.
1650 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1652 if ( ( queuename
== NULL
) || ( PSTRENGLEN( queuename
) == 0 ) )
1653 return st
->current_queue
;
1655 if ( !use_external( TSD
, queuename
) )
1657 q
= find_queue( TSD
, st
, queuename
) ;
1658 if ( ( code
== 'r' ) || ( q
!= NULL
) )
1661 q
->u
.i
.isReal
= 1 ; /* not sure if this's right */
1664 /* create a new queue */
1665 q
= find_free_slot( TSD
) ;
1666 q
->type
= QisInternal
;
1667 name
= Str_dupTSD( queuename
) ;
1668 q
->u
.i
.name
= Str_upper( name
) ;
1672 #if !defined( NO_EXTERNAL_QUEUES )
1673 /* always use a fresh connection for external queues. There are too many
1674 * circumstances to keep in mind to check cleanly, whether or not to use
1675 * the current connection or if it exists already. The caller will check
1676 * for same names later.
1678 q
= find_free_slot( TSD
) ;
1680 name
= Str_dupTSD( queuename
) ;
1681 if ( save_parse_queue( TSD
, name
, q
, 1 ) < 0 )
1683 Free_stringTSD( name
);
1686 if ( get_socket_details_and_connect( TSD
, q
) != 0 )
1688 disconnect_from_rxstack( TSD
, q
) ;
1691 set_queue_in_rxstack( TSD
, q
->u
.e
.socket
, name
);
1699 /* returns 1 if the two queue pointers point to the same physical queue,
1702 int addr_same_queue( const tsd_t
*TSD
, const Queue
*q1
, const Queue
*q2
)
1704 int t1
, t2
, retval
= 0 ;
1705 #if !defined( NO_EXTERNAL_QUEUES )
1711 if ( ( t1
= q1
->type
) == QisSESSION
)
1713 if ( ( t2
= q2
->type
) == QisSESSION
)
1717 if (t1
== QisInternal
)
1718 return !Str_cmp( q1
->u
.i
.name
, q2
->u
.i
.name
) ;
1719 assert( q1
->type
== QisExternal
) ;
1720 if ( q1
->u
.e
.address
!= q2
->u
.e
.address
)
1722 if ( q1
->u
.e
.portno
!= q2
->u
.e
.portno
)
1724 /* we have to use the slow name comparison */
1725 #if !defined( NO_EXTERNAL_QUEUES )
1726 if ( get_queue_from_rxstack( TSD
, q1
, &n1
) != 0 )
1728 if ( get_queue_from_rxstack( TSD
, q2
, &n2
) != 0 )
1730 Free_stringTSD( n1
) ;
1733 retval
= !Str_cmp( n1
, n2
) ;
1734 Free_stringTSD( n1
) ;
1735 Free_stringTSD( n2
) ;
1740 /* addr_redir_queue moves the content of the top buffer of an existing queue
1741 * to a new temporary queue.
1743 Queue
*addr_redir_queue( const tsd_t
*TSD
, Queue
*q
)
1747 #if !defined( NO_EXTERNAL_QUEUES )
1752 assert( ( q
->type
== QisSESSION
)
1753 || ( q
->type
== QisInternal
)
1754 || ( q
->type
== QisExternal
) ) ;
1755 retval
= find_free_slot( TSD
) ;
1756 retval
->type
= QisTemp
;
1758 if ( ( q
->type
== QisSESSION
) || ( q
->type
== QisInternal
) )
1761 if ( ( b
= q
->u
.i
.top
) != NULL
)
1766 q
->u
.i
.elements
-= b
->elements
;
1768 retval
->u
.t
.higher
= retval
->u
.t
.lower
= NULL
;
1769 b
->top
= b
->bottom
= NULL
;
1773 #if !defined( NO_EXTERNAL_QUEUES )
1776 /* loop until EOF. We can't use lines_in_stack, since the number may
1777 * change because of multiple accesses by different clients.
1779 while ( get_line_from_rxstack( TSD
, q
->u
.e
.socket
, &contents
, 1 ) == 0 )
1781 ptr
= (StackLine
*) MallocTSD( sizeof( StackLine
) ) ;
1782 ptr
->contents
= contents
;
1783 FIFO_LINE( &retval
->u
.t
, ptr
) ;
1790 /* addr_purge_queue discards the contents of a queue. It is caused by a
1791 * ADDRESS WITH ??? REPLACE ??? or at the end of the use of an input
1794 void addr_purge_queue( const tsd_t
*TSD
, Queue
*q
)
1799 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1800 assert( ( q
->type
== QisSESSION
)
1801 || ( q
->type
== QisInternal
)
1802 || ( q
->type
== QisExternal
) ) ;
1804 if ( ( q
->type
== QisSESSION
) || ( q
->type
== QisInternal
) )
1806 ENSURE_BUFFER( q
) ;
1808 q
->u
.i
.elements
-= b
->elements
;
1809 delete_buffer_content( TSD
, st
, b
) ;
1811 #if !defined( NO_EXTERNAL_QUEUES )
1814 clear_queue_on_rxstack( TSD
, q
->u
.e
.socket
) ;
1819 streng
*addr_io_queue( tsd_t
*TSD
, Queue
*q
, streng
*buffer
, int isFIFO
)
1820 /* This is the working routine for the ADDRESS WITH-redirection. q is
1821 * the return value of addr_reopen_queue. buffer must be NULL for a read
1822 * operation or a filled buffer.
1823 * The return value is NULL in case of a write operation or in case of EOF
1825 * buffer is consumed if given and indicates a push operation instead of a
1826 * pull operation. isFIFO indicates the type of the push operation.
1829 StackLine
*ptr
, *newbox
;
1833 if ( buffer
== NULL
)
1835 /* pull operation */
1840 ENSURE_BUFFER( q
) ;
1841 b
= q
->u
.i
.top
; /* Work on the top buffer only */
1842 POP_LINE( b
, ptr
) ;
1846 retval
= ptr
->contents
;
1852 POP_LINE( b
, ptr
) ;
1855 retval
= ptr
->contents
;
1859 #if !defined( NO_EXTERNAL_QUEUES )
1861 if ( get_line_from_rxstack( TSD
, q
->u
.e
.socket
, &retval
, 1 ) == 0 )
1869 /* default: (probably an unused queue) */
1873 /* buffer's not NULL */
1874 assert( ( Str_max( buffer
) >= Str_len( buffer
) ) ) ;
1876 #if !defined(NO_EXTERNAL_QUEUES)
1877 if ( q
->type
== QisExternal
)
1880 queue_line_fifo_to_rxstack( TSD
, q
->u
.e
.socket
, buffer
) ;
1882 queue_line_lifo_to_rxstack( TSD
, q
->u
.e
.socket
, buffer
) ;
1887 newbox
= (StackLine
*) MallocTSD( sizeof( StackLine
) ) ;
1888 newbox
->contents
= buffer
;
1891 /* push FIFO operation */
1896 ENSURE_BUFFER( q
) ;
1899 FIFO_LINE( b
, newbox
) ;
1905 FIFO_LINE( b
, newbox
) ;
1914 /* finally, we process push LIFO */
1919 ENSURE_BUFFER( q
) ;
1922 LIFO_LINE( b
, newbox
) ;
1928 LIFO_LINE( b
, newbox
) ;
1937 /* addr_close_queue closes a queue opened by addr_reopen_queue.
1938 * Never use another routine to do this.
1939 * It is also capable to purge and close temporary stacks.
1941 void addr_close_queue( const tsd_t
*TSD
, Queue
*q
)
1945 st
= (stk_tsd_t
*)TSD
->stk_tsd
;
1946 if ( q
->type
== QisTemp
)
1948 delete_a_temp_queue( TSD
, st
, q
) ;
1951 #if !defined(NO_EXTERNAL_QUEUES)
1952 if ( ( q
!= st
->current_queue
) && ( q
->type
== QisExternal
) )
1953 delete_an_external_queue( TSD
, st
, q
) ;