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