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