stackOverflow.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 2008-2014 Rexx Language Association. All rights reserved. */
4 /* */
5 /* This program and the accompanying materials are made available under */
6 /* the terms of the Common Public License v1.0 which accompanies this */
7 /* distribution. A copy is also available at the following address: */
8 /* http://www.oorexx.org/license.html */
9 /* */
10 /* Redistribution and use in source and binary forms, with or */
11 /* without modification, are permitted provided that the following */
12 /* conditions are met: */
13 /* */
14 /* Redistributions of source code must retain the above copyright */
15 /* notice, this list of conditions and the following disclaimer. */
16 /* Redistributions in binary form must reproduce the above copyright */
17 /* notice, this list of conditions and the following disclaimer in */
18 /* the documentation and/or other materials provided with the distribution. */
19 /* */
20 /* Neither the name of Rexx Language Association nor the names */
21 /* of its contributors may be used to endorse or promote products */
22 /* derived from this software without specific prior written permission. */
23 /* */
24 /* THIS SOFTWARE IS PROVIDED BY THE COPYright HOLDERS AND CONTRIBUTORS */
25 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
26 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
27 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYright */
28 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
29 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
30 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
31 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
32 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
33 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
34 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
35 /* */
36 /*----------------------------------------------------------------------------*/
37 
38 /**
39  * A simple example that creates an instance of the interpreter and uses that
40  * instance to execute a Rexx routine defined in this program.
41  *
42  * Both routines cause an infinite recursion. One version of the routine traps
43  * any error, the other does not. This shows how to handle conditions raised
44  * inside the interpreter execution, i.e., outside of your native code
45  * execution.
46  *
47  * To have the second routine execute, specify any argument on the command line.
48  * For example:
49  *
50  * stackOverflow 1
51  *
52  * With no argument, the first routine is used:
53  *
54  * starckOverflow
55  */
56 
57 #include "oorexxapi.h"
58 #include <stdio.h>
59 #include <string.h>
60 
61 #if defined(_WIN32)
62 #define _CDECL __cdecl
63 #else
64 #define _CDECL
65 #endif
66 
67 #define RECURSIVE_ROUTINE1 \
68  "signal on any name error\n\n" \
69  "say 'Starting infinite recursison'\n" \
70  "line = 'interpret line'\n" \
71  "interpret line\n" \
72  "return 0\n\n" \
73  "error:\n" \
74  "obj = condition('O')\n" \
75  "say 'Trapped error:' obj~code '('obj~errorText')'\n" \
76  "return -9"
77 
78 #define RECURSIVE_ROUTINE2 \
79  "say 'Starting infinite recursison'\n" \
80  "line = 'interpret line'\n" \
81  "interpret line\n" \
82  "return 0\n\n" \
83 
84 /* Prototypes for several simple helper functions that demonstrate usage of some
85  * of the native C++ APIs. The functions themselves are at the bottom of the
86  * file.
87  */
88 bool checkForCondition(RexxThreadContext *c, bool clear);
90 
91 int _CDECL main(int argc, char **argv)
92 {
93  // These are the arguments to RexxCreateInterpreter(). An array of any
94  // number of Rexx options can be passed in, but for this example we do not
95  // need any options. So, we use NULL.
96  RexxInstance *interpreter;
97  RexxThreadContext *threadContext;
98  RexxOption *options = NULL;
99 
100  if ( RexxCreateInterpreter(&interpreter, &threadContext, options) == 0 )
101  {
102  printf("Failed to create interpreter, aborting.\n");
103  exit(1);
104  }
105  printInterpreterVersion(interpreter);
106 
107  // Get the source code to use. We copy it into a buffer just to illustrate
108  // a point. How your program fills the code buffer could be by any means.
109  char buf[512];
110  if ( argc == 1 )
111  {
112  // No argument on the command line use the routine that traps any error.
113  strcpy(buf, RECURSIVE_ROUTINE1);
114  }
115  else
116  {
117  // An argument on the command line, use the routine that does not trap
118  // any error.
119  strcpy(buf, RECURSIVE_ROUTINE2);
120  }
121 
122  // Create a routine object from the source code.
123  RexxRoutineObject obj = threadContext->NewRoutine("stackOverflow", buf, strlen(buf));
124  if ( obj == NULL )
125  {
126  checkForCondition(threadContext, true);
127  printf("Error creating routine object, aborting\n");
128  exit(1);
129  }
130 
131  // Execute the routine.
132  RexxObjectPtr result = threadContext->CallRoutine(obj, NULL);
133 
134  // Check for a condition raised during CallRoutine().
135  checkForCondition(threadContext, true);
136 
137  // Now wait for the interpreter to terminate and we are done.
138  interpreter->Terminate();
139 
140  return 0;
141 }
142 
143 /**
144  * Below are several helper functions that demonstrate how to use some of the
145  * different C++ native APIs.
146  */
147 
148 /**
149  * Given an interpreter instance, prints out the interpreter version and
150  * language version. The documentation in the ooRexx programming guide explains
151  * the byte encoding of the version numbers.
152  */
154 {
155  wholenumber_t ver = interpreter->InterpreterVersion();
156  wholenumber_t lang = interpreter->LanguageLevel();
157  printf("Created interpreter instance version=%ld.%ld.%ld language level=%ld.%02ld\n\n",
158  long((ver & 0xff0000) >> 16), long((ver & 0x00ff00) >> 8), long(ver & 0x0000ff), long((lang & 0xff00) >> 8), long(lang & 0x00ff));
159 }
160 
161 
162 /**
163  * Given a condition object, extracts and returns as a whole number the subcode
164  * of the condition.
165  */
167 {
168  return (condition->code - (condition->rc * 1000));
169 }
170 
171 
172 /**
173  * Outputs the typical condition message. For example:
174  *
175  * 4 *-* say dt~number
176  * Error 97 running C:\work\qTest.rex line 4: Object method not found
177  * Error 97.1: Object "a DateTime" does not understand message "NUMBER"
178  *
179  * @param c The thread context we are operating in.
180  * @param condObj The condition information object. The object returned from
181  * the C++ API GetConditionInfo()
182  * @param condition The RexxCondition struct. The filled in struct from the
183  * C++ API DecodeConditionInfo().
184  *
185  * @assumes There is a condition and that condObj and condition are valid.
186  */
188 {
189  RexxObjectPtr list = c->SendMessage0(condObj, "TRACEBACK");
190  if ( list != NULLOBJECT )
191  {
192  RexxArrayObject a = (RexxArrayObject)c->SendMessage0(list, "ALLITEMS");
193  if ( a != NULLOBJECT )
194  {
195  size_t count = c->ArrayItems(a);
196  for ( size_t i = 1; i <= count; i++ )
197  {
198  RexxObjectPtr o = c->ArrayAt(a, i);
199  if ( o != NULLOBJECT )
200  {
201  printf("%s\n", c->ObjectToStringValue(o));
202  }
203  }
204  }
205  }
206  printf("Error %ld running %s line %ld: %s\n", long(condition->rc), c->CString(condition->program),
207  long(condition->position), c->CString(condition->errortext));
208 
209  printf("Error %ld.%03ld: %s\n", long(condition->rc), long(conditionSubCode(condition)), c->CString(condition->message));
210 }
211 
212 
213 /**
214  * Given a thread context, checks for a raised condition, and prints out the
215  * standard condition message if there is a condition.
216  *
217  * @param c Thread context we are operating in.
218  * @param clear Whether to clear the condition or not.
219  *
220  * @return True if there was a condition, otherwise false.
221  */
223 {
224  if ( c->CheckCondition() )
225  {
226  RexxCondition condition;
227  RexxDirectoryObject condObj = c->GetConditionInfo();
228 
229  if ( condObj != NULLOBJECT )
230  {
231  c->DecodeConditionInfo(condObj, &condition);
232  standardConditionMsg(c, condObj, &condition);
233 
234  if ( clear )
235  {
236  c->ClearCondition();
237  }
238  return true;
239  }
240  }
241  return false;
242 }
RexxReturnCode RexxEntry RexxCreateInterpreter(RexxInstance **instance, RexxThreadContext **context, RexxOption *options)
struct _RexxArrayObject * RexxArrayObject
Definition: rexx.h:130
struct _RexxObjectPtr * RexxObjectPtr
Definition: rexx.h:127
#define NULLOBJECT
Definition: rexx.h:147
ssize_t wholenumber_t
Definition: rexx.h:230
struct _RexxRoutineObject * RexxRoutineObject
Definition: rexx.h:134
struct _RexxDirectoryObject * RexxDirectoryObject
Definition: rexx.h:137
#define _CDECL
#define RECURSIVE_ROUTINE2
wholenumber_t conditionSubCode(RexxCondition *condition)
bool checkForCondition(RexxThreadContext *c, bool clear)
void standardConditionMsg(RexxThreadContext *c, RexxDirectoryObject condObj, RexxCondition *condition)
void printInterpreterVersion(RexxInstance *)
int _CDECL main(int argc, char **argv)
#define RECURSIVE_ROUTINE1
wholenumber_t rc
Definition: oorexxapi.h:425
wholenumber_t code
Definition: oorexxapi.h:424
size_t position
Definition: oorexxapi.h:426
RexxStringObject message
Definition: oorexxapi.h:428
RexxStringObject errortext
Definition: oorexxapi.h:429
RexxStringObject program
Definition: oorexxapi.h:430