RoutineClass.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 /* REXX Kernel RoutineClass.cpp */
40 /* */
41 /* Primitive Routine Class */
42 /* */
43 /******************************************************************************/
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include "RexxCore.h"
48 #include "StringClass.hpp"
49 #include "ArrayClass.hpp"
50 #include "RexxCode.hpp"
51 #include "RexxNativeCode.hpp"
52 #include "RexxActivity.hpp"
53 #include "RexxActivation.hpp"
54 #include "RexxNativeActivation.hpp"
55 #include "MethodClass.hpp"
56 #include "PackageClass.hpp"
57 #include "SourceFile.hpp"
58 #include "DirectoryClass.hpp"
59 #include "ProtectedObject.hpp"
60 #include "BufferClass.hpp"
61 #include "RexxInternalApis.h"
62 #include "RexxSmartBuffer.hpp"
63 #include "ProgramMetaData.hpp"
64 #include "Utilities.hpp"
65 #include "SystemInterpreter.hpp"
66 #include "PackageManager.hpp"
67 #include "InterpreterInstance.hpp"
68 #include <ctype.h>
69 
70 // singleton class instance
72 
73 
74 /**
75  * Create initial class object at bootstrap time.
76  */
78 {
79  CLASS_CREATE(Routine, "Routine", RexxClass);
80 }
81 
82 
83 /**
84  * Initialize a Routine object from a generated code object. Generally
85  * used for routines generated from ::ROUTINE directives.
86  *
87  * @param name The routine name.
88  * @param codeObj The associated code object.
89  */
91 {
92  OrefSet(this, this->code, codeObj); /* store the code */
93  OrefSet(this, this->executableName, name);
94 }
95 
96 
97 /**
98  * Initialize a RoutineClass object from a file source.
99  *
100  * @param name The routine name (and the resolved name of the file).
101  */
103 {
104  // we need to protect this object until the constructor completes.
105  // the code generation step will create lots of new objects, giving a
106  // pretty high probability that it will be collected.
107  ProtectedObject p(this);
108  OrefSet(this, this->executableName, name);
109  // get a source object to generat this from
110  RexxSource *_source = new RexxSource(name);
111  ProtectedObject p2(_source);
112  // generate our code object and make the file hook up.
113  RexxCode *codeObj = _source->generateCode(false);
114  OrefSet(this, this->code, codeObj);
115 }
116 
117 
118 /**
119  * Initialize a Routine object using a buffered source.
120  *
121  * @param name The name of the routine.
122  * @param source the source buffer.
123  */
125 {
126  // we need to protect this object until the constructor completes.
127  // the code generation step will create lots of new objects, giving a
128  // pretty high probability that it will be collected.
129  ProtectedObject p(this);
130  OrefSet(this, this->executableName, name);
131  // get a source object to generat this from
132  RexxSource *_source = new RexxSource(name, s);
133  ProtectedObject p2(_source);
134  // generate our code object and make the file hook up.
135  RexxCode *codeObj = _source->generateCode(false);
136  OrefSet(this, this->code, codeObj);
137 }
138 
139 
140 /**
141  * Initialize a Routine object using directly provided source.
142  *
143  * @param name The name of the routine.
144  * @param data The source data buffer pointer.
145  * @param length the length of the source buffer.
146  */
147 RoutineClass::RoutineClass(RexxString *name, const char *data, size_t length)
148 {
149  // we need to protect this object until the constructor completes.
150  // the code generation step will create lots of new objects, giving a
151  // pretty high probability that it will be collected.
152  ProtectedObject p(this);
153  OrefSet(this, this->executableName, name);
154  // get a source object to generat this from
155  RexxSource *_source = new RexxSource(name, data, length);
156  ProtectedObject p2(_source);
157  // generate our code object and make the file hook up.
158  RexxCode *codeObj = _source->generateCode(false);
159  OrefSet(this, this->code, codeObj);
160 }
161 
162 
163 /**
164  * Initialize a Routine object using an array source.
165  *
166  * @param name The name of the routine.
167  * @param source the source buffer.
168  */
169 RoutineClass::RoutineClass(RexxString *name, RexxArray *s, size_t startLine, RexxString *programName)
170 {
171  // we need to protect this object until the constructor completes.
172  // the code generation step will create lots of new objects, giving a
173  // pretty high probability that it will be collected.
174  ProtectedObject p(this);
175  OrefSet(this, this->executableName, name);
176  // get a source object to generat this from
177  RexxSource *_source = new RexxSource(programName ? programName : name, s);
178  ProtectedObject p2(_source);
179  if (startLine != 0) _source->adjustLine(startLine, startLine + s->size() - 1);
180  // generate our code object and make the file hook up.
181  RexxCode *codeObj = _source->generateCode(false);
182  OrefSet(this, this->code, codeObj);
183 }
184 
185 
186 void RoutineClass::live(size_t liveMark)
187 /******************************************************************************/
188 /* Function: Normal garbage collection live marking */
189 /******************************************************************************/
190 {
191  memory_mark(this->code);
193  memory_mark(this->objectVariables);
194 }
195 
197 /******************************************************************************/
198 /* Function: Generalized object marking */
199 /******************************************************************************/
200 {
201  memory_mark_general(this->code);
203  memory_mark_general(this->objectVariables);
204 }
205 
207 /******************************************************************************/
208 /* Function: Flatten an object */
209 /******************************************************************************/
210 {
212 
213  flatten_reference(newThis->code, envelope);
214  flatten_reference(newThis->executableName, envelope);
215  flatten_reference(newThis->objectVariables, envelope);
216 
218 }
219 
220 
222  RexxActivity *activity, /* activity running under */
223  RexxString *msgname, /* message to be run */
224  RexxObject**argPtr, /* arguments to the method */
225  size_t argcount, /* the count of arguments */
226  size_t named_argcount,
227  ProtectedObject &result) // the method result
228 /******************************************************************************/
229 /* Function: Call a method as a top level program or external function call */
230 /******************************************************************************/
231 {
232  ProtectedObject p(this); // belt-and-braces to make sure this is protected
233  // just forward this to the code object
234  code->call(activity, this, msgname, argPtr, argcount, named_argcount, result);
235 }
236 
237 
239  RexxActivity *activity, /* activity running under */
240  RexxString *msgname, /* message to be run */
241  RexxObject**argPtr, /* arguments to the method */
242  size_t argcount, /* the count of arguments */
243  size_t named_argcount,
244  RexxString *calltype, /* COMMAND/ROUTINE/FUNCTION */
245  RexxString *environment, /* initial command environment */
246  int context, /* type of context */
247  ProtectedObject &result) // the method result
248 /******************************************************************************/
249 /* Function: Call a method as a top level program or external function call */
250 /******************************************************************************/
251 {
252  ProtectedObject p(this); // belt-and-braces to make sure this is protected
253  // just forward this to the code object
254  code->call(activity, this, msgname, argPtr, argcount, named_argcount, calltype, environment, context, result);
255 }
256 
257 
258 /**
259  * Call a routine object from Rexx-level code.
260  *
261  * @param args The call arguments.
262  * @param count The count of arguments.
263  *
264  * @return The call result (if any).
265  */
266 RexxObject *RoutineClass::callRexx(RexxObject **args, size_t count, size_t named_count)
267 {
268  ProtectedObject result;
269 
270  code->call(ActivityManager::currentActivity, this, executableName, args, count, named_count, result);
271  return (RexxObject *)result;
272 }
273 
274 
275 /**
276  * Call a routine object from Rexx-level code.
277  *
278  * @param args The call arguments.
279  *
280  * @return The call result (if any).
281  */
283  RexxObject **named_arglist, size_t named_argcount)
284 {
285  // this is required and must be an array
286  args = arrayArgument(args, OREF_positional, ARG_ONE);
287  ProtectedObject p(args);
288  size_t count = args->size();
289 
290  // Named arguments
291  // >>-callWith(-array-+--------------------------+-)---><
292  // +-,-namedArguments-:-exprd-+
293 
294  // use strict named arg namedArguments=.NIL
295  NamedArguments expectedNamedArguments(1); // At most, one named argument
296  expectedNamedArguments[0] = NamedArgument("NAMEDARGUMENTS", 1, TheNilObject); // At least 1 characters, default value = .NIL
297  expectedNamedArguments.check(named_arglist, named_argcount, /*strict*/ true, /*extraAllowed*/ false);
298  RexxDirectory *named_args_value = (RexxDirectory*)expectedNamedArguments[0].value;
299 
300  ProtectedObject p_named_args_value;
301  size_t named_count = 0;
302  if (named_args_value != OREF_NULL && named_args_value != TheNilObject)
303  {
304  /* get a directory version */
305  named_args_value = named_args_value->requestDirectory();
306  p_named_args_value = named_args_value; // GC protect
307 
308  /* not a directory item ? */
309  if (named_args_value == TheNilObject)
310  {
311  reportException(Error_Execution_user_defined , "CALLWITH namedArguments must be a directory or NIL");
312  }
313  named_count = named_args_value->items();
314  }
315 
316  RexxArray *new_args = args;
317  ProtectedObject p_new_args;
318  if (named_count != 0)
319  {
320  new_args = (RexxArray *)args->copy();
321  p_new_args = new_args;
322  named_args_value->appendAllIndexesItemsTo(new_args, /*from*/ count+1); // from is 1-based index
323  }
324 
325  ProtectedObject result;
326  code->call(ActivityManager::currentActivity, this, executableName, new_args->data(), count, named_count, result);
327  return (RexxObject *)result;
328 }
329 
330 
331 
333  RexxActivity *activity,
334  RexxString * calltype, /* type of invocation */
335  RexxString * environment, /* initial address */
336  RexxObject **arguments, /* array of arguments */
337  size_t argCount, /* the number of arguments */
338  size_t named_argCount,
339  ProtectedObject &result) // the method result
340 /****************************************************************************/
341 /* Function: Run a method as a program */
342 /****************************************************************************/
343 {
344  ProtectedObject p(this); // belt-and-braces to make sure this is protected
345  code->call(activity, this, executableName, arguments, argCount, named_argCount, calltype, environment, PROGRAMCALL, result);
346 }
347 
348 
350  RexxActivity *activity,
351  RexxObject **arguments, /* array of arguments */
352  size_t argCount, /* the number of arguments */
353  size_t named_argCount,
354  ProtectedObject &result) // the method result
355 /****************************************************************************/
356 /* Function: Run a method as a program */
357 /****************************************************************************/
358 {
359  ProtectedObject p(this); // belt-and-braces to make sure this is protected
360  code->call(activity, this, executableName, arguments, argCount, named_argCount, OREF_COMMAND, activity->getInstance()->getDefaultEnvironment(), PROGRAMCALL, result);
361 }
362 
363 
365  RexxObject *manager) /* supplied security manager */
366 /******************************************************************************/
367 /* Function: Associate a security manager with a method's source */
368 /******************************************************************************/
369 {
370  return code->setSecurityManager(manager);
371 }
372 
373 
375 /******************************************************************************/
376 /* Function: Flatten translated method into a buffer for storage into EA's etc*/
377 /******************************************************************************/
378 {
379  /* Get new envelope object */
380  RexxEnvelope *envelope = new RexxEnvelope;
381  ProtectedObject p(envelope);
382  /* now pack up the envelope for */
383  /* saving. */
384  return envelope->pack(this);
385 }
386 
387 
388 /**
389  * Save a routine into an externalized buffer form in an RXSTRING.
390  *
391  * @param outBuffer The target output RXSTRING.
392  */
394 {
395  ProtectedObject p(this);
396  RexxBuffer *methodBuffer = save(); /* flatten the routine */
397  // create a full buffer of the data, plus the information header.
398  ProgramMetaData *data = new (methodBuffer) ProgramMetaData(methodBuffer);
399  // we just hand this buffer of data right over...that's all, we're done.
400  outBuffer->strptr = (char *)data;
401  outBuffer->strlength = data->getDataSize();
402 }
403 
404 
405 /**
406  * Save a routine to a target file.
407  *
408  * @param filename The name of the file (fully resolved already).
409  */
410 void RoutineClass::save(const char *filename)
411 {
412  FILE *handle = fopen(filename, "wb");/* open the output file */
413  if (handle == NULL) /* get an open error? */
414  {
415  /* got an error here */
417  }
418  ProtectedObject p(this);
419 
420  // save to a flattened buffer
421  RexxBuffer *buffer = save();
422  ProtectedObject p2(buffer);
423 
424  // create an image header
425  ProgramMetaData metaData(size_v(buffer->getDataLength()));
426  {
427  UnsafeBlock releaser;
428 
429  // write out the header information
430  metaData.write(handle, buffer);
431  fclose(handle);
432  }
433 }
434 
435 
436 void *RoutineClass::operator new (size_t size)
437 /******************************************************************************/
438 /* Function: create a new method instance */
439 /******************************************************************************/
440 {
441  /* get a new method object */
442  return new_object(size, T_Routine);
443 }
444 
445 
446 /**
447  * Construct a Routine using different forms of in-memory
448  * source file.
449  *
450  * @param pgmname The name of the program.
451  * @param source The program source. This can be a string or an array of strings.
452  * @param position The argument position used for error reporting.
453  * @param parentSource
454  * A parent source context used to provide additional class and
455  * routine definitions.
456  *
457  * @return A constructed Routine object.
458  */
459 RoutineClass *RoutineClass::newRoutineObject(RexxString *pgmname, RexxObject *source, RexxObject *position, RexxSource *parentSource, bool isBlock)
460 {
461  // request this as an array. If not convertable, then we'll use it as a string
462  RexxArray *newSourceArray = source->requestArray();
463  ProtectedObject p_newSourceArray(newSourceArray);
464  /* couldn't convert? */
465  if (newSourceArray == (RexxArray *)TheNilObject)
466  {
467  /* get the string representation */
468  RexxString *sourceString = source->makeString();
469  ProtectedObject p(sourceString);
470  /* got back .nil? */
471  if (sourceString == (RexxString *)TheNilObject)
472  {
473  /* raise an error */
474  reportException(Error_Incorrect_method_no_method, OREF_positional, position);
475  }
476  /* wrap an array around the value */
477  newSourceArray = new_array(sourceString);
478  }
479  else /* have an array, make sure all */
480  {
481  /* is it single dimensional? */
482  if (newSourceArray->getDimension() != 1)
483  {
484  /* raise an error */
485  reportException(Error_Incorrect_method_noarray, OREF_positional, position);
486  }
487  /* element are strings. */
488  /* Make sure all elements in array */
489  for (size_t counter = 1; counter <= newSourceArray->size(); counter++)
490  {
491  /* Get element as string object */
492  RexxObject *item = newSourceArray ->get(counter);
493  RexxString *sourceString = (item == OREF_NULL) ? OREF_NULLSTRING : item->makeString();
494  /* Did it convert? */
495  if (sourceString == (RexxString *)TheNilObject)
496  {
497  /* and report the error. */
499  }
500  else
501  {
502  /* itsa string add to source array */
503  newSourceArray ->put(sourceString, counter);
504  }
505  }
506  }
507  p_newSourceArray = newSourceArray;
508 
509  // if we've been provided with a scope, use it
510  if (parentSource == OREF_NULL)
511  {
512  // see if we have an active context and use the current source as the basis for the lookup
514  if (currentContext != OREF_NULL)
515  {
516  parentSource = currentContext->getSourceObject();
517  }
518  }
519 
520  // pgnname is the name of the routine (can be "").
521  // Until now, it was also used as programName for the RexxSource created from the source array.
522  // That was not good for the trace, because the name of the routine was also considered as the name of the package (or vice versa): // >I> Routine <routineName> in package <routineName> bad case
523  // >I> Routine <packageName> in package <packageName> I saw that when tracing initialization of packages
524  // >I> Routine in package I see that for RexxBlock which is an anonymous executable
525  // Now, for the package name, I use the programName of the parentSource, if available.
526  RexxString *programName = parentSource ? parentSource->getProgramName() : OREF_NULL;
527 
528  // create the routine
529  RoutineClass *result = new RoutineClass(pgmname, newSourceArray, 0, programName);
530  ProtectedObject p(result);
531  result->getSourceObject()->setIsBlock(isBlock);
532 
533  // if there is a parent source, then merge in the scope information
534  if (parentSource != OREF_NULL)
535  {
536  result->getSourceObject()->inheritSourceContext(parentSource);
537  }
538 
539  return result;
540 }
541 
542 
543 /**
544  * Construct a Routine using different forms of in-memory
545  * source file.
546  *
547  * @param pgmname The name of the program.
548  * @param source The program source. This can be a string or an array of strings.
549  * @param position The argument position used for error reporting.
550  * @param parentSource
551  * A parent source context used to provide additional class and
552  * routine definitions.
553  *
554  * @return A constructed Routine object.
555  */
557 {
558  // request this as an array. If not convertable, then we'll use it as a string
559  RexxArray *newSourceArray = source->requestArray();
560  /* couldn't convert? */
561  if (newSourceArray == (RexxArray *)TheNilObject)
562  {
563  /* raise an error */
565  }
566  else /* have an array, make sure all */
567  {
568  /* is it single dimensional? */
569  if (newSourceArray->getDimension() != 1)
570  {
571  /* raise an error */
572  reportException(Error_Incorrect_method_noarray, OREF_positional, position);
573  }
574  /* element are strings. */
575  /* Make a source array safe. */
576  ProtectedObject p(newSourceArray);
577  /* Make sure all elements in array */
578  for (size_t counter = 1; counter <= newSourceArray->size(); counter++)
579  {
580  /* Get element as string object */
581  RexxString *sourceString = newSourceArray ->get(counter)->makeString();
582  ProtectedObject p(sourceString);
583  /* Did it convert? */
584  if (sourceString == (RexxString *)TheNilObject)
585  {
586  /* and report the error. */
588  }
589  else
590  {
591  /* itsa string add to source array */
592  newSourceArray ->put(sourceString, counter);
593  }
594  }
595  }
596  ProtectedObject p(newSourceArray);
597  // create the routine
598  return new RoutineClass(pgmname, newSourceArray);
599 }
600 
601 
603  RexxObject **init_args, /* subclass init arguments */
604  size_t argCount, /* number of arguments passed */
605  size_t named_argCount)
606 /******************************************************************************/
607 /* Function: Create a new method from REXX code contained in a string or an */
608 /* array */
609 /******************************************************************************/
610 {
611  RexxObject *pgmname; /* method name */
612  RexxObject *_source; /* Array or string object */
613  RexxObject *option = OREF_NULL;
614  size_t initCount = 0; /* count of arguments we pass along */
615 
616  /* break up the arguments */
617 
618  RexxClass::processNewArgs(init_args, argCount, &init_args, &initCount, 2, (RexxObject **)&pgmname, (RexxObject **)&_source);
619  /* get the method name as a string */
620  RexxString *nameString = stringArgument(pgmname, OREF_positional, ARG_ONE);
621  ProtectedObject p_nameString(nameString);
622  requiredArgument(_source, OREF_positional, ARG_TWO); /* make sure we have the second too */
623 
624  RexxSource *sourceContext = OREF_NULL;
625  // retrieve extra parameter if exists
626  if (initCount != 0)
627  {
628  RexxClass::processNewArgs(init_args, initCount, &init_args, &initCount, 1, (RexxObject **)&option, NULL);
629  if (isOfClass(Method, option))
630  {
631  sourceContext = ((RexxMethod *)option)->getSourceObject();
632  }
633  if (isOfClass(Routine, option))
634  {
635  sourceContext = ((RoutineClass *)option)->getSourceObject();
636  }
637  else if (isOfClass(Package, option))
638  {
639  sourceContext = ((PackageClass *)option)->getSourceObject();
640  }
641  else
642  {
643  RexxString *info = new_string("Method, Routine, or Package object");
644  ProtectedObject p(info);
646  }
647  }
648 
649  bool isBlock = false;
650  // retrieve extra parameter if exists
651  if (initCount != 0)
652  {
653  RexxClass::processNewArgs(init_args, initCount, &init_args, &initCount, 1, (RexxObject **)&option, NULL);
654  isBlock = option->truthValue(Error_Logical_value_logical_list);
655  }
656 
657  RoutineClass *newRoutine = newRoutineObject(nameString, _source, IntegerTwo, sourceContext, isBlock);
658  ProtectedObject p(newRoutine);
659  /* Give new object its behaviour */
660  newRoutine->setBehaviour(((RexxClass *)this)->getInstanceBehaviour());
661  if (((RexxClass *)this)->hasUninitDefined())
662  {
663  newRoutine->hasUninit(); /* Make sure everyone is notified. */
664  }
665  /* now send an INIT message */
666  newRoutine->sendMessage(OREF_INIT, init_args, initCount, named_argCount);
667  return newRoutine; /* return the new method */
668 }
669 
670 
672  RexxString *filename) /* name of the target file */
673 /******************************************************************************/
674 /* Function: Create a method from a fully resolved file name */
675 /******************************************************************************/
676 {
677  /* get the method name as a string */
678  filename = stringArgument(filename, OREF_positional, ARG_ONE);
679  /* finish up processing of this */
680  RoutineClass * newMethod = new RoutineClass(filename);
681  ProtectedObject p2(newMethod);
682  /* Give new object its behaviour */
683  newMethod->setBehaviour(((RexxClass *)this)->getInstanceBehaviour());
684  /* does object have an UNINT method */
685  if (((RexxClass *)this)->hasUninitDefined())
686  {
687  newMethod->hasUninit(); /* Make sure everyone is notified. */
688  }
689  /* now send an INIT message */
690  newMethod->sendMessage(OREF_INIT);
691  return newMethod;
692 }
693 
694 
695 /**
696  * Create a routine from a macrospace source.
697  *
698  * @param name The name of the macrospace item.
699  *
700  * @return The inflatted macrospace routine.
701  */
703 {
704  RXSTRING buffer; /* instorage buffer */
705 
706  MAKERXSTRING(buffer, NULL, 0);
707  /* get the image of function */
708  RexxResolveMacroFunction(name->getStringData(), &buffer);
709  /* unflatten the method now */
710  RoutineClass *routine = restore(&buffer, name);
711  // release the buffer memory
713  return routine;
714 }
715 
716 
718 /******************************************************************************/
719 /* Function: Process instorage execution arguments */
720 /******************************************************************************/
721 {
722  // just a generic empty one indicating that we should check the macrospace?
723  if (instore[0].strptr == NULL && instore[1].strptr == NULL)
724  {
725  unsigned short temp;
726 
727  /* see if this exists */
728  if (!RexxQueryMacro(name->getStringData(), &temp))
729  {
730  return restoreFromMacroSpace(name);
731  }
732  return OREF_NULL; // not found
733  }
734  if (instore[1].strptr != NULL) /* have an image */
735  {
736  /* go convert into a method */
737  RoutineClass *routine = restore(&instore[1], name);
738  if (routine != OREF_NULL)
739  { /* did it unflatten successfully? */
740  if (instore[0].strptr != NULL) /* have source also? */
741  {
742  /* get a buffer object */
743  RexxBuffer *source_buffer = new_buffer(instore[0]);
744  /* reconnect this with the source */
745  routine->getSourceObject()->setBufferedSource(source_buffer);
746  }
747  return routine; /* go return it */
748  }
749  }
750  if (instore[0].strptr != NULL) /* have instorage source */
751  {
752  /* get a buffer object */
753  RexxBuffer *source_buffer = new_buffer(instore[0]);
754  if (source_buffer->getData()[0] == '#' && source_buffer->getData()[1] == '!')
755  {
756  memcpy(source_buffer->getData(), "--", 2);
757  }
758 
759  /* translate this source */
760  RoutineClass *routine = new RoutineClass(name, source_buffer);
761  ProtectedObject p(routine);
762  /* return this back in instore[1] */
763  routine->save(&instore[1]);
764  return routine; /* return translated source */
765  }
766  return OREF_NULL; /* processing failed */
767 }
768 
769 /**
770  * Restore a saved routine directly from character data.
771  *
772  * @param data The data pointer.
773  * @param length the data length.
774  *
775  * @return The unflattened routine object.
776  */
777 RoutineClass *RoutineClass::restore(const char *data, size_t length)
778 {
779  // create a buffer object and restore from it
780  RexxBuffer *buffer = new_buffer(data, length);
781  ProtectedObject p(buffer);
782  return restore(buffer, buffer->getData(), length);
783 }
784 
785 
787  RexxBuffer *buffer, /* buffer containing the method */
788  char *startPointer, /* first character of the method */
789  size_t length) // length of data to unflatten
790 /******************************************************************************/
791 /* Function: Unflatten a translated method. Passed a buffer object containing*/
792 /* the method */
793 /******************************************************************************/
794 {
795  /* Get new envelope object */
796  RexxEnvelope *envelope = new RexxEnvelope;
797  ProtectedObject p(envelope);
798  /* now puff up the method object */
799  envelope->puff(buffer, startPointer, length);
800  /* The receiver object is an envelope*/
801  /* whose receiver is the actual */
802  /* method object we're restoring */
803  return (RoutineClass *)envelope->getReceiver();
804 }
805 
806 
807 /**
808  * Restore a program from a simple buffer.
809  *
810  * @param buffer The source buffer.
811  *
812  * @return The inflated Routine object, if valid.
813  */
815 {
816  const char *data = buffer->getData();
817 
818  // does this start with a hash-bang? Need to scan forward to the first
819  // newline character
820  if (data[0] == '#' && data[1] == '!')
821  {
822  data = Utilities::strnchr(data, buffer->getDataLength(), '\n');
823  if (data == OREF_NULL)
824  {
825  return OREF_NULL;
826  }
827  // step over the linend
828  data++;
829  }
830 
831  ProgramMetaData *metaData = (ProgramMetaData *)data;
832  bool badVersion = false;
833  // make sure this is valid for interpreter
834  if (!metaData->validate(badVersion))
835  {
836  // if the failure was due to a version mismatch, this is an error condition.
837  if (badVersion)
838  {
840  }
841  return OREF_NULL;
842  }
843  // this should be valid...try to restore.
844  RoutineClass *routine = restore(buffer, metaData->getImageData(), metaData->getImageSize());
845  routine->getSourceObject()->setProgramName(fileName);
846  return routine;
847 }
848 
849 
850 /**
851  * Restore a routine object from a previously saved instore buffer.
852  *
853  * @param inData The input data (in RXSTRING form).
854  *
855  * @return The unflattened object.
856  */
858 {
859  const char *data = inData->strptr;
860 
861  // does this start with a hash-bang? Need to scan forward to the first
862  // newline character
863  if (data[0] == '#' && data[1] == '!')
864  {
865  data = Utilities::strnchr(data, inData->strlength, '\n');
866  if (data == OREF_NULL)
867  {
868  return OREF_NULL;
869  }
870  // step over the linend
871  data++;
872  }
873 
874 
875  ProgramMetaData *metaData = (ProgramMetaData *)data;
876  bool badVersion;
877  // make sure this is valid for interpreter
878  if (!metaData->validate(badVersion))
879  {
880  // if the failure was due to a version mismatch, this is an error condition.
881  if (badVersion)
882  {
884  }
885  return OREF_NULL;
886  }
887  RexxBuffer *bufferData = metaData->extractBufferData();
888  ProtectedObject p(bufferData);
889  // we're restoring from the beginning of this.
890  RoutineClass *routine = restore(bufferData, bufferData->getData(), metaData->getImageSize());
891  // if this restored properly (and it should), reconnect it to the source file
892  if (routine != OREF_NULL)
893  {
894  routine->getSourceObject()->setProgramName(name);
895  }
896  return routine;
897 }
898 
899 
900 /**
901  * Retrieve a routine object from a file. This will first attempt
902  * to restore a previously translated image, then will try to
903  * translate the source if that fails.
904  *
905  * @param filename The target file name.
906  *
907  * @return A resulting Routine object, if possible.
908  */
910 {
911  /* load the program file */
912  RexxBuffer *program_buffer = SystemInterpreter::readProgram(filename->getStringData());
913  if (program_buffer == OREF_NULL) /* Program not found or read error? */
914  {
915  /* report this */
917  }
918 
919  // try to restore a flattened program first
920  RoutineClass *routine = restore(filename, program_buffer);
921  if (routine != OREF_NULL)
922  {
923  return routine;
924  }
925 
926  // process this from the source
927  return new RoutineClass(filename, program_buffer);
928 }
929 
930 
931 /**
932  * Create a routine from an external library source.
933  *
934  * @param name The routine name.
935  *
936  * @return The resolved routine object, or OREF_NULL if unable to load
937  * the routine.
938  */
940 {
941  name = stringArgument(name, OREF_positional, "name");
942  ProtectedObject p1(name);
943  descriptor = stringArgument(descriptor, OREF_positional, "descriptor");
944  ProtectedObject p2(descriptor);
945  /* convert external into words */
946  RexxArray *_words = StringUtil::words(descriptor->getStringData(), descriptor->getBLength());
947  ProtectedObject p(_words);
948  // "LIBRARY libbar [foo]"
949  if (((RexxString *)(_words->get(1)))->strCompare(CHAR_LIBRARY))
950  {
951  RexxString *library = OREF_NULL;
952  // the default entry point name is the internal name
953  RexxString *entry = name;
954 
955  // full library with entry name version?
956  if (_words->size() == 3)
957  {
958  library = (RexxString *)_words->get(2);
959  entry = (RexxString *)_words->get(3);
960  }
961  else if (_words->size() == 2)
962  {
963  library = (RexxString *)_words->get(2);
964  }
965  else // wrong number of tokens
966  {
967  /* this is an error */
969  }
970 
971  /* create a new native method */
972  RoutineClass *routine = PackageManager::loadRoutine(library, entry);
973  // raise an exception if this entry point is not found.
974  if (routine == OREF_NULL)
975  {
976  return (RoutineClass *)TheNilObject;
977  }
978  return routine;
979  }
980  else
981  {
982  /* unknown external type */
984  }
985  return OREF_NULL;
986 }
987 
void reportException(wholenumber_t error)
RexxArray * new_array(size_t s)
Definition: ArrayClass.hpp:259
RexxBuffer * new_buffer(sizeB_t s)
@ T_Routine
#define PROGRAMCALL
#define OREF_NULL
Definition: RexxCore.h:60
#define IntegerThree
Definition: RexxCore.h:192
RexxString * stringArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:303
#define OrefSet(o, r, v)
Definition: RexxCore.h:94
const int ARG_TWO
Definition: RexxCore.h:81
#define IntegerTwo
Definition: RexxCore.h:191
#define isOfClass(t, r)
Definition: RexxCore.h:212
#define TheNilObject
Definition: RexxCore.h:181
const int ARG_ONE
Definition: RexxCore.h:80
RexxArray * arrayArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:407
void requiredArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:291
#define Error_Execution_user_defined
#define Error_Translation_bad_external
#define Error_Incorrect_method_no_method
#define Error_Incorrect_method_nostring_inarray
#define Error_Incorrect_method_argType
#define Error_Program_unreadable_name
#define Error_Logical_value_logical_list
#define Error_Program_unreadable_output_error
#define Error_Program_unreadable_version
#define Error_Incorrect_method_noarray
RexxReturnCode REXXENTRY RexxResolveMacroFunction(const char *, PRXSTRING)
#define memory_mark(oref)
Definition: RexxMemory.hpp:445
RexxObject * new_object(size_t s)
Definition: RexxMemory.hpp:431
#define flatten_reference(oref, envel)
Definition: RexxMemory.hpp:493
#define CLASS_CREATE(name, id, className)
Definition: RexxMemory.hpp:498
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:446
#define cleanUpFlatten
Definition: RexxMemory.hpp:479
#define setUpFlatten(type)
Definition: RexxMemory.hpp:473
RexxString * new_string(const char *s, stringsizeB_t bl, sizeC_t cl=-1)
static RexxActivity *volatile currentActivity
virtual RexxObject * setSecurityManager(RexxObject *manager)
virtual void call(RexxActivity *, RoutineClass *, RexxString *, RexxObject **, size_t, size_t, RexxString *, RexxString *, int, ProtectedObject &)
RexxArray * source()
RexxString * executableName
Definition: MethodClass.hpp:97
BaseCode * code
Definition: MethodClass.hpp:98
RexxSource * getSourceObject()
Definition: MethodClass.hpp:85
RexxString * getDefaultEnvironment()
void check(RexxObject **namedArglist, size_t namedArgCount, bool strict, bool extraAllowed, size_t minimumRequired=0)
static RoutineClass * loadRoutine(RexxString *packageName, RexxString *function)
void write(FILE *handle, RexxBuffer *program)
RexxBuffer * extractBufferData()
bool validate(bool &)
RexxSource * getSourceObject()
InterpreterInstance * getInstance()
RexxActivation * getCurrentRexxFrame()
size_t getDimension()
Definition: ArrayClass.cpp:693
void put(RexxObject *eref, size_t pos)
Definition: ArrayClass.cpp:208
RexxObject * copy()
Definition: ArrayClass.cpp:122
RexxString * makeString(RexxString *, RexxString *)
size_t size()
Definition: ArrayClass.hpp:202
RexxObject * get(size_t pos)
Definition: ArrayClass.hpp:203
RexxObject ** data()
Definition: ArrayClass.hpp:204
sizeB_t getDataLength()
Definition: BufferClass.hpp:53
virtual char * getData()
static void processNewArgs(RexxObject **, size_t, RexxObject ***, size_t *, size_t, RexxObject **, RexxObject **)
size_t appendAllIndexesItemsTo(RexxArray *array, size_t from)
RexxBuffer * pack(RexxObject *)
void puff(RexxBuffer *, char *, size_t length)
RexxObject * getReceiver()
void setBehaviour(RexxBehaviour *b)
RexxString * makeString()
RexxArray * requestArray()
void sendMessage(RexxString *, RexxArray *, RexxDirectory *, ProtectedObject &)
RexxDirectory * requestDirectory()
bool truthValue(int)
void setBufferedSource(RexxBuffer *newSource)
Definition: SourceFile.hpp:151
RexxString * getProgramName()
Definition: SourceFile.hpp:300
RexxCode * generateCode(bool isMethod)
void adjustLine(size_t, size_t)
Definition: SourceFile.cpp:365
void setIsBlock(bool b)
Definition: SourceFile.hpp:144
void setProgramName(RexxString *name)
Definition: SourceFile.cpp:338
void inheritSourceContext(RexxSource *source)
const char * getStringData()
sizeB_t getBLength()
void runProgram(RexxActivity *activity, RexxString *calltype, RexxString *environment, RexxObject **arguments, size_t argCount, size_t named_argCount, ProtectedObject &result)
RexxObject * callRexx(RexxObject **, size_t, size_t)
RexxObject * setSecurityManager(RexxObject *)
static RoutineClass * restoreFromMacroSpace(RexxString *name)
RexxBuffer * save()
RoutineClass(RexxString *n, BaseCode *_code)
RoutineClass * loadExternalRoutine(RexxString *name, RexxString *descriptor)
void call(RexxActivity *, RexxString *, RexxObject **, size_t, size_t, RexxString *, RexxString *, int, ProtectedObject &)
static RoutineClass * restore(RexxBuffer *, char *, size_t length)
RexxObject * callWithRexx(RexxArray *, RexxObject **, size_t)
void liveGeneral(int reason)
static RoutineClass * processInstore(PRXSTRING instore, RexxString *name)
void live(size_t)
RoutineClass * newRexx(RexxObject **, size_t, size_t)
static RoutineClass * fromFile(RexxString *filename)
RoutineClass * newFileRexx(RexxString *)
static RoutineClass * newRoutineObject(RexxString *, RexxObject *, RexxObject *, RexxSource *s, bool isBlock)
static void createInstance()
static RexxClass * classInstance
void flatten(RexxEnvelope *)
static RexxArray * words(const char *data, sizeB_t length)
static RexxBuffer * readProgram(const char *file_name)
static void releaseResultMemory(void *)
static const char * strnchr(const char *, sizeB_t n, char ch)
Definition: Utilities.cpp:172
RexxReturnCode REXXENTRY RexxQueryMacro(CONSTANT_STRING, unsigned short *)
#define MAKERXSTRING(r, p, l)
Definition: rexx.h:182
#define size_v(X)
Definition: rexx.h:237
size_t strlength
Definition: rexx.h:157
char * strptr
Definition: rexx.h:158