unix/rxqueue.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 
39 /*********************************************************************/
40 /* */
41 /* Program Name: RXQUEUE.EXE */
42 /* */
43 /* Description: Program to act as a filter between an input */
44 /* stream and the queueing services provided with */
45 /* with REXX-SAA/PL */
46 /* */
47 /* Usage: RXQUEUE [ [ [/FIFO] [/LIFO] [/CLEAR] ] */
48 /* [queuename] ] */
49 /* */
50 /*********************************************************************/
51 #ifdef HAVE_CONFIG_H
52 # include "config.h"
53 #endif
54 
55 #if defined( HAVE_FEATURES_H )
56 # include <features.h>
57 #endif
58 
59 #if defined( HAVE_NL_TYPES_H )
60 # include <nl_types.h>
61 #endif
62 
63 #include <limits.h>
64 #include <stdio.h> /* needed for screen output */
65 #include <stdlib.h> /* needed for miscellaneous functions */
66 #include <string.h> /* needed for string functions */
67 #include "rexx.h" /* needed for queue functions & codes */
68 #include "RexxMessageNumbers.h"
69 
70 #define RXQUEUE_CLEAR -2 /* used for queue mode CLEAR flag */
71 #define BAD_MESSAGE -6 /* Exit RC for message not found. */
72 
73 #define MSG_BUF_SIZE 256 /* Error message buffer size */
74 #define LINEBUFSIZE 65472 /* Arbitrary but matches current docs */
75 
76 #define REXXMESSAGEFILE "rexx.cat"
77 #ifndef CATD_ERR
78 #define CATD_ERR -1
79 #endif
80 
81 char line[LINEBUFSIZE]; /* buffer for data to add to queue */
82 char work[256]; /* buffer for queue name, if default */
83 int queuemode=-1; /* mode for access to queue */
84 
85 void options_error(int type, const char *queuename ) ;
86 
87  /* function to read stdin */
88 size_t get_line(char *, size_t, size_t *);
89 
90 
91 int main(
92  int argc,
93  char *argv[] )
94 {
95  int i; /* loop counter for arguments */
96  int rc; /* return code from API calls */
97  size_t entries; /* number of entries in queue */
98  const char *quename=NULL; /* initialize queuename to NULL */
99  size_t linelen ; /* input line length */
100  CONSTRXSTRING queuedata; /* data added to the queue */
101  char *t; /* argument pointer */
102 
103 
104 /*********************************************************************/
105 /* Initialize string buffers to empty strings: */
106 /*********************************************************************/
107 
108  memset(line, '\0', sizeof(line)); /* clear buffer 'line' -for data */
109  memset(work, '\0', sizeof(work)); /* clear buffer 'work' -for */
110  /* queuename */
111 
112 
113 /*********************************************************************/
114 /* Interpret options from invocation and set appropriate values: */
115 /*********************************************************************/
116 
117  for (i=1; i<argc; i++)
118  { /* go through the argument list... */
119  t = argv[i]; /* point to next argument */
120  if ((t[0]=='/') || (t[0]=='-'))
121  {/*if options character in */
122  t[0]='/'; /* argument, then make character '/' */
123  if ( !strcasecmp(t,"/FIFO") && /* if FIFO flag and */
124  queuemode==-1) /* no queuemode selected yet, then */
125  {
126  queuemode=RXQUEUE_FIFO;/* set queuemode to FIFO, otherwise */
127  }
128  else if ( !strcasecmp(t,"/LIFO") && /* if LIFO flag and */
129  queuemode==-1) /* no queuemode selected yet, then */
130  {
131  queuemode=RXQUEUE_LIFO;/* set queuemode to LIFO, otherwise */
132  }
133  else if ( !strcasecmp(t,"/CLEAR") && /* if CLEAR flag and */
134  queuemode==-1) /* no queuemode selected yet, then */
135  {
136  queuemode=RXQUEUE_CLEAR;/* set queue for CLEAR, otherwise */
137  }
138  else
139  {
140  options_error( /* there was an error in invokation */
141  0,
142  quename ) ;
143  }
144  }
145  else if (!quename) /* if not option and no queue name */
146  {
147  quename=t; /* yet, then assign name */
148  }
149  else
150  {
151  options_error( /* otherwise illegal parameter */
152  0,
153  quename ) ;
154  }
155  }
156  if (queuemode==-1) /* if no queue mode requested, then */
157  {
158  queuemode=RXQUEUE_FIFO; /* use default value of FIFO */
159  }
160 
161 
162 /*********************************************************************/
163 /* Make sure there is a queue name before API calls: */
164 /*********************************************************************/
165 
166  if (!quename) /* if there is no queue specified: */
167  {
168  /* scan current environment */
169  if (!(quename = getenv("RXQUEUE")) || !quename)
170  {
171  quename = "SESSION"; /* use session if not found */
172  }
173  }
174 
175 /*********************************************************************/
176 /* Call RxQueueQuery() to check for the existence of the queue: */
177 /*********************************************************************/
178 
179  if ((rc=RexxQueryQueue(quename,/* search for existence of 'quename' */
180  &entries)))/* get number of entries in queue*/
181  {
182  options_error( rc, /* generate error if API fails */
183  quename );
184  }
185 
186 /*********************************************************************/
187 /* Get all input data and write each line to the proper queue */
188 /* (not CLEAR): */
189 /*********************************************************************/
190 
191  if (queuemode != RXQUEUE_CLEAR)
192  { /* if not CLEAR operation... */
193  while (!get_line( line, /* while more data passed in: */
194  sizeof( line ),
195  &linelen))
196  { /* express in RXSTRING form */
197  MAKERXSTRING(queuedata, line, linelen);
198  if ((rc=RexxAddQueue( /* write info to the queue */
199  quename, /* queue to write into */
200  &queuedata, /*information to add to queue */
201  queuemode))) /* size of information to add */
202  {
203  /* FIFO || LIFO mode */
204  options_error( rc, /* generate error if API fails*/
205  quename ) ;
206  }
207  }
208  }
209  else
210  {
211  // clearing is easy
212  RexxClearQueue(quename);
213  }
214  exit(0);
215 }
216 
217 
218 /*********************************************************************/
219 /* End Of Main Program */
220 /*********************************************************************/
221 
222 /*********************************************************************/
223 /* Function: Print errors from RXQUEUE.EXE. */
224 /* */
225 /* Description: Retrieve message from message file, print the */
226 /* message and exit. If the message printed */
227 /* successfully, exit with a return code of 0. */
228 /* Otherwise, exit with a return code of */
229 /* BAD_MESSAGE (-6). */
230 /* */
231 /* Inputs: Error code, active queue name. */
232 /* */
233 /* Outputs: Nothing. Called for side effects only. */
234 /* */
235 /* Side effects: Message retrieved from message file. Message */
236 /* written to stdout. Program exits. */
237 /* */
238 /*********************************************************************/
239 
240 void options_error( int type, /* Error type. */
241  const char *quename ) /* Name of offending queue. */
242 {
243  char DataArea[ MSG_BUF_SIZE ]; /* Message buffer. */
244  char achIMessage[2*MSG_BUF_SIZE];/* Message with insertion. */
245  int MsgNumber; /* Message number. */
246 #if defined( HAVE_NL_TYPES_H )
247  nl_catd catd; /* catalog descriptor */
248 #endif
249  int set_num = 1; /* message set 1 from catalog */
250  const char *pszMessage; /* message pointer */
251  char *pInsert = NULL; /* Pointer for insertion char */
252 
253  /*******************************************************************/
254  /* Most error messages come from the REXX message file. Set the */
255  /* initial setting of the file name to point to the REXX message */
256  /* file, and change it if necessary. */
257  /*******************************************************************/
258  ( void ) memset( DataArea,
259  0,
260  sizeof( DataArea ) ) ;
261 
262  /*******************************************************************/
263  /* Set the message file and the message number from the error */
264  /* type. If the message has substitution parameters, set them */
265  /* as well. If the pointer to the substitution parameter is NULL, */
266  /* substitute an empty string for the parameter. */
267  /*******************************************************************/
268  /* assign message numbers to error codes */
269  switch (type)
270  {
271  case 0: /* invocation error */
272  MsgNumber = Error_RXQUE_syntax_msg;
273  break;
274 
275  case RXQUEUE_NOTINIT:
276  MsgNumber = Error_RXQUE_notinit_msg;
277  break;
278 
279  case RXQUEUE_NOEMEM:
280  MsgNumber = Error_RXQUE_nomem_msg;
281  break;
282 
283  case RXQUEUE_SIZE:
284  MsgNumber = Error_RXQUE_size_msg;
285  break;
286 
287  case RXQUEUE_BADQNAME:
288  MsgNumber = Error_RXQUE_name_msg;
289  break;
290 
291  case RXQUEUE_PRIORITY:
292  MsgNumber = Error_RXQUE_access_msg;
293  break;
294 
295  case RXQUEUE_NOTREG:
296  MsgNumber = Error_RXQUE_exist_msg;
297  break;
298 
299  default:
300  MsgNumber = Error_RXQUE_syntax_msg;
301  }
302 
303 
304 #if defined( HAVE_CATOPEN )
305  /* Open the message catalog via environment variable NLSPATH ----------- */
306  if ((catd = catopen(REXXMESSAGEFILE, 0)) == (nl_catd)CATD_ERR)
307  {
308  snprintf(DataArea, sizeof DataArea, "%s/%s", ORX_CATDIR, REXXMESSAGEFILE);
309  if ((catd = catopen(DataArea, 0)) == (nl_catd)CATD_ERR)
310  {
311  printf("\nCannot open REXX message catalog %s. Not in NLSPATH or %s.\n",
312  REXXMESSAGEFILE, ORX_CATDIR);
313  }
314  }
315  /* retrieve message from repository */
316  pszMessage = catgets(catd, set_num, MsgNumber, NULL);
317 
318  if (!pszMessage)
319  {
320  snprintf(DataArea, sizeof DataArea, "%s/%s", ORX_CATDIR, REXXMESSAGEFILE);
321  if ((catd = catopen(DataArea, 0)) == (nl_catd)CATD_ERR)
322  {
323  snprintf(DataArea, sizeof DataArea, "\nCannot open REXX message catalog %s. Not in NLSPATH or %s.\n",
324  REXXMESSAGEFILE, ORX_CATDIR);
325  }
326  else
327  {
328  pszMessage = catgets(catd, set_num, MsgNumber, NULL);
329  if (!pszMessage) /* got a message ? */
330  {
331  strcpy(DataArea,"Error message not found!");
332  }
333  else
334  {
335  strcpy(DataArea, pszMessage);
336  }
337  }
338  }
339  else
340  {
341  /* search %1 and replace it with %s for message insertion */
342  strncpy(DataArea, pszMessage, MSG_BUF_SIZE -1);
343  }
344  catclose(catd); /* close the catalog */
345 #else
346  snprintf(DataArea, sizeof DataArea, "*** Cannot get description for error!");
347 #endif
348  /* now do the parameter substitutions in the message template... */
349  pInsert = strstr(DataArea, "%1");
350  if (pInsert)
351  {
352  pInsert++; /* advance to 1 of %1 */
353  *pInsert = 's';
354  snprintf(achIMessage, sizeof achIMessage, DataArea,quename);
355  pszMessage = achIMessage;
356  }
357  else
358  {
359  pszMessage = &DataArea[0];
360  }
361 
362  printf("\nREX%d: %s\n", MsgNumber, pszMessage); /* print the msg */
363 
364  exit(type);
365 }
366 
367 
368 /*********************************************************************/
369 /* Function: Read a line from stdin into a buffer */
370 /* */
371 /* Description: Read a line from stdin using DosRead into */
372 /* the supplied buffer. If the line is longer */
373 /* than the buffer, then it will be truncated */
374 /* and the remainder of the line thrown away. */
375 /* */
376 /* Inputs: Buffer and size of buffer. */
377 /* */
378 /* Outputs: Success/failure flage, */
379 /* plus number of bytes read. */
380 /* */
381 /* Side effects: Logical line read from stdin. */
382 /* */
383 /*********************************************************************/
384 
385 size_t get_line( char *buffer, /* Read buffer */
386  size_t bufsize, /* Buffer size */
387  size_t *linelen) /* length of line */
388 {
389  static char savechar = '\0'; /* cached character */
390  static bool eof = false; /* not hit eof yet */
391  size_t actual; /* actual bytes read */
392  char newchar; /* character read */
393  size_t length; /* length read */
394 
395  if (eof) /* already hit end? */
396  {
397  return true; /* all done */
398  }
399 
400  length = 0; /* nothing read yet */
401  if (savechar)
402  { /* have a saved character */
403  *buffer++ = savechar; /* save this */
404  length++; /* add to count */
405  savechar = '\0'; /* zap for next time */
406  }
407  /* read first character */
408  actual = fread(&newchar, 1, 1, stdin);
409  while (!ferror(stdin))
410  { /* while no error */
411  if (!actual)
412  { /* EOF? */
413  *linelen = length; /* set length */
414  if (!length) /* nothing read? */
415  {
416  return true; /* raise end of file */
417  }
418  else
419  {
420  eof = true; /* quick out next time */
421  return false; /* have real line here */
422  }
423  }
424  if (newchar == '\r')
425  { /* end of line */
426  *linelen = length; /* passback length read */
427  /* read next character */
428  actual = fread(&newchar, 1, 1, stdin);
429  /* newline char? */
430  if (!ferror(stdin) && actual && newchar != '\n')
431  {
432  savechar = newchar; /* save this for next time */
433  }
434  return false; /* should be ok this time */
435  }
436  else if (newchar == '\n')
437  { /* end of line */
438  *linelen = length; /* passback length read */
439  return false; /* should be ok this time */
440  }
441  else if (newchar == 0x1a)
442  { /* EOF character? */
443  *linelen = length; /* give length */
444  eof = true; /* set flag for next time */
445  if (length) /* if something read */
446  {
447  return true; /* this is EOF now */
448  }
449  else
450  {
451  return false; /* no error yet */
452  }
453  }
454  else
455  { /* real character */
456  if (length < bufsize)
457  { /* room for this? */
458  length++; /* remember it */
459  *buffer++ = newchar; /* copy over character */
460  }
461  }
462  /* read next character */
463  actual = fread(&newchar, 1, 1, stdin);
464  }
465  /* had an error */
466  if (length)
467  { /* something read? */
468  *linelen = length; /* return this */
469  eof = true; /* can't read more */
470  return false; /* but no error yet */
471  }
472  else
473  {
474  return true; /* treat this as an EOF */
475  }
476 }
477 
478 
#define Error_RXQUE_syntax_msg
#define Error_RXQUE_notinit_msg
#define Error_RXQUE_name_msg
#define Error_RXQUE_exist_msg
#define Error_RXQUE_nomem_msg
#define Error_RXQUE_size_msg
#define Error_RXQUE_access_msg
int type
Definition: cmdparse.cpp:1888
RexxReturnCode REXXENTRY RexxClearQueue(CONSTANT_STRING)
RexxReturnCode REXXENTRY RexxAddQueue(CONSTANT_STRING, PCONSTRXSTRING, size_t)
#define MAKERXSTRING(r, p, l)
Definition: rexx.h:182
RexxReturnCode REXXENTRY RexxQueryQueue(CONSTANT_STRING, size_t *)
#define RXQUEUE_NOEMEM
Definition: rexxapidefs.h:254
#define RXQUEUE_BADQNAME
Definition: rexxapidefs.h:255
#define RXQUEUE_FIFO
Definition: rexxapidefs.h:239
#define RXQUEUE_PRIORITY
Definition: rexxapidefs.h:256
#define RXQUEUE_LIFO
Definition: rexxapidefs.h:240
#define RXQUEUE_NOTREG
Definition: rexxapidefs.h:259
#define RXQUEUE_SIZE
Definition: rexxapidefs.h:252
#define RXQUEUE_NOTINIT
Definition: rexxapidefs.h:249
int main(int argc, char *argv[])
int queuemode
char work[256]
#define RXQUEUE_CLEAR
size_t get_line(char *, size_t, size_t *)
#define CATD_ERR
char line[LINEBUFSIZE]
#define MSG_BUF_SIZE
#define REXXMESSAGEFILE
void options_error(int type, const char *queuename)
#define LINEBUFSIZE