REXX FAQ

Источник: https://ossite.ru/index.php?dir=os/os2/&file=rexxfaq

REXX FAQ

Часто задаваемые вопросы по REXX

 

1. Что такое REXX ? Язык командных файлов OS/2 ?
2. Как получить список доступных дисков под REXX ?
3. Как вызывать REXX-функции из своей программы ?
4. Как добавлять свои функции к REXX-интерпретатору ?
5. Как реализовать Rexx subcommand handler ?
6. Какие библиотеки для программирования на Rexx существуют ?
7. Как проверить существование файла в REXX (if exist) ?

 

1. Что такое REXX ? Язык командных файлов OS/2 ?

И командных файлов - тоже. В том случае, когда интеpпpетатоp pекса вызывается из cmd.exe (или 4os2.exe) он исполняет командный файл. Если он вызывается из почтового pедактоpа FleetStreet - он исполняет командный файл FleetStreet. Сам по себе REXX не пpивязан к конкpетной части системы и может использоваться любой пpогpаммой как "свой" язык, пpи этом каждая из использующих REXX пpогpамм может добавить к нему свои функции и опеpатоpы, котоpые будут доступны только пpи pаботе pекса в контексте этой пpогpаммы. Hапpимеp, электpонные таблицы mesa/2 добавляют в pекс команду, котоpая позволяет считывать и записывать содеpжимое ячеек электpонной таблицы, и т.п.

 2. Как получить список доступных дисков под REXX ?

С помощью следующего кода можно получить список имён дисков типа A: C: D: E:, сетевых - Novell, NFS, LanServer и дp.

if RxFuncQuery("SysLoadFuncs") then

do

    call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs';

    call SysLoadFuncs;

end

 

DrvMap = SysDriveMap() ;

Say DrvMap

Say "-------------------------------------"

 i = 1

Do While Word( DrvMap, i ) \= ""

     Say SysDriveInfo( Word( DrvMap, i ) )

    i = i + 1 ;

 End

Exit( 0 ) ;

 

3. Как вызывать REXX-функции из своей программы ?

Это - кусок кода из U1 - выложен как пример.

RXSTRING arg[2];       // argument string for REXX 

RXSTRING rexxretval;   // return value from REXX   

APIRET   rc;           // return code from REXX    

SHORT    rexxrc = 0;   // return code from function

     if( prog == NULL || strlen(prog) == 0 )

            return Err;

 // By setting the strlength of the output RXSTRING to zero,

// we force the interpreter to allocate memory and return

// it to us. We could provide a buffer for the interpreter

// to use instead.

 rexxretval.strlength = 0L;   // initialize return to empty

 if( a1 == NULL ) a1 = "";

MAKERXSTRING(arg[0], a1, strlen(a1)); // input argument

 if( a2 == NULL ) a2 = "";

MAKERXSTRING(arg[1], a2, strlen(a2)); // input argument

 // Here we call the interpreter.  We don't really need

// to use all the casts in this call; they just help

// illustrate the data types used.

rc=RexxStart(

(LONG)      2,     // number of arguments

(PRXSTRING)  &arg,  // array of arguments

(PSZ)        prog,  // name of REXX file

(PRXSTRING)  0,     // No INSTORE used

(PSZ)        "U1",  // Command env. name

(LONG)       RXSUBROUTINE,  // Code for how invoked

(PRXSYSEXIT) 0,             // No EXITs on this call

(PSHORT)     &rexxrc,       // Rexx program output

(PRXSTRING)  &rexxretval ); // Rexx program output

 

debug( "CallRexx() = '%s', int=%d, rexx=%d", rexxretval.strptr, rc, (int)rexxrc );

 

//  printf("Interpreter Return Code: %d\n", rc);

//  printf("Function Return Code:    %d\n", (int) rexxrc);

//  printf("Args:         '%s', '%s'\n", arg[0].strptr, arg[1].strptr );

//  printf("Ret :         '%s'\n", rexxretval.strptr);

 

if( rexxretval.strptr != NULL )

  out = rexxretval.strptr;

 

DosFreeMem(rexxretval.strptr);   // Release storage

                                 // given to us by REXX.

 if( rexxrc != 0 )

            {

error( EI_None, "CallRexx( '%s', out, '%s', '%s' ) returned %d",

            prog, a1, a2, (int) rexxrc );

return Err;

            }

     return rc == 0 ? Ok : Err;

    }

 4. Как добавлять свои функции к REXX-интерпретатору ?

Пример из U1. После выполнения Register_Rexx_Function_Handlers() любая REXX-процедура, работающая в контексте вашей программы, сможет использовать REXX-функцию MatchAKA.

#define INCL_RXFUNC

#define INCL_RXSUBCOM

#define INCL_RXSHV

#define INCL_REXXSAA

#include <rexxsaa.h>     /* needed for RexxStart()     */

#include <stdio.h>       /* needed for printf()        */

#include <string.h>      /* needed for strlen()        */

#include <strng.h>       /* needed for strlen()        */

 

LONG   EXPENTRY MatchAKA(

  PSZ        name,       /* function name              */

  LONG       argc,       /* count of arguments         */

  PRXSTRING  argv,       /* argument RXSTRINGs         */

  PSZ        queue,      /* current Rexx queue         */

  PRXSTRING  retstr );   /* returned string value      */

 

extern "SYSTEM" void

DeRegister_Rexx_Function_Handlers( void )

            {

            RexxDeregisterFunction("MatchAKA");

            }

bool

Register_Rexx_Function_Handlers( void )

            {

            atexit( DeRegister_Rexx_Function_Handlers );

             RexxRegisterFunctionExe("MatchAKA", (PFN)MatchAKA );

            return Ok;

            }

 // MatchAKA - External Rexx function

 LONG   EXPENTRY MatchAKA(

  PSZ        name,          /* function name              */

  LONG       argc,          /* count of arguments         */

  PRXSTRING  argv,          /* argument RXSTRINGs         */

  PSZ        queue,         /* current Rexx queue         */

  PRXSTRING  retstr )       /* returned string value      */

            {

            fido_addr         a;

            ftn_def             def;

            const char *in = RXSTRPTR(argv[0]);

            a.aparse( in );

            ftn::match( def, a ); // Это C++-ная функция, которая

                                         //выполняет саму работу.

             const char *res = ((string)def.fido_a).c_str();

             strcpy(RXSTRPTR(*retstr), res); 

                                               // copy over current precision

             retstr->strlength = strlen(res); // set new length

            return 0;                        // completed successfully

            }

 5. Какреализовать Rexx subcommand handler ?

Вот пример из U1:

#define INCL_RXFUNC

#define INCL_RXSUBCOM

#define INCL_RXSHV

#define INCL_REXXSAA

#include <rexxsaa.h>      /* needed for RexxStart()     */

#include <stdio.h>        /* needed for printf()        */

#include <string.h>       /* needed for strlen()        */

#include <strng.h>        /* needed for strlen()        */

 APIRET  EXPENTRY U1_Command(PRXSTRING cmd, PUSHORT flags, PRXSTRING ret );

bool

Register_Rexx_Subcommand_Handler( void )

            {

             RexxRegisterSubcomExe("U1", (PFN)U1_Command, NULL);

            return Ok;

            }

#define TEST( v, s ) ( strncmp( v, s, sizeof( s ) - 1 ) == 0 )

#defineSC_SUCCESS                       { strcpy(ret->strptr, "0"); ret->strlength = 1; return 0; }

#defineSC_FAILURE(code)  { *flags = RXSUBCOM_FAILURE; strcpy(ret->strptr, code); ret->strlength = 1; return 0; }

#defineSC_ERROR(code)                 { *flags = RXSUBCOM_ERROR; strcpy(ret->strptr, code); ret->strlength = 1; return 0; }

#define CMD( tail )                 { if( (rc = sc_##tail( cmd )) != 0 ) { sprintf( rcs, "%d", rc ); SC_ERROR(rcs); } }

static sc_log( string & );

static sc_warning( string & );

static sc_error( string & );

static sc_fatal( string & );

APIRET  EXPENTRY

U1_Command(PRXSTRING r_cmd, PUSHORT flags, PRXSTRING ret )

            {

            string cmd( r_cmd->strptr );

            const char *p1, *p2;

            const maxv = 25;

            char  verb[maxv];

 

            // for CMD macro

            int        rc;

            char     rcs[10];

            p1 = cmd.c_str();

            p2 = strpbrk( p1, " \t" );

            strncpy( verb, p1, min( maxv, p2-p1 ) );

            verb[min( maxv, p2-p1 )] = '\0';

             strlwr( verb );

             while( *p2 == ' ' || *p2 == '\t' )

                        p2++;

             cmd = p2;

            debug( "Rexx cmd got verb '%s' and tail '%s'", verb, cmd.c_str() );

             if( TEST( verb, "log" ) )            CMD( log  )     else

            if( TEST( verb, "warning" ) )    CMD( warning )          else

            if( TEST( verb, "error" ) )         CMD( error  )  else

            if( TEST( verb, "fatal" ) )          CMD( fatal  )   else

                        {

                        error( EI_None, "Rexx subcommand: unknown verb '%s'", verb );

                        SC_FAILURE("33");

                        }

             SC_SUCCESS;

            }

static int

sc_log( string &s )

            {

            log( "x#", "%s", s.c_str() );

            return 0;

            }

static int

sc_warning( string &s )

            {

            warning( EI_None, "%s", s.c_str() );

            return 0;

            }

static int

sc_error( string &s )

            {

            error( EI_None, "%s", s.c_str() );

            return 0;

            }

static int

sc_fatal( string &s )

            {

            fatal( EC_Dunno, EI_None, "%s", s.c_str() );

            return 0;

            }

6. Какие библиотеки для программирования на Rexx существуют ?

Для начала - ydbautil. Наиболее полная библиотека того, чего в REXX обычно недостает с начала работы.
Вторая библиотека - rxasync, предназначена для работы с COM-портами. Полный набор функций низкого уровня, т.е. без протоколов, упаковки, модемов.
Rxsocket - набор функций для работы с TCP/IP из REXX.
Rxipc - Inter Process Communication для REXX. Перекрывается возможностями ydbautil.
EPMBBS - пакет для написания макро к EPM на REXX и собственном макроязыке EPM.
Есть еще библиотеки, позволяющие использовать некоторый набор controls в PM-программах из REXX, обычно Message Box, Input Line с кнопками Ok и Cancel, List Box и т.п.

7. Как проверить существование файла в REXX (if exist) ?

File_Exist.cmd:

Parse Arg Name

Call SysFileTree Name, Result

if Result.0 = 0 then

            Return 0

else

            Return 1

Использование:


do while( file_exist(netdir'\Hold.!!!') ) call syssleep 10 end

Вариант:
if stream( 'myfile.txt', 'c', 'query exists' ) \= '' then say 'Ok!'