1 /*
2    ATP QWK MAIL READER FOR READING AND REPLYING TO QWK MAIL PACKETS.
3    Copyright (C) 1992, 1993, 1997  Thomas McWilliams
4    Copyright (C) 1990  Rene Cougnenc
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 /*
22 system.c
23 */
24 
25 /*
26  * Operating System system-dependant functions for ATP
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include "reader.h"
33 #include "readlib.h"
34 #include "ansi.h"
35 #include "qlib.h"
36 
37 #ifdef DJGPP
38 #include <pc.h>
39 #include <dos.h>
40 #endif
41 
42 #if defined(__MSDOS__)
43 #ifdef _MSC_
44 #include <direct.h>
45 #else
46 #include <dir.h>
47 #endif
48 #include <io.h>
49 #include <dos.h>
50 #endif
51 
52 #ifdef WIN32
53 #include <direct.h>
54 #include <io.h>
55 #endif
56 
57 /*
58  * Erase - deletes ALL files in a directory pointed to by PathName.
59  * This is system-dependant.
60  */
61 void
Erase(const char * PathName)62 Erase(const char *PathName)
63 {
64     char Pattern[MAXPATHS];
65 
66 #if defined(DIRENTRY)
67     DIR *dirp;
68     struct DIRENTRY *firp;
69 
70     dirp = opendir(PathName);
71     if (dirp != NULL) {
72 	while ((firp = readdir(dirp)) != NULL)  /*@-strictops */
73 	    if (firp->d_name[0] != '.') {       /*@=strictops */
74 		sprintf(Pattern, "%s%c%s", PathName, SEP, firp->d_name);
75 		do_unlink(Pattern);
76 	    }
77 	(void)closedir(dirp);
78     } else {
79 	printf("Can't seem to open %s\n", PathName);
80     }
81 
82 #elif defined(UNIXCMDS)
83     sprintf(Pattern, "rm -f %s/*", PathName);
84     system(Pattern);
85 
86 #elif !defined(WIN32)		/* for dos, this method saves you from an annoying prompt */
87     /* see below for WIN32 variation */
88     int ok;
89     char tmp[130];
90     char cwd[130];
91     struct ffblk FileDoc;
92 
93     GETCWD(cwd, 128);
94     sprintf((char *) Pattern, "%s\\*.*", PathName);
95 
96     if ((ok = findfirst((char *) Pattern, &FileDoc, 0)) == ATP_OK) {
97 	while (ok == ATP_OK) {
98 	    sprintf(tmp, "%s\\%s", PathName, FileDoc.ff_name);
99 	    do_unlink(tmp);
100 	    ok = findnext(&FileDoc);
101 	}
102 	CHPATH(cwd);
103     }
104 /* WIN32 below */
105 #else
106 
107     int ok;
108     long filegrouphandle;
109     char tmp[MAXPATHS];
110     char cwd[MAXPATHS];
111 
112     struct _finddata_t FileDoc;
113 
114     GETCWD(cwd, MAXPATHS - 2);
115     sprintf((char *) Pattern, "%s\\*.*", PathName);
116 
117     if ((ok = _findfirst((char *) Pattern, &FileDoc)) == ATP_OK) {
118 	filegrouphandle = ok;
119 	while (ok == ATP_OK) {
120 	    sprintf(tmp, "%s\\%s", PathName, FileDoc.name);
121 	    do_unlink(tmp);
122 	    ok = _findnext(filegrouphandle, &FileDoc);
123 	}
124 	_findclose(filegrouphandle);
125 	CHPATH(cwd);
126     }
127 #endif
128 }				/* end of Erase() */
129 
130 
131 #if !defined(HAVE_STRNICMP)
132 
133 /*
134  * strnicmp - case insensitive counted string comparison.
135  */
136 int
strnicmp(const char * s1,const char * s2,size_t n)137 strnicmp(const char *s1, const char *s2, size_t n)
138 {
139     while (n && *s1 && *s2) {
140 	if (tolower(*s1) != tolower(*s2))
141 	    return (tolower(*s1) > tolower(*s2) ? 1 : -1);
142 	s1++;
143 	s2++;
144 	n--;
145     }
146     if (n) {
147 	if (*s1)
148 	    return (1);
149 	if (*s2)
150 	    return (-1);
151     }
152     return (0);
153 }
154 
155 
156 /*
157  * strnicmp - case insensitive string comparison.
158  */
159 int
stricmp(const char * s1,const char * s2)160 stricmp(const char *s1, const char *s2)
161 {
162     while (*s1 != NUL_CHAR && *s2 != NUL_CHAR) {
163 	if (tolower(*s1) != tolower(*s2))
164 	    return (tolower(*s1) > tolower(*s2) ? 1 : -1);
165 	s1++;
166 	s2++;
167     }
168     if (*s1)
169 	return (1);
170     if (*s2)
171 	return (-1);
172     return (0);
173 }
174 
175 #endif
176 
177 #if !defined(HAVE_STRUPR)
178 /*@-strictops */
179 /*
180  * strlwr - converts string to lower case.
181  */
182 char *
strlwr(char * s)183 strlwr(char *s)
184 {
185     char *s1;
186 
187     s1 = s;
188     while (*s1 != NUL_CHAR ) {
189 	*s1 = tolower(*s1);
190 	s1++;
191     }
192     return (s);
193 }
194 
195 /*
196  * strupr - converts string to upper case.
197  */
198 char *
strupr(char * s)199 strupr(char *s)
200 {
201     char *s1;
202 
203     s1 = s;
204     while (*s1 != NUL_CHAR) {
205 	*s1 = toupper(*s1);
206 	s1++;
207     }
208     return (s);
209 }
210 /*@=strictops */
211 #endif
212 
213 #if !defined(HAVE_STRSTR) || defined(NEED_STRSTR)
214 /*
215  *  Copyright (C) 1991, 1992 Free Software Foundation, Inc.
216  *  This function is part of the GNU C Library.
217  */
218 
219 /*
220  * strstr - find a substring in another string (from GNU C library).
221  *
222  * Return the first ocurrence of NEEDLE in HAYSTACK.
223  */
224 char *
strstr(const char * haystack,const char * needle)225 strstr(const char *haystack, const char *needle)
226 {
227     const char CONSPTR needle_end = strchr(needle, NUL_CHAR);
228     const char CONSPTR haystack_end = strchr(haystack, NUL_CHAR);
229     const size_t needle_len = needle_end - needle;
230     const size_t needle_last = needle_len - 1;
231     const char *begin;
232 
233     if (needle_len == 0)
234 	return (char *) haystack;	/* ANSI 4.11.5.7, line 25.  */
235     if ((size_t) (haystack_end - haystack) < needle_len)
236 	return NULL;
237 
238     for (begin = &haystack[needle_last]; begin < haystack_end; ++begin) {
239 	const char *n = &needle[needle_last];
240 	const char *h = begin;
241 
242 	do {
243 	    if (*h != *n)
244 		goto loop;	/* continue for loop */
245 	} while (--n >= needle && --h >= haystack);
246 
247 	return (char *) h;
248 
249       loop:;
250     }
251     return NULL;
252 }
253 #endif
254 
255 #if !defined(HAVE_TMPNAM) || defined(NEEDTMPNAM)
256 
257 #undef L_tmpnam
258 #define L_tmpnam 30
259 
260 /*
261  * mytmprnam - provides the posix tmpnam() function.
262  *  assumes the existence of the non-posix mktemp() function.
263  */
264 char *
mytmprnam(char * buf)265 mytmprnam(char *buf)
266 {
267     static char tbf[(L_tmpnam + 1)];
268     char *tbptr;
269 
270     tbf[0] = NUL_CHAR;
271 #if defined(SYS_UNIX)
272     strcpy(tbf, "/usr/tmp/");
273 #endif
274     strcat(tbf, "tmXXXXXX");
275     tbptr = mktemp(tbf);
276     if (tbptr == NULL) {	/* try to return something anyway */
277 	tbptr = tbf;
278     }
279     if (buf != NULL) {
280 	strcpy(buf, tbptr);
281 	tbptr = buf;
282     }
283     return tbptr;
284 }
285 
286 #endif
287 
288 /* unix terminal functions, see system.h for more info */
289 #if defined(SYS_UNIX)
290 /*
291  * restore_terminal - reset terminal from previously saved attributes.
292  */
293 static struct ATPSRTERM savedterm;
294 void
restore_terminal(void)295 restore_terminal(void)
296 {
297     (void)ATPSETERM;
298 }
299 
300 /*
301  * save_terminal - store terminal attributes for later retrieval.
302  */
303 void
save_terminal(void)304 save_terminal(void)
305 {
306     (void)ATPGETERM;
307 }
308 
309 #endif
310 
311 
312 /*
313  * BEGIN PROCESS CREATION ROUTINES
314  *
315  */
316 
317 #if defined(USE_FORK)
318 static char *eargv[101], tbf[MAXPATHS];
319 
320 /*@-strictops */
321 /*
322  * build_eargv, build array of arguments for execvp.
323  */
324 static atp_ERROR_T
build_eargv(const char * prg,const char * prgfile)325 build_eargv(const char *prg, const char *prgfile)
326 {
327     atp_ERROR_T ret_code = ATP_ERROR;
328     char *tp = tbf;
329 
330     /* create command line */
331     sprintf(tbf, "%s %s", prg, prgfile);
332     StripLSpace(tbf);
333 
334     /* decompose command line into arguments */
335     if (tbf[0] != NUL_CHAR) {
336 	int i = 1;
337 	for (; i < 100; i++) {
338 	    eargv[i] = 0;
339 	    while (*tp != SPC_CHAR && *tp != TAB_CHAR && *tp != NUL_CHAR)
340 		tp++;
341 	    if (*tp != NUL_CHAR)
342 		*tp = NUL_CHAR;
343 	    else
344 		break;
345 	    tp++;
346 	    while (*tp == SPC_CHAR || *tp == TAB_CHAR) {
347 		*tp = NUL_CHAR;
348 		tp++;
349 	    }
350 	    if (*tp != NUL_CHAR)
351 		eargv[i] = tp;
352 	    else
353 		break;
354 	    tp++;
355 	}
356 	eargv[0] = tbf;
357 	eargv[100] = 0;
358 	ret_code = ATP_OK;
359     }
360     return ret_code;
361 }
362 /*@=strictops */
363 #endif
364 
365 
366 #ifdef USE_FORK
367 static pid_t Proc_ID = NO_CHILD;
368 static atp_BOOL_T reperror = FALSE ;
369 
370 /*
371  * get_reperror - returns value of reperror reply error flag.
372  */
373 atp_BOOL_T
get_reperror(void)374 get_reperror(void)
375 {
376     return reperror;
377 }
378 
379 /*
380  * reset_reperror - resets value of reperror reply error flag to FALSE.
381  */
382 void
reset_reperror(void)383 reset_reperror(void)
384 {
385     reperror = FALSE;
386 }
387 /*@-paramuse */
388 
389 /*
390  * kill_child - signal handler for SIGINT to catch a signal in Reply().
391  */
392 RETSIGTYPE
kill_child(int dummy_arg)393 kill_child(int dummy_arg)
394 {
395 #ifndef HAVE_SIGACTION
396     signal(SIGINT, SIG_IGN);
397 #endif
398     if (Proc_ID > 0) {
399 	(void)kill(Proc_ID, SIGTERM);
400 	(void)sleep(2);
401 	(void)kill(Proc_ID, SIGKILL);
402 #ifndef HAVE_SIGACTION
403 	signal(SIGINT, kill_child);
404 #endif
405     }
406     restore_terminal();		/* restore terminal parameters */
407     reperror = TRUE;
408 }
409 /*@=paramuse */
410 #endif				/* USE_FORK */
411 
412 
413 /*
414  * fork_execvp - spawn process via fork()/execvp() or system().
415  */
416 void
fork_execvp(const char * prg,const char * prgfile)417 fork_execvp(const char *prg, const char *prgfile)
418 {
419 #ifdef USE_FORK
420     Proc_ID = NO_CHILD;                            /*@-strictops */
421     if (build_eargv(prg, prgfile) == ATP_OK) {     /*@=strictops */
422 	if ((Proc_ID = fork()) == 0) {
423 	    /* child */
424 	    (void)execvp(tbf, eargv);
425 	    /* this should never be reached */
426 	    exit(EXIT_FAILURE);
427 	}
428 	if (Proc_ID < 0) {
429 	    reperror = TRUE;
430 	} else {
431 	    /* parent */
432 	    /* set new handler for SIGINT */
433 	    pid_t npid;
434 	    sig_chint();
435 	    do {
436 		int childstatus;
437 		npid = wait(&childstatus);
438 	    } while (npid != Proc_ID);
439 	    sig_ignore(SIGINT);
440 	}
441 	/* reset Proc_ID to indicate no active child */
442 	Proc_ID = NO_CHILD;
443     }
444 #else
445     char forkbuf[MAXPATHS];
446     /* build command for call system() */
447     sprintf(forkbuf, "%s %s", prg, prgfile);
448     /* execute command */
449     system(forkbuf);
450 #endif
451 }
452 /* END OF PROCESS CREATION ROUTINES */
453 
454 
455 
456 /*
457  * replacement for missing getcwd() function
458  */
459 
460 #if !defined(HAVE_GETCWD) || defined(NEEDGETCWD)
461 
462 #ifdef no_proto
463 char *getwd();
464 #else
465 EXTERNC char *getwd(char *p);
466 #endif
467 
468 /*
469  * mygetcwd - provides posix getcwd() assuming getwd() is available.
470  */
471 char *
mygetcwd(char * buf,size_t siz)472 mygetcwd(char *buf, size_t siz)
473 {
474     char tmp[MAXPATHS];
475 
476     memset(tmp, 0, (size_t) (siz - 1));
477     getwd(tmp);
478 #ifdef DJGPP
479     addrive(tmp);
480 #endif
481     if (siz <= MAXPATHS)
482 	tmp[siz - 1] = 0;
483     strcpy(buf, tmp);
484     return (buf);
485 }
486 #endif
487 
488 /* ************************************************************************ */
489 /* THE FOLLOWING SECTION IS DEVOTED TO MS-DOS, OS/2, AND WINDOWS STUFF ONLY */
490 /* ************************************************************************ */
491 
492 #ifdef __MSDOS__
493 
494 /*
495  * DosChPath - (msdos) changes active path to new drive and directory.
496  */
497 atp_ERROR_T
DosChPath(const char * path)498 DosChPath(const char *path)
499 {
500     int driv;
501     atp_ERROR_T ret_code = ATP_ERROR;
502 
503     /* get drive letter from path */
504     driv = toupper(path[0]);
505 
506     /*  test for valid drive designator at start of path */
507     if ((path[2] == SEP || path[2] == '/') && path[1] == ':' && driv > '@' && driv < 'Q') {
508 	/* convert to numeric */
509 	const int drive_mask = 15;
510 	driv &= drive_mask;
511 #ifndef _MSC_
512 	driv--;
513 #endif
514 	if (setdisk(driv) < driv) {
515 	    /* can't set drive */
516 	    printf("ERROR: can't set drive to '%c:'\n", driv);
517 	    sleep(4);
518 	} else if (chdir(path) == ATP_OK) {
519 	    ret_code = ATP_OK;
520 	} else {
521 	    /* can't change to new path */
522 	    printf("ERROR: can't change path to '%s:'\n", path);
523 	    sleep(4);
524 	}
525     }
526     return ret_code;
527 }
528 #endif
529 
530 #if defined(_OS2) || defined(__MSDOS__)
531 
532 /*
533  * addrive - (msdos) prepends a drive designator to a path name.
534  */
535 void
addrive(char * path)536 addrive(char *path)
537 {
538     if ((path[2] != SEP && path[2] != SEPDOS) || path[1] != ':') {
539 	char tmp[MAXPATHS];
540 	int driv;
541 #ifdef __EMX__
542 	driv = _getdrive();
543 #else
544 	driv = getdisk();
545 	driv = driv + 'A';
546 #endif
547 	if (path[0] != SEP && path[0] != SEPDOS)
548 #ifdef DJGPP
549 	    sprintf(tmp, "%c:%c%s", driv, '/', path);
550 #else
551 	    sprintf(tmp, "%c:%c%s", driv, SEP, path);
552 #endif
553 	else
554 	    sprintf(tmp, "%c:%s", (char) driv, path);
555 	strcpy(path, tmp);
556     }
557 }
558 
559 #endif
560 
561 #ifdef NEEDISKS
562 
563 #ifdef __MSDOS__
564 
565 /*
566  * getdisk - (msdos) get and return current active drive.
567  */
568 int
getdisk(void)569 getdisk(void)
570 {
571     const int drive_mask = 15;
572     int temp;
573 #ifdef _MSC_
574     _dos_getdrive(&temp);
575     return temp;
576 #else
577     union REGS regs;
578 
579     regs.h.ah = 0x19;
580     regs.x.dx = 0;
581     regs.h.al = 0;
582 
583     temp = intdos(&regs, &regs);
584     return (temp & drive_mask);
585 #endif
586 }
587 
588 /*
589  * setdisk - (msdos) set the current active disk drive.
590  */
591 int
setdisk(int driv)592 setdisk(int driv)
593 {
594     int temp;
595     const int mask = 0x7F;
596 #ifdef _MSC_
597     _dos_setdrive(driv, &temp);
598 #else
599     union REGS regs;
600 
601     regs.h.ah = 0x0e;
602     regs.h.dl = (char) (driv & mask);
603     regs.h.al = 0;
604 
605     temp = intdos(&regs, &regs);
606 #endif
607     return (temp);
608 }
609 
610 #endif
611 #endif
612 
613 #ifdef NEED_SLEEP
614 /* Microsoft QuickC 2.0 doesnt' seem to have sleep() in its library */
615 
616 #ifdef __MSDOS__
617 
618 #define DOS_TICK_CNTR 0x046c
619 
620 #define time_t long
621 
622 /*
623  * sleep - (msdos) provides sleep routine for Microsoft C.
624  */
625 void
sleep(unsigned sec)626 sleep(unsigned sec)
627 {
628     time_t *ticker = (time_t *) DOS_TICK_CNTR;
629     time_t tick, tock;
630 
631     tock = (time_t) ((181 * sec) + 5) / 10;	/* fixed point math with round up */
632     tick = *ticker;
633     tock += tick;
634 
635     do {
636 	A_DVPAUZ;		/* if we are desqview aware this is defined to dv_pause(); */
637 	tick = *ticker;
638     } while (tick < tock);
639 }
640 
641 #else
642 void
sleep(int sec)643 sleep(int sec)
644 {
645     time_t tick1, tick2, tock;
646 
647     tick1 = time(&tock);
648     do {
649 	tick2 = time(&tock);
650     } while ((tick2 - tick1) < sec);
651 
652 }
653 #endif
654 #endif				/* need sleep */
655 
656 
657 #ifdef DOSTIME
658 /*
659  * msdos_time_init - (msdos) pseudo-posix time zone routine for MSDOS.
660  */
661 void
msdos_time_init(void)662 msdos_time_init(void)
663 {
664     char *tp;
665     if (!((tp = getenv("TZ")) != NULL && *tp
666           && strlen(tp) > 3 && atoi(tp + 3) != 0)) {
667         putenv("TZ=TML0CAL");
668     }
669     tzset();
670 }
671 #endif
672 
673 
674 #if 0
675 
676 /******************************************************************/
677 /******* THE FUNCTIONS BELOW ARE CURRENTLY UNUSED BY ATP! *********/
678 /******************************************************************/
679 /******* THE FUNCTIONS BELOW ARE CURRENTLY UNUSED BY ATP! *********/
680 /******************************************************************/
681 /******* THE FUNCTIONS BELOW ARE CURRENTLY UNUSED BY ATP! *********/
682 /******************************************************************/
683 
684 #if defined(NEEDREADLINE)
685 
686 #ifndef UNIXCMDS
687 #define STOPIT (int)'\r'
688 #else
689 #define STOPIT (int)'\n'
690 #endif
691 /*
692  **readline - display prompt and retrieve user's response.
693  */
694 char *
695 readline(char *prmt, int scrollflag)
696 {
697 
698     static char rdlnbuf[128];
699     extern char *luxptr;
700     char *buf, *tempr;
701     int cin = 0, idx = 0, i, firsthere = TRUE;
702 
703     buf = (char *) malloc(128);	/* inialize buffers */
704     rdlnbuf[0] = buf[0] = 0;
705 
706     printf("%s", prmt);		/* display prompt */
707     if (luxptr != NULL) {
708 	strcpy(rdlnbuf, luxptr);
709 	printf("%s\n", luxptr);
710 	up(1);
711 	right(14);
712 	buf[0] = 1;
713     }
714     fflush(stdout);
715     while ((cin = getch()) != STOPIT) {
716 	if (firsthere) {
717 	    for (i = idx; i < field_len; i++)
718 		printf(" ");	/* clear line */
719 	    for (i = idx; i < field_len; i++)
720 		printf("\b");
721 	    buf[0] = 1;
722 	    firsthere = FALSE;
723 	}
724 	if (cin > 31) {
725 	    printf("%c", cin);
726 	    buf[idx] = (char) cin;
727 	    idx++;
728 	    buf[idx] = 0;
729 	    if (idx > 24) {
730 		idx--;
731 		printf("\b");
732 	    };
733 	} else if (cin == '\b' && idx > 0) {	/* do backspace */
734 	    printf("\b \b");
735 	    buf[--idx] = 0;
736 	} else if (cin == 0) {
737 	    buf[idx] = 0;
738 #ifdef __TURBOC__		/* check for special keys */
739 	    tempr = NULL;
740 	    if (luxptr == NULL) {
741 		switch (cin = getch()) {
742 		case 0x3b:
743 		    tempr = "help";
744 		    break;
745 		case 0x3c:
746 		    tempr = "tag help";
747 		    break;
748 		case 0x3d:
749 		    tempr = "tag list";
750 		    break;
751 		case 0x3e:
752 		    tempr = "qlist";
753 		    break;
754 		case 0x49:
755 		    tempr = "-";
756 		    break;
757 		case 0x51:
758 		    tempr = "+";
759 		    break;
760 		case 0x4f:
761 		    tempr = "last";
762 		    break;
763 		case 0x47:
764 		    tempr = "1";
765 		    break;
766 		case 0x3f:
767 		    tempr = "show terms";
768 		    break;
769 		case 0x4c:
770 		    tempr = "N";
771 		    break;
772 		default:
773 		    break;
774 		}
775 		if (tempr != NULL) {
776 		    strcpy(buf, tempr);
777 		    printf("\n");
778 		    return buf;
779 		}
780 	    }
781 #endif
782 	} else {
783 	    buf[idx] = 0;
784 	}
785 	fflush(stdout);
786     }
787     printf("\n");
788     if (buf[0] == 1)
789 	strcpy(buf, rdlnbuf);
790     return buf;
791 
792 };
793 
794 void				/* dummy function for compatibility */
795 rl_initialize(void)
796 {
797 }
798 
799 #endif
800 
801 #ifdef NEEDFIXPATH
802 void
803 fixpath(char *path)
804 {
805 
806     char *tptr;
807 
808     tptr = path;
809     while (*tptr) {
810 	if (*tptr == '/')
811 	    *tptr = '\\';
812 	tptr++;
813     }
814 }
815 #endif
816 
817 #if defined(NEEDTEMPNAM)
818 char *
819 mytempnam(const char *workpath, const char *rep)
820 {
821 
822     char *tp1, *tp2;
823     static char tbuf[MAXPATHS];
824     char buffy[15];
825 
826     strcpy(buffy, "atpXXXXXX");
827     tp2 = tbuf;
828     tp1 = mktemp(buffy);
829     if (tp1 != NULL) {
830 	strcpy(tbuf, workpath);
831 	while (*tp2)
832 	    tp2++;
833 	tp2--;
834 	if (*tp2 != SEP) {
835 	    tp2++;
836 	    *tp2 = SEP;
837 	    tp2++;
838 	    *tp2 = NUL_CHAR;
839 	}
840 	strcat(tbuf, rep);
841 	strcat(tbuf, tp1);
842 	tp1 = tbuf;
843     }
844     return tp1;
845 }
846 #endif
847 
848 #if defined(NEEDSYSTEM)
849 #ifdef UNIXCMDS
850 #define ATPSWC "-c"
851 #else
852 #define ATPSWC "/C"
853 #endif
854 
855 int
856 mysystem(char *command)
857 {
858     pid_t mpid, npid;
859     int statloc;
860     char *shelbuf;
861 
862     if ((shelbuf = malloc(MAXPATHS)) == NULL)
863 	return (0);
864     shelbuf = getenv(SHELL);
865 
866     mpid = fork();
867 
868     if (mpid == 0) {		/* child */
869 	execl(shelbuf, shelbuf, ATPSWC, command, NULL);
870 	free(shelbuf);
871 	abort();
872     } else if (mpid < 0) {
873 	printf("Unable to fork %s\n", command);
874 	free(shelbuf);
875 	return (0);
876     } else {			/* parent */
877       wmore:
878 	npid = wait(&statloc);
879 	if (npid != mpid)
880 	    goto wmore;
881     }
882     free(shelbuf);
883     return (1);
884 }
885 
886 #endif
887 #endif				/* UNUSED BY ATP */
888