From 3635ff7370f8baa6ce64a62268710d09e3a0a34a Mon Sep 17 00:00:00 2001 From: Asger Ottar Alstrup Date: Tue, 12 Oct 1999 21:37:10 +0000 Subject: [PATCH] - Backported the HTML export feature (Jean-Marc, can configure check for "tth"?) - Cleaned up the systemcall stuff a bit - Better documentation for support/FileInfo.h git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@188 a592a061-630c-0410-9148-cb99ea01b6c8 --- CHANGES | 3 + ChangeLog | 20 +++++++ lib/bind/de_menus.bind | 1 + lib/bind/fr_menus.bind | 1 + lib/bind/hu_menus.bind | 1 + lib/bind/menus.bind | 1 + lib/bind/pt_menus.bind | 1 + lib/bind/sv_menus.bind | 1 + lib/lyxrc.example | 5 ++ src/Chktex.C | 2 +- src/ImportLaTeX.C | 2 +- src/ImportNoweb.C | 2 +- src/LaTeX.C | 6 +- src/Literate.C | 8 +-- src/lyx_cb.C | 12 ++-- src/lyxfunc.C | 22 +++++++ src/lyxrc.h | 2 + src/lyxvc.C | 2 +- src/menus.C | 12 +++- src/support/FileInfo.h | 40 ++++++------- src/support/syscall.C | 114 +++++++++++++++++++++---------------- src/support/syscall.h | 83 ++++++++++++++++++--------- src/support/syscontr.C | 91 +++++++++++++++-------------- src/support/syscontr.h | 35 ++++-------- src/support/syssingleton.C | 24 +++----- 25 files changed, 290 insertions(+), 201 deletions(-) diff --git a/CHANGES b/CHANGES index 59abf348b9..03f5ad47da 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +since 1.0.4 +- New feature: "File->Export->As HTML..." using tth (Asger) + since 1.0.4pre8 - small fix to qoutes in DocBook. (Jose) - blurb about DocBook in LaTeXConfig (Jose) diff --git a/ChangeLog b/ChangeLog index d7a0c93735..f8f15495cb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +1999-10-12 Asger Alstrup Nielsen + + * src/sys*: Cleaned up the Systemcall stuff a bit. Added "kill(int)" + method to the SystemCall class which can kill a process, but it's + not fully implemented yet. + + * src/*.C: Changed Systemcalls::Startscript() to startscript() + + * src/support/FileInfo.h: Better documentation + + * src/lyxfunc.C: Added support for buffer-export html + + * src/menus.C: Added Export->As HTML... + + * lib/bind/*.bind: Added short-cut for buffer-export html + + * src/lyxrc.*: Added support for new \tth_command + + * lib/lyxrc.example: Added stuff for new \tth_command + 1999-10-12 Lars Gullik Bjønnes * src/LaTeX.C: some no-op changes moved declaration of some diff --git a/lib/bind/de_menus.bind b/lib/bind/de_menus.bind index cb494e8f85..b342246e0d 100644 --- a/lib/bind/de_menus.bind +++ b/lib/bind/de_menus.bind @@ -66,6 +66,7 @@ \bind "M-d e p" "buffer-export postscript" \bind "M-d e l" "buffer-export linuxdoc" \bind "M-d e t" "buffer-export ascii" +\bind "M-d e h" "buffer-export html" \bind "M-d e b" "buffer-export custom" \bind "M-d b" "lyx-quit" \bind "M-d space" "menu-open Datei" diff --git a/lib/bind/fr_menus.bind b/lib/bind/fr_menus.bind index 44d73ca0bc..352f04aeeb 100644 --- a/lib/bind/fr_menus.bind +++ b/lib/bind/fr_menus.bind @@ -49,6 +49,7 @@ \bind "M-f x d" "buffer-export dvi" \bind "M-f x p" "buffer-export postscript" \bind "M-f x a" "buffer-export ascii" +\bind "M-f x h" "buffer-export html" \bind "M-f x s" "buffer-export custom" \bind "M-f q" "lyx-quit" \bind "M-f space" "menu-open Fichier" diff --git a/lib/bind/hu_menus.bind b/lib/bind/hu_menus.bind index 707bf27704..b393f434e8 100644 --- a/lib/bind/hu_menus.bind +++ b/lib/bind/hu_menus.bind @@ -44,6 +44,7 @@ \bind "M-f l" "buffer-export latex" \bind "M-f u" "buffer-export linuxdoc" \bind "M-f c" "buffer-export ascii" +\bind "M-f h" "buffer-export html" \bind "M-f s" "buffer-export custom" \bind "M-f k" "lyx-quit" \bind "M-f x" "lyx-quit" diff --git a/lib/bind/menus.bind b/lib/bind/menus.bind index 710ffb40e7..a6fe6a5310 100644 --- a/lib/bind/menus.bind +++ b/lib/bind/menus.bind @@ -48,6 +48,7 @@ \bind "M-f e p" "buffer-export postscript" \bind "M-f e d" "buffer-export linuxdoc" \bind "M-f e t" "buffer-export ascii" +\bind "M-f e h" "buffer-export html" \bind "M-f e m" "buffer-export custom" \bind "M-f x" "lyx-quit" \bind "M-f space" "menu-open File" diff --git a/lib/bind/pt_menus.bind b/lib/bind/pt_menus.bind index ca7695441e..271699285a 100644 --- a/lib/bind/pt_menus.bind +++ b/lib/bind/pt_menus.bind @@ -51,6 +51,7 @@ \bind "M-a e p" "buffer-export postscript" \bind "M-a e d" "buffer-export linuxdoc" \bind "M-a e t" "buffer-export ascii" +\bind "M-a e h" "buffer-export html" \bind "M-a e m" "buffer-export custom" \bind "M-a s" "lyx-quit" \bind "M-a space" "menu-open Arquivo" diff --git a/lib/bind/sv_menus.bind b/lib/bind/sv_menus.bind index ecfd94f5d4..91d97db497 100644 --- a/lib/bind/sv_menus.bind +++ b/lib/bind/sv_menus.bind @@ -53,6 +53,7 @@ \bind "M-f l" "buffer-export latex" \bind "M-f x" "buffer-export linuxdoc" \bind "M-f S-T" "buffer-export ascii" +\bind "M-f h" "buffer-export html" \bind "M-f S-A" "buffer-export custom" \bind "M-f a" "lyx-quit" \bind "M-f space" "menu-open Fil" diff --git a/lib/lyxrc.example b/lib/lyxrc.example index ac0ff7ee75..95f1eeae2f 100644 --- a/lib/lyxrc.example +++ b/lib/lyxrc.example @@ -119,6 +119,11 @@ # Example: use this to ignore warnings about using "\ldots" instead of "..." #\chktex_command "chktex -n11 -n1 -n3 -n6 -n9 -22 -n25 -n30 -n38" +# Define which program to use to run "tth", the LaTeX to HTML converter +# You should include options. The default is "tth -t" +# Example: use this to let math be italic +#\tth_command "tth -t -i" + # If you want to pass extra flags to the LinuxDoc sgml scripts, insert them # here. # Example: the next line activates iso-latin1 support: diff --git a/src/Chktex.C b/src/Chktex.C index 707b0cdc0c..a9925def5d 100644 --- a/src/Chktex.C +++ b/src/Chktex.C @@ -46,7 +46,7 @@ int Chktex::run(TeXErrors &terr) string log = ChangeExtension(file, ".log", true); string tmp = cmd + " -q -v0 -b0 -x " + file + " -o " + log; Systemcalls one; - int result= one.Startscript(Systemcalls::System, tmp); + int result= one.startscript(Systemcalls::System, tmp); if (result == 0) { result = scanLogFile(terr); } else { diff --git a/src/ImportLaTeX.C b/src/ImportLaTeX.C index cddd0d75e5..0a38e96c3c 100644 --- a/src/ImportLaTeX.C +++ b/src/ImportLaTeX.C @@ -42,7 +42,7 @@ Buffer * ImportLaTeX::run() string tmp = lyxrc->relyx_command + " -f " + file; Systemcalls one; Buffer * buf = 0; - int result= one.Startscript(Systemcalls::System, tmp); + int result= one.startscript(Systemcalls::System, tmp); if (result==0) { string filename = ChangeExtension(file, ".lyx", false); // File was generated without problems. Load it. diff --git a/src/ImportNoweb.C b/src/ImportNoweb.C index f366387a4d..66071111e3 100644 --- a/src/ImportNoweb.C +++ b/src/ImportNoweb.C @@ -37,7 +37,7 @@ Buffer * ImportNoweb::run() documentclass() + " -f " + file; Systemcalls one; Buffer * buf = 0; - int result= one.Startscript(Systemcalls::System, tmp); + int result= one.startscript(Systemcalls::System, tmp); if (result==0) { string filename = file + ".lyx"; // File was generated without problems. Load it. diff --git a/src/LaTeX.C b/src/LaTeX.C index a4999fa270..0c8318d91b 100644 --- a/src/LaTeX.C +++ b/src/LaTeX.C @@ -425,7 +425,7 @@ int LaTeX::operator()() string tmp = cmd + ' ' + file + " > nul"; #endif Systemcalls one; - return one.Startscript(Systemcalls::System, tmp); + return one.startscript(Systemcalls::System, tmp); } @@ -442,7 +442,7 @@ bool LaTeX::runMakeIndex(string const &file) string tmp = "makeindex -c -q "; tmp += file; Systemcalls one; - one.Startscript(Systemcalls::System, tmp); + one.startscript(Systemcalls::System, tmp); return true; } @@ -468,7 +468,7 @@ bool LaTeX::runBibTeX(string const &file) string tmp="bibtex "; tmp += ChangeExtension(file, string(), true); Systemcalls one; - one.Startscript(Systemcalls::System, tmp); + one.startscript(Systemcalls::System, tmp); return true; } diff --git a/src/Literate.C b/src/Literate.C index 28e2f886ab..74339838ec 100644 --- a/src/Literate.C +++ b/src/Literate.C @@ -63,8 +63,8 @@ int Literate::weave(TeXErrors &terr, MiniBuffer *minib) // tmp1 = literate_cmd + " < " + litfile + " > " + file + " 2> " + litfile + ".out"; tmp2 = literate_filter + " < " + litfile + ".out" + " > " + litfile + ".log"; - ret1 = one.Startscript(Systemcalls::System, tmp1); - ret2 = two.Startscript(Systemcalls::System, tmp2); + ret1 = one.startscript(Systemcalls::System, tmp1); + ret2 = two.startscript(Systemcalls::System, tmp2); lyxerr.debug() << "LITERATE {" << tmp1 << "} {" << tmp2 << "}" << endl; scanres = scanLiterateLogFile(terr); if (scanres & Literate::ERRORS) return scanres; // return on literate error @@ -96,8 +96,8 @@ int Literate::build(TeXErrors &terr, MiniBuffer *minib) // tmp1 = build_cmd + ' ' + litfile + " > " + litfile + ".out 2>&1"; tmp2 = build_filter + " < " + litfile + ".out" + " > " + litfile + ".log"; - ret1 = one.Startscript(Systemcalls::System, tmp1); - ret2 = two.Startscript(Systemcalls::System, tmp2); + ret1 = one.startscript(Systemcalls::System, tmp1); + ret2 = two.startscript(Systemcalls::System, tmp2); scanres = scanBuildLogFile(terr); lyxerr[Debug::LATEX] << "Done." << endl; diff --git a/src/lyx_cb.C b/src/lyx_cb.C index 8b9c11a6cb..4e9e78d556 100644 --- a/src/lyx_cb.C +++ b/src/lyx_cb.C @@ -616,10 +616,10 @@ bool RunScript(Buffer *buffer, bool wait, #warning What should we do here? #endif minibuffer->Set(_("Executing command:"), cmd); - result = one.Startscript(Systemcalls::System, cmd); + result = one.startscript(Systemcalls::System, cmd); } else { minibuffer->Set(_("Executing command:"), cmd); - result = one.Startscript(wait ? Systemcalls::Wait + result = one.startscript(wait ? Systemcalls::Wait : Systemcalls::DontWait, cmd); } PathPop(); @@ -1277,21 +1277,21 @@ int RunLinuxDoc(int flag, string const & filename) MakeDisplayPath(filename), "'..."); s2 = "sgml2lyx " + lyxrc->sgml_extra_options + ' ' + name; - if (one.Startscript(Systemcalls::System, s2)) + if (one.startscript(Systemcalls::System, s2)) errorcode = 1; break; case 0: /* TeX output asked */ minibuffer->Set(_("Converting LinuxDoc SGML to TeX file...")); s2 = "sgml2latex " + add_flags + " -o tex " + lyxrc->sgml_extra_options + ' ' + name; - if (one.Startscript(Systemcalls::System, s2)) + if (one.startscript(Systemcalls::System, s2)) errorcode = 1; break; case 1: /* dvi output asked */ minibuffer->Set(_("Converting LinuxDoc SGML to dvi file...")); s2 = "sgml2latex " + add_flags + " -o dvi " + lyxrc->sgml_extra_options + ' ' + name; - if (one.Startscript(Systemcalls::System, s2)) { + if (one.startscript(Systemcalls::System, s2)) { errorcode = 1; } else current_view->currentBuffer()->markDviClean(); @@ -1348,7 +1348,7 @@ int RunDocBook(int flag, string const & filename) case 1: /* dvi output asked */ minibuffer->Set(_("Converting DocBook SGML to dvi file...")); s2 = "sgmltools --backend dvi " + name; - if (one.Startscript(Systemcalls::System, s2)) { + if (one.startscript(Systemcalls::System, s2)) { errorcode = 1; } else current_view->currentBuffer()->markDviClean(); diff --git a/src/lyxfunc.C b/src/lyxfunc.C index 3b9897713f..78db42d0cf 100644 --- a/src/lyxfunc.C +++ b/src/lyxfunc.C @@ -58,6 +58,7 @@ #include "trans_mgr.h" #include "ImportLaTeX.h" #include "ImportNoweb.h" +#include "support/syscall.h" extern bool cursor_follows_scrollbar; @@ -730,6 +731,27 @@ string LyXFunc::Dispatch(int ac, MenuSendto(); break; } + // HTML + else if (extyp == "html") { + // First, create LaTeX file + MenuMakeLaTeX(owner->currentBuffer()); + + // And now, run tth + string file = owner->currentBuffer()->getFileName(); + file = ChangeExtension(file, ".tex", false); + string result = ChangeExtension(file, ".html", false); + string tmp = lyxrc->tth_command + " < " + file + + " > " + result ; + Systemcalls one; + int res = one.startscript(Systemcalls::System, tmp); + if (res == 0) { + setMessage(string( + N_("Document exported as HTML to file: ")) + result); + } else { + setErrorMessage(string( + N_("An unexpected error occured while converting document to HTML in file:")) + result); + } + } else { setErrorMessage(string(N_("Unknown export type: ")) + extyp); diff --git a/src/lyxrc.h b/src/lyxrc.h index df45383962..e3147cfb90 100644 --- a/src/lyxrc.h +++ b/src/lyxrc.h @@ -98,6 +98,8 @@ public: LYX_PAPER_SIZE default_papersize; /// command to run chktex incl. options string chktex_command; + /// command to run tth incl. options + string tth_command; /// string sgml_extra_options; /// diff --git a/src/lyxvc.C b/src/lyxvc.C index f1430b693c..70f361c3be 100644 --- a/src/lyxvc.C +++ b/src/lyxvc.C @@ -386,7 +386,7 @@ int LyXVC::doVCCommand(string const & cmd) lyxerr[Debug::LYXVC] << "doVCCommand: " << cmd << endl; Systemcalls one; PathPush(_owner->filepath); - int ret = one.Startscript(Systemcalls::System, cmd); + int ret = one.startscript(Systemcalls::System, cmd); PathPop(); return ret; } diff --git a/src/menus.C b/src/menus.C index f582e2185f..3cbf155a69 100644 --- a/src/menus.C +++ b/src/menus.C @@ -423,7 +423,8 @@ void Menus::ShowFileMenu(FL_OBJECT *ob, long) "|as DVI...%x41" "|as PostScript...%x42" "|as Ascii Text...%x43" - "|Custom...%x44")); + "|as HTML...%x44" + "|Custom...%x45")); else if(LinuxDoc) SubFileExport=fl_defpup(FL_ObjWin(ob), _("Export%t" @@ -443,7 +444,10 @@ void Menus::ShowFileMenu(FL_OBJECT *ob, long) fl_setpup_shortcut(SubFileExport, 41, scex(_("FEX|Dd#d#D"))); fl_setpup_shortcut(SubFileExport, 42, scex(_("FEX|Pp#p#P"))); fl_setpup_shortcut(SubFileExport, 43, scex(_("FEX|Tt#t#T"))); - fl_setpup_shortcut(SubFileExport, 44, scex(_("FEX|mM#m#M"))); + if (!LinuxDoc && !DocBook) { + fl_setpup_shortcut(SubFileExport, 44, scex(_("FEX|Hh#h#H"))); + fl_setpup_shortcut(SubFileExport, 45, scex(_("FEX|mM#m#M"))); + } int FileMenu = fl_defpup(FL_ObjWin(ob), _("New..." @@ -592,7 +596,9 @@ void Menus::ShowFileMenu(FL_OBJECT *ob, long) break; case 43: tmpfunc->Dispatch(LFUN_EXPORT, "ascii"); break; - case 44: tmpfunc->Dispatch(LFUN_EXPORT, "custom"); + case 44: tmpfunc->Dispatch(LFUN_EXPORT, "html"); + break; + case 45: tmpfunc->Dispatch(LFUN_EXPORT, "custom"); break; case 17: tmpfunc->Dispatch(LFUN_QUIT); break; // Lastfiles: diff --git a/src/support/FileInfo.h b/src/support/FileInfo.h index 69ea2a3616..4eeea35899 100644 --- a/src/support/FileInfo.h +++ b/src/support/FileInfo.h @@ -31,28 +31,28 @@ public: the file that is obtained by tracing the links. */ FileInfo(string const & path, bool link = false); - /// + /// File descriptor FileInfo(int fildes); /// ~FileInfo(); - /// + /// Query a new file FileInfo& newFile(string const & path, bool link = false); - /// + /// Query a new file descriptor FileInfo& newFile(int fildes); - /// returns a character describing file type (ls -F) + /// Returns a character describing file type (ls -F) char const * typeIndicator() const; - /// + /// File protection mode mode_t getMode() const; - /// + /// Get "preferred" block size for efficient file system I/O long getBlockSize() const; - /// constructs standard mode string (ls style) + /// Constructs standard mode string (ls style) void modeString(char * szString) const; /// returns a letter describing a file type (ls style) @@ -73,34 +73,37 @@ public: /// time_t getStatusChangeTime() const; - /// + /// Total file size in bytes off_t getSize() const; - /// + /// Number of hard links nlink_t getNumberOfLinks() const; - /// + /// User ID of owner uid_t getUid() const; - /// + + /// Group ID of owner gid_t getGid() const; - /// + + /// Is the file information correct? Did the query succeed? bool isOK() const; - /// + + /// Permission flags enum perm_test { rperm = R_OK, // test for read permission wperm = W_OK, // test for write permission xperm = X_OK, // test for execute (search) permission eperm = F_OK // test for existence of file }; - /// + /// Test whether the current user has a given set of permissions bool access(int p); - /// + /// Is the file writable for the current user? bool writable() { return access(FileInfo::wperm); } - /// + /// Is the file readable for the current user? bool readable() { return access(FileInfo::rperm); } - /// + /// Is the file executable for the current user? bool executable() { return access(FileInfo::xperm); } - /// + /// Does the file exist? bool exist() { return access(FileInfo::eperm); } /// bool isLink() const; @@ -139,4 +142,3 @@ private: }; #endif - diff --git a/src/support/syscall.C b/src/support/syscall.C index e30722459f..c5c99eadea 100644 --- a/src/support/syscall.C +++ b/src/support/syscall.C @@ -4,87 +4,101 @@ #pragma implementation #endif +#include #include #include +#include #include #include -#include "debug.h" #include +#include "debug.h" #include "syscall.h" #include "syscontr.h" #include "support/lstrings.h" -//---------------------------------------------------------------------- -// Class, which controlls a system-call -//---------------------------------------------------------------------- - -// constructor -Systemcalls::Systemcalls() -{ - pid = (pid_t) 0; // yet no child +Systemcalls::Systemcalls() { + pid = (pid_t) 0; // No child yet } -// constructor -// -// starts child -Systemcalls::Systemcalls(Starttype how, string what, Callbackfct cback) +Systemcalls::Systemcalls(Starttype how, string const & what, Callbackfct cback) { start = how; command = what; cbk = cback; - pid = (pid_t) 0; // no child yet + pid = (pid_t) 0; retval = 0; - Startscript(); + startscript(); } -// destructor -// not yet implemented (?) -Systemcalls::~Systemcalls() -{ +Systemcalls::~Systemcalls() { +#if 0 + // If the child is alive, we have to brutally kill it + if (getpid() != 0) { + ::kill(getpid(), SIGKILL); + } +#endif } // Start a childprocess // // if child runs in background, add information to global controller. -int Systemcalls::Startscript() -{ +int Systemcalls::startscript() { retval = 0; switch (start) { case System: retval = system(command.c_str()); - Callback(); + callback(); break; case Wait: - pid = Fork(); + pid = fork(); if (pid>0) { // Fork succesful. Wait for child waitForChild(); - Callback(); + callback(); } else retval = 1; break; case DontWait: - pid=Fork(); + pid = fork(); if (pid>0) { // Now integrate into Controller SystemcallsSingletoncontroller::Startcontroller starter; - SystemcallsSingletoncontroller *contr= - starter.GetController(); - // Add this to contr - contr->AddCall(*this); + SystemcallsSingletoncontroller * contr = starter.getController(); + // Add this to controller + contr->addCall(*this); } else retval = 1; break; - //default: // error(); - //break; } return retval; } +void Systemcalls::kill(int tolerance) { + if (getpid() == 0) { + lyxerr << "LyX: Can't kill non-existing process." << endl; + return; + } + int ret = ::kill(getpid(), SIGHUP); + bool wait_for_death = true; + if (ret != 0) { + if (errno == ESRCH) { + // The process is already dead! + wait_for_death = false; + } else { + // Something is rotten - maybe we lost permissions? + } + } + if (wait_for_death) { + // Here, we should add the PID to a list of + // waiting processes to kill if they are not + // dead without tolerance seconds +#warning Implement this using the timer of the singleton systemcontroller (Asger) + } +} + // Wait for child process to finish. Returns returncode from child. -void Systemcalls::waitForChild() -{ +void Systemcalls::waitForChild() { // We'll pretend that the child returns 1 on all errorconditions. retval = 1; int status; @@ -92,7 +106,7 @@ void Systemcalls::waitForChild() while (wait) { pid_t waitrpid = waitpid(pid, &status, WUNTRACED); if (waitrpid == -1) { - perror("LyX: Error waiting for child"); + lyxerr << "LyX: Error waiting for child:" << strerror(errno) << endl; wait = false; } else if (WIFEXITED(status)) { // Child exited normally. Update return value. @@ -100,18 +114,17 @@ void Systemcalls::waitForChild() wait = false; } else if (WIFSIGNALED(status)) { lyxerr << "LyX: Child didn't catch signal " - << WTERMSIG(status) - <<" and died. Too bad." << endl; + << WTERMSIG(status) + << "and died. Too bad." << endl; wait = false; } else if (WIFSTOPPED(status)) { - lyxerr << "LyX: Child (pid: " << pid + lyxerr << "LyX: Child (pid: " << pid << ") stopped on signal " - << WSTOPSIG(status) + << WSTOPSIG(status) << ". Waiting for child to finish." << endl; } else { lyxerr << "LyX: Something rotten happened while " - "waiting for child " - << pid << endl; + "waiting for child " << pid << endl; wait = false; } } @@ -120,9 +133,9 @@ void Systemcalls::waitForChild() // generate child in background -pid_t Systemcalls::Fork() +pid_t Systemcalls::fork() { - pid_t cpid=fork(); + pid_t cpid= ::fork(); if (cpid == 0) { // child string childcommand(command); // copy string rest = split(command, childcommand, ' '); @@ -130,7 +143,7 @@ pid_t Systemcalls::Fork() char *syscmd = 0; char *argv[MAX_ARGV]; int index = 0; - bool Abbruch; + bool more; do { if (syscmd == 0) { syscmd = new char[childcommand.length() + 1]; @@ -142,17 +155,17 @@ pid_t Systemcalls::Fork() tmp[childcommand.length()] = '\0'; argv[index++] = tmp; // reinit - Abbruch = !rest.empty(); - if (Abbruch) + more = !rest.empty(); + if (more) rest = split(rest, childcommand, ' '); - } while (Abbruch); + } while (more); argv[index] = 0; // replace by command. Expand using PATH-environment-var. execvp(syscmd, argv); // If something goes wrong, we end up here: - perror("LyX: execvp failed"); + lyxerr << "LyX: execvp failed: " << strerror(errno) << endl; } else if (cpid < 0) { // error - perror("LyX: Could not fork"); + lyxerr << "LyX: Could not fork: " << strerror(errno) << endl; } else { // parent return cpid; } @@ -162,14 +175,15 @@ pid_t Systemcalls::Fork() // Reuse of instance -int Systemcalls::Startscript(Starttype how, string what, Callbackfct cback) +int Systemcalls::startscript(Starttype how, string const & what, + Callbackfct cback) { start = how; command = what; cbk = cback; pid = (pid_t) 0; // yet no child retval = 0; - return Startscript(); + return startscript(); } diff --git a/src/support/syscall.h b/src/support/syscall.h index 37617279a7..11c28fc58d 100644 --- a/src/support/syscall.h +++ b/src/support/syscall.h @@ -1,78 +1,105 @@ // -*- C++ -*- #include -#include + +#include "LString.h" #ifdef __GNUG__ #pragma interface #endif +/** + This class can be used to start child processes. -/*@Doc: - Instance starts and represents childprocesses. + An instance of the class represents a child process. You should use this class if you need to start an external program in LyX. - You can start a child in the background and have a callback function - executed when the child finishes by using the DontWait starttype. + If you wish, you can have a callback function executed when the process + finishes. + You can chose between three kinds of child processes: + 1) System processes, which are initiated with the "system" call, + where the main thread waits for the system call to return. + 2) Wait for child process, which are forked, but the main thread waits for + the child to end. + 3) Don't wait, which are forked, but the main thread is not stopped. + The process can be considered a background process. + A timer will make sure that any callback function is called when + the child process ends. + + Notice that any callback associated with a process is called whatever + the kind of child process. */ class Systemcalls { public: /// enum Starttype { - System, - Wait, - DontWait + System, // Uses system() which uses /bin/sh + Wait, // Uses fork() and execvp() + DontWait // Uses fork() and execvp() }; - /// Callback function gets commandline and returnvalue from child + /// Callback function gets commandline and return value from child typedef void (*Callbackfct)(string cmd, int retval); /// Systemcalls(); - /** Geberate instance and start childprocess + /** Generate instance and start child process. The string "what" contains a commandline with arguments separated by spaces. When the requested program finishes, the callback-function is - called with the commandline and the returnvalue from the program. - The instance is automatically added to a timercheck if starttype is - DontWait (i.e. background execution). When a background child - finishes, the timercheck will automatically call the callback + called with the commandline and the return value from the program. + The instance is automatically added to a timer check if starttype + is DontWait (i.e. background execution). When a background child + finishes, the timer check will automatically call the callback function. */ - Systemcalls(Starttype how, string what, Callbackfct call = 0); - + Systemcalls(Starttype how, string const & what, Callbackfct call = 0); /// ~Systemcalls(); - /** Start childprocess. what contains a command on systemlevel. + /** Start childprocess. "what" contains a command at system level. + * This is for reuse of the Systemcalls instance. */ - int Startscript(Starttype how, string what, Callbackfct call = 0); // for reuse + int startscript(Starttype how, string const & what, + Callbackfct call = 0); /** gets PID of childprocess. Used by timer */ - inline pid_t Getpid() { return pid; } + pid_t getpid() { return pid; } /// Start callback - inline void Callback() { if (cbk) cbk(command, retval); } - + void callback() { if (cbk) cbk(command, retval); } + /** Set return value. Used by timer */ - inline void setRetValue(int r) { retval = r; } + void setRetValue(int r) { retval = r; } + + /** Kill child prematurely. + First, a SIGHUP is sent to the child. + If that does not end the child process within "tolerance" + seconds, the SIGKILL signal is sent to the child. + When the child is dead, the callback is called. + */ + void kill(int tolerance = 5); private: /// Type of execution: system, wait for child or background - Starttype start; + Starttype start; + /// Callback function - Callbackfct cbk; + Callbackfct cbk; + /// Commmand line - string command; + string command; + /// Process ID of child - pid_t pid; + pid_t pid; + /// Return value from child int retval; /// - int Startscript(); + int startscript(); /// - pid_t Fork(); + pid_t fork(); /// Wait for child process to finish. Updates returncode from child. void waitForChild(); diff --git a/src/support/syscontr.C b/src/support/syscontr.C index 8c0bc960c9..51c903a2e0 100644 --- a/src/support/syscontr.C +++ b/src/support/syscontr.C @@ -1,62 +1,59 @@ #include +#include #include #include #include #include "syscontr.h" #include "syscall.h" +#include "debug.h" #ifdef __GNUG__ #pragma implementation #endif -//---------------------------------------------------------------------- -// Controller-Implementation -//---------------------------------------------------------------------- // -// default contstructor +// Default constructor // SystemcallsSingletoncontroller::SystemcallsSingletoncontroller() { - SysCalls = 0; + sysCalls = 0; } // -// destructor +// Destructor // // destroy structs for leaving program -// open question: should we stop here childs? +// open question: should we stop childs here? // Asger says no: I like to have my xdvi open after closing LyX. Maybe // I want to print or something. SystemcallsSingletoncontroller::~SystemcallsSingletoncontroller() { ControlledCalls *next; - while (SysCalls) + while (sysCalls) { - next = SysCalls->next; - delete SysCalls; - SysCalls = next; + next = sysCalls->next; + delete sysCalls; + sysCalls = next; } } // -// Add childprocessinformation into controlled list +// Add child process information into controlled list // void -SystemcallsSingletoncontroller::AddCall(Systemcalls const &newcall) -{ -// not yet implemented - ControlledCalls *newCall = new ControlledCalls; +SystemcallsSingletoncontroller::addCall(Systemcalls const &newcall) { + ControlledCalls * newCall = new ControlledCalls; if (newCall == 0) // sorry, no idea return; - newCall->next = SysCalls; + newCall->next = sysCalls; newCall->call = new Systemcalls(newcall); - SysCalls = newCall; + sysCalls = newCall; } // @@ -66,33 +63,43 @@ SystemcallsSingletoncontroller::AddCall(Systemcalls const &newcall) // void -SystemcallsSingletoncontroller::Timer() -{ +SystemcallsSingletoncontroller::timer() { // check each entry of our list, if it's finished ControlledCalls *prev = 0; - for (ControlledCalls *actCall=SysCalls; actCall; actCall=actCall->next) - { - pid_t pid=actCall->call->Getpid(); - int stat_loc; - waitpid(pid, &stat_loc, WNOHANG); - if (WIFEXITED(stat_loc) || WIFSIGNALED(stat_loc)) { + for (ControlledCalls *actCall=sysCalls; actCall; actCall=actCall->next) + { + pid_t pid=actCall->call->getpid(); + int stat_loc; + int waitrpid = waitpid(pid, &stat_loc, WNOHANG); + if (waitrpid == -1) { + lyxerr << "LyX: Error waiting for child:" + << strerror(errno) << endl; + } else if (WIFEXITED(stat_loc) || WIFSIGNALED(stat_loc)) { + if (WIFEXITED(stat_loc)) { // Ok, the return value goes into retval. - if (WIFEXITED(stat_loc)) { - actCall->call->setRetValue(WEXITSTATUS(stat_loc)); - } else { - // Child died, so pretend it returned 1 - actCall->call->setRetValue(1); - } - // callback and release - actCall->call->Callback(); - if (actCall == SysCalls) { - SysCalls = actCall->next; - } else { - prev->next = actCall->next; - } - delete actCall; - actCall = prev; + actCall->call->setRetValue(WEXITSTATUS(stat_loc)); + } else { + // Child died, so pretend it returned 1 + actCall->call->setRetValue(1); } - prev = actCall; + // Callback and release + actCall->call->callback(); + if (actCall == sysCalls) { + sysCalls = actCall->next; + } else { + prev->next = actCall->next; + } + delete actCall; + actCall = prev; + } else if (WIFSTOPPED(stat_loc)) { + lyxerr << "LyX: Child (pid: " << pid + << ") stopped on signal " + << WSTOPSIG(stat_loc) + << ". Waiting for child to finish." << endl; + } else { + lyxerr << "LyX: Something rotten happened while " + "waiting for child " << pid << endl; } + prev = actCall; + } } diff --git a/src/support/syscontr.h b/src/support/syscontr.h index 02ae8bdb6f..4080b9b0a9 100644 --- a/src/support/syscontr.h +++ b/src/support/syscontr.h @@ -9,42 +9,27 @@ class Systemcalls; -/// -class SystemcallsSingletoncontroller{ +class SystemcallsSingletoncontroller { public: - /// - class Startcontroller{ + class Startcontroller { public: - /// Startcontroller(); - /// ~Startcontroller(); - /// - static SystemcallsSingletoncontroller *GetController(); - /// - void ReduceRefcount() { refcount--; } + static SystemcallsSingletoncontroller * getController(); + void reduceRefcount() { refcount--; } private: - /// - static SystemcallsSingletoncontroller *contr; - /// + static SystemcallsSingletoncontroller * contr; static int refcount; }; - /// ~SystemcallsSingletoncontroller(); - /// - void AddCall(Systemcalls const &newcall); - /// - void Timer(); + void addCall(Systemcalls const & newcall); + void timer(); // private: // DEC cxx does not like that (JMarc) - /// SystemcallsSingletoncontroller(); private: - /// struct ControlledCalls { - /// Systemcalls *call; - /// - ControlledCalls *next; }; - /// - ControlledCalls *SysCalls; + ControlledCalls *next; + }; + ControlledCalls * sysCalls; }; diff --git a/src/support/syssingleton.C b/src/support/syssingleton.C index a3553c6345..926f583cc1 100644 --- a/src/support/syssingleton.C +++ b/src/support/syssingleton.C @@ -1,8 +1,5 @@ #include -#include -#include -#include #include "syscontr.h" @@ -19,30 +16,23 @@ contr = 0; int SystemcallsSingletoncontroller::Startcontroller:: refcount = 0; -// default constructor. -// Nothing to do at moment. SystemcallsSingletoncontroller::Startcontroller:: -Startcontroller() -{ +Startcontroller() { } -// default destructor. -// Nothing to do at moment SystemcallsSingletoncontroller::Startcontroller:: -~Startcontroller() -{ +~Startcontroller() { } // Give reference to global controller-instance // SystemcallsSingletoncontroller * -SystemcallsSingletoncontroller::Startcontroller:: -GetController() +SystemcallsSingletoncontroller::Startcontroller::getController() { - if (! contr) - { // generate the global controller - contr = new SystemcallsSingletoncontroller; - } + if (!contr) { + // Create the global controller + contr = new SystemcallsSingletoncontroller; + } refcount++; return contr; }