]> git.lyx.org Git - lyx.git/blob - src/support/syscall.C
the merge from branch debugstream
[lyx.git] / src / support / syscall.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include <sys/types.h>
8 #include <sys/wait.h>
9 #include <cstdlib>
10 #include <cstdio>
11 #include "debug.h"
12 #include <unistd.h>
13 #include "syscall.h"
14 #include "syscontr.h"
15 #include "support/lstrings.h"
16
17 //----------------------------------------------------------------------
18 // Class, which controlls a system-call
19 //----------------------------------------------------------------------
20
21 // constructor
22 Systemcalls::Systemcalls()
23 {
24         pid = (pid_t) 0; // yet no child
25 }
26
27 // constructor
28 // 
29 // starts child
30 Systemcalls::Systemcalls(Starttype how, string what, Callbackfct cback)
31 {
32         start   = how;
33         command = what;
34         cbk     = cback;
35         pid     = (pid_t) 0; // no child yet
36         retval  = 0;
37         Startscript();
38 }
39
40 // destructor
41 // not yet implemented (?)
42 Systemcalls::~Systemcalls()
43 {
44 }
45
46 // Start a childprocess
47 // 
48 // if child runs in background, add information to global controller.
49
50 int Systemcalls::Startscript()
51 {
52         retval = 0;
53         switch (start) {
54         case System: 
55                 retval = system(command.c_str());
56                 Callback();
57                 break;
58         case Wait:   
59                 pid = Fork();
60                 if (pid>0) { // Fork succesful. Wait for child
61                         waitForChild();
62                         Callback();
63                 } else
64                         retval = 1;
65                 break;
66         case DontWait:
67                 pid=Fork();
68                 if (pid>0) {
69                         // Now integrate into Controller
70                         SystemcallsSingletoncontroller::Startcontroller starter;
71                         SystemcallsSingletoncontroller *contr=
72                                 starter.GetController();
73                         // Add this to contr
74                         contr->AddCall(*this);
75                 } else
76                         retval = 1;
77                 break;
78                 //default:  // error();
79                 //break;
80         }
81         return retval;
82 }
83
84
85 // Wait for child process to finish. Returns returncode from child.
86 void Systemcalls::waitForChild()
87 {
88         // We'll pretend that the child returns 1 on all errorconditions.
89         retval = 1;
90         int status;
91         bool wait = true;
92         while (wait) {
93                 pid_t waitrpid = waitpid(pid, &status, WUNTRACED);
94                 if (waitrpid == -1) {
95                         perror("LyX: Error waiting for child");
96                         wait = false;
97                 } else if (WIFEXITED(status)) {
98                         // Child exited normally. Update return value.
99                         retval = WEXITSTATUS(status);
100                         wait = false;
101                 } else if (WIFSIGNALED(status)) {
102                         lyxerr << "LyX: Child didn't catch signal "
103                                << WTERMSIG(status)
104                                <<" and died. Too bad." << endl;
105                         wait = false;
106                 } else if (WIFSTOPPED(status)) {
107                         lyxerr << "LyX: Child (pid: " << pid
108                                << ") stopped on signal "
109                                << WSTOPSIG(status)
110                                << ". Waiting for child to finish." << endl;
111                 } else {
112                         lyxerr << "LyX: Something rotten happened while "
113                                 "waiting for child "
114                                << pid << endl;
115                         wait = false;
116                 }
117         }
118 }
119
120
121 // generate child in background
122
123 pid_t Systemcalls::Fork()
124 {
125         pid_t cpid=fork();
126         if (cpid == 0) { // child
127                 string childcommand(command); // copy
128                 string rest = split(command, childcommand, ' ');
129                 const int MAX_ARGV = 255;
130                 char *syscmd = 0; 
131                 char *argv[MAX_ARGV];
132                 int  index = 0;
133                 bool Abbruch;
134                 do {
135                         if (syscmd == 0) {
136                                 syscmd = new char[childcommand.length() + 1];
137                                 childcommand.copy(syscmd, childcommand.length());
138                                 syscmd[childcommand.length()] = '\0';
139                         }
140                         char * tmp = new char[childcommand.length() + 1];
141                         childcommand.copy(tmp, childcommand.length());
142                         tmp[childcommand.length()] = '\0';
143                         argv[index++] = tmp;
144                         // reinit
145                         Abbruch = !rest.empty();
146                         if (Abbruch) 
147                                 rest = split(rest, childcommand, ' ');
148                 } while (Abbruch);
149                 argv[index] = 0;
150                 // replace by command. Expand using PATH-environment-var.
151                 execvp(syscmd, argv);
152                 // If something goes wrong, we end up here:
153                 perror("LyX: execvp failed");
154         } else if (cpid < 0) { // error
155                 perror("LyX: Could not fork");
156         } else { // parent
157                 return cpid;
158         }
159         return 0;
160 }
161
162
163 // Reuse of instance
164
165 int Systemcalls::Startscript(Starttype how, string what, Callbackfct cback)
166 {
167         start   = how;
168         command = what;
169         cbk     = cback;
170         pid     = (pid_t) 0; // yet no child
171         retval  = 0;
172         return Startscript();
173 }
174
175
176
177 //
178 // Mini-Test-environment for script-classes
179 //
180 #ifdef TEST_MAIN
181 #include <stdio.h>
182
183
184 int SimulateTimer;
185 void back(string cmd, int retval)
186 {
187         printf("Done: %s gave %d\n", cmd.c_str(), retval);
188         SimulateTimer = 0;
189 }
190
191
192 int main(int, char**)
193 {
194         
195         SystemcallsSingletoncontroller::Startcontroller starter; 
196         SystemcallsSingletoncontroller *contr=starter.GetController();
197         
198         Systemcalls one(Systemcalls::System, "ls -ltag", back);
199         Systemcalls two(Systemcalls::Wait, "ls -ltag", back);
200         SimulateTimer = 1;
201         Systemcalls three(Systemcalls::DontWait , "ls -ltag", back);
202         // Simulation of timer
203         while (SimulateTimer)
204                 {
205                         sleep(1);
206                         contr->Timer();
207                 }
208 }
209 #endif