2012-09-26 2 views
0

나는 다음과 같은 절차가 있습니다Tcl의 이름 변경은 Tcl의 C 라이브러리의 네임 스페이스에서 작동하지 않습니다

rename proc _proc 
_proc proc {name args body} { 
    global pass_log_trace 

    set g_log_trace "0" 
    if {[info exists pass_log_trace]} { 
     set g_log_trace $pass_log_trace 
    } 

    # simple check if we have double declaration of the same procedure 
    if {[info procs $name] != ""} { 
     puts "\nERROR: redeclaration of procedure: $name" 
    } 

    _proc $name $args $body 

    if {$g_log_trace != 0} { 
     trace add execution $name enter trace_report_enter 
     trace add execution $name leave trace_report_leave 
    } 
} 

이는 티클 인터프리터 C library를 사용하여 내장 된 C 쉘에서 호출됩니다. 쉘의 코드는 다음과 같습니다 :

#define _GNU_SOURCE 

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <getopt.h> 
#include <signal.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <tcl.h> 

#include <readline/readline.h> 
#include <readline/history.h> 


/* Global variables */ 

static char init_file[256]; 
static char history_file[256]; 
static pid_t sfg_pid; 
static Tcl_Interp *tcl_interp = NULL; 

static int help(char *prog); 

/** 
* Print the application help. 
* @param prog 
* @return 
*/ 
static int 
help(char *prog) 
{ 
    printf("Usage: %s [OPTIONS]\n", prog); 
    printf("\n"); 
    printf(" -h|-?     Print this message and exit.\n"); 
    printf(" --init/-i file   Source this file when tcl is started.\n"); 
    printf(" --history/-f file  Read/Save history using this existing file.\n"); 
    printf(" --log/-l file   Save the Tcl log to the specified file.\n"); 
    printf("\n"); 

    exit(EXIT_SUCCESS); 
} 

int 
main(int argc, char ** argv) 
{ 
    const int buf_size = 1024; 
    const useconds_t sfg_init_tmo_usec = 100000; 
    char buf[buf_size+1]; 
    int rc; 
    char *inp = NULL; 
    char pwd[buf_size+1]; 
    int hfile; 
    char *prompt = NULL; 

    int c; 
    int option_index = 0; 
    struct option long_options[] = { 
     /*name   arg  flag val */ 
     {"help",   0,  0,  'h'}, 
     {"init",   1,  0,  'i'}, 
     {"log",   1,  0,  'l'}, 
     {"configuration", 1,  0,  'c'}, 
     {0,    0,  0,  0} 
    }; 

    /* default values */ 
    strcpy(init_file, "log_init.tcl"); 
    sfg_pid = 0; 

    /** 
    * Options processing... 
    */ 

    while ((c = getopt_long (argc, argv, "?hi:f:s:t:p:b:l:c:er", 
          long_options, &option_index)) != -1) { 
     switch (c) { 
     case 'h': 
     case '?': 
      help(argv[0]); 
      break; 

     case 'i': 
      strncpy(init_file, optarg, sizeof(init_file)-1); 
      break; 

     default: 
      printf ("?? getopt returned character code %c ??\n", c); 
     } 
    } 

    if (optind < argc) { 
     printf ("non-option ARGV-elements: "); 
     while (optind < argc) 
      printf ("%s ", argv[optind++]); 
     printf ("\n"); 
     exit(EXIT_FAILURE); 
    } 

    /** 
    * Start and configure tcl interpreter 
    */ 
    if ((tcl_interp = Tcl_CreateInterp()) == NULL) { 
     printf("Could not create Tcl interpreter: %s\n", Tcl_ErrnoMsg(Tcl_GetErrno())); 
     exit(EXIT_FAILURE); 
    } 

    /* allocate a prompt string, default to diag_tcl> , link to TCL variable */ 
    if ((prompt = Tcl_Alloc(256)) == NULL) { 
     printf("Cannot allocate a prompt variable: %s\n", tcl_interp->result); 
     exit(EXIT_FAILURE); 
    } 
    strncpy(prompt, "diag_tcl> ", 256); 
    if (Tcl_LinkVar(tcl_interp, "g_shell_prompt", (char *)&prompt, TCL_LINK_STRING) != TCL_OK) { 
     printf("Unable to link to a prompt global variable: %s\n", tcl_interp->result); 
    } 

    /* Source an init file if specified */ 
    if (init_file[0]) { 
     strcpy(buf, "source "); 
     strncat(buf, init_file, (buf_size - strlen(buf))); 
     if ((rc = Tcl_Eval(tcl_interp, buf)) != TCL_OK) { 
      printf("Tcl Interpreter Error: %s\n", tcl_interp->result); 
     } 
    } 

    /** 
    * Main single command loop 
    */ 
    while (1) { 
     if (inp) { 
      free(inp); 
      inp = NULL; 
     } 

     inp = readline(prompt); 
     if (inp == NULL) 
      break; 

     if (*inp == '\n' || *inp == '\r' || *inp == 0) { 
      continue; 
     } 
     if (feof(stdin)) 
      break; 

     if ((rc = Tcl_Eval(tcl_interp, inp)) != TCL_OK) { 
      printf("Tcl Interpreter Error: %s\n", 
        Tcl_GetVar(tcl_interp, "errorInfo", TCL_GLOBAL_ONLY)); 
     } 
    } 

    return 0; 
} 

메이크 :이 절차의

INC=-I/net/tools/include 
LIB=-L/net/tools/lib -L/lib32 -L/usr/lib -m32 
BIN=diag.lin 

GCC     = gcc 

all: diag_tclsh 

diag_tclsh: diag_tclsh.c 
    $(GCC) $^ $(INC) $(LIB) -ltcl8.4 -lreadline -lncurses -ltermcap -o [email protected] 

install: 
    cp -f strad /net/tools/bin/$(BIN) 

clean: 
    -rm -f diag_tclsh 

목적, 주로 코드의 모든 절차에 입구와 출구 지점 추적기를 추가하는 것입니다. 그러나 어떤 이유로 그것은 네임 스페이스 범위 지정을 제거합니다. 예를 들어, 다음과 같은 코드 :

namespace eval bob { 
    namespace eval joe { 
     proc proc1 {} {} 
    } 
    proc proc2 {} { 
     puts "proc2" 
    } 
} 

puts "Namespace calling [info procs ::bob\::*]" 

bob 네임 스페이스의 절차를 만들 수 있지만 글로벌 네임 스페이스에하지 않을까요. namespace current을 호출하면 항상 ::가 반환됩니다.

아이디어가 있으십니까?

답변

2

세계적인 네임 스페이스 (::)를 가진 스택 프레임을 현재 NS로 푸시하는 동안 표준 proc이 현재 네임 스페이스에 상대적인 명령을 만듭니다 (물론 절대 이름을 사용하지 않는 한). 즉, _proc에 전화 할 때 잘못된 네임 스페이스를 사용하고있는 것입니다.

수정 프로그램 (uplevel 1 namespace current로 검색 가능) 발신자의 이름 공간과 필요에 따라 이름을 규정하는 호출자의 컨텍스트에서 _proc, 또는 전화를 uplevel 1을 사용하는 것입니다. 귀하의 경우에는 두 번째 기술을 사용하는 것이 가장 좋습니다 (존재 확인을하고 실행 흔적을 추가하여 다른 목적을 위해 이름을 필요로 함) :

관련 문제