windows/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.ibm.com/developerworks/oss/CPLv1.0.htm */
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 /* Program Name: RXQUEUE.EXE */
41 /* */
42 /* Description: Program to act as a filter between an input */
43 /* stream and the queueing services provided with */
44 /* with REXX-SAA/PL */
45 /* */
46 /* Usage: RXQUEUE [ [ [/FIFO] [/LIFO] [/CLEAR] ] */
47 /* [queuename] ] */
48 /* */
49 /*********************************************************************/
50 
51 #include <stdio.h> /* needed for screen output */
52 #include <conio.h> /* needed for input */
53 #include <stdlib.h> /* needed for miscellaneous functions */
54 #include <string.h> /* needed for string functions */
55 #include "rexx.h" /* needed for queue functions & codes */
56 /* used for queue name */
57 #include "RexxErrorCodes.h" /* generated file containing message numbers */
58 
59 #define RXQUEUE_CLEAR -2 /* used for queue mode CLEAR flag */
60 #define BAD_MESSAGE -6 /* Exit RC for message not found. */
61 
62 #define ENVBUFSIZE 256
63 #define LINEBUFSIZE 65472 /* Arbitrary but matches current docs */
64 
65 #define DLLNAME "rexx.dll"
66 
67 char line[LINEBUFSIZE]; /* buffer for data to add to queue */
68 char work[256]; /* buffer for queue name, if default */
69 
70 static void options_error( /* function called on errors */
71  int type,
72  const char *queuename ) ;
73 
74 /* function to read stdin */
75 static bool get_line(char *, size_t, size_t *);
76 
77 
78 int __cdecl main(
79  int argc,
80  char *argv[] )
81 {
82  int i; /* loop counter for arguments */
83  RexxReturnCode rc; /* return code from API calls */
84  size_t entries; /* number of entries in queue */
85  const char *quename = NULL; /* initialize queuename to NULL */
86  size_t linelen ; /* input line length */
87  RXSTRING queuedata; /* data added to the queue */
88  char * t; /* argument pointer */
89  int queuemode = -1; /* mode for access to queue */
90 
91 /*********************************************************************/
92 /* Initialize string buffers to empty strings: */
93 /*********************************************************************/
94 
95  memset(line, '\0', sizeof(line)); /* clear buffer 'line' -for data */
96  memset(work, '\0', sizeof(work)); /* clear buffer 'work' -for */
97  /* queuename */
98 
99 /*********************************************************************/
100 /* Interpret options from invocation and set appropriate values: */
101 /*********************************************************************/
102 
103  for (i = 1; i < argc; i++)
104  { /* go through the argument list... */
105  t = argv[i]; /* point to next argument */
106  if ((t[0]=='/') || (t[0]=='-'))
107  {/*if options character in */
108  t[0]='/'; /* argument, then make character '/' */
109  // FIFO flag?
110  if (stricmp(t,"/FIFO") == 0 && queuemode == -1)
111  {
112  queuemode = RXQUEUE_FIFO; // set queuemode to FIFO, otherwise
113  }
114  else if (stricmp(t,"/LIFO") == 0 && queuemode == -1)
115  {
116  queuemode = RXQUEUE_LIFO; // set queuemode to LIFO, otherwise
117  }
118  else if (stricmp(t,"/CLEAR") == 0 && queuemode == -1)
119  {
120  queuemode=RXQUEUE_CLEAR;/* set queue for CLEAR, otherwise */
121  }
122  // unknown or duplicate option
123  else options_error(0, quename) ;
124  }
125  else if (quename == NULL) /* if not option and no queue name */
126  {
127  quename = t; /* yet, then assign name */
128  }
129  else
130  {
131  // illegal parameter of somekind
132  options_error(0, quename);
133  }
134  }
135 
136  if (queuemode==-1) /* if no queue mode requested, then */
137  {
138  queuemode=RXQUEUE_FIFO; /* use default value of FIFO */
139  }
140 
141 
142 /*********************************************************************/
143 /* Make sure there is a queue name before API calls: */
144 /*********************************************************************/
145 
146  if (quename == NULL) /* if there is no queue specified: */
147  {
148  quename = "SESSION"; /* No name -> this is a session queue */
149  }
150 
151 /*********************************************************************/
152 /* Call RxQueueQuery() to check for the existence of the queue: */
153 /*********************************************************************/
154 
155  rc = RexxQueryQueue(quename, &entries);
156  if (rc != RXQUEUE_OK)
157  {
158  options_error(rc, quename);
159  }
160 
161 /*********************************************************************/
162 /* Get all input data and write each line to the proper queue */
163 /* (not CLEAR): */
164 /*********************************************************************/
165 
166  if (queuemode != RXQUEUE_CLEAR)
167  { /* if not CLEAR operation... */
168  // read until we get an EOF
169  while (!get_line(line, sizeof(line), &linelen))
170  {
171  /* express in RXSTRING form */
172  MAKERXSTRING(queuedata, line, linelen);
173  // now write to the named queue
174  rc = RexxAddQueue(quename, (PCONSTRXSTRING)&queuedata, queuemode);
175  if (rc != RXQUEUE_OK)
176  {
177  options_error(rc, quename);
178  }
179  }
180  }
181  else
182  {
183  RexxClearQueue(quename);
184  }
185  return 0;
186 }
187 
188 
189 /*********************************************************************/
190 /* End Of Main Program */
191 /*********************************************************************/
192 
193 /*********************************************************************/
194 /* Function: Print errors from RXQUEUE.EXE. */
195 /* */
196 /* Description: Retrieve message from message file, print the */
197 /* message and exit. If the message printed */
198 /* successfully, exit with a return code of 0. */
199 /* Otherwise, exit with a return code of */
200 /* BAD_MESSAGE (-6). */
201 /* */
202 /* Inputs: Error code, active queue name. */
203 /* */
204 /* Outputs: Nothing. Called for side effects only. */
205 /* */
206 /* Side effects: Message retrieved from message file. Message */
207 /* written to stdout. Program exits. */
208 /* */
209 /*********************************************************************/
210 
211 
212 static void options_error(int type, /* Error type. */
213  const char *quename ) /* Name of offending queue. */
214 {
215  int rc = 0 ; /* Exit return code. */
216  char DataArea[ 256 ] ; /* Message buffer. */
217  char DataArea2[ 256 ] ; /* Message buffer. */
218  int MsgNumber ; /* Message number. */
219  HINSTANCE hDll=NULL;
220 
221  /*******************************************************************/
222  /* Most error messages come from the REXX message file. Set the */
223  /* initial setting of the file name to point to the REXX message */
224  /* file, and change it if necessary. */
225  /*******************************************************************/
226 
227  memset(DataArea, 0, sizeof(DataArea)) ;
228 
229  /*******************************************************************/
230  /* Set the message file and the message number from the error */
231  /* type. If the message has substitution parameters, set them */
232  /* as well. If the pointer to the substitution parameter is NULL, */
233  /* substitute an empty string for the parameter. */
234  /*******************************************************************/
235  /* Begin assign message numbers to error codes */
236  switch (type)
237  {
238  case 0: /* invocation error */
239  MsgNumber = Error_RXQUE_syntax;
240  break;
241 
242  case RXQUEUE_NOTINIT:
243  MsgNumber = Error_RXQUE_notinit;
244  break;
245 
246  case RXQUEUE_SIZE:
247  MsgNumber = Error_RXQUE_size;
248  break;
249 
250  case RXQUEUE_NOEMEM:
251  MsgNumber = Error_RXQUE_nomem;
252  break;
253 
254  case RXQUEUE_BADQNAME:
255  MsgNumber = Error_RXQUE_name;
256  break;
257 
258  case RXQUEUE_PRIORITY:
259  MsgNumber = Error_RXQUE_access;
260  break;
261 
262  case RXQUEUE_NOTREG:
263  MsgNumber = Error_RXQUE_exist;
264  break;
265 
266  default:
267  MsgNumber = Error_RXQUE_syntax;
268  } /* endswitch */
269 
270  hDll = LoadLibrary(DLLNAME);
271 
272  if (hDll)
273  {
274  if (LoadString(hDll, MsgNumber, DataArea, sizeof(DataArea)))
275  {
276  /* check for messages with inserts */
277  if ((MsgNumber == Error_RXQUE_name) || (MsgNumber == Error_RXQUE_exist))
278  {
279  char *pInsert = NULL;
280 
281  /* search %1 and replace it with %s for message insertion */
282  strcpy(DataArea2, DataArea);
283  pInsert = strstr(DataArea2, "%1");
284  if (pInsert)
285  {
286  pInsert++; /* advance to 1 of %1 */
287  *pInsert = 's';
288  sprintf(DataArea, DataArea2, quename);
289  }
290  }
291  }
292  else
293  {
294  strcpy(DataArea,"Error, but no error message available.");
295  }
296  }
297  else
298  {
299  strcpy(DataArea,"Error, but no error message available because REXX.DLL not loaded.");
300  }
301 
302 
303  /******************************************************************/
304  /* Look up the message text. If we can find it, print the */
305  /* message and return 0 when we exit. Otherwise, do not print */
306  /* and return an error code when we exit. */
307  /******************************************************************/
308 
309  printf("REX%d: %s\n", MsgNumber, DataArea);
310  FreeLibrary(hDll);
311 
312  exit(type);
313 }
314 
315 /*********************************************************************/
316 /* Function: Read a line from stdin into a buffer */
317 /* */
318 /* Description: Read a line from stdin using DosRead into */
319 /* the supplied buffer. If the line is longer */
320 /* than the buffer, then it will be truncated */
321 /* and the remainder of the line thrown away. */
322 /* */
323 /* Inputs: Buffer and size of buffer. */
324 /* */
325 /* Outputs: Success/failure flage, */
326 /* plus number of bytes read. */
327 /* */
328 /* Side effects: Logical line read from stdin. */
329 /* */
330 /*********************************************************************/
331 
332 static bool get_line(char *buffer, /* Read buffer */
333  size_t bufsize, /* Buffer size */
334  size_t *linelen) /* length of line */
335 {
336  static char savechar = '\0'; /* cached character */
337  static bool eof = false; /* not hit eof yet */
338  size_t actual; /* actual bytes read */
339  char newchar; /* character read */
340  size_t length; /* length read */
341 
342  if (eof) /* already hit end? */
343  {
344  return true; /* all done */
345  }
346 
347  length = 0; /* nothing read yet */
348  if (savechar) // do we have a saved character?
349  {
350  *buffer++ = savechar; /* save this */
351  length++; /* add to count */
352  savechar = '\0'; /* zap for next time */
353  }
354  /* read first character */
355  actual = fread(&newchar, 1, 1, stdin);
356  while (!ferror(stdin)) // while no read errors
357  {
358  if (actual == 0) // nothing read? must be EOF
359  {
360  *linelen = length; // set length
361  if (length == 0) // nothing read?
362  {
363  return true; // raise end of file
364  }
365  else
366  {
367  eof = true; // quick out next time
368  return false; // have real line here
369  }
370  }
371  if (newchar == '\r') // hit a linend char?
372  {
373  *linelen = length; // passback length read
374  // read next character
375  actual = fread(&newchar, 1, 1, stdin);
376  // second part of the CRLF?
377  if (!ferror(stdin) && actual != 0 && newchar != '\n')
378  {
379  savechar = newchar; // save this for next time
380  }
381  return false; // should be ok this time
382  }
383  else if (newchar == '\n') // new line by itself?
384  {
385  *linelen = length; // passback length read
386  return false; // should be ok this time
387  }
388  else if (newchar == 0x1a) // EOF character?
389  {
390  *linelen = length; // give length
391  eof = true; // set flag for next time
392  if (length != 0) // if something read
393  {
394  return true; // this is EOF now
395  }
396  else
397  {
398  return false; // no error yet
399  }
400  }
401  else
402  { // real character, see if we have room
403  if (length < bufsize)
404  {
405  length++; // remember it
406  *buffer++ = newchar; // copy over character
407  }
408  }
409  // read next character
410  actual = fread(&newchar, 1, 1, stdin);
411  }
412  // had an error
413  if (actual != 0) // something read?
414  {
415  *linelen = actual; // return this
416  eof = true; // can't read more
417  return false; // but no error yet
418  }
419  else
420  {
421  return true; /* treat this as an EOF */
422  }
423 }
#define Error_RXQUE_nomem
#define Error_RXQUE_name
#define Error_RXQUE_access
#define Error_RXQUE_notinit
#define Error_RXQUE_syntax
#define Error_RXQUE_size
#define Error_RXQUE_exist
int type
Definition: cmdparse.cpp:383
RexxReturnCode REXXENTRY RexxClearQueue(CONSTANT_STRING)
RexxReturnCode REXXENTRY RexxAddQueue(CONSTANT_STRING, PCONSTRXSTRING, size_t)
CONSTANT_RXSTRING * PCONSTRXSTRING
Definition: rexx.h:186
#define MAKERXSTRING(r, p, l)
Definition: rexx.h:182
RexxReturnCode REXXENTRY RexxQueryQueue(CONSTANT_STRING, size_t *)
int RexxReturnCode
Definition: rexx.h:73
#define RXQUEUE_NOEMEM
Definition: rexxapidefs.h:254
#define RXQUEUE_OK
Definition: rexxapidefs.h:248
#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 queuemode
char work[256]
int __cdecl main(int argc, char *argv[])
#define RXQUEUE_CLEAR
static bool get_line(char *, size_t, size_t *)
#define DLLNAME
char line[LINEBUFSIZE]
static void options_error(int type, const char *queuename)
#define LINEBUFSIZE