Version 1 of Unix Terminal Extension

Updated 2002-05-09 22:06:12

GPS - Thu May 9, 2002: I wrote this little extension for my file server. My file server is a console application that prompts the user for a password. Being the pedantic programmer that I am I decided I didn't want someone to be able to see the password while the user enters it. I also wanted to receive a character at a time, so that I could display * for each entered char. This extension provides four commands. Please feel free to add to this. I place the code in the public domain.


  #include <stdio.h>
  #include <stdlib.h>
  #include <termios.h>
  #include <string.h>
  #include <sys/syslimits.h> /*For MAX_CANON */
  #include <tcl.h>

  #define CMD_ARGS (ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])

  int TerminalEchoOff CMD_ARGS {
    struct termios terminal;
    int fid = fileno (stdout);

    if (objc != 1) {
      Tcl_WrongNumArgs (interp, 0, NULL, "terminal:echoOff");
      return TCL_ERROR;
    }

    tcgetattr (fid, &terminal);
    terminal.c_lflag &= (~ECHO);
    tcsetattr (fid, TCSANOW, &terminal);

    return TCL_OK;
  }

  int TerminalEchoOn CMD_ARGS {
    struct termios terminal;
    int fid = fileno (stdout);

    if (objc != 1) {
      Tcl_WrongNumArgs (interp, 0, NULL, "terminal:echoOn");
      return TCL_ERROR;
    }

    tcgetattr (fid, &terminal);
    terminal.c_lflag |= (ECHO);
    tcsetattr (fid, TCSANOW, &terminal);

    return TCL_OK;
  }

  int TerminalCanonicalOff CMD_ARGS {
    struct termios terminal;
    int fid = fileno (stdin);

    if (objc != 1) {
      Tcl_WrongNumArgs (interp, 0, NULL, "terminal:canonicalOff");
      return TCL_ERROR;
    }

    tcgetattr (fid, &terminal);
    terminal.c_lflag &= (~ICANON);
    terminal.c_cc[VTIME] = 0;
    terminal.c_cc[VMIN] = 1;
    tcsetattr (fid, TCSANOW, &terminal);

    return TCL_OK;
  }

  int TerminalCanonicalOn CMD_ARGS {
    struct termios terminal; 
    int fid = fileno (stdin);

    if (objc != 1) {
      Tcl_WrongNumArgs (interp, 0, NULL, "terminal:canonicalOn");
      return TCL_ERROR;
    }

    tcgetattr (fid, &terminal);
    terminal.c_lflag |= (ICANON);
    terminal.c_cc[VTIME] = 0;
    terminal.c_cc[VMIN] = MAX_CANON;
    tcsetattr (fid, TCSANOW, &terminal);

    return TCL_OK;
  }

  int Terminal_Init (Tcl_Interp *interp) {
    #define OBJ_CMD(name,func) Tcl_CreateObjCommand(interp, name, func, (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL)

    OBJ_CMD ("terminal:echoOff", TerminalEchoOff);
    OBJ_CMD ("terminal:echoOn", TerminalEchoOn);
    OBJ_CMD ("terminal:canonicalOff", TerminalCanonicalOff);
    OBJ_CMD ("terminal:canonicalOn", TerminalCanonicalOn);

    #undef OBJ_CMD
    return TCL_OK;
  }