close Warning: Can't synchronize with repository "(default)" (/var/svn/tolp does not appear to be a Subversion repository.). Look in the Trac log for more information.

Opened 14 years ago

Last modified 10 years ago

#1118 accepted enhancement

System function returning the answer

Reported by: Pedro Gea Owned by: Pedro Gea
Priority: high Milestone: Mantainance
Component: System Version: head
Severity: critical Keywords:
Cc:

Description

Se solicita la implementación de una alternativa a las funciones System o WinSystem que permita hacer llamadas al sistema operativo y que canalice las respuestas de la llamada.

De las dos funciones actuales sólo System es capaz de ejecutar comandos del sistema operativo como dir o copy. Sería deseable que esto fuese siempre así.

El siguiente código funciona con System pero no con WinSystem:

Real System("dir c:\\ > c:\\temp\\dir.txt");
Real System("del c:\\temp\\dir.txt");

Sin embargo ninguna es capaz de devolver la respuesta de la llamada, ni siquiera del error de la llamada devolviendo siempre:

  • System:
    ERROR: [] 
    [2]=No such file or directory
    No se pudo ejecutar el mandato: 
    <...>
    
  • WinSystem:
    ERROR: [] Error del Sistema Operativo 
    Creando el proceso 
    <...>
    El sistema no puede encontrar el archivo especificado.
    

A continuación se adjunta una implementación en código TOL de la función buscada que se apoya en la construcción de archivos temporales:

Text AnsSystem(Text cmd) {
  Text batFile = TmpDir<<"ans.bat";
  Text ansFile = TmpDir<<"ans.txt";
  Text errFile = TmpDir<<"ans.err.txt";
  Real FileDelete(batFile);
  Real FileDelete(ansFile);
  Real FileDelete(errFile);
  Text WriteFile(batFile, cmd<<" > "<<Qt(ansFile)<<" 2> "<<Qt(errFile));
  Real WinSystem(batFile, False, True);
  Text ans = ReadFile(ansFile);
  Text err = ReadFile(errFile);
  If(TextLength(err), Write("[AnsSystem] "<<err,"E"));
  Real FileDelete(batFile);
  Real FileDelete(ansFile);
  Real FileDelete(errFile);
  ans
};

Entiendo que sobre el modo de encaminar la respuesta y los errores hay distintas formas y quizá podría implementarse una variedad de la función que no mostrase el error sino que lo devolviese, algo semejante a Tcl_Eval devolviendo un conjunto con un real que indique el éxito de la llamada y un texto con la respuesta o el mensaje de error de la llamada.
Esta función podría implementarse como System_Eval o algo así.

Attachments (2)

tclexec.tcl (319 bytes) - added by Jorge 13 years ago.
tclexec.tol (227 bytes) - added by Jorge 13 years ago.

Download all attachments as: .zip

Change History (18)

comment:1 Changed 14 years ago by Víctor de Buen Remiro

Component: KernelSystem
Owner: changed from Víctor de Buen Remiro to Jorge
Status: newassigned

TOL es un sistema multiplataforma por lo que hay que tender a dar soluciones que funciones de forma independiente del sistema operativo. Redirecciono este ticket a Jorge por ese motivo.

comment:2 Changed 14 years ago by Pedro Gea

Priority: normalhigh
Severity: normalcritical

Changed 13 years ago by Jorge

Attachment: tclexec.tcl added

Changed 13 years ago by Jorge

Attachment: tclexec.tol added

comment:3 Changed 13 years ago by Jorge

En los archivos adjuntos se da una solución multiplataforma basada en Tcl, un ejemplo de uso es:

Set TclExec( [["svn", "ls"]] );

retorna un conjunto de 3 elementos:

  • Text errorCode: cadena que contiene el código interno del error o NONE si no hay error
  • Text errorInfo: cadena que contiene una traza del error según la pila de evaluación de Tcl
  • Text Output: cadena que contiene la salida del comando tal y como se mostraría al ejecutarlo desde una consola de comandos.

comment:4 Changed 13 years ago by Jorge

El siguiente ejemplo contiene una función exec basada en popen y pclose que puediera servir de base para la implementación en TOL.

Hay que verificarlo en windows todavía.

#include <string>
#include <iostream>
#include <stdio.h>

#ifdef WIN32
#define popen _popen
#define pclose _pclose
#endif

std::string exec(const char* cmd) {
  FILE* pipe = popen(cmd, "r");
  if (!pipe) return "ERROR";
  char buffer[128];
  std::string result = "";
  while(!feof(pipe)) {
    if(fgets(buffer, 128, pipe) != NULL)
      result += buffer;
  }
  pclose(pipe);
  return result;
}

int main( int argc, char*argv[] )
{
  if ( argc == 1 ) {
    std::cout << "nothing to execute\n";
    return 0;
  }
  std::string output;
  std::string cmd;
  
  for ( int i = 1; i < argc; i++ ) {
    cmd += '"';
    cmd += argv[i];
    cmd += "\" ";
  }
  std::cout << "executing: " << cmd << "\n";
  output = exec( cmd.c_str() );
  std::cout << output << "\n";
  return 0;
}

comment:5 Changed 13 years ago by Jorge

Owner: changed from Jorge to Humberto Carralero

comment:6 Changed 13 years ago by Jorge

(In [3977]) refs #1118, function POpen, must compiled and tested on windows

Set View( POpen( [[ "svn", "status" ]] ), "" );

comment:7 Changed 13 years ago by Jorge

Owner: changed from Humberto Carralero to Jorge
Status: assignedaccepted

comment:8 Changed 13 years ago by Jorge

(In [3978]) refs #1118, POpen compilado en windows. Si los argumentos contienen espacios hay que protegerlo con \"\", ej:

!java
Set dir = POpen( [[ "dir", "\"c:\\Archivos de Programa\"" ]] );
WriteLn( dir::output );

comment:9 Changed 13 years ago by Jorge

En windows los argumentos con espacio se protegen con \"...\", en cambio en linux hay que escapar los espacios '\ ', la función pudiera encargarse de protegerlos si esto no vienen protegidos.

comment:10 Changed 13 years ago by Jorge

(In [3981]) refs #1118, using PExec as a more appropiate name, also implementing automatic protect of arguments with spaces (pending check on windows)

comment:11 Changed 13 years ago by Jorge

(In [3982]) refs #1118, verified spaces escaping on windows.

comment:12 Changed 13 years ago by Pedro Gea

(In [4631]) Refs #1502, #1118
Se cambia la implementación interna de _AnsSystem por una apoyada en PExec (Véase #1118).

comment:13 Changed 13 years ago by Pedro Gea

Es necesario revisar el funcionamiento de PExec para que devuelva el estado (3er. argumento) a 0 si hubo errores y reencamine los errores a la salida (2o. argumento).

También es necesario evitar la aparición de la ventana de la consola en Windows.

comment:14 Changed 10 years ago by Pedro Gea

Owner: changed from Jorge to Pedro Gea

comment:15 Changed 10 years ago by Pedro Gea

(In [6280]) Refs #1118

Se separa parte del cuerpo del método void BSetPExec::CalcContens() y se traslada a un procedimiento en BSys (BSys::PExecQuiet) que es donde se encuentran las funcionalidades con llamadas al sistema operativo.
Se redirige la salida estándar de errores de la llamada a pexec a un archivo para poder capturarla y así detectar las llamadas con errores. Se usa un mecanismo similar al que usa WinSystem para capturar los errores de las llamadas precedidas por cmd.
Sin embargo, no parece que hay forma de evitar que la ventana de la consola aparezca al ejecutar PExec con Windows.

Para evitar la ventana de la consola, se crea un nuevo procedimiento en BSys (BSys::WinSystemQuiet) parecido al de PExec y que permite realizar la llamada y obtener las salidas sin mostrar la ventana.
Se crea un nuevo par de funciones AnsSystem y AnsSystemQuiet que permiten realizar llamadas al sistema operativo y obtener su respuesta y que se redirigen a BSys::WinSystemQuiet y BSys::PExecQuiet según el sistema operativo sea Windows o no.
La primera: AnsSystem devuelve la salida estándar de la llamada y muestra los errores en caso de haberlos.
La segunda: AnsSystemQuiet devuelve un conjunto con el estado de la llamada al proceso y las salidas estándar y de errores. Con esta función TOL no muestra los errores.

comment:16 Changed 10 years ago by Jorge

(In [6293]) refs #1118

SetLastError is not defined on UNIX

Note: See TracTickets for help on using tickets.