⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qgsgrassshell.cpp

📁 一个非常好的GIS开源新版本
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/***************************************************************************     qgsgrassshell.cpp     --------------------------------------    Date                 : Sun Sep 16 12:06:10 AKDT 2007    Copyright            : (C) 2007 by Gary E. Sherman    Email                : sherman at mrcc dot com *************************************************************************** *                                                                         * *   This program is free software; you can redistribute it and/or modify  * *   it under the terms of the GNU General Public License as published by  * *   the Free Software Foundation; either version 2 of the License, or     * *   (at your option) any later version.                                   * *                                                                         * ***************************************************************************/#include <iostream>#include <vector>#include <qstring.h>#include <qapplication.h>#include <qpushbutton.h>#include <qwidget.h>#include <q3textedit.h>#include <q3process.h>#include <qmessagebox.h>#include <q3cstring.h>#include <qfile.h>#include <qdatastream.h>#include <qstringlist.h>#include <qsocketnotifier.h>#include <q3socket.h>#include <q3socketdevice.h>#include <qevent.h>#include <q3textbrowser.h>#include <qregexp.h>#include <qcursor.h>#include <qlayout.h>#include <qclipboard.h>#include <qfontmetrics.h>#include <q3progressbar.h>#include "qgsapplication.h"#include "qgsgrassshell.h"//Added by qt3to4:#include <QGridLayout>#include <QKeyEvent>#include <QResizeEvent>#include <QMouseEvent>extern "C" {#include <stdio.h>#include <stdlib.h>#ifndef _MSC_VER#include <unistd.h>#else#include <io.h>#endif#ifndef WIN32#ifdef Q_OS_MACX#include <util.h>#else#ifdef __NetBSD__#include <util.h>#else#ifdef __FreeBSD__#include <termios.h>#include <libutil.h>#else#include <pty.h>#endif#endif#endif#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <fcntl.h>#include <signal.h>#include <sys/wait.h>#endif //!WIN32}QgsGrassShell::QgsGrassShell ( QgsGrassTools *tools,     QTabWidget * parent, const char * name  ):QDialog(parent), QgsGrassShellBase(), mTools(tools){  mValid = false;  mSkipLines = 2;  mTabWidget = parent;#ifdef WIN32  QMessageBox::warning( 0, "Warning",     "GRASS Shell is not supported on Windows." );  return;#else   setupUi(this);  QGridLayout *layout = new QGridLayout( mTextFrame, 1, 1 );  mText = new QgsGrassShellText( this, mTextFrame);  layout->addWidget ( mText, 0 , 0 );  mText->show();  connect(mCloseButton, SIGNAL(clicked()), this, SLOT(closeShell()));  mFont = QFont ( "Courier", 10 );  mAppDir = mTools->appDir();#ifndef Q_WS_MAC  // Qt4.3.2/Mac Q3TextEdit readOnly property causes keys to be processed as keyboard actions  mText->setReadOnly(TRUE);#endif  //mText->setFocusPolicy ( QWidget::NoFocus ); // To get key press directly#ifndef HAVE_OPENPTY  mText->append ( "GRASS shell is not supported" );   return;#endif  // TODO set cursor IbeamCursor  // This does not work - the cursor is used for scrollbars -> disabled  //mText->setCursor ( QCursor(Qt::IbeamCursor) );  mParagraph = -1; // first will be 0  mIndex = -1;  mNewLine = true;  for ( int i = 0; i < ModeCount; i++ )  {    resetMode(i);  }  int uid;  seteuid( uid=getuid() );	/* Run unprivileged */  // Get and open pseudo terminal   // Note: 0 (stdin), 1 (stdout) or 2 (stderr)  int fdSlave; // slave file descriptor  seteuid(0);  int ret =  openpty ( &mFdMaster, &fdSlave, NULL, NULL, NULL );  if ( ret != 0 )  {    QMessageBox::warning( 0, "Warning", "Cannot open pseudo terminal" );    return;  }  fchown( fdSlave, uid, (gid_t)-1);  fchmod( fdSlave, S_IRUSR | S_IWUSR);  seteuid(uid);#ifdef QGISDEBUG  std::cerr << "mFdMaster = " << mFdMaster << std::endl;  std::cerr << "fdSlave = " << fdSlave << std::endl;#endif  fcntl( mFdMaster, F_SETFL, O_NDELAY);   //fcntl( fdSlave, F_SETFL, O_NDELAY); // enable?   QString slaveName = ttyname(fdSlave);#ifdef QGISDEBUG  std::cerr << "master ttyname = " << ttyname(mFdMaster)  << std::endl;  std::cerr << "slave ttyname = " << ttyname(fdSlave)  << std::endl;#endif  //close ( fdSlave ); // -> crash    // Fork slave and open shell   int pid = fork();#ifdef QGISDEBUG  std::cerr << "pid = " << pid << std::endl;#endif  if ( pid == -1 )  {    QMessageBox::warning( 0, "Warning", "Cannot fork shell" );    return;  }  // Child - slave  if ( pid == 0 )   {#ifdef QGISDEBUG    std::cerr << "child ->" << std::endl;#endif    // TODO close all opened file descriptors - close(0)???#ifndef Q_OS_DARWIN    // Makes child process unusable on Mac    close ( mFdMaster );#endif    //close ( fdSlave ); // -> freeze      setsid();    seteuid(0);    int fd = open ( (char*) slaveName.ascii(), O_RDWR);    if ( fd < 0 )     {      QMessageBox::warning( 0, "Warning", "Cannot open slave file "        "in child process" );      return;    }    fchown(fd, uid, (gid_t)-1);    fchmod(fd, S_IRUSR | S_IWUSR);    setuid(uid);    dup2 (fd, 0);  /* stdin */    dup2 (fd, 1);  /* stdout */    dup2 (fd, 2);  /* stderr */    // TODO: test if shell is available    QString shell = ( getenv("SHELL") );    if ( shell.isEmpty() )    {      shell = "/bin/bash";    }    const char *norc = "";    QFileInfo si(shell);    if ( si.fileName() ==  "bash" || si.fileName() ==  "sh" )    {       norc = "--norc";    }    else if ( si.fileName() ==  "tcsh" || si.fileName() ==  "csh" )    {       norc = "-f";    }    // Warning: execle + --norc will not inherit not given variables    // -> overwrite here    const char *env = "GRASS_MESSAGE_FORMAT=gui";    char *envstr = new char[strlen(env)+1];    strcpy ( envstr, env );    putenv( envstr );    putenv ( (char *) "GISRC_MODE_MEMORY" );  // unset    env = "PS1=GRASS > ";    envstr = new char[strlen(env)+1];    strcpy ( envstr, env );    putenv( envstr );    env = "TERM=vt100";    envstr = new char[strlen(env)+1];    strcpy ( envstr, env );    putenv( envstr );    //char *envar[] = { "PS1=GRASS > ", "TERM=vt100", "GISRC_MODE_MEMORY=",     //                  "GRASS_MESSAGE_FORMAT=gui", (char *)0 };    //execle ( (char*)shell.ascii(), (char *)si.fileName().ascii(),     //         norc, (char *) 0, envar);    execl ( (char*)shell.ascii(), (char *)si.fileName().ascii(),       norc, (char *) 0);    // Failed (QMessageBox here does not work)    fprintf ( stderr, "GRASS_INFO_ERROR(1,1): Cannot start shell %s\n",       (char*)shell.ascii() );    exit(1);  }  mPid = pid;  // Create socket notifier  mOutNotifier = new QSocketNotifier ( mFdMaster, QSocketNotifier::Read, this);  QObject::connect ( mOutNotifier, SIGNAL(activated(int)),    this, SLOT(readStdout(int)));  // Set tab stops ???  mTabStop.resize(200);  for ( int i = 0 ; i * 8 < (int)mTabStop.size(); i++ )  {    mTabStop[i*8] = true;  }  // Set trap to write history on SIGUSR1  //QString trap = "trap 'history -w' SIGUSR1\015\012";  QString trap = "trap 'history -w' SIGUSR1\015";  write( mFdMaster, trap.ascii(), trap.length());  mText->clear();  resizeTerminal();  mValid = true;#endif // !WIN32}QgsGrassShell::~QgsGrassShell(){#ifdef QGISDEBUG  std::cerr << "QgsGrassShell::~QgsGrassShell()" << std::endl;#endif#ifndef WIN32  // This was old trick to write history  /*  write( mFdMaster, "exit\015\012", 6);  while ( 1 )   {  readStdout(0);  int status;  if ( waitpid ( mPid, &status, WNOHANG ) > 0 ) break;  struct timespec t, r;  t.tv_sec = 0;  t.tv_nsec = 10000000; // 0.01 s  nanosleep ( &t, &r );  }  */  // Write history  if ( kill(mPid,SIGUSR1) == -1 )  {    std::cerr << "cannot write history (signal SIGUSR1 to pid = " << mPid << ")" << std::endl;  }  std::cerr << "kill shell pid = " << mPid << std::endl;  if ( kill(mPid,SIGTERM ) == -1 )  {    std::cerr << "cannot kill shell pid = " << mPid << std::endl;  }#endif}void QgsGrassShell::keyPressEvent( QKeyEvent * e  ){#ifdef QGISDEBUG  std::cerr << "QgsGrassShell::keyPressEvent()" << std::endl;#endif  char s[10];  int length = 0;  int ret = 0;  if ( !mValid ) return;  mProgressBar->setProgress ( 0, 100 );  char c = (char) e->ascii();#ifdef QGISDEBUG  std::cerr << "c = " << (int)c << " key = " << e->key()     << " text = " << e->text().local8Bit().data() << std::endl;#endif  s[0] = c;  length = 1;  // Set key down   if ( e->key() == Qt::Key_Control ) mKeyDown[DownControl] = true;  else if ( e->key() == Qt::Key_Shift ) mKeyDown[DownShift] = true;  else if ( e->key() == Qt::Key_Alt ) mKeyDown[DownAlt] = true;  else if ( e->key() == Qt::Key_Meta ) mKeyDown[DownMeta] = true;  if ( c == 0 )  {    switch ( e->key() )    {    case Qt::Key_Up :      strcpy ( s, "\033[A" );      length = 3;      break;    case Qt::Key_Down :      strcpy ( s, "\033[B" );      length = 3;      break;    case Qt::Key_Right :      strcpy ( s, "\033[C" );      length = 3;      break;    case Qt::Key_Left :      strcpy ( s, "\033[D" );      length = 3;      break;    }  }  ret = write( mFdMaster, s, length);#ifdef QGISDEBUG  std::cerr << "write ret = " << ret << std::endl;#endif}void QgsGrassShell::keyReleaseEvent( QKeyEvent * e  ){#ifdef QGISDEBUG  //    std::cerr << "QgsGrassShell::keyReleaseEvent()" << std::endl;#endif  // Reset key down   if ( e->key() == Qt::Key_Control ) mKeyDown[DownControl] = false;  else if ( e->key() == Qt::Key_Shift ) mKeyDown[DownShift] = false;  else if ( e->key() == Qt::Key_Alt ) mKeyDown[DownAlt] = false;  else if ( e->key() == Qt::Key_Meta ) mKeyDown[DownMeta] = false;}void QgsGrassShell::readStdout( int socket ){#ifdef QGISDEBUG  //std::cerr << "QgsGrassShell::readStdout()" << std::endl;#endif  char buf[4097];  int len;   while ( (len = read( mFdMaster, buf, 4096)) > 0 )  {	    // Terminate string    buf[len] = '\0';    mStdoutBuffer.append ( buf );  }  printStdout();}void QgsGrassShell::printStdout(){  // Debug#ifdef QGISDEBUG  std::cerr << "****** buffer ******" << std::endl;  std::cerr << "-->";  for ( int i = 0; i < (int)mStdoutBuffer.length(); i++ )  {    int c = mStdoutBuffer[i];    QString s = "";    if ( c > '\037' && c != '\177' ) // control characters    {      s = (char) c;      std::cerr << s.local8Bit().data();    }    else    {      std::cerr << "(c=" << QString::number(c,8).local8Bit().data() << ")";    }  }  std::cerr << "<--" << std::endl;#endif  eraseCursor();  // To make it faster we want to print maximum lenght blocks from buffer  while ( mStdoutBuffer.length() > 0 )   {#ifdef QGISDEBUG    std::cerr << "------ cycle ------" << std::endl;#endif    // Search control character    int control = -1;     for ( int i = 0; i < (int)mStdoutBuffer.length(); i++ )    {      int c = mStdoutBuffer[i];      if ( c < '\037' || c == '\177' )      {        control = i;        break;      }    }#ifdef QGISDEBUG    std::cerr << "control = " << control << std::endl;#endif    // Process control character if found at index 0    if ( control == 0 )     {      int c = mStdoutBuffer[0];#ifdef QGISDEBUG      std::cerr << "c = " << QString::number(c,8).local8Bit().data() << std::endl;#endif      // control sequence      if ( c == '\033' )      {        //std::cerr << "control sequence" << std::endl;        bool found = false;        // It is sequence, so it should be at least one more character        // wait for more data         if ( mStdoutBuffer.length() < 2 ) break;        if ( mStdoutBuffer[1] == ']' && mStdoutBuffer.length() < 3 ) break;        // ESC ] Ps ; Pt BEL    (xterm title hack)        QRegExp rx ( "\\](\\d+);([^\\a]+)\\a" );         if ( rx.search ( mStdoutBuffer, 1 ) == 1 )         {          int mlen = rx.matchedLength();#ifdef QGISDEBUG          std::cerr << "ESC(set title): " << rx.cap(2).local8Bit().data() << std::endl;#endif          mStdoutBuffer.remove ( 0, mlen+1 );          found = true;        }        if ( !found )         {          //    ESC [ Pn ; Pn FINAL          // or ESC [ = Pn ; Pn FINAL          // or ESC [ = Pn ; Pn FINAL          // TODO: QRegExp captures only last of repeated patterns 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -