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", TheNilObject); // At least 1 characters, default value = .NIL
297  expectedNamedArguments.match(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(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  // this method is defined on the object class, but this is actually attached
612  // to a class object instance. Therefore, any use of the this pointer
613  // will be touching the wrong data. Use the classThis pointer for calling
614  // any methods on this object from this method.
615  RexxClass *classThis = (RexxClass *)this;
616  classThis->checkAbstract(); // ooRexx5
617 
618  RexxObject *pgmname; /* method name */
619  RexxObject *_source; /* Array or string object */
620  RexxObject *option = OREF_NULL;
621  size_t initCount = 0; /* count of arguments we pass along */
622 
623  /* break up the arguments */
624 
625  RexxClass::processNewArgs(init_args, argCount, &init_args, &initCount, 2, (RexxObject **)&pgmname, (RexxObject **)&_source);
626  /* get the method name as a string */
627  RexxString *nameString = stringArgument(pgmname, OREF_positional, ARG_ONE);
628  ProtectedObject p_nameString(nameString);
629  requiredArgument(_source, OREF_positional, ARG_TWO); /* make sure we have the second too */
630 
631  RexxSource *sourceContext = OREF_NULL;
632  // retrieve extra parameter if exists
633  if (initCount != 0)
634  {
635  RexxClass::processNewArgs(init_args, initCount, &init_args, &initCount, 1, (RexxObject **)&option, NULL);
636  if (isOfClass(Method, option))
637  {
638  sourceContext = ((RexxMethod *)option)->getSourceObject();
639  }
640  if (isOfClass(Routine, option))
641  {
642  sourceContext = ((RoutineClass *)option)->getSourceObject();
643  }
644  else if (isOfClass(Package, option))
645  {
646  sourceContext = ((PackageClass *)option)->getSourceObject();
647  }
648  else
649  {
650  RexxString *info = new_string("Method, Routine, or Package object");
651  ProtectedObject p(info);
653  }
654  }
655 
656  bool isBlock = false;
657  // retrieve extra parameter if exists
658  if (initCount != 0)
659  {
660  RexxClass::processNewArgs(init_args, initCount, &init_args, &initCount, 1, (RexxObject **)&option, NULL);
661  isBlock = option->truthValue(Error_Logical_value_logical_list);
662  }
663 
664  RoutineClass *newRoutine = newRoutineObject(nameString, _source, IntegerTwo, sourceContext, isBlock);
665  ProtectedObject p(newRoutine);
666  /* Give new object its behaviour */
667  newRoutine->setBehaviour(classThis->getInstanceBehaviour());
668  if (classThis->hasUninitDefined())
669  {
670  newRoutine->hasUninit(); /* Make sure everyone is notified. */
671  }
672  /* now send an INIT message */
673  newRoutine->sendMessage(OREF_INIT, init_args, initCount, named_argCount);
674  return newRoutine; /* return the new method */
675 }
676 
677 
679  RexxString *filename) /* name of the target file */
680 /******************************************************************************/
681 /* Function: Create a method from a fully resolved file name */
682 /******************************************************************************/
683 {
684  // this method is defined on the object class, but this is actually attached
685  // to a class object instance. Therefore, any use of the this pointer
686  // will be touching the wrong data. Use the classThis pointer for calling
687  // any methods on this object from this method.
688  RexxClass *classThis = (RexxClass *)this;
689  classThis->checkAbstract(); // ooRexx5
690 
691  /* get the method name as a string */
692  filename = stringArgument(filename, OREF_positional, ARG_ONE);
693  /* finish up processing of this */
694  RoutineClass * newMethod = new RoutineClass(filename);
695  ProtectedObject p2(newMethod);
696  /* Give new object its behaviour */
697  newMethod->setBehaviour(classThis->getInstanceBehaviour());
698  /* does object have an UNINT method */
699  if (classThis->hasUninitDefined())
700  {
701  newMethod->hasUninit(); /* Make sure everyone is notified. */
702  }
703  /* now send an INIT message */
704  newMethod->sendMessage(OREF_INIT);
705  return newMethod;
706 }
707 
708 
709 /**
710  * Create a routine from a macrospace source.
711  *
712  * @param name The name of the macrospace item.
713  *
714  * @return The inflatted macrospace routine.
715  */
717 {
718  RXSTRING buffer; /* instorage buffer */
719 
720  MAKERXSTRING(buffer, NULL, 0);
721  /* get the image of function */
722  RexxResolveMacroFunction(name->getStringData(), &buffer);
723  /* unflatten the method now */
724  RoutineClass *routine = restore(&buffer, name);
725  // release the buffer memory
727  return routine;
728 }
729 
730 
732 /******************************************************************************/
733 /* Function: Process instorage execution arguments */
734 /******************************************************************************/
735 {
736  // just a generic empty one indicating that we should check the macrospace?
737  if (instore[0].strptr == NULL && instore[1].strptr == NULL)
738  {
739  unsigned short temp;
740 
741  /* see if this exists */
742  if (!RexxQueryMacro(name->getStringData(), &temp))
743  {
744  return restoreFromMacroSpace(name);
745  }
746  return OREF_NULL; // not found
747  }
748  if (instore[1].strptr != NULL) /* have an image */
749  {
750  /* go convert into a method */
751  RoutineClass *routine = restore(&instore[1], name);
752  if (routine != OREF_NULL)
753  { /* did it unflatten successfully? */
754  if (instore[0].strptr != NULL) /* have source also? */
755  {
756  /* get a buffer object */
757  RexxBuffer *source_buffer = new_buffer(instore[0]);
758  /* reconnect this with the source */
759  routine->getSourceObject()->setBufferedSource(source_buffer);
760  }
761  return routine; /* go return it */
762  }
763  }
764  if (instore[0].strptr != NULL) /* have instorage source */
765  {
766  /* get a buffer object */
767  RexxBuffer *source_buffer = new_buffer(instore[0]);
768  if (source_buffer->getData()[0] == '#' && source_buffer->getData()[1] == '!')
769  {
770  memcpy(source_buffer->getData(), "--", 2);
771  }
772 
773  /* translate this source */
774  RoutineClass *routine = new RoutineClass(name, source_buffer);
775  ProtectedObject p(routine);
776  /* return this back in instore[1] */
777  routine->save(&instore[1]);
778  return routine; /* return translated source */
779  }
780  return OREF_NULL; /* processing failed */
781 }
782 
783 /**
784  * Restore a saved routine directly from character data.
785  *
786  * @param data The data pointer.
787  * @param length the data length.
788  *
789  * @return The unflattened routine object.
790  */
791 RoutineClass *RoutineClass::restore(const char *data, size_t length)
792 {
793  // create a buffer object and restore from it
794  RexxBuffer *buffer = new_buffer(data, length);
795  ProtectedObject p(buffer);
796  return restore(buffer, buffer->getData(), length);
797 }
798 
799 
801  RexxBuffer *buffer, /* buffer containing the method */
802  char *startPointer, /* first character of the method */
803  size_t length) // length of data to unflatten
804 /******************************************************************************/
805 /* Function: Unflatten a translated method. Passed a buffer object containing*/
806 /* the method */
807 /******************************************************************************/
808 {
809  /* Get new envelope object */
810  RexxEnvelope *envelope = new RexxEnvelope;
811  ProtectedObject p(envelope);
812  /* now puff up the method object */
813  envelope->puff(buffer, startPointer, length);
814  /* The receiver object is an envelope*/
815  /* whose receiver is the actual */
816  /* method object we're restoring */
817  return (RoutineClass *)envelope->getReceiver();
818 }
819 
820 
821 /**
822  * Restore a program from a simple buffer.
823  *
824  * @param buffer The source buffer.
825  *
826  * @return The inflated Routine object, if valid.
827  */
829 {
830  const char *data = buffer->getData();
831 
832  // does this start with a hash-bang? Need to scan forward to the first
833  // newline character
834  if (data[0] == '#' && data[1] == '!')
835  {
836  data = Utilities::strnchr(data, buffer->getDataLength(), '\n');
837  if (data == OREF_NULL)
838  {
839  return OREF_NULL;
840  }
841  // step over the linend
842  data++;
843  }
844 
845  ProgramMetaData *metaData = (ProgramMetaData *)data;
846  bool badVersion = false;
847  // make sure this is valid for interpreter
848  if (!metaData->validate(badVersion))
849  {
850  // if the failure was due to a version mismatch, this is an error condition.
851  if (badVersion)
852  {
854  }
855  return OREF_NULL;
856  }
857  // this should be valid...try to restore.
858  RoutineClass *routine = restore(buffer, metaData->getImageData(), metaData->getImageSize());
859  routine->getSourceObject()->setProgramName(fileName);
860  return routine;
861 }
862 
863 
864 /**
865  * Restore a routine object from a previously saved instore buffer.
866  *
867  * @param inData The input data (in RXSTRING form).
868  *
869  * @return The unflattened object.
870  */
872 {
873  const char *data = inData->strptr;
874 
875  // does this start with a hash-bang? Need to scan forward to the first
876  // newline character
877  if (data[0] == '#' && data[1] == '!')
878  {
879  data = Utilities::strnchr(data, inData->strlength, '\n');
880  if (data == OREF_NULL)
881  {
882  return OREF_NULL;
883  }
884  // step over the linend
885  data++;
886  }
887 
888 
889  ProgramMetaData *metaData = (ProgramMetaData *)data;
890  bool badVersion;
891  // make sure this is valid for interpreter
892  if (!metaData->validate(badVersion))
893  {
894  // if the failure was due to a version mismatch, this is an error condition.
895  if (badVersion)
896  {
898  }
899  return OREF_NULL;
900  }
901  RexxBuffer *bufferData = metaData->extractBufferData();
902  ProtectedObject p(bufferData);
903  // we're restoring from the beginning of this.
904  RoutineClass *routine = restore(bufferData, bufferData->getData(), metaData->getImageSize());
905  // if this restored properly (and it should), reconnect it to the source file
906  if (routine != OREF_NULL)
907  {
908  routine->getSourceObject()->setProgramName(name);
909  }
910  return routine;
911 }
912 
913 
914 /**
915  * Retrieve a routine object from a file. This will first attempt
916  * to restore a previously translated image, then will try to
917  * translate the source if that fails.
918  *
919  * @param filename The target file name.
920  *
921  * @return A resulting Routine object, if possible.
922  */
924 {
925  /* load the program file */
926  RexxBuffer *program_buffer = SystemInterpreter::readProgram(filename->getStringData());
927  if (program_buffer == OREF_NULL) /* Program not found or read error? */
928  {
929  /* report this */
931  }
932 
933  // try to restore a flattened program first
934  RoutineClass *routine = restore(filename, program_buffer);
935  if (routine != OREF_NULL)
936  {
937  return routine;
938  }
939 
940  // process this from the source
941  return new RoutineClass(filename, program_buffer);
942 }
943 
944 
945 /**
946  * Create a routine from an external library source.
947  *
948  * @param name The routine name.
949  *
950  * @return The resolved routine object, or OREF_NULL if unable to load
951  * the routine.
952  */
954 {
955  name = stringArgument(name, OREF_positional, "name");
956  ProtectedObject p1(name);
957  descriptor = stringArgument(descriptor, OREF_positional, "descriptor");
958  ProtectedObject p2(descriptor);
959  /* convert external into words */
960  RexxArray *_words = StringUtil::words(descriptor->getStringData(), descriptor->getLength());
961  ProtectedObject p(_words);
962  // "LIBRARY libbar [foo]"
963  if (((RexxString *)(_words->get(1)))->strCompare(CHAR_LIBRARY))
964  {
965  RexxString *library = OREF_NULL;
966  // the default entry point name is the internal name
967  RexxString *entry = name;
968 
969  // full library with entry name version?
970  if (_words->size() == 3)
971  {
972  library = (RexxString *)_words->get(2);
973  entry = (RexxString *)_words->get(3);
974  }
975  else if (_words->size() == 2)
976  {
977  library = (RexxString *)_words->get(2);
978  }
979  else // wrong number of tokens
980  {
981  /* this is an error */
983  }
984 
985  /* create a new native method */
986  RoutineClass *routine = PackageManager::loadRoutine(library, entry);
987  // raise an exception if this entry point is not found.
988  if (routine == OREF_NULL)
989  {
990  return (RoutineClass *)TheNilObject;
991  }
992  return routine;
993  }
994  else
995  {
996  /* unknown external type */
998  }
999  return OREF_NULL;
1000 }
1001 
void reportException(wholenumber_t error)
RexxArray * new_array(size_t s)
Definition: ArrayClass.hpp:259
RexxBuffer * new_buffer(size_t s)
@ T_Routine
#define PROGRAMCALL
#define OREF_NULL
Definition: RexxCore.h:61
#define IntegerThree
Definition: RexxCore.h:202
RexxString * stringArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:315
#define OrefSet(o, r, v)
Definition: RexxCore.h:101
const int ARG_TWO
Definition: RexxCore.h:84
#define IntegerTwo
Definition: RexxCore.h:201
#define isOfClass(t, r)
Definition: RexxCore.h:224
#define TheNilObject
Definition: RexxCore.h:191
const int ARG_ONE
Definition: RexxCore.h:83
RexxArray * arrayArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:395
void requiredArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:303
#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:450
RexxObject * new_object(size_t s)
Definition: RexxMemory.hpp:436
#define flatten_reference(oref, envel)
Definition: RexxMemory.hpp:498
#define CLASS_CREATE(name, id, className)
Definition: RexxMemory.hpp:503
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:451
#define cleanUpFlatten
Definition: RexxMemory.hpp:484
#define setUpFlatten(type)
Definition: RexxMemory.hpp:478
RexxString * new_string(const char *s, stringsize_t l)
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
BaseCode * code
RexxSource * getSourceObject()
RexxString * getDefaultEnvironment()
void match(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
size_t getDataLength()
Definition: BufferClass.hpp:53
virtual char * getData()
static void processNewArgs(RexxObject **, size_t, RexxObject ***, size_t *, size_t, RexxObject **, RexxObject **)
void checkAbstract()
RexxBehaviour * getInstanceBehaviour()
Definition: ClassClass.hpp:135
bool hasUninitDefined()
Definition: ClassClass.hpp:125
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:152
RexxString * getProgramName()
Definition: SourceFile.hpp:301
RexxCode * generateCode(bool isMethod)
void adjustLine(size_t, size_t)
Definition: SourceFile.cpp:365
void setIsBlock(bool b)
Definition: SourceFile.hpp:145
void setProgramName(RexxString *name)
Definition: SourceFile.cpp:338
void inheritSourceContext(RexxSource *source)
size_t getLength()
const char * getStringData()
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, size_t length)
static RexxBuffer * readProgram(const char *file_name)
static void releaseResultMemory(void *)
static const char * strnchr(const char *, size_t n, char ch)
Definition: Utilities.cpp:192
RexxReturnCode REXXENTRY RexxQueryMacro(CONSTANT_STRING, unsigned short *)
#define MAKERXSTRING(r, p, l)
Definition: rexx.h:182
size_t strlength
Definition: rexx.h:157
char * strptr
Definition: rexx.h:158