[KLF Backend][KLF Tools][KLF Home]
KLatexFormula Project
klfblockprocess.cpp
1 /***************************************************************************
2  * file klfblockprocess.cpp
3  * This file is part of the KLatexFormula Project.
4  * Copyright (C) 2011 by Philippe Faist
5  * philippe.faist@bluewin.ch
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the *
19  * Free Software Foundation, Inc., *
20  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  ***************************************************************************/
22 /* $Id: klfblockprocess.cpp 1013 2017-02-07 03:02:14Z phfaist $ */
23 
24 #include <QProcess>
25 #include <QCoreApplication>
26 #include <QEventLoop>
27 #include <QFile>
28 #include <QThread>
29 
30 #include <klfutil.h>
31 #include <klfsysinfo.h>
32 #include "klfblockprocess.h"
33 
34 static bool is_binary_file(QString fn)
35 {
36  klfDbg("is_binary_file("<<fn<<")") ;
37  if (!QFile::exists(fn)) {
38  fn = klfSearchPath(fn);
39  klfDbg("is_binary_file: file doesn't exist directly, path search gave "<<fn) ;
40  }
41  QFile fpeek(fn);
42  if (!fpeek.open(QIODevice::ReadOnly)) {
43  klfDbg("fn="<<fn<<", Can't peek into file "<<fn<<"!") ;
44  return true; // assumption by default
45  }
46  QByteArray line;
47  int n = 0, j;
48  while (n++ < 5 && (line = fpeek.readLine(1024)).size()) {
49  for (j = 0; j < line.size(); ++j) {
50  if ((int)line[j] >= 127 || (int)line[j] <= 0) {
51  klfDbg("fn="<<fn<<" found binary char '"<<(char)line[j]<<"'=="<<(int)line[j]
52  <<" on line "<<n<<", column "<< j) ;
53  return true;
54  }
55  }
56  }
57  klfDbg("fn="<<fn<<", file seems to be ascii based on the first few lines") ;
58  return false;
59 }
60 
61 #if defined(Q_OS_WIN)
62 const static QString script_extra_paths = QString("C:\\Python27;C:\\Python*");
63 const static QString exe_suffix = ".exe";
64 #elif defined(Q_OS_MAC)
65 const static QString script_extra_paths =
66  "/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin" // general unix
67  "/usr/local/opt/*/bin:/opt/local/bin:" // homebrew
68  "/opt/local/sbin" // macports
69  "/Library/TeX/texbin:/usr/texbin"; // mactex binaries
70 const static QString exe_suffix = "";
71 #else
72 const static QString script_extra_paths =
73  "/usr/bin:/bin:/usr/local/bin:/usr/sbin:/sbin:/usr/local/sbin"; // general unix paths
74 const static QString exe_suffix = "";
75 #endif
76 
77 
78 // static
79 QString KLFBlockProcess::detectInterpreterPath(const QString& interp, const QStringList & addpaths)
80 {
81  QString search_paths = script_extra_paths;
82  search_paths += addpaths.join(KLF_PATH_SEP);
83  // first, try exact name (python.exe, bash.exe)
84  QString s = klfSearchPath(interp+exe_suffix, script_extra_paths);
85  if (!s.isEmpty()) {
86  return s;
87  }
88  // otherwise, try name with some suffix (e.g. python2.exe) -- dont directly try with
89  // wildcard, because we want the exact name if it exists (and not some other program,
90  // such as 'bashbug', which happened to be found first)
91  return klfSearchPath(interp+"*"+exe_suffix, script_extra_paths);
92 }
93 
94 
95 
96 
98  : QProcess(p)
99 {
100  mProcessAppEvents = true;
101  connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(ourProcExited()));
102 }
103 
104 
106 {
107 }
108 
109 void KLFBlockProcess::ourProcGotOurStdinData()
110 {
111 }
112 
113 void KLFBlockProcess::ourProcExited()
114 {
115  _runstatus = 1; // exited
116 }
117 
119 {
121  klfDbg("ext = " << ext) ;
122  if (ext == "py") {
123  return detectInterpreterPath("python");
124  } else if (ext == "sh") {
125  return detectInterpreterPath("bash");
126  } else if (ext == "rb") {
127  return detectInterpreterPath("ruby");
128  }
129  return QString();
130 }
131 
133 {
134  return startProcess(cmd, QByteArray(), env);
135 }
136 
138 {
139  klfDbg("Running: "<<cmd<<", stdindata/size="<<stdindata.size());
140 
141  _runstatus = 0;
142 
143  KLF_ASSERT_CONDITION(cmd.size(), "Empty command list given.", return false;) ;
144 
145  // For scripts, use the interpreter explicitly. This so that the script doesn't have to
146  // be executable, and also for an old bug on Ubuntu with epstopdf.
147  //
148  // We peek into executable to see if it is script. If it is, use the correct interpreter.
149 
150  if (!is_binary_file(cmd[0])) {
151  // check what script type it is and invoke the corresponding interpreter.
152  QString ext = cmd[0].split('.').last();
153  QByteArray exec_proc = getInterpreterPath(ext).toLocal8Bit();
154  if (exec_proc.size()) {
155  cmd.prepend(exec_proc);
156  }
157  }
158 
159  QString program = cmd[0];
160 
161  klfDbg("Running cmd="<<cmd);
162  klfDbg("env="<<env<<", curenv="<<environment());
163 
164  if (env.size() > 0) {
165  setEnvironment(env);
166  }
167 
168  QStringList args = cmd;
169  args.erase(args.begin());
170  klfDbg("Starting "<<program<<", "<<args) ;
171  start(program, args);
172  if ( ! waitForStarted() ) {
173  klfDbg("Can't wait for started! Error="<<error()) ;
174  return false;
175  }
176 
177  write(stdindata.constData(), stdindata.size());
179 
180  klfDbg("wrote input data (size="<<stdindata.size()<<")") ;
181 
182  if (mProcessAppEvents) {
183  klfDbg("letting current thread (="<<QThread::currentThread()<<") process events ...") ;
184  while (_runstatus == 0) {
185  QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1000);
186  klfDbg("events processed, maybe more?") ;
187  }
188  } else {
189  if (!waitForFinished()) {
190  klfDbg("Can't wait for finished!");
191  return false;
192  }
193  }
194  klfDbg("Process should have finished now.");
195 
196  if (_runstatus < 0) { // some error occurred somewhere
197  klfDbg("some error occurred, _runstatus="<<_runstatus) ;
198  return false;
199  }
200 
201  return true;
202 }
203 
Defines the KLFBlockProcess class.
QString program() const
virtual QString getInterpreterPath(const QString &ext)
The interpter path to use for the given extension.
QProcess::ProcessError error() const
KLF_EXPORT QString klfSearchPath(const QString &programName, const QString &extra_path)
#define klfDbg(streamableItems)
#define KLF_DEBUG_BLOCK(msg)
iterator erase(iterator pos)
QString join(const QString &separator) const
bool exists() const
int size() const
void processEvents(QEventLoop::ProcessEventsFlags flags)
bool isEmpty() const
const char * constData() const
void finished(int exitCode)
QByteArray toLocal8Bit() const
#define KLF_FUNC_NAME
bool waitForStarted(int msecs)
bool startProcess(QStringList cmd, QByteArray stdindata, QStringList env=QStringList())
KLFBlockProcess(QObject *parent=0)
void setEnvironment(const QStringList &environment)
QThread * currentThread()
T & last()
qint64 write(const char *data, qint64 maxSize)
void prepend(const T &value)
#define KLF_ASSERT_CONDITION(expr, msg, failaction)
QStringList environment() const
int size() const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void closeWriteChannel()
iterator begin()
void start(const QString &program, const QStringList &arguments, OpenMode mode)
bool waitForFinished(int msecs)

Generated by doxygen 1.8.13