source: trunk/dll/systemf.c@ 775

Last change on this file since 775 was 775, checked in by Gregg Young, 18 years ago

Minor clean up add comments re recent changes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.8 KB
RevLine 
[78]1
2/***********************************************************************
3
4 $Id: systemf.c 775 2007-08-11 21:07:07Z gyoung $
5
6 System Interfaces
7
8 Copyright (c) 1993-98 M. Kimes
[330]9 Copyright (c) 2003, 2006 Steven H.Levine
[78]10
[330]11 21 Nov 03 SHL Comments
12 31 Jul 04 SHL Indent -i2
13 01 Aug 04 SHL Rework lstrip/rstrip usage
14 17 Jul 06 SHL Use Runtime_Error
[373]15 26 Jul 06 SHL Use convert_nl_to_nul
[441]16 15 Aug 06 SHL More error popups
[519]17 01 Nov 06 SHL runemf2: temp fix for hung windows caused by termq errors
[540]18 03 Nov 06 SHL runemf2: rework termination queue logic to work for multiple threads
[552]19 07 Jan 07 GKY Move error strings etc. to string file
[775]20 06 Aug 07 GKY Reduce DosSleep times (ticket 148)
[78]21
[775]22
[78]23***********************************************************************/
24
[2]25#define INCL_WIN
26#define INCL_WINERRORS
27#define INCL_DOS
28#define INCL_DOSERRORS
[330]29#include <os2.h>
[2]30
31#include <stdlib.h>
32#include <stdio.h>
33#include <stdarg.h>
34#include <string.h>
35#include <ctype.h>
36#include <time.h>
[330]37
[2]38#include "fm3dll.h"
39#include "fm3dlg.h"
40#include "fm3str.h"
41
[330]42static PSZ pszSrcFile = __FILE__;
43
[632]44#pragma alloc_text(SYSTEMF,ShowSession,ExecOnList,runemf2)
[2]45
[105]46#define MAXSTRG (4096) /* used to build command line strings */
[2]47
[519]48//== ShowSession() bring session for foreground ==
[2]49
[105]50BOOL ShowSession(HWND hwnd, PID pid)
[78]51{
[105]52 HSWITCH hswitch;
53 SWCNTRL swctl;
54 ULONG rc;
[2]55
[519]56 hswitch = WinQuerySwitchHandle(pid ? (HWND)0 : hwnd, pid);
[441]57 if (hswitch) {
[105]58 rc = WinQuerySwitchEntry(hswitch, &swctl);
[441]59 if (!rc) {
[105]60 if (swctl.idProcess == pid && swctl.uchVisibility == SWL_VISIBLE)
61 rc = WinSwitchToProgram(hswitch);
62 if (!rc)
63 return TRUE;
[78]64 // else saymsg(MB_ENTER,HWND_DESKTOP,DEBUG_STRING,"Failed: %lu/%lx",rc,rc);
[2]65
[105]66 }
67 }
68 return FALSE;
[2]69}
70
[519]71//== ExecOnList() Invoke runemf2 for command and file/directory list ==
72
[105]73int ExecOnList(HWND hwnd, char *command, int flags, char *tpath,
74 char **list, char *prompt)
[78]75{
[105]76 /* executes the command once for all files in list */
[2]77
[105]78 char path[CCHMAXPATH], commandline[2048], modpath[CCHMAXPATH], listfile[CCHMAXPATH],
79 *p, *pp, drive, *file, *ext, *dot;
[2]80 register int x;
[105]81 BOOL spaces;
[2]82
[441]83 if (!command || !*command) {
84 Runtime_Error2(pszSrcFile, __LINE__, IDS_NODATATEXT);
[105]85 return -1;
[441]86 }
[2]87 *listfile = 0;
[123]88 bstrip(command);
[2]89
90 *path = 0;
[105]91 if (tpath && *tpath)
92 strcpy(path, tpath);
[441]93 else if (*command != '<' || !strchr(command, '>')) {
[105]94 strcpy(path, command + (*command == '"'));
95 if (*command == '\"')
96 p = strchr(path, '\"');
[2]97 else
[105]98 p = strchr(path, ' ');
99 if (p)
[2]100 *p = 0;
[105]101 p = strrchr(path, '\\');
102 if (!p)
103 p = strrchr(path, ':');
[441]104 if (p) {
105 if (*p == ':') {
[105]106 p++;
107 *p = '\\';
108 p++;
[2]109 }
110 *p = 0;
111 }
112 else
113 *path = 0;
114 }
[441]115 if (!*path) {
[105]116 if (list && list[0])
117 strcpy(path, list[0]);
118 p = strrchr(path, '\\');
119 if (!p)
120 p = strrchr(path, ':');
[441]121 if (p) {
122 if (*p == ':') {
[105]123 p++;
124 *p = '\\';
125 p++;
[2]126 }
127 *p = 0;
128 }
129 else
130 *path = 0;
131 }
132 *modpath = 0;
[105]133 if (list && list[0])
134 strcpy(modpath, list[0]);
135 p = strrchr(modpath, '\\');
136 if (!p)
137 p = strrchr(modpath, ':');
[441]138 if (p) {
139 if (*p == ':') {
[2]140 p++;
141 *p = '\\';
142 p++;
143 }
144 *p = 0;
145 }
146 else
147 *modpath = 0;
[105]148 if (!*modpath)
149 strcpy(modpath, path);
150 if (*path)
[2]151 MakeFullName(path);
[105]152 if (*modpath)
[2]153 MakeFullName(modpath);
[105]154 if (IsFullName(path))
155 drive = toupper(*path);
156 else
157 drive = 0;
[2]158
[105]159 p = command; // substitue for special % sequences
[2]160
[105]161 pp = commandline;
162 *commandline = 0;
[441]163 while (*p) {
164 if (*p == '%') {
165 switch (*(p + 1)) {
[105]166 case '!': /* write list to file, add filename */
[441]167 if (list) {
168 if (!*listfile) {
[105]169 FILE *fp;
[2]170
[105]171 save_dir2(listfile);
172 if (listfile[strlen(listfile) - 1] != '\\')
173 strcat(listfile, "\\");
174 sprintf(&listfile[strlen(listfile)], "%s%03x",
[766]175 LISTTEMPROOT, (clock() & 4095));
[330]176 fp = xfopen(listfile, "w",pszSrcFile,__LINE__);
[441]177 if (fp) {
[105]178 for (x = 0; list[x]; x++)
179 {
180 fputs(list[x], fp);
181 if (list[x + 1])
182 fputc('\n', fp);
183 }
184 fclose(fp);
185 }
186 }
187 strcpy(pp, listfile);
188 pp += strlen(listfile);
189 }
190 p += 2;
191 break;
[2]192
[105]193 case 'c': /* add name of command processor */
194 {
195 char *env = GetCmdSpec(FALSE);
[2]196
[441]197 if (needs_quoting(env) && !strchr(env, '\"')) {
[105]198 *pp = '\"';
199 pp++;
200 spaces = TRUE;
201 }
202 else
203 spaces = FALSE;
204 strcpy(pp, env);
205 p += 2;
206 pp += strlen(env);
[441]207 if (spaces) {
[105]208 *pp = '\"';
209 pp++;
210 }
211 }
212 break;
[2]213
[105]214 case 't': /* add Target directory */
[441]215 if (needs_quoting(targetdir) && !strchr(targetdir, '\"')) {
[105]216 *pp = '\"';
217 pp++;
218 spaces = TRUE;
219 }
220 else
221 spaces = FALSE;
222 strcpy(pp, targetdir);
223 p += 2;
224 pp += strlen(targetdir);
[441]225 if (spaces) {
[105]226 *pp = '\"';
227 pp++;
228 }
229 break;
[2]230
[105]231 case '$': /* add drive letter */
232 if (drive)
233 *pp = drive;
[441]234 else {
[766]235 ULONG ulDriveNum = 3, ulDriveMap;
[2]236
[105]237 DosQCurDisk(&ulDriveNum, &ulDriveMap);
238 *pp = (char) (ulDriveNum + '@');
239 }
240 pp++;
241 p += 2;
242 break;
[2]243
[105]244 case 'U': /* add path of first list component */
245 case 'u':
[441]246 if (*modpath) {
247 if (needs_quoting(modpath) && !strchr(modpath, '\"')) {
[105]248 spaces = TRUE;
249 *pp = '\"';
250 pp++;
251 }
252 else
253 spaces = FALSE;
[441]254 if (*(p + 1) == 'u') {
[105]255 strcpy(pp, modpath);
256 pp += strlen(modpath);
257 }
[441]258 else {
[105]259 strcpy(pp, modpath + 2);
260 pp += strlen(modpath + 2);
261 }
[441]262 if (spaces) {
263 if (modpath[strlen(modpath) - 1] == '\\') {
[105]264 *pp = '\\';
265 pp++;
266 }
267 *pp = '\"';
268 pp++;
269 }
270 }
[441]271 else {
[105]272 char temp[CCHMAXPATH];
[2]273
[105]274 save_dir2(temp);
[441]275 if (needs_quoting(temp) && !strchr(temp, '\"')) {
[105]276 spaces = TRUE;
277 *pp = '\"';
278 pp++;
279 }
280 else
281 spaces = FALSE;
282 strcpy(pp, temp);
283 pp += strlen(temp);
[441]284 if (spaces) {
285 if (temp[strlen(temp) - 1] == '\\') {
[105]286 *pp = '\\';
287 pp++;
288 }
289 *pp = '\"';
290 pp++;
291 }
292 }
293 p += 2;
294 break;
[2]295
[105]296 case 'P': /* add path of execution */
297 case 'p':
[441]298 if (*path) {
299 if (needs_quoting(path) && !strchr(path, '\"')) {
[105]300 spaces = TRUE;
301 *pp = '\"';
302 pp++;
303 }
304 else
305 spaces = FALSE;
[441]306 if (*(p + 1) == 'p') {
[105]307 strcpy(pp, path);
308 pp += strlen(path);
309 }
[441]310 else {
[105]311 strcpy(pp, path + 2);
312 pp += strlen(path + 2);
313 }
[441]314 if (spaces) {
315 if (path[strlen(path) - 1] == '\\') {
[105]316 *pp = '\\';
317 pp++;
318 }
319 *pp = '\"';
320 pp++;
321 }
322 }
[441]323 else {
[105]324 char temp[CCHMAXPATH];
[2]325
[105]326 save_dir2(temp);
[441]327 if (needs_quoting(temp) && !strchr(temp, '\"')) {
[105]328 spaces = TRUE;
329 *pp = '\"';
330 pp++;
331 }
332 else
333 spaces = FALSE;
334 strcpy(pp, temp);
335 pp += strlen(temp);
[441]336 if (spaces) {
337 if (temp[strlen(temp) - 1] == '\\') {
[105]338 *pp = '\\';
339 pp++;
340 }
341 *pp = '\"';
342 pp++;
343 }
344 }
345 p += 2;
346 break;
[2]347
[105]348 case 'D':
[441]349 if (hwndMain) {
[105]350 PCNRITEM pci;
[2]351
[105]352 pci = (PCNRITEM) WinSendMsg(WinWindowFromID(WinWindowFromID(
353 hwndTree, FID_CLIENT), TREE_CNR),
354 CM_QUERYRECORDEMPHASIS,
355 MPFROMLONG(CMA_FIRST),
356 MPFROMSHORT(CRA_CURSORED));
[730]357 if (pci && (int) pci != -1 && *pci->pszFileName) {
358 if (needs_quoting(pci->pszFileName) &&
359 !strchr(pci->pszFileName, '\"'))
[105]360 {
361 *pp = '\"';
362 pp++;
363 spaces = TRUE;
364 }
365 else
366 spaces = FALSE;
[730]367 strcpy(pp, pci->pszFileName);
368 pp += strlen(pci->pszFileName);
[441]369 if (spaces) {
[105]370 *pp = '\"';
371 pp++;
372 }
373 }
374 }
375 p += 2;
376 break;
[2]377
[105]378 case 'd':
[441]379 if (hwndMain) {
[105]380 HENUM henum;
381 char retstr[CCHMAXPATH];
382 HWND hwndC, hwndDir;
383 USHORT id;
384 BOOL first = TRUE;
[2]385
[105]386 henum = WinBeginEnumWindows(hwndMain);
[441]387 while ((hwndC = WinGetNextWindow(henum)) != NULLHANDLE) {
388 if (hwndC != hwndTree) {
[105]389 id = WinQueryWindowUShort(hwndC, QWS_ID);
[441]390 if (id) {
[105]391 hwndDir = WinWindowFromID(hwndC, FID_CLIENT);
[441]392 if (hwndDir) {
[105]393 hwndDir = WinWindowFromID(hwndDir, DIR_CNR);
[441]394 if (hwndDir) {
[105]395 *retstr = 0;
396 WinSendMsg(hwndC, UM_CONTAINERDIR, MPFROMP(retstr), MPVOID);
[441]397 if (*retstr) {
398 if (!first) {
[105]399 *pp = ' ';
400 pp++;
401 }
402 first = FALSE;
[441]403 if (needs_quoting(retstr) && !strchr(retstr, '\"')) {
[105]404 *pp = '\"';
405 pp++;
406 spaces = TRUE;
407 }
408 else
409 spaces = FALSE;
410 strcpy(pp, retstr);
411 pp += strlen(retstr);
[441]412 if (spaces) {
[105]413 *pp = '\"';
414 pp++;
415 }
416 }
417 }
418 }
419 }
420 }
421 }
422 WinEndEnumWindows(henum);
423 }
424 p += 2;
425 break;
[2]426
[105]427 case '%':
428 *pp = '%';
429 pp++;
430 p += 2;
431 break;
[2]432
[105]433 case 'R':
434 case 'F':
435 case 'A':
436 case 'r':
437 case 'f':
438 case 'a':
439 case 'e':
[441]440 if (list) {
[105]441 for (x = 0; list[x]; x++)
442 {
443 file = strrchr(list[x], '\\');
444 if (!file)
445 file = strrchr(list[x], ':');
446 if (file)
447 file++;
448 else
449 file = list[x];
450 ext = strrchr(file, '.');
451 dot = ext;
452 if (ext)
453 ext++;
[441]454 switch (*(p + 1)) {
[105]455 case 'R':
456 case 'r':
457 if (pp + strlen(list[x]) > commandline + 1250)
458 goto BreakOut;
[441]459 if (*(p + 1) == 'r') {
[105]460 strcpy(pp, list[x]);
461 pp += strlen(list[x]);
462 }
[441]463 else {
[105]464 strcpy(pp, list[x] + 2);
465 pp += strlen(list[x] + 2);
466 }
467 break;
[2]468
[105]469 case 'F':
470 case 'f':
471 if (*(p + 1) == 'F' && dot)
472 *dot = 0;
473 if (pp + strlen(file) > commandline + 1250)
474 goto BreakOut;
[441]475 if (needs_quoting(file)) {
[105]476 spaces = TRUE;
477 *pp = '\"';
478 pp++;
479 }
480 else
481 spaces = FALSE;
482 strcpy(pp, file);
483 pp += strlen(file);
484 if (*(p + 1) == 'F' && dot)
485 *dot = '.';
[441]486 if (spaces) {
487 if (*(pp - 1) != '\"') {
[105]488 *pp = '\"';
489 pp++;
490 }
491 }
492 break;
[2]493
[105]494 case 'A':
495 case 'a':
496 if (pp + strlen(list[x]) > commandline + 1250)
497 goto BreakOut;
[441]498 if (needs_quoting(list[x]) && !strchr(list[x], '\"')) {
[105]499 spaces = TRUE;
500 *pp = '\"';
501 pp++;
502 }
503 else
504 spaces = FALSE;
[441]505 if (*(p + 1) == 'a') {
[105]506 strcpy(pp, list[x]);
507 pp += strlen(list[x]);
508 }
[441]509 else {
[105]510 strcpy(pp, list[x] + 2);
511 pp += strlen(list[x] + 2);
512 }
[441]513 if (spaces) {
514 if (list[x][strlen(list[x]) - 1] == '\\') {
[105]515 *pp = '\\';
516 pp++;
517 }
518 *pp = '\"';
519 pp++;
520 }
521 break;
[2]522
[105]523 case 'e':
[441]524 if (ext) {
[105]525 if (pp + strlen(ext) > commandline + 1250)
526 goto BreakOut;
[441]527 if (needs_quoting(ext)) {
[105]528 spaces = TRUE;
529 *pp = '\"';
530 pp++;
[2]531 }
[105]532 else
533 spaces = FALSE;
534 strcpy(pp, ext);
535 pp += strlen(ext);
[441]536 if (spaces) {
537 if (*(pp - 1) != '\"') {
[105]538 *pp = '\"';
539 pp++;
540 }
[2]541 }
[105]542 }
543 break;
544 }
[441]545 if (list[x + 1]) {
[105]546 *pp = ' ';
547 pp++;
548 }
549 }
[2]550 }
[105]551 p += 2;
552 break;
[2]553
[105]554 default:
555 *pp = *p;
556 p++;
557 pp++;
558 break;
559 }
560 }
[441]561 else {
[105]562 *pp = *p;
563 pp++;
564 p++;
565 }
566 *pp = 0;
567 }
568
[2]569BreakOut:
570
[105]571 {
572 EXECARGS ex;
573 ULONG size;
574 int ret;
[2]575
[105]576 memset(&ex, 0, sizeof(EXECARGS));
577 size = sizeof(ex.environment) - 1;
578 PrfQueryProfileData(fmprof, FM3Str, command, ex.environment, &size);
[441]579 if (flags & PROMPT) {
580 /* allow editing command line */
[105]581 ex.flags = (flags & (~PROMPT));
582 ex.commandline = commandline;
583 strcpy(ex.path, path);
584 if (prompt)
585 strcpy(ex.title, prompt);
586 ret = WinDlgBox(HWND_DESKTOP, hwnd, CmdLineDlgProc, FM3ModHandle,
587 EXEC_FRAME, &ex);
588 if (ret != 1)
589 return (ret == 0) ? -1 : -2;
590 }
591 else
592 ex.flags = flags;
593 ex.flags &= (~PROMPT);
594 return runemf2(ex.flags, hwnd, path,
595 (*ex.environment) ? ex.environment : NULL,
596 "%s", commandline);
597 }
[2]598}
599
[519]600//== runemf2() run requested app, return -1 if problem starting else return app rc ==
[441]601
[540]602int runemf2(int type, HWND hwnd, char *pszDirectory, char *pszEnvironment,
[105]603 char *formatstring,...)
[78]604{
[105]605 /* example:
606
[2]607 * status = runemf2(SEPARATE | WINDOWED,
608 * hwnd,
609 * NullStr,
610 * NULL,
611 * "%s /C %s",
612 * getenv("COMSPEC"),
613 * batchfilename);
[105]614 *
615 * use (HWND)0 for hwnd if window handle not handy.
616 */
[2]617
618 /*
619 * type bitmapped flag -- see FM3DLL.H
620 */
621
[105]622 va_list parguments;
623 int ret = -1;
[540]624 RESULTCODES results;
[519]625 STARTDATA sdata;
[105]626 REQUESTDATA rq;
[562]627 ULONG ulSessID;
628 ULONG ulLength;
629 UINT ctr;
630 ULONG ulAppType;
[105]631 PID sessPID;
632 BOOL wasquote;
[540]633 char *pszPgm, *pszArgs = NULL;
634 char szObject[32] = "", *p, szSavedir[CCHMAXPATH];
635 BOOL useTermQ = FALSE;
636 char szTempdir[CCHMAXPATH];
637
[519]638 typedef struct {
639 USHORT usSessID;
640 USHORT usRC;
641 } TERMINFO;
642
[540]643 TERMINFO *pTermInfo;
[105]644 BYTE bPriority;
645 APIRET rc;
[519]646 PIB *ppib;
647 TIB *ptib;
[2]648
[540]649 // Shared by all threads
650# define TERMQ_BASE_NAME "\\QUEUES\\FM3WAIT"
651 static char szTermQName[30];
652 static HQUEUE hTermQ;
653 static HEV hTermQSem;
654
655 if (pszDirectory && *pszDirectory) {
656 if (!DosQueryPathInfo(pszDirectory,
[105]657 FIL_QUERYFULLNAME,
[540]658 szTempdir,
659 sizeof(szTempdir)))
660 pszDirectory = szTempdir;
[105]661 }
[2]662
[105]663 if (!hwnd)
664 hwnd = HWND_DESKTOP;
[2]665
[540]666 rc = DosAllocMem((PVOID)&pszPgm,
[105]667 MAXSTRG,
668 PAG_COMMIT | OBJ_TILE | PAG_READ | PAG_WRITE);
[330]669 if (rc) {
670 Dos_Error(MB_CANCEL,rc,hwnd,pszSrcFile,__LINE__,GetPString(IDS_OUTOFMEMORY));
[105]671 return -1;
[330]672 }
[2]673
[540]674 *szSavedir = 0;
[2]675
[540]676 *pszPgm = 0;
[105]677 va_start(parguments,
678 formatstring);
[540]679 vsprintf(pszPgm,
[105]680 formatstring,
681 parguments);
682 va_end(parguments);
[2]683
[540]684 if (pszEnvironment) {
685 p = &pszEnvironment[strlen(pszEnvironment)] + 1;
[105]686 *p = 0;
[540]687 p = pszEnvironment;
[373]688 while ((p = convert_nl_to_nul(p)) != NULL)
689 ; // loop
[105]690 }
[2]691
[540]692 if (!*pszPgm) {
[105]693 p = GetCmdSpec(FALSE);
[540]694 strcpy(pszPgm, p);
695 if (!*pszPgm) {
[441]696 Runtime_Error2(pszSrcFile, __LINE__, IDS_NODATATEXT);
[105]697 return -1;
[441]698 }
[105]699 }
[2]700
[540]701 if (*pszPgm) {
702 if (*pszPgm == '<' && strchr(pszPgm, '>')) {
[441]703 /* is a workplace object */
[105]704 HOBJECT hWPSObject;
705 char temp;
[2]706
[540]707 p = strchr(pszPgm, '>');
[105]708 p++;
709 temp = *p;
[330]710 if (temp) {
[540]711 rc = DosAllocMem((PVOID)&pszArgs,
[105]712 MAXSTRG * 2,
713 PAG_COMMIT | OBJ_TILE | PAG_READ | PAG_WRITE);
[330]714 if (rc)
[540]715 Dos_Error(MB_CANCEL,rc,hwnd,pszSrcFile,__LINE__,GetPString(IDS_OUTOFMEMORY));
[330]716 }
[105]717 else
[540]718 pszArgs = NULL;
[105]719 *p = 0;
720 /* Find the handle of the WPS object */
[540]721 hWPSObject = WinQueryObject(pszPgm);
[105]722 *p = temp;
[441]723 if (hWPSObject != NULLHANDLE) {
[540]724 if (pszArgs && *p) {
725 sprintf(pszArgs,"OPEN=DEFAULT;PARAMETERS=\"%s\"",p);
726 WinSetObjectData(hWPSObject,pszArgs);
[105]727 }
728 else
[441]729 WinSetObjectData(hWPSObject,"OPEN=DEFAULT");
[105]730 ret = 0;
731 }
732 goto ObjectInterrupt;
733 }
[2]734
[773]735 if ((type & RUNTYPE_MASK) == SYNCHRONOUS ||
736 (type & RUNTYPE_MASK) == ASYNCHRONOUS ||
737 (type & RUNTYPE_MASK) == DETACHED)
[105]738 {
[540]739 strip_lead_char(" \t", pszPgm);
740 p = pszPgm;
[105]741 wasquote = FALSE;
742 while (*p &&
743 (wasquote ||
744 (*p != ' ' &&
745 *p != '\t')))
746 {
[441]747 if (*p == '\"') {
748 if (!wasquote) {
[105]749 wasquote = TRUE;
750 memmove(p,
751 p + 1,
752 strlen(p));
753 while (*p == ' ' ||
754 *p == '\t')
755 p++;
756 }
[441]757 else {
[105]758 memmove(p,
759 p + 1,
760 strlen(p));
761 break;
762 }
763 }
764 else
765 p++;
766 }
[441]767 if (*p) {
[105]768 *p = 0;
769 p++;
770 }
771 else
[540]772 p = pszPgm;
[105]773 p[strlen(p) + 1] = 0; /* double-terminate args */
[540]774 if (*pszPgm) {
775 if (!strchr(pszPgm, '\\') &&
776 !strchr(pszPgm, ':') &&
777 pszDirectory &&
778 *pszDirectory)
[105]779 {
[540]780 save_dir2(szSavedir);
781 switch_to(pszDirectory);
[105]782 }
[562]783 rc = DosQueryAppType(pszPgm,&ulAppType);
[540]784 if (!strchr(pszPgm, '\\') &&
785 !strchr(pszPgm, ':') &&
786 pszDirectory &&
787 *pszDirectory)
788 switch_to(szSavedir);
[441]789 if (rc) {
[562]790 Dos_Error(MB_CANCEL,rc,hwnd,pszSrcFile,__LINE__,
791 GetPString(IDS_DOSQAPPTYPEFAILEDTEXT),
792 pszPgm);
[540]793 DosFreeMem(pszPgm);
794 if (pszArgs)
795 DosFreeMem(pszArgs);
[105]796 return -1;
797 }
[562]798 if (ulAppType) {
799 if (ulAppType & FAPPTYP_DLL || ulAppType & FAPPTYP_VIRTDRV ||
800 ulAppType & FAPPTYP_PHYSDRV || ulAppType & FAPPTYP_PROTDLL)
[105]801 {
[562]802 Runtime_Error(pszSrcFile, __LINE__,
803 GetPString(IDS_APPTYPEUNEXPECTEDTEXT),
804 ulAppType, pszPgm);
[540]805 if (pszPgm)
806 DosFreeMem(pszPgm);
807 if (pszArgs)
808 DosFreeMem(pszArgs);
[105]809 return -1;
810 }
[562]811 if (ulAppType & FAPPTYP_DOS || ulAppType & FAPPTYP_WINDOWSREAL ||
812 ulAppType & FAPPTYP_WINDOWSPROT || ulAppType & FAPPTYP_WINDOWSPROT31)
[105]813 {
[562]814 Runtime_Error(pszSrcFile, __LINE__,
815 GetPString(IDS_APPTYPEUNEXPECTEDTEXT),
816 ulAppType, pszPgm);
[540]817 if (pszPgm)
818 DosFreeMem(pszPgm);
819 if (pszArgs)
820 DosFreeMem(pszArgs);
[105]821 return -1;
822 }
823 }
[540]824 memset(&results, 0, sizeof(results));
825 if (pszDirectory && *pszDirectory) {
826 save_dir2(szSavedir);
827 switch_to(pszDirectory);
[105]828 }
[540]829 ret = DosExecPgm(szObject, sizeof(szObject),
[773]830 ((type & RUNTYPE_MASK) == ASYNCHRONOUS ? EXEC_ASYNC : 0) +
831 ((type & RUNTYPE_MASK) == DETACHED ? EXEC_BACKGROUND : 0),
[540]832 pszPgm, pszEnvironment, &results, pszPgm);
833 if (pszDirectory && *pszDirectory)
834 switch_to(szSavedir);
[330]835 if (ret) {
836 Dos_Error(MB_ENTER,ret,hwnd,pszSrcFile,__LINE__,
[540]837 GetPString(IDS_DOSEXECPGMFAILEDTEXT), pszPgm);
[330]838 }
[105]839 }
840 }
[441]841 else {
[519]842 if (~type & FULLSCREEN)
[105]843 type |= WINDOWED;
[540]844 rc = DosAllocMem((PVOID) & pszArgs, MAXSTRG * 2,
[105]845 PAG_COMMIT | OBJ_TILE | PAG_READ | PAG_WRITE);
[441]846 if (rc) {
[540]847 Dos_Error(MB_CANCEL,rc,hwnd,pszSrcFile,__LINE__,GetPString(IDS_OUTOFMEMORY));
848 DosFreeMem(pszPgm);
[105]849 return -1;
850 }
[540]851 *pszArgs = 0;
852 memset(&sdata, 0, sizeof(sdata));
853 strip_lead_char(" \t", pszPgm);
854 p = pszPgm;
[105]855 wasquote = FALSE;
[441]856 while (*p && (wasquote || (*p != ' ' && *p != '\t'))) {
857 if (*p == '\"') {
858 if (!wasquote) {
[105]859 wasquote = TRUE;
860 memmove(p, p + 1, strlen(p));
861 while (*p == ' ' || *p == '\t')
862 p++;
863 }
[441]864 else {
[105]865 memmove(p, p + 1, strlen(p));
866 break;
867 }
868 }
869 else
870 p++;
[540]871 } // while
[441]872 if (*p) {
[105]873 *p = 0;
874 p++;
875 }
876 else
877 p = NullStr;
878 if (*p)
[540]879 strcpy(pszArgs, p);
[2]880
[540]881 p = strrchr(pszPgm, '.');
[441]882 if (p) {
[105]883 char temp[CCHMAXPATH + 1];
[2]884
[441]885 if (!stricmp(p, ".BAT")) {
[540]886 strcpy(temp, pszPgm);
887 strcpy(pszPgm, pszArgs);
888 strcpy(pszArgs, "/C ");
889 strcat(pszArgs, temp);
890 strcat(pszArgs, " ");
891 strcat(pszArgs, pszPgm);
892 strcpy(pszPgm, GetCmdSpec(TRUE)); // DOS
[105]893 }
[540]894 else if (!stricmp(p, ".CMD") || !stricmp(p, ".BTM")) {
895 // Assume 4OS2 is BTM
896 strcpy(temp, pszPgm);
897 strcpy(pszPgm, pszArgs);
898 strcpy(pszArgs, "/C ");
899 strcat(pszArgs, temp);
900 strcat(pszArgs, " ");
901 strcat(pszArgs, pszPgm);
902 strcpy(pszPgm, GetCmdSpec(FALSE)); // OS/2
[105]903 }
904 }
[2]905
[105]906 /* goddamned OS/2 limit */
[2]907
[540]908 if (strlen(pszPgm) + strlen(pszArgs) > 1024)
909 pszArgs[1024 - strlen(pszPgm)] = 0;
[2]910
[540]911 if (!strchr(pszPgm, '\\') &&
912 !strchr(pszPgm, ':') &&
913 pszDirectory &&
914 *pszDirectory)
[105]915 {
[540]916 save_dir2(szSavedir);
917 switch_to(pszDirectory);
[105]918 }
[562]919 rc = DosQueryAppType(pszPgm,&ulAppType);
[540]920 if (!strchr(pszPgm, '\\') &&
921 !strchr(pszPgm, ':') &&
922 pszDirectory &&
923 *pszDirectory)
924 switch_to(szSavedir);
[441]925 if (rc) {
[562]926 Dos_Error(MB_CANCEL,rc,hwnd,pszSrcFile,__LINE__,
927 GetPString(IDS_DOSQAPPTYPEFAILEDTEXT),
928 pszPgm);
[540]929 DosFreeMem(pszPgm);
930 if (pszArgs)
931 DosFreeMem(pszArgs);
[105]932 return -1;
933 }
[2]934
[562]935 if (ulAppType) {
936 if (ulAppType & (FAPPTYP_DLL | FAPPTYP_VIRTDRV | FAPPTYP_PHYSDRV | FAPPTYP_PROTDLL))
[105]937 {
[562]938 Runtime_Error(pszSrcFile, __LINE__,
939 GetPString(IDS_APPTYPEUNEXPECTEDTEXT),
940 pszPgm);
[540]941 DosFreeMem(pszPgm);
942 if (pszArgs)
943 DosFreeMem(pszArgs);
[105]944 return -1;
945 }
[562]946 ulAppType &= ~FAPPTYP_BOUND;
947 if (ulAppType & (FAPPTYP_DOS | FAPPTYP_WINDOWSREAL | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSPROT31))
[105]948 {
[562]949 if (ulAppType & (FAPPTYP_WINDOWSREAL | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSPROT31))
[105]950 {
[540]951 if (~type & FULLSCREEN &&
[562]952 ulAppType & (FAPPTYP_WINDOWSREAL | FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSPROT31))
[105]953 {
[540]954 ret = RunSeamless(pszPgm, pszArgs, hwnd);
955 if (pszPgm)
956 DosFreeMem(pszPgm);
957 if (pszArgs)
958 DosFreeMem(pszArgs);
[441]959 return ret ? 0 : -1;
[105]960 }
[441]961 else {
[540]962 strcat(pszPgm, " ");
963 strcat(pszPgm, pszArgs);
964 *pszArgs = 0;
[562]965 if (ulAppType & (FAPPTYP_WINDOWSPROT | FAPPTYP_WINDOWSREAL | FAPPTYP_WINDOWSPROT31))
[540]966 strcat(pszArgs, "/3 ");
967 strcat(pszArgs, pszPgm);
968 strcpy(pszPgm, "WINOS2.COM");
[105]969 }
970 }
[441]971 else {
[540]972 if (~type & FULLSCREEN) {
[105]973 type |= WINDOWED;
[562]974 ulAppType = SSF_TYPE_WINDOWEDVDM;
[105]975 }
[441]976 else {
[540]977 type &= ~WINDOWED;
[562]978 ulAppType = SSF_TYPE_VDM;
[105]979 }
980 }
981 }
[562]982 else if (ulAppType & FAPPTYP_32BIT) {
983 ulAppType &= ~FAPPTYP_32BIT;
984 if (ulAppType == FAPPTYP_WINDOWAPI)
985 ulAppType = SSF_TYPE_PM;
986 else if (ulAppType == FAPPTYP_WINDOWCOMPAT)
987 ulAppType = SSF_TYPE_WINDOWABLEVIO;
988 else if (ulAppType == FAPPTYP_NOTWINDOWCOMPAT) {
989 ulAppType = SSF_TYPE_FULLSCREEN;
[540]990 type &= ~WINDOWED;
[105]991 type |= FULLSCREEN;
992 }
993 else /* ? */
[562]994 ulAppType = SSF_TYPE_WINDOWABLEVIO;
[105]995 }
[562]996 else if (ulAppType == FAPPTYP_WINDOWAPI)
997 ulAppType = SSF_TYPE_PM;
998 else if (ulAppType == FAPPTYP_WINDOWCOMPAT)
999 ulAppType = SSF_TYPE_WINDOWABLEVIO;
1000 else if (ulAppType == FAPPTYP_NOTWINDOWCOMPAT) {
[540]1001 type &= ~WINDOWED;
[562]1002 ulAppType = SSF_TYPE_FULLSCREEN;
[105]1003 }
1004 else
[562]1005 ulAppType = SSF_TYPE_DEFAULT;
[540]1006 if ((type & FULLSCREEN || ~type & WINDOWED) &&
[562]1007 ulAppType == SSF_TYPE_WINDOWABLEVIO)
[105]1008 {
[562]1009 ulAppType = SSF_TYPE_FULLSCREEN;
[105]1010 }
[519]1011 // fixme parens?
[540]1012 else if (type & FULLSCREEN ||
[562]1013 (type & WINDOWED && ulAppType == SSF_TYPE_WINDOWEDVDM))
1014 {
1015 ulAppType = SSF_TYPE_VDM;
1016 }
[105]1017 }
[562]1018 if (ulAppType == SSF_TYPE_WINDOWEDVDM && type & SEPARATEKEEP) {
[519]1019 type &= ~SEPARATEKEEP;
[105]1020 type |= SEPARATE;
1021 }
[2]1022
[519]1023 DosGetInfoBlocks(&ptib, &ppib);
1024
[540]1025 if (~type & WAIT)
1026 useTermQ = FALSE;
[519]1027 else {
[540]1028 rc = 0;
1029 DosEnterCritSec();
1030 if (!hTermQ) {
1031 // Create term queue and event semaphore just once
1032 sprintf(szTermQName, TERMQ_BASE_NAME "_%x", ppib->pib_ulpid);
1033 rc = DosCreateQueue(&hTermQ, QUE_FIFO | QUE_CONVERT_ADDRESS, szTermQName);
1034 if (rc) {
1035 hTermQ = (HQUEUE)0; // Try to survive
1036 DosExitCritSec();
1037 Dos_Error(MB_CANCEL,rc,hwnd,pszSrcFile,__LINE__,"DosCreateQueue");
1038 }
1039 else {
1040 rc = DosCreateEventSem(NULL,(PHEV)&hTermQSem,0,FALSE);
1041 if (rc) {
1042 hTermQSem = (HEV)0; // Try to survive
1043 DosCloseQueue(hTermQ);
1044 hTermQ = (HQUEUE)0; // Try to survive
1045 DosExitCritSec();
1046 Dos_Error(MB_ENTER,rc,HWND_DESKTOP,pszSrcFile,__LINE__,"DoCreateEventSem");
1047 }
[562]1048 // if (!rc) fprintf(stderr,"%s %d qcreated ptib %x hTermQ %x\n",__FILE__, __LINE__,ptib,hTermQ);
[540]1049 }
1050 } // if 1st time
1051 useTermQ = hTermQ && hTermQSem;
1052 if (!rc)
1053 DosExitCritSec();
1054 } // if wait
[562]1055
1056 memset(&sdata,0,sizeof(sdata));
[519]1057 sdata.Length = sizeof(sdata);
[562]1058 sdata.Related = type & (WAIT | CHILD) ? SSF_RELATED_CHILD :
1059 SSF_RELATED_INDEPENDENT;
[519]1060 sdata.FgBg = type & BACKGROUND ? SSF_FGBG_BACK : SSF_FGBG_FORE;
1061 sdata.TraceOpt = SSF_TRACEOPT_NONE;
[540]1062 sdata.PgmName = pszPgm;
[562]1063 if (*pszArgs)
1064 sdata.PgmInputs = pszArgs;
1065 if (useTermQ)
1066 sdata.TermQ = szTermQName;
[540]1067 sdata.Environment = pszEnvironment;
[519]1068 sdata.InheritOpt = SSF_INHERTOPT_PARENT;
[562]1069 sdata.SessionType = ulAppType;
[540]1070 sdata.ObjectBuffer = szObject;
1071 sdata.ObjectBuffLen = sizeof(szObject);
[773]1072 if ((type & RUNTYPE_MASK) == SEPARATEKEEP)
[562]1073 sdata.PgmControl |= SSF_CONTROL_NOAUTOCLOSE;
1074 if (type & MAXIMIZED)
1075 sdata.PgmControl |= SSF_CONTROL_MAXIMIZE;
1076 if (type & MINIMIZED)
1077 sdata.PgmControl |= SSF_CONTROL_MINIMIZE;
1078 if (type & INVISIBLE)
1079 sdata.PgmControl |= SSF_CONTROL_INVISIBLE;
1080
[540]1081 if (pszDirectory && *pszDirectory) {
1082 save_dir2(szSavedir);
1083 switch_to(pszDirectory);
[105]1084 }
[562]1085
[563]1086 // printf("%s %d DosStartsession thread 0x%x data\n ",
[562]1087 // __FILE__, __LINE__,ptib->tib_ordinal); fflush(stdout); // 10 Mar 07 SHL hang
[563]1088 // printf(" %d %d %d %s %s %s %d %d\n %s %x %x\n",
[562]1089 // sdata.Length , sdata.Related, sdata.FgBg, sdata.PgmName,
[563]1090 // sdata.PgmInputs, sdata.TermQ, sdata.InheritOpt,
1091 // sdata.SessionType, szTermQName,
1092 // hTermQ, hTermQSem); fflush(stdout);
[519]1093 ret = DosStartSession(&sdata, &ulSessID, &sessPID);
[562]1094
[563]1095 // if (type & WAIT) {
1096 // printf("%s %d DosStartession thread 0x%x rc = %d sess = %u pid = 0x%x\n",
1097 // __FILE__, __LINE__, ptib->tib_ordinal,ret, ulSessID, sessPID); fflush(stdout); // 10 Mar 07 SHL hang
1098 // }
1099 // else {
1100 // printf("%s %d DosStartession thread 0x%x nowait rc = %d\n",
1101 // __FILE__, __LINE__, ptib->tib_ordinal,ret); fflush(stdout); // 10 Mar 07 SHL hang
1102 // }
1103
[540]1104 if (pszDirectory && *pszDirectory)
1105 switch_to(szSavedir);
[562]1106
[330]1107 if (ret && ret != ERROR_SMG_START_IN_BACKGROUND) {
1108 Dos_Error(MB_CANCEL,ret,hwnd,pszSrcFile,__LINE__,
[540]1109 GetPString(IDS_DOSSTARTSESSIONFAILEDTEXT),pszPgm,pszArgs);
[330]1110 }
[441]1111 else if (type & WAIT) {
[105]1112 if (!(type & (BACKGROUND | MINIMIZED | INVISIBLE)))
1113 ShowSession(hwnd, sessPID);
[2]1114
[540]1115 if (!useTermQ) {
[562]1116 STATUSDATA sd;
[540]1117 // Could not create queue - fallback - fixme to be gone?
[563]1118 // printf("%s %d waiting wo/termq\n", __FILE__, __LINE__); fflush(stdout); // 12 Mar 07 SHL hang
[2]1119
[105]1120 memset(&sd, 0, sizeof(sd));
1121 sd.Length = (USHORT) sizeof(sd);
1122 sd.SelectInd = SET_SESSION_UNCHANGED;
1123 sd.BondInd = SET_SESSION_UNCHANGED;
1124 for (ctr = 0;; ctr++)
1125 {
[771]1126 DosSleep(100);//05 Aug 07 GKY 200
[519]1127 if (DosSetSession(ulSessID, &sd)) // Check if session gone (i.e. finished)
[105]1128 break;
[519]1129 if (ctr > 10) {
[563]1130 // printf("%s %d thread 0x%x showing slow sess %u pid 0x%x\n",
1131 // __FILE__, __LINE__,ptib->tib_ordinal,ulSessID,sessPID); fflush(stdout); // 12 Mar 07 SHL
[519]1132 ShowSession(hwnd, sessPID); // Show every 2 seconds
1133 ctr = 0;
1134 }
[105]1135 }
1136 }
[441]1137 else {
[105]1138 for (ctr = 0;; ctr++)
1139 {
[540]1140 if (ctr < 20) {
1141 rc = DosReadQueue(hTermQ, &rq, &ulLength, (PPVOID)&pTermInfo, 0,
1142 DCWW_NOWAIT, &bPriority, hTermQSem);
1143 if (rc == ERROR_QUE_EMPTY) {
[771]1144 DosSleep(50);//05 Aug 07 GKY 100
[540]1145 continue;
[105]1146 }
1147 }
[441]1148 else {
[562]1149 if (ctr == 20) {
[563]1150 // printf("%s %d thread 0x%x showing slow sess %u pid 0x%x\n",
[562]1151 // __FILE__, __LINE__,ptib->tib_ordinal,ulSessID,sessPID); fflush(stdout);
[540]1152 ShowSession(hwnd, sessPID); // Show long running session
[562]1153 }
[540]1154 rc = DosReadQueue(hTermQ, &rq, &ulLength, (PPVOID)&pTermInfo, 0,
1155 DCWW_WAIT, &bPriority, 0);
1156 }
1157
1158 if (rc) {
1159 // Oh heck
1160 Dos_Error(MB_CANCEL,rc,hwnd,pszSrcFile,__LINE__,"DosReadQueue");
[771]1161 DosSleep(100);//05 Aug 07 GKY 500
[540]1162 continue;
1163 }
1164
[563]1165 // printf("%s %d DosReadQueue thread 0x%x sess %u sessRC %u rq.pid 0x%x rq.data 0x%x\n",
[562]1166 // __FILE__, __LINE__,ptib->tib_ordinal,pTermInfo->usSessID,pTermInfo->usRC,rq.pid, rq.ulData); fflush(stdout);
1167
[540]1168 if (pTermInfo->usSessID == ulSessID)
1169 break; // Our session is done
1170
[562]1171 // Requeue session for other thread
[540]1172 {
1173 static ULONG ulLastSessID;
[563]1174 // printf("%s %d requeue thread 0x%x our sess %u term sess %u term rc %u\n",
[562]1175 // __FILE__, __LINE__,ptib->tib_ordinal,ulSessID,pTermInfo->usSessID,pTermInfo->usRC); fflush(stdout);
1176 // fixme to be gone when no longer needed for debug?
[540]1177 if (ulLastSessID) {
[771]1178 DosSleep(100);//05 Aug 07 GKY 500
[540]1179 ulLastSessID = pTermInfo->usSessID;
[519]1180 }
[562]1181 // requeue term report for other thread and do not free yet
[540]1182 rc = DosWriteQueue(hTermQ, rq.ulData, ulLength,(PVOID)pTermInfo, bPriority);
1183 if (rc)
1184 Dos_Error(MB_CANCEL,rc,hwnd,pszSrcFile,__LINE__,"DosWriteQueue");
[771]1185 DosSleep(50); //05 Aug 07 GKY 100 // Let other thread see queue entry
[105]1186 }
[519]1187 } // for
[540]1188
[562]1189 ret = pTermInfo->usRC == 0; // Set 1 if rc 0 else 0
[563]1190 // printf("%s %d thread 0x%x term for sess %u\n",
1191 // __FILE__, __LINE__,ptib->tib_ordinal,ulSessID);fflush(stdout);
[540]1192 DosFreeMem(pTermInfo);
[105]1193 }
[540]1194 } // if wait
[105]1195 else if (!(type & (BACKGROUND | MINIMIZED | INVISIBLE)))
1196 ShowSession(hwnd, sessPID);
1197 }
1198 }
[2]1199
1200ObjectInterrupt:
1201
[540]1202 if (pszPgm)
1203 DosFreeMem(pszPgm);
1204 if (pszArgs)
1205 DosFreeMem(pszArgs);
[562]1206
[105]1207 return ret;
[2]1208}
1209
[519]1210//== Exec() Start application with WinStartApp ==
1211
[105]1212HAPP Exec(HWND hwndNotify, BOOL child, char *startdir, char *env,
[519]1213 PROGTYPE *progt, ULONG fl, char *formatstring,...)
[78]1214{
[105]1215 PROGDETAILS pgd;
[2]1216 register char *p;
[105]1217 char *parameters = NULL, *executable = NULL;
[519]1218 HAPP happ = (HAPP)0;
[105]1219 ULONG ulOptions = SAF_INSTALLEDCMDLINE;
1220 BOOL wasquote;
1221 va_list parguments;
[2]1222
[105]1223 if (child)
[2]1224 ulOptions |= SAF_STARTCHILDAPP;
1225
[330]1226 executable = xmallocz(MAXSTRG,pszSrcFile,__LINE__);
1227 if (executable) {
[105]1228 va_start(parguments, formatstring);
1229 vsprintf(executable, formatstring, parguments);
[2]1230 va_end(parguments);
[105]1231 strip_lead_char(" \t", executable);
[441]1232 if (*executable) {
[330]1233 parameters = xmalloc(MAXSTRG,pszSrcFile,__LINE__);
[441]1234 if (parameters) {
[105]1235 p = executable;
1236 wasquote = FALSE;
[441]1237 while (*p && (wasquote || (*p != ' ' && *p != '\t'))) {
1238 if (*p == '\"') {
1239 if (!wasquote) {
[105]1240 wasquote = TRUE;
1241 memmove(p, p + 1, strlen(p));
1242 while (*p == ' ' || *p == '\t')
1243 p++;
1244 }
[441]1245 else {
[105]1246 memmove(p, p + 1, strlen(p));
1247 break;
1248 }
1249 }
1250 else
1251 p++;
1252 }
[441]1253 if (*p) {
[105]1254 *p = 0;
1255 p++;
1256 }
1257 else
1258 p = NullStr;
1259 if (*p)
1260 strcpy(parameters, p);
[2]1261
[441]1262 if (p && (!stricmp(p, ".BAT") || !stricmp(p, ".CMD"))) {
[105]1263 char *temp;
[2]1264
[330]1265 temp = xmalloc(CCHMAXPATH * 2,pszSrcFile,__LINE__);
[441]1266 if (temp) {
1267 if (!stricmp(p, ".BAT")) {
[105]1268 strcpy(temp, executable);
1269 strcpy(executable, parameters);
1270 strcpy(parameters, "/C ");
1271 strcat(parameters, temp);
1272 strcat(parameters, " ");
1273 strcat(parameters, executable);
1274 strcpy(executable, GetCmdSpec(TRUE));
1275 }
[441]1276 else if (!stricmp(p, ".CMD")) {
[105]1277 strcpy(temp, executable);
1278 strcpy(executable, parameters);
1279 strcpy(parameters, "/C ");
1280 strcat(parameters, temp);
1281 strcat(parameters, " ");
1282 strcat(parameters, executable);
1283 strcpy(executable, GetCmdSpec(FALSE));
1284 }
1285 free(temp);
1286 }
1287 }
[2]1288
[105]1289 memset(&pgd, 0, sizeof(pgd));
1290 pgd.Length = sizeof(pgd);
1291 pgd.progt = *progt;
1292 pgd.swpInitial.fl = fl;
1293 pgd.pszEnvironment = env;
1294 pgd.pszStartupDir = startdir;
[562]1295 pgd.pszParameters = *parameters ? parameters : NULL;
[105]1296 pgd.pszExecutable = executable;
1297 pgd.swpInitial.hwndInsertBehind = HWND_TOP;
1298 happ = WinStartApp(hwndNotify, &pgd, NULL, NULL, ulOptions);
1299 free(parameters);
[2]1300 }
1301 }
1302 free(executable);
1303 }
1304 return happ;
1305}
Note: See TracBrowser for help on using the repository browser.