9b88b7ff29568bf519cf0d5912520f35dae0ebb9
[p5sagit/p5-mst-13.2.git] / os2 / os2.c
1 #define INCL_DOS
2 #define INCL_NOPM
3 #ifndef NO_SYS_ALLOC 
4 #  define INCL_DOSMEMMGR
5 #  define INCL_DOSERRORS
6 #endif /* ! defined NO_SYS_ALLOC */
7 #include <os2.h>
8
9 /*
10  * Various Unix compatibility functions for OS/2
11  */
12
13 #include <stdio.h>
14 #include <errno.h>
15 #include <limits.h>
16 #include <process.h>
17
18 #include "EXTERN.h"
19 #include "perl.h"
20
21 /*****************************************************************************/
22 /* priorities */
23
24 int setpriority(int which, int pid, int val)
25 {
26   return DosSetPriority((pid < 0) ? PRTYS_PROCESSTREE : PRTYS_PROCESS,
27                         val >> 8, val & 0xFF, abs(pid));
28 }
29
30 int getpriority(int which /* ignored */, int pid)
31 {
32   TIB *tib;
33   PIB *pib;
34   DosGetInfoBlocks(&tib, &pib);
35   return tib->tib_ptib2->tib2_ulpri;
36 }
37
38 /*****************************************************************************/
39 /* spawn */
40
41 static int
42 result(int flag, int pid)
43 {
44         int r, status;
45         Signal_t (*ihand)();     /* place to save signal during system() */
46         Signal_t (*qhand)();     /* place to save signal during system() */
47
48         if (pid < 0 || flag != 0) 
49                 return pid;
50
51         ihand = signal(SIGINT, SIG_IGN);
52         qhand = signal(SIGQUIT, SIG_IGN);
53         do {
54             r = wait4pid(pid, &status, 0);
55         } while (r == -1 && errno == EINTR);
56         signal(SIGINT, ihand);
57         signal(SIGQUIT, qhand);
58
59         statusvalue = (U16)status;
60         if (r < 0)
61                 return -1;
62         return status & 0xFFFF;
63 }
64
65 int
66 do_aspawn(really,mark,sp)
67 SV *really;
68 register SV **mark;
69 register SV **sp;
70 {
71     register char **a;
72     char *tmps;
73     int rc;
74     int flag = P_WAIT, trueflag;
75
76     if (sp > mark) {
77         New(401,Argv, sp - mark + 1, char*);
78         a = Argv;
79
80         if (mark < sp && SvIOKp(*(mark+1))) {
81                 ++mark;
82                 flag = SvIVx(*mark);
83         }
84
85         while (++mark <= sp) {
86             if (*mark)
87                 *a++ = SvPVx(*mark, na);
88             else
89                 *a++ = "";
90         }
91         *a = Nullch;
92
93         trueflag = flag;
94         if (flag == P_WAIT)
95                 flag = P_NOWAIT;
96
97         if (*Argv[0] != '/' && *Argv[0] != '\\') /* will swawnvp use PATH? */
98             TAINT_ENV();        /* testing IFS here is overkill, probably */
99         if (really && *(tmps = SvPV(really, na)))
100             rc = result(trueflag, spawnvp(flag,tmps,Argv));
101         else
102             rc = result(trueflag, spawnvp(flag,Argv[0],Argv));
103
104         if (rc < 0 && dowarn)
105             warn("Can't spawn \"%s\": %s", Argv[0], Strerror(errno));
106         if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
107     } else
108         rc = -1;
109     do_execfree();
110     return rc;
111 }
112
113 int
114 do_spawn(cmd)
115 char *cmd;
116 {
117     register char **a;
118     register char *s;
119     char flags[10];
120     char *shell, *copt;
121     int rc;
122
123 #ifdef TRYSHELL
124     if ((shell = getenv("EMXSHELL")) != NULL)
125         copt = "-c";
126     else if ((shell = getenv("SHELL")) != NULL)
127         copt = "-c";
128     else if ((shell = getenv("COMSPEC")) != NULL)
129         copt = "/C";
130     else
131         shell = "cmd.exe";
132 #else
133     /* Consensus on perl5-porters is that it is _very_ important to
134        have a shell which will not change between computers with the
135        same architecture, to avoid "action on a distance". 
136        And to have simple build, this shell should be sh. */
137     shell = "sh.exe";
138     copt = "-c";
139 #endif 
140
141     while (*cmd && isSPACE(*cmd))
142         cmd++;
143
144     /* save an extra exec if possible */
145     /* see if there are shell metacharacters in it */
146
147     if (*cmd == '.' && isSPACE(cmd[1]))
148         goto doshell;
149
150     if (strnEQ(cmd,"exec",4) && isSPACE(cmd[4]))
151         goto doshell;
152
153     for (s = cmd; *s && isALPHA(*s); s++) ;     /* catch VAR=val gizmo */
154     if (*s == '=')
155         goto doshell;
156
157     for (s = cmd; *s; s++) {
158         if (*s != ' ' && !isALPHA(*s) && strchr("$&*(){}[]'\";\\|?<>~`\n",*s)) {
159             if (*s == '\n' && !s[1]) {
160                 *s = '\0';
161                 break;
162             }
163           doshell:
164             rc = result(P_WAIT,
165                           spawnl(P_NOWAIT,shell,shell,copt,cmd,(char*)0));
166             if (rc < 0 && dowarn)
167                 warn("Can't spawn \"%s\": %s", shell, Strerror(errno));
168             if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
169             return rc;
170         }
171     }
172
173     New(402,Argv, (s - cmd) / 2 + 2, char*);
174     Cmd = savepvn(cmd, s-cmd);
175     a = Argv;
176     for (s = Cmd; *s;) {
177         while (*s && isSPACE(*s)) s++;
178         if (*s)
179             *(a++) = s;
180         while (*s && !isSPACE(*s)) s++;
181         if (*s)
182             *s++ = '\0';
183     }
184     *a = Nullch;
185     if (Argv[0]) {
186         rc = result(P_WAIT, spawnvp(P_NOWAIT,Argv[0],Argv));
187         if (rc < 0 && dowarn)
188             warn("Can't spawn \"%s\": %s", Argv[0], Strerror(errno));
189         if (rc < 0) rc = 255 << 8; /* Emulate the fork(). */
190     } else
191         rc = -1;
192     do_execfree();
193     return rc;
194 }
195
196 FILE *
197 my_popen(cmd,mode)
198 char    *cmd;
199 char    *mode;
200 {
201     char *shell = getenv("EMXSHELL");
202     FILE *res;
203     
204     my_setenv("EMXSHELL", "sh.exe");
205     res = popen(cmd, mode);
206     my_setenv("EMXSHELL", shell);
207     return res;
208 }
209
210 /*****************************************************************************/
211
212 #ifndef HAS_FORK
213 int
214 fork(void)
215 {
216     die(no_func, "Unsupported function fork");
217     errno = EINVAL;
218     return -1;
219 }
220 #endif
221
222 /*****************************************************************************/
223 /* not implemented in EMX 0.9a */
224
225 void *  ctermid(x)      { return 0; }
226
227 #ifdef MYTTYNAME /* was not in emx0.9a */
228 void *  ttyname(x)      { return 0; }
229 #endif
230
231 void *  gethostent()    { return 0; }
232 void *  getnetent()     { return 0; }
233 void *  getprotoent()   { return 0; }
234 void *  getservent()    { return 0; }
235 void    sethostent(x)   {}
236 void    setnetent(x)    {}
237 void    setprotoent(x)  {}
238 void    setservent(x)   {}
239 void    endhostent(x)   {}
240 void    endnetent(x)    {}
241 void    endprotoent(x)  {}
242 void    endservent(x)   {}
243
244 /*****************************************************************************/
245 /* stat() hack for char/block device */
246
247 #if OS2_STAT_HACK
248
249     /* First attempt used DosQueryFSAttach which crashed the system when
250        used with 5.001. Now just look for /dev/. */
251
252 int
253 os2_stat(char *name, struct stat *st)
254 {
255     static int ino = SHRT_MAX;
256
257     if (stricmp(name, "/dev/con") != 0
258      && stricmp(name, "/dev/tty") != 0)
259         return stat(name, st);
260
261     memset(st, 0, sizeof *st);
262     st->st_mode = S_IFCHR|0666;
263     st->st_ino = (ino-- & 0x7FFF);
264     st->st_nlink = 1;
265     return 0;
266 }
267
268 #endif
269
270 #ifndef NO_SYS_ALLOC
271
272 static char *old2K;
273
274 #define ONE_K (1<<10)
275 #define TWO_K (1<<11)
276 #define FOUR_K (1<<12)
277 #define FOUR_K_FLAG (FOUR_K - 1)
278
279
280 void *
281 sbrk(int size)
282 {
283     char *got;
284     APIRET rc;
285     int is2K = 0;
286
287     if (!size) return 0;
288     else if (size == TWO_K) {
289         is2K = 1;
290         if (old2K) {
291             char *ret = old2K;
292
293             old2K = 0;
294             return (void *)ret;
295         }
296         size = FOUR_K;
297     } else if (size & FOUR_K_FLAG) {
298         croak("Memory allocation in units %li not multiple to 4K", size);
299     }
300     rc = DosAllocMem((void **)&got, size, PAG_COMMIT | PAG_WRITE);
301     if (rc == ERROR_NOT_ENOUGH_MEMORY) {
302         return (void *) -1;
303     } else if ( rc ) die("Got an error from DosAllocMem: %li", (long)rc);
304     if (is2K) old2K = got + TWO_K;
305     return (void *)got;
306 }
307 #endif /* ! defined NO_SYS_ALLOC */
308
309 /* tmp path */
310
311 char *tmppath = TMPPATH1;
312
313 void
314 settmppath()
315 {
316     char *p = getenv("TMP"), *tpath;
317     int len;
318
319     if (!p) p = getenv("TEMP");
320     if (!p) return;
321     len = strlen(p);
322     tpath = (char *)malloc(len + strlen(TMPPATH1) + 2);
323     strcpy(tpath, p);
324     tpath[len] = '/';
325     strcpy(tpath + len + 1, TMPPATH1);
326     tmppath = tpath;
327 }