source: trunk/src/helpers/dosh.c@ 13

Last change on this file since 13 was 13, checked in by umoeller, 25 years ago

Updates for V0.9.6.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 52.7 KB
Line 
1
2/*
3 *@@sourcefile dosh.c:
4 * dosh.c contains Control Program helper functions.
5 *
6 * This file has miscellaneous system functions,
7 * drive helpers, file helpers, and partition functions.
8 *
9 * Usage: All OS/2 programs.
10 *
11 * Function prefixes (new with V0.81):
12 * -- dosh* Dos (Control Program) helper functions
13 *
14 * These funcs are forward-declared in dosh.h, which
15 * must be #include'd first.
16 *
17 * The resulting dosh.obj object file can be linked
18 * against any application object file. As opposed to
19 * the code in dosh2.c, it does not require any other
20 * code from the helpers.
21 *
22 * dosh.obj can also be used with the VAC subsystem
23 * library (/rn compiler option).
24 *
25 * Note: Version numbering in this file relates to XWorkplace version
26 * numbering.
27 *
28 *@@header "helpers\dosh.h"
29 */
30
31/*
32 * This file Copyright (C) 1997-2000 Ulrich M”ller.
33 * This file is part of the XWorkplace source package.
34 * XWorkplace is free software; you can redistribute it and/or modify
35 * it under the terms of the GNU General Public License as published
36 * by the Free Software Foundation, in version 2 as it comes in the
37 * "COPYING" file of the XWorkplace main distribution.
38 * This program is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 * GNU General Public License for more details.
42 */
43
44#define OS2EMX_PLAIN_CHAR
45 // this is needed for "os2emx.h"; if this is defined,
46 // emx will define PSZ as _signed_ char, otherwise
47 // as unsigned char
48
49#define INCL_DOS
50#define INCL_DOSDEVIOCTL
51#define INCL_DOSERRORS
52#define INCL_KBD
53#include <os2.h>
54#include <stdlib.h>
55#include <string.h>
56#include <stdio.h>
57// #include <ctype.h>
58
59#include "setup.h" // code generation and debugging options
60
61#include "helpers\dosh.h"
62
63#pragma hdrstop
64
65const CHAR G_acDriveLetters[28] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
66
67/*
68 *@@category: Helpers\Control program helpers\Miscellaneous
69 */
70
71/* ******************************************************************
72 * *
73 * Miscellaneous *
74 * *
75 ********************************************************************/
76
77/*
78 *@@ doshGetChar:
79 * reads a single character from the keyboard.
80 * Useful for VIO sessions, since there's great
81 * confusion between the various C dialects about
82 * how to use getc(), and getc() doesn't work
83 * with the VAC subsystem library.
84 *
85 *@@added V0.9.4 (2000-07-27) [umoeller]
86 */
87
88CHAR doshGetChar(VOID)
89{
90 // CHAR c;
91 // ULONG ulRead = 0;
92
93 KBDKEYINFO kki;
94 KbdCharIn(&kki,
95 0, // wait
96 0);
97
98 return (kki.chChar);
99}
100
101/*
102 *@@ doshQueryShiftState:
103 * returns TRUE if any of the SHIFT keys are
104 * currently pressed. Useful for checks during
105 * WM_COMMAND messages from menus.
106 *
107 *@@changed V0.9.5 (2000-09-27) [umoeller]: added error checking
108 */
109
110BOOL doshQueryShiftState(VOID)
111{
112 BOOL brc = FALSE;
113 APIRET arc = NO_ERROR;
114 HFILE hfKbd;
115 ULONG ulAction;
116
117 arc = DosOpen("KBD$", &hfKbd, &ulAction, 0,
118 FILE_NORMAL, FILE_OPEN,
119 OPEN_ACCESS_READONLY | OPEN_SHARE_DENYWRITE,
120 (PEAOP2)NULL);
121 if (arc == NO_ERROR)
122 {
123 SHIFTSTATE ShiftState;
124 ULONG cbDataLen = sizeof(ShiftState);
125
126 arc = DosDevIOCtl(hfKbd, IOCTL_KEYBOARD, KBD_GETSHIFTSTATE,
127 NULL, 0, NULL, // no parameters
128 &ShiftState, cbDataLen, &cbDataLen);
129 if (arc == NO_ERROR)
130 brc = ((ShiftState.fsState & 3) != 0);
131
132 DosClose(hfKbd);
133 }
134
135 return brc;
136}
137
138
139/*
140 *@@ doshIsWarp4:
141 * returns TRUE only if at least OS/2 Warp 4 is running.
142 *
143 *@@changed V0.9.2 (2000-03-05) [umoeller]: reported TRUE on Warp 3 also; fixed
144 *@@changed V0.9.6 (2000-10-16) [umoeller]: patched for speed
145 */
146
147BOOL doshIsWarp4(VOID)
148{
149 static BOOL s_brc = FALSE;
150 static BOOL s_fQueried = FALSE;
151 if (!s_fQueried)
152 {
153 // first call:
154 ULONG aulBuf[3];
155
156 DosQuerySysInfo(QSV_VERSION_MAJOR, // 11
157 QSV_VERSION_MINOR, // 12
158 &aulBuf, sizeof(aulBuf));
159 // Warp 3 is reported as 20.30
160 // Warp 4 is reported as 20.40
161 // Aurora is reported as 20.45
162
163 if ( (aulBuf[0] > 20) // major > 20; not the case with Warp 3, 4, 5
164 || ( (aulBuf[0] == 20) // major == 20 and minor >= 40
165 && (aulBuf[1] >= 40)
166 )
167 )
168 s_brc = TRUE;
169
170 s_fQueried = TRUE;
171 }
172
173 return (s_brc);
174}
175
176/*
177 *@@ doshQuerySysErrorMsg:
178 * this retrieves the error message for a system error
179 * (APIRET) from the system error message file (OSO001.MSG).
180 * This file better be on the DPATH (it normally is).
181 *
182 * This returns the string in the "SYSxxx: blahblah" style,
183 * which is normally displayed on the command line when
184 * errors occur.
185 *
186 * The error message is returned in a newly allocated
187 * buffer, which should be free()'d afterwards.
188 *
189 * Returns NULL upon errors.
190 */
191
192PSZ doshQuerySysErrorMsg(APIRET arc) // in: DOS error code
193{
194 PSZ pszReturn = 0;
195 CHAR szDosError[1000];
196 ULONG cbDosError = 0;
197 DosGetMessage(NULL, 0, // no string replacements
198 szDosError, sizeof(szDosError),
199 arc,
200 "OSO001.MSG", // default OS/2 message file
201 &cbDosError);
202 if (cbDosError > 2)
203 {
204 szDosError[cbDosError - 2] = 0;
205 pszReturn = strdup(szDosError);
206 }
207 return (pszReturn);
208}
209
210/*
211 *@@category: Helpers\Control program helpers\Memory management
212 */
213
214/* ******************************************************************
215 * *
216 * Memory helpers *
217 * *
218 ********************************************************************/
219
220/*
221 *@@ doshAllocSharedMem:
222 * wrapper for DosAllocSharedMem which has
223 * a malloc()-like syntax. Just due to my
224 * lazyness.
225 *
226 * Note that ulSize is always rounded up to the
227 * next 4KB value, so don't use this hundreds of times.
228 *
229 * Returns NULL upon errors. Possible errors include
230 * that a memory block calle pcszName has already been
231 * allocated.
232 *
233 * Use DosFreeMem(pvrc) to free the memory. The memory
234 * will only be freed if no other process has requested
235 * access.
236 *
237 *@@added V0.9.3 (2000-04-18) [umoeller]
238 */
239
240PVOID doshAllocSharedMem(ULONG ulSize, // in: requested mem block size (rounded up to 4KB)
241 const char* pcszName) // in: name of block ("\\SHAREMEM\\xxx") or NULL
242{
243 PVOID pvrc = NULL;
244 APIRET arc = DosAllocSharedMem((PVOID*)(&pvrc),
245 (PSZ)pcszName,
246 ulSize,
247 PAG_COMMIT | PAG_READ | PAG_WRITE);
248 if (arc == NO_ERROR)
249 return (pvrc);
250
251 return (NULL);
252}
253
254/*
255 *@@ doshRequestSharedMem:
256 * requests access to a block of named shared memory
257 * allocated by doshAllocSharedMem.
258 *
259 * Returns NULL upon errors.
260 *
261 * Use DosFreeMem(pvrc) to free the memory. The memory
262 * will only be freed if no other process has requested
263 * access.
264 *
265 *@@added V0.9.3 (2000-04-19) [umoeller]
266 */
267
268PVOID doshRequestSharedMem(const char *pcszName)
269{
270 PVOID pvrc = NULL;
271 APIRET arc = DosGetNamedSharedMem((PVOID*)(pvrc),
272 (PSZ)pcszName,
273 PAG_READ | PAG_WRITE);
274 if (arc == NO_ERROR)
275 return (pvrc);
276
277 return (NULL);
278}
279
280/*
281 *@@category: Helpers\Control program helpers\Drive management
282 */
283
284/* ******************************************************************
285 * *
286 * Drive helpers *
287 * *
288 ********************************************************************/
289
290/*
291 *@@ doshEnumDrives:
292 * this function enumerates all valid drive letters on
293 * the system by composing a string of drive letters
294 * in the buffer pointed to by pszBuffer, which should
295 * be 27 characters in size to hold information for
296 * all drives. The buffer will be null-terminated.
297 *
298 * If (pcszFileSystem != NULL), only drives matching
299 * the specified file system type (e.g. "HPFS") will
300 * be enumerated. If (pcszFileSystem == NULL), all
301 * drives will be enumerated.
302 *
303 * If (fSkipRemovables == TRUE), removeable drives will
304 * be skipped. This applies to floppy, CD-ROM, and
305 * virtual floppy drives. This will start the search
306 * at drive letter C: so that drives A: and B: will
307 * never be checked (to avoid the hardware bumps).
308 *
309 * Otherwise, the search starts at drive A:. Still,
310 * removeable drives will only be added if valid media
311 * is inserted.
312 *
313 *@@changed V0.9.4 (2000-07-03) [umoeller]: this stopped at the first invalid drive letter; fixed
314 *@@changed V0.9.4 (2000-07-03) [umoeller]: added fSkipRemoveables
315 */
316
317VOID doshEnumDrives(PSZ pszBuffer, // out: drive letters
318 const char *pcszFileSystem, // in: FS's to match or NULL
319 BOOL fSkipRemoveables) // in: if TRUE, only non-removeable disks will be returned
320{
321 CHAR szName[5] = "";
322 ULONG ulLogicalDrive = 1, // start with drive A:
323 ulFound = 0; // found drives count
324 APIRET arc = NO_ERROR; // return code
325
326 if (fSkipRemoveables)
327 // start with drive C:
328 ulLogicalDrive = 3;
329
330 // go thru the drives, start with C: (== 3), stop after Z: (== 26)
331 while (ulLogicalDrive <= 26)
332 {
333 UCHAR nonRemovable=0;
334 ULONG parmSize=2;
335 ULONG dataLen=1;
336
337 #pragma pack(1)
338 struct
339 {
340 UCHAR dummy,drive;
341 } parms;
342 #pragma pack()
343
344 parms.drive=(UCHAR)(ulLogicalDrive-1);
345 arc = DosDevIOCtl((HFILE)-1,
346 IOCTL_DISK,
347 DSK_BLOCKREMOVABLE,
348 &parms,
349 parmSize,
350 &parmSize,
351 &nonRemovable,
352 1,
353 &dataLen);
354
355 /* _Pmpf((" ul = %d, Drive %c: arc = %d nonRemoveable = %d",
356 ulLogicalDrive,
357 G_acDriveLetters[ulLogicalDrive],
358 arc,
359 nonRemovable)); */
360
361 if ( // fixed disk and non-removeable
362 ((arc == NO_ERROR) && (nonRemovable))
363 // or network drive:
364 || (arc == ERROR_NOT_SUPPORTED)
365 )
366 {
367 ULONG ulOrdinal = 0; // ordinal of entry in name list
368 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
369 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
370 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
371
372 szName[0] = G_acDriveLetters[ulLogicalDrive];
373 szName[1] = ':';
374 szName[2] = '\0';
375
376 arc = DosQueryFSAttach(szName, // logical drive of attached FS
377 ulOrdinal, // ignored for FSAIL_QUERYNAME
378 FSAIL_QUERYNAME, // return data for a Drive or Device
379 pfsqBuffer, // returned data
380 &cbBuffer); // returned data length
381
382 if (arc == NO_ERROR)
383 {
384 // The data for the last three fields in the FSQBUFFER2
385 // structure are stored at the offset of fsqBuffer.szName.
386 // Each data field following fsqBuffer.szName begins
387 // immediately after the previous item.
388 CHAR* pszFSDName = (PSZ)&(pfsqBuffer->szName) + (pfsqBuffer->cbName) + 1;
389 if (pcszFileSystem == NULL)
390 {
391 // enum-all mode: always copy
392 pszBuffer[ulFound] = szName[0]; // drive letter
393 ulFound++;
394 }
395 else if (strcmp(pszFSDName, pcszFileSystem) == 0)
396 {
397 pszBuffer[ulFound] = szName[0]; // drive letter
398 ulFound++;
399 }
400 }
401 }
402
403 ulLogicalDrive++;
404 } // end while (G_acDriveLetters[ulLogicalDrive] <= 'Z')
405
406 pszBuffer[ulFound] = '\0';
407}
408
409/*
410 *@@ doshQueryBootDrive:
411 * returns the letter of the boot drive as a
412 * single (capital) character, which is useful for
413 * constructing file names using sprintf and such.
414 */
415
416CHAR doshQueryBootDrive(VOID)
417{
418 ULONG ulBootDrive;
419 DosQuerySysInfo(5, 5, &ulBootDrive, sizeof(ulBootDrive));
420 return (G_acDriveLetters[ulBootDrive]);
421}
422
423/*
424 *@@ doshAssertDrive:
425 * this checks for whether the given drive
426 * is currently available without provoking
427 * those ugly white "Drive not ready" popups.
428 *
429 * This returns (from my testing):
430 * -- NO_ERROR: drive is available.
431 * -- ERROR_INVALID_DRIVE (15): drive letter does not exist.
432 * -- ERROR_NOT_READY (21): drive exists, but is not ready
433 * (e.g. CD-ROM drive without CD inserted).
434 * -- ERROR_NOT_SUPPORTED (50): this is returned by the RAMFS.IFS
435 * file system; apparently, the IFS doesn't support
436 * DASD opening.
437 *
438 *@@changed V0.9.1 (99-12-13) [umoeller]: rewritten, prototype changed. Now using DosOpen on the drive instead of DosError.
439 *@@changed V0.9.1 (2000-01-08) [umoeller]: DosClose was called even if DosOpen failed, which messed up OS/2 error handling.
440 *@@changed V0.9.1 (2000-02-09) [umoeller]: this didn't work for network drives, including RAMFS; fixed.
441 *@@changed V0.9.3 (2000-03-28) [umoeller]: added check for network drives, which weren't working
442 *@@changed V0.9.4 (2000-08-03) [umoeller]: more network fixes
443 */
444
445APIRET doshAssertDrive(ULONG ulLogicalDrive) // in: 1 for A:, 2 for B:, 3 for C:, ...
446{
447 CHAR szDrive[3] = "C:";
448 HFILE hfDrive = 0;
449 ULONG ulTemp = 0;
450 APIRET arc;
451
452 szDrive[0] = 'A' + ulLogicalDrive - 1;
453
454 arc = DosOpen(szDrive, // "C:", "D:", ...
455 &hfDrive,
456 &ulTemp,
457 0,
458 FILE_NORMAL,
459 OPEN_ACTION_FAIL_IF_NEW
460 | OPEN_ACTION_OPEN_IF_EXISTS,
461 OPEN_FLAGS_DASD
462 | OPEN_FLAGS_FAIL_ON_ERROR
463 | OPEN_ACCESS_READONLY
464 | OPEN_SHARE_DENYNONE,
465 NULL);
466
467 // _Pmpf((__FUNCTION__ ": DosOpen(OPEN_FLAGS_DASD) returned %d", arc));
468
469 switch (arc)
470 {
471 case ERROR_NETWORK_ACCESS_DENIED: // 65
472 // added V0.9.3 (2000-03-27) [umoeller];
473 // according to user reports, this is returned
474 // by all network drives, which apparently don't
475 // support DASD DosOpen
476 case ERROR_ACCESS_DENIED: // 5
477 // added V0.9.4 (2000-07-10) [umoeller]
478 // LAN drives still didn't work... apparently
479 // the above only works for NFS drives
480 case ERROR_PATH_NOT_FOUND: // 3
481 // added V0.9.4 (2000-08-03) [umoeller]:
482 // this is returned by some other network types...
483 // sigh...
484 case ERROR_NOT_SUPPORTED: // 50
485 {
486 // this is returned by file systems which don't
487 // support DASD DosOpen;
488 // use some other method then, this isn't likely
489 // to fail -- V0.9.1 (2000-02-09) [umoeller]
490 FSALLOCATE fsa;
491 arc = DosQueryFSInfo(ulLogicalDrive,
492 FSIL_ALLOC,
493 &fsa,
494 sizeof(fsa));
495 break; }
496
497 case NO_ERROR:
498 DosClose(hfDrive);
499 break;
500 }
501
502 return (arc);
503
504 /* FSALLOCATE fsa;
505 APIRET arc = NO_ERROR;
506
507 if (fSuppress)
508 {
509 DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
510 DosEnterCritSec();
511 }
512
513 arc = DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa));
514
515 if (fSuppress)
516 {
517 DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
518 DosExitCritSec();
519 }
520
521 return (arc); */
522}
523
524/*
525 *@@ doshQueryDiskFree:
526 * returns the number of bytes remaining on the disk
527 * specified by the given logical drive, or -1 upon errors.
528 *
529 * Note: This returns a "double" value, because a ULONG
530 * can only hold values of some 4 billion, which would
531 * lead to funny results for drives > 4 GB.
532 *
533 *@@changed V0.9.0 [umoeller]: fixed another > 4 GB bug (thanks to Rdiger Ihle)
534 */
535
536double doshQueryDiskFree(ULONG ulLogicalDrive) // in: 1 for A:, 2 for B:, 3 for C:, ...
537{
538 FSALLOCATE fsa;
539 double dbl = -1;
540
541 if (ulLogicalDrive)
542 if (DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa))
543 == NO_ERROR)
544 dbl = ((double)fsa.cSectorUnit * fsa.cbSector * fsa.cUnitAvail);
545 // ^ fixed V0.9.0
546
547 return (dbl);
548}
549
550/*
551 *@@ doshQueryDiskFSType:
552 * copies the file-system type of the given disk object
553 * (HPFS, FAT, CDFS etc.) to pszBuf.
554 * Returns the DOS error code.
555 *
556 *@@changed V0.9.1 (99-12-12) [umoeller]: added cbBuf to prototype
557 */
558
559APIRET doshQueryDiskFSType(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
560 PSZ pszBuf, // out: buffer for FS type
561 ULONG cbBuf) // in: size of that buffer
562{
563 APIRET arc = NO_ERROR;
564 CHAR szName[5];
565
566 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
567 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
568 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
569
570 // compose "D:"-type string from logical drive letter
571 szName[0] = G_acDriveLetters[ulLogicalDrive];
572 szName[1] = ':';
573 szName[2] = '\0';
574
575 arc = DosQueryFSAttach(szName, // logical drive of attached FS ("D:"-style)
576 0, // ulOrdinal, ignored for FSAIL_QUERYNAME
577 FSAIL_QUERYNAME, // return name for a drive or device
578 pfsqBuffer, // buffer for returned data
579 &cbBuffer); // sizeof(*pfsqBuffer)
580
581 if (arc == NO_ERROR)
582 {
583 if (pszBuf)
584 {
585 // The data for the last three fields in the FSQBUFFER2
586 // structure are stored at the offset of fsqBuffer.szName.
587 // Each data field following fsqBuffer.szName begins
588 // immediately after the previous item.
589 strcpy(pszBuf,
590 (CHAR*)(&pfsqBuffer->szName) + pfsqBuffer->cbName + 1);
591 }
592 }
593
594 return (arc);
595}
596
597/*
598 *@@ doshIsFixedDisk:
599 * checks whether a disk is fixed or removeable.
600 * ulLogicalDrive must be 1 for drive A:, 2 for B:, ...
601 * The result is stored in *pfFixed.
602 * Returns DOS error code.
603 *
604 * Warning: This uses DosDevIOCtl, which has proved
605 * to cause problems with some device drivers for
606 * removeable disks.
607 */
608
609APIRET doshIsFixedDisk(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
610 PBOOL pfFixed) // out: TRUE for fixed disks
611{
612 APIRET arc = ERROR_INVALID_DRIVE;
613
614 if (ulLogicalDrive)
615 {
616 // parameter packet
617 #pragma pack(1)
618 struct {
619 UCHAR command, drive;
620 } parms;
621 #pragma pack()
622
623 // data packet
624 UCHAR ucNonRemoveable;
625
626 ULONG ulParmSize = sizeof(parms);
627 ULONG ulDataSize = sizeof(ucNonRemoveable);
628
629 parms.drive = (UCHAR)(ulLogicalDrive-1);
630 arc = DosDevIOCtl((HFILE)-1,
631 IOCTL_DISK,
632 DSK_BLOCKREMOVABLE,
633 &parms,
634 ulParmSize,
635 &ulParmSize,
636 &ucNonRemoveable,
637 ulDataSize,
638 &ulDataSize);
639
640 if (arc == NO_ERROR)
641 *pfFixed = (BOOL)ucNonRemoveable;
642 }
643
644 return (arc);
645}
646
647/*
648 *@@ doshQueryDiskParams:
649 * this retrieves more information about a given drive,
650 * which is stored in the specified DRIVEPARAMS structure
651 * (dosh.h).
652 *
653 * Warning: This uses DosDevIOCtl, which has proved
654 * to cause problems with some device drivers for
655 * removeable disks.
656 *
657 * This returns the DOS error code of DosDevIOCtl.
658 *
659 *@@added V0.9.0 [umoeller]
660 */
661
662APIRET doshQueryDiskParams(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
663 PDRIVEPARAMS pdp) // out: drive parameters
664{
665 APIRET arc = ERROR_INVALID_DRIVE;
666
667 if (ulLogicalDrive)
668 {
669 #pragma pack(1)
670 // parameter packet
671 struct {
672 UCHAR command, drive;
673 } parms;
674 #pragma pack()
675
676 ULONG ulParmSize = sizeof(parms);
677 ULONG ulDataSize = sizeof(DRIVEPARAMS);
678
679 parms.command = 1; // read currently inserted media
680 parms.drive=(UCHAR)(ulLogicalDrive-1);
681
682 arc = DosDevIOCtl((HFILE)-1,
683 IOCTL_DISK,
684 DSK_GETDEVICEPARAMS,
685 // parameter packet:
686 &parms, ulParmSize, &ulParmSize,
687 // data packet: DRIVEPARAMS structure
688 pdp, ulDataSize, &ulDataSize);
689 }
690
691 return (arc);
692}
693
694/*
695 *@@ doshQueryDiskLabel:
696 * this returns the label of a disk into
697 * *pszVolumeLabel, which must be 12 bytes
698 * in size.
699 *
700 * This function was added because the Toolkit
701 * information for DosQueryFSInfo is only partly
702 * correct. On OS/2 2.x, that function does not
703 * take an FSINFO structure as input, but a VOLUMELABEL.
704 * On Warp, this does take an FSINFO.
705 *
706 * DosSetFSInfo is even worse. See doshSetDiskLabel.
707 *
708 * See http://zebra.asta.fh-weingarten.de/os2/Snippets/Bugi6787.HTML
709 * for details.
710 *
711 *@@added V0.9.0 [umoeller]
712 */
713
714APIRET doshQueryDiskLabel(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
715 PSZ pszVolumeLabel) // out: volume label (must be 12 chars in size)
716{
717 APIRET arc;
718
719 #ifdef __OS2V2X__
720 VOLUMELABEL FSInfoBuf;
721 #else
722 FSINFO FSInfoBuf;
723 #endif
724
725 arc = DosQueryFSInfo(ulLogicalDrive,
726 FSIL_VOLSER,
727 &FSInfoBuf,
728 sizeof(FSInfoBuf)); // depends
729
730 #ifdef __OS2V2X__
731 strcpy(pszVolumeLabel, FSInfoBuf.szVolLabel);
732 #else
733 strcpy(pszVolumeLabel, FSInfoBuf.vol.szVolLabel);
734 #endif
735
736 return (arc);
737}
738
739/*
740 *@@ doshSetDiskLabel:
741 * this sets the label of a disk.
742 *
743 * This function was added because the Toolkit
744 * information for DosSetFSInfo is flat out wrong.
745 * That function does not take an FSINFO structure
746 * as input, but a VOLUMELABEL. As a result, using
747 * that function with the Toolkit's calling specs
748 * results in ERROR_LABEL_TOO_LONG always.
749 *
750 * See http://zebra.asta.fh-weingarten.de/os2/Snippets/Bugi6787.HTML
751 * for details.
752 *
753 *@@added V0.9.0 [umoeller]
754 */
755
756APIRET doshSetDiskLabel(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
757 PSZ pszNewLabel)
758{
759 VOLUMELABEL FSInfoBuf;
760
761 // check length; 11 chars plus null byte allowed
762 FSInfoBuf.cch = (BYTE)strlen(pszNewLabel);
763 if (FSInfoBuf.cch < sizeof(FSInfoBuf.szVolLabel))
764 {
765 strcpy(FSInfoBuf.szVolLabel, pszNewLabel);
766
767 return (DosSetFSInfo(ulLogicalDrive,
768 FSIL_VOLSER,
769 &FSInfoBuf,
770 sizeof(FSInfoBuf)));
771 }
772 else
773 return (ERROR_LABEL_TOO_LONG);
774}
775
776/*
777 *@@category: Helpers\Control program helpers\File management
778 */
779
780/* ******************************************************************
781 * *
782 * File helpers *
783 * *
784 ********************************************************************/
785
786/*
787 *@@ doshGetExtension:
788 * finds the file name extension of pszFilename,
789 * which can be a file name only or a fully
790 * qualified filename.
791 *
792 * This returns a pointer into pszFilename to
793 * the character after the last dot.
794 *
795 * Returns NULL if not found (e.g. if the filename
796 * has no dot in it).
797 *
798 *@@added V0.9.6 (2000-10-16) [umoeller]
799 */
800
801PSZ doshGetExtension(const char *pcszFilename)
802{
803 PSZ pszExtension = 0;
804
805 if (pcszFilename)
806 {
807 // find filename
808 PSZ p2 = strrchr(pcszFilename + 2, '\\'),
809 // works on "C:\blah" or "\\unc\blah"
810 p3 = NULL;
811
812 if (!p2)
813 // no backslash found: then this is not qualified...
814 // use start of filename
815 p2 = (PSZ)pcszFilename;
816
817 // find last dot in filename
818 p3 = strrchr(p2 + 1, '.');
819 if (p3)
820 pszExtension = p3 + 1;
821 }
822
823 return (pszExtension);
824}
825
826/*
827 *@@ doshIsFileOnFAT:
828 * returns TRUE if pszFileName resides on
829 * a FAT drive. Note that pszFileName must
830 * be fully qualified (i.e. the drive letter
831 * must be the first character), or this will
832 * return garbage.
833 */
834
835BOOL doshIsFileOnFAT(const char* pcszFileName)
836{
837 BOOL brc = FALSE;
838 CHAR szName[5];
839
840 APIRET rc = NO_ERROR; // return code
841 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
842 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
843 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
844
845 szName[0] = pcszFileName[0]; // copy drive letter
846 szName[1] = ':';
847 szName[2] = '\0';
848
849 rc = DosQueryFSAttach(szName, // logical drive of attached FS
850 0, // ulOrdinal, ignored for FSAIL_QUERYNAME
851 FSAIL_QUERYNAME, // return data for a Drive or Device
852 pfsqBuffer, // returned data
853 &cbBuffer); // returned data length
854
855 if (rc == NO_ERROR)
856 {
857 // The data for the last three fields in the FSQBUFFER2
858 // structure are stored at the offset of fsqBuffer.szName.
859 // Each data field following fsqBuffer.szName begins
860 // immediately after the previous item.
861 if (strncmp((PSZ)&(pfsqBuffer->szName) + pfsqBuffer->cbName + 1,
862 "FAT",
863 3)
864 == 0)
865 brc = TRUE;
866 }
867
868 return (brc);
869}
870
871/*
872 *@@ doshQueryFileSize:
873 * returns the size of an already opened file
874 * or 0 upon errors.
875 * Use doshQueryPathSize to query the size of
876 * any file.
877 */
878
879ULONG doshQueryFileSize(HFILE hFile)
880{
881 FILESTATUS3 fs3;
882 if (DosQueryFileInfo(hFile, FIL_STANDARD, &fs3, sizeof(fs3)))
883 return (0);
884 else
885 return (fs3.cbFile);
886}
887
888/*
889 *@@ doshQueryPathSize:
890 * returns the size of any file,
891 * or 0 if the file could not be
892 * found.
893 * Use doshQueryFileSize instead to query the
894 * size if you have a HFILE.
895 */
896
897ULONG doshQueryPathSize(PSZ pszFile)
898{
899 FILESTATUS3 fs3;
900 if (DosQueryPathInfo(pszFile, FIL_STANDARD, &fs3, sizeof(fs3)))
901 return (0);
902 else
903 return (fs3.cbFile);
904}
905
906/*
907 *@@ doshQueryPathAttr:
908 * returns the file attributes of pszFile,
909 * which can be fully qualified. The
910 * attributes will be stored in *pulAttr.
911 * pszFile can also specify a directory,
912 * although not all attributes make sense
913 * for directories.
914 *
915 * fAttr can be:
916 * -- FILE_ARCHIVED
917 * -- FILE_READONLY
918 * -- FILE_SYSTEM
919 * -- FILE_HIDDEN
920 *
921 * This returns the APIRET of DosQueryPathAttr.
922 * *pulAttr is only valid if NO_ERROR is
923 * returned.
924 *
925 *@@added V0.9.0 [umoeller]
926 */
927
928APIRET doshQueryPathAttr(const char* pcszFile, // in: file or directory name
929 PULONG pulAttr) // out: attributes
930{
931 FILESTATUS3 fs3;
932 APIRET arc = DosQueryPathInfo((PSZ)pcszFile,
933 FIL_STANDARD,
934 &fs3,
935 sizeof(fs3));
936 if (arc == NO_ERROR)
937 {
938 if (pulAttr)
939 *pulAttr = fs3.attrFile;
940 else
941 arc = ERROR_INVALID_PARAMETER;
942 }
943
944 return (arc);
945}
946
947/*
948 *@@ doshSetPathAttr:
949 * sets the file attributes of pszFile,
950 * which can be fully qualified.
951 * pszFile can also specify a directory,
952 * although not all attributes make sense
953 * for directories.
954 *
955 * fAttr can be:
956 * -- FILE_ARCHIVED
957 * -- FILE_READONLY
958 * -- FILE_SYSTEM
959 * -- FILE_HIDDEN
960 *
961 * Note that this simply sets all the given
962 * attributes; the existing attributes
963 * are lost.
964 *
965 * This returns the APIRET of DosQueryPathInfo.
966 */
967
968APIRET doshSetPathAttr(const char* pcszFile, // in: file or directory name
969 ULONG ulAttr) // in: new attributes
970{
971 FILESTATUS3 fs3;
972 APIRET rc = DosQueryPathInfo((PSZ)pcszFile,
973 FIL_STANDARD,
974 &fs3,
975 sizeof(fs3));
976
977 if (rc == NO_ERROR)
978 {
979 fs3.attrFile = ulAttr;
980 rc = DosSetPathInfo((PSZ)pcszFile,
981 FIL_STANDARD,
982 &fs3,
983 sizeof(fs3),
984 DSPI_WRTTHRU);
985 }
986 return (rc);
987}
988
989/*
990 *@@ doshReadTextFile:
991 * reads a text file from disk, allocates memory
992 * via malloc() and sets a pointer to this
993 * buffer (or NULL upon errors).
994 *
995 * This returns the APIRET of DosOpen and DosRead.
996 * If any error occured, no buffer was allocated.
997 * Otherwise, you should free() the buffer when
998 * no longer needed.
999 */
1000
1001APIRET doshReadTextFile(PSZ pszFile, // in: file name to read
1002 PSZ* ppszContent) // out: newly allocated buffer with file's content
1003{
1004 ULONG ulSize,
1005 ulBytesRead = 0,
1006 ulAction, ulLocal;
1007 HFILE hFile;
1008 PSZ pszContent = NULL;
1009
1010 APIRET arc = DosOpen(pszFile,
1011 &hFile,
1012 &ulAction, // action taken
1013 5000L, // primary allocation size
1014 FILE_ARCHIVED | FILE_NORMAL, // file attribute
1015 OPEN_ACTION_OPEN_IF_EXISTS, // open flags
1016 OPEN_FLAGS_NOINHERIT
1017 | OPEN_SHARE_DENYNONE
1018 | OPEN_ACCESS_READONLY, // read-only mode
1019 NULL); // no EAs
1020
1021 if (arc == NO_ERROR)
1022 {
1023 ulSize = doshQueryFileSize(hFile);
1024 pszContent = (PSZ)malloc(ulSize+1);
1025 arc = DosSetFilePtr(hFile,
1026 0L,
1027 FILE_BEGIN,
1028 &ulLocal);
1029 arc = DosRead(hFile,
1030 pszContent,
1031 ulSize,
1032 &ulBytesRead);
1033 DosClose(hFile);
1034 *(pszContent+ulBytesRead) = 0;
1035
1036 // set output buffer pointer
1037 *ppszContent = pszContent;
1038 }
1039 else
1040 *ppszContent = 0;
1041
1042 return (arc);
1043}
1044
1045/*
1046 *@@ doshCreateBackupFileName:
1047 * creates a valid backup filename of pszExisting
1048 * with a numerical file name extension which does
1049 * not exist in the directory where pszExisting
1050 * resides.
1051 * Returns a PSZ to a new buffer which was allocated
1052 * using malloc().
1053 *
1054 * <B>Example:</B> returns "C:\CONFIG.002" for input
1055 * "C:\CONFIG.SYS" if "C:\CONFIG.001" already exists.
1056 *
1057 *@@changed V0.9.1 (99-12-13) [umoeller]: this crashed if pszExisting had no file extension
1058 */
1059
1060PSZ doshCreateBackupFileName(const char* pszExisting)
1061{
1062 CHAR szFilename[CCHMAXPATH];
1063 PSZ pszLastDot;
1064 ULONG ulCount = 1;
1065 CHAR szCount[5];
1066
1067 strcpy(szFilename, pszExisting);
1068 pszLastDot = strrchr(szFilename, '.');
1069 if (!pszLastDot)
1070 // no dot in filename:
1071 pszLastDot = szFilename + strlen(szFilename);
1072 do
1073 {
1074 sprintf(szCount, ".%03lu", ulCount);
1075 strcpy(pszLastDot, szCount);
1076 ulCount++;
1077 } while (doshQueryPathSize(szFilename) != 0);
1078
1079 return (strdup(szFilename));
1080}
1081
1082/*
1083 *@@ doshWriteTextFile:
1084 * writes a text file to disk; pszFile must contain the
1085 * whole path and filename.
1086 *
1087 * An existing file will be backed up if (pszBackup != NULL),
1088 * using doshCreateBackupFileName. In that case, pszBackup
1089 * receives the name of the backup created, so that buffer
1090 * should be CCHMAXPATH in size.
1091 *
1092 * If (pszbackup == NULL), an existing file will be overwritten.
1093 *
1094 * On success (NO_ERROR returned), *pulWritten receives
1095 * the no. of bytes written.
1096 *
1097 *@@changed V0.9.3 (2000-05-01) [umoeller]: optimized DosOpen; added error checking; changed prototype
1098 *@@changed V0.9.3 (2000-05-12) [umoeller]: added pszBackup
1099 */
1100
1101APIRET doshWriteTextFile(const char* pszFile, // in: file name
1102 const char* pszContent, // in: text to write
1103 PULONG pulWritten, // out: bytes written (ptr can be NULL)
1104 PSZ pszBackup) // in/out: create-backup?
1105{
1106 APIRET arc = NO_ERROR;
1107 ULONG ulWritten = 0;
1108
1109 if ((!pszFile) || (!pszContent))
1110 arc = ERROR_INVALID_PARAMETER;
1111 else
1112 {
1113 ULONG ulAction = 0,
1114 ulLocal = 0;
1115 HFILE hFile = 0;
1116
1117 ULONG ulSize = strlen(pszContent); // exclude 0 byte
1118
1119 if (pszBackup)
1120 {
1121 PSZ pszBackup2 = doshCreateBackupFileName(pszFile);
1122 DosCopy((PSZ)pszFile,
1123 pszBackup2,
1124 DCPY_EXISTING); // delete existing
1125 strcpy(pszBackup, pszBackup2);
1126 free(pszBackup2);
1127 }
1128
1129 arc = DosOpen((PSZ)pszFile,
1130 &hFile,
1131 &ulAction, // action taken
1132 ulSize, // primary allocation size
1133 FILE_ARCHIVED | FILE_NORMAL, // file attribute
1134 OPEN_ACTION_CREATE_IF_NEW
1135 | OPEN_ACTION_REPLACE_IF_EXISTS, // open flags
1136 OPEN_FLAGS_NOINHERIT
1137 | OPEN_FLAGS_SEQUENTIAL // sequential, not random access
1138 | OPEN_SHARE_DENYWRITE // deny write mode
1139 | OPEN_ACCESS_WRITEONLY, // write mode
1140 NULL); // no EAs
1141
1142 if (arc == NO_ERROR)
1143 {
1144 arc = DosSetFilePtr(hFile,
1145 0L,
1146 FILE_BEGIN,
1147 &ulLocal);
1148 if (arc == NO_ERROR)
1149 {
1150 arc = DosWrite(hFile,
1151 (PVOID)pszContent,
1152 ulSize,
1153 &ulWritten);
1154 if (arc == NO_ERROR)
1155 arc = DosSetFileSize(hFile, ulSize);
1156 }
1157
1158 DosClose(hFile);
1159 }
1160 } // end if ((pszFile) && (pszContent))
1161
1162 if (pulWritten)
1163 *pulWritten = ulWritten;
1164
1165 return (arc);
1166}
1167
1168/*
1169 *@@ doshOpenLogFile:
1170 * this opens a log file in the root directory of
1171 * the boot drive; it is titled pszFilename, and
1172 * the file handle is returned.
1173 */
1174
1175HFILE doshOpenLogFile(const char* pcszFilename)
1176{
1177 APIRET rc;
1178 CHAR szFileName[CCHMAXPATH];
1179 HFILE hfLog;
1180 ULONG ulAction;
1181 ULONG ibActual;
1182
1183 sprintf(szFileName, "%c:\\%s", doshQueryBootDrive(), pcszFilename);
1184 rc = DosOpen(szFileName,
1185 &hfLog,
1186 &ulAction,
1187 0, // file size
1188 FILE_NORMAL,
1189 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
1190 OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
1191 (PEAOP2)NULL);
1192 if (rc == NO_ERROR)
1193 {
1194 DosSetFilePtr(hfLog, 0, FILE_END, &ibActual);
1195 return (hfLog);
1196 }
1197 else
1198 return (0);
1199}
1200
1201/*
1202 * doshWriteToLogFile
1203 * writes a string to a log file, adding a
1204 * leading timestamp.
1205 */
1206
1207APIRET doshWriteToLogFile(HFILE hfLog, const char* pcsz)
1208{
1209 if (hfLog)
1210 {
1211 DATETIME dt;
1212 CHAR szTemp[2000];
1213 ULONG cbWritten;
1214 DosGetDateTime(&dt);
1215 sprintf(szTemp, "Time: %02d:%02d:%02d %s",
1216 dt.hours, dt.minutes, dt.seconds,
1217 pcsz);
1218 return (DosWrite(hfLog, (PVOID)szTemp, strlen(szTemp), &cbWritten));
1219 }
1220 else return (ERROR_INVALID_HANDLE);
1221}
1222
1223/*
1224 *@@category: Helpers\Control program helpers\Directory management
1225 */
1226
1227/* ******************************************************************
1228 * *
1229 * Directory helpers *
1230 * *
1231 ********************************************************************/
1232
1233/*
1234 *@@ doshQueryDirExist:
1235 * returns TRUE if the given directory
1236 * exists.
1237 */
1238
1239BOOL doshQueryDirExist(PSZ pszDir)
1240{
1241 FILESTATUS3 fs3;
1242 APIRET arc = DosQueryPathInfo(pszDir, FIL_STANDARD, &fs3, sizeof(fs3));
1243 if (arc == NO_ERROR)
1244 // file found:
1245 return ((fs3.attrFile & FILE_DIRECTORY) != 0);
1246 else
1247 return FALSE;
1248}
1249
1250/*
1251 *@@ doshCreatePath:
1252 * this creates the specified directory.
1253 * As opposed to DosCreateDir, this
1254 * function can create several directories
1255 * at the same time, if the parent
1256 * directories do not exist yet.
1257 */
1258
1259APIRET doshCreatePath(PSZ pszPath,
1260 BOOL fHidden) // in: if TRUE, the new directories will get FILE_HIDDEN
1261{
1262 APIRET arc0 = NO_ERROR;
1263 CHAR path[CCHMAXPATH];
1264 CHAR *cp, c;
1265 ULONG cbPath;
1266
1267 strcpy(path, pszPath);
1268 cbPath = strlen(path);
1269
1270 if (path[cbPath] != '\\')
1271 {
1272 path[cbPath] = '\\';
1273 path[cbPath+1] = 0;
1274 }
1275
1276 cp = path;
1277 // advance past the drive letter only if we have one
1278 if (*(cp+1) == ':')
1279 cp += 3;
1280
1281 // go!
1282 while (*cp != 0)
1283 {
1284 if (*cp == '\\')
1285 {
1286 c = *cp;
1287 *cp = 0;
1288 if (!doshQueryDirExist(path))
1289 {
1290 APIRET arc = DosCreateDir(path,
1291 0); // no EAs
1292 if (arc != NO_ERROR)
1293 {
1294 arc0 = arc;
1295 break;
1296 }
1297 else
1298 if (fHidden)
1299 {
1300 // hide the directory we just created
1301 doshSetPathAttr(path, FILE_HIDDEN);
1302 }
1303 }
1304 *cp = c;
1305 }
1306 cp++;
1307 }
1308 return (arc0);
1309}
1310
1311/*
1312 *@@ doshQueryCurrentDir:
1313 * writes the current directory into
1314 * the specified buffer, which should be
1315 * CCHMAXPATH in size.
1316 *
1317 * As opposed to DosQueryCurrentDir, this
1318 * includes the drive letter.
1319 *
1320 *@@added V0.9.4 (2000-07-22) [umoeller]
1321 */
1322
1323APIRET doshQueryCurrentDir(PSZ pszBuf)
1324{
1325 APIRET arc = NO_ERROR;
1326 ULONG ulCurDisk = 0;
1327 ULONG ulMap = 0;
1328 arc = DosQueryCurrentDisk(&ulCurDisk, &ulMap);
1329 if (arc == NO_ERROR)
1330 {
1331 ULONG cbBuf = CCHMAXPATH - 3;
1332 *pszBuf = G_acDriveLetters[ulCurDisk];
1333 *(pszBuf + 1) = ':';
1334 *(pszBuf + 2) = '\\';
1335 arc = DosQueryCurrentDir(0, pszBuf + 3, &cbBuf);
1336 }
1337
1338 return (arc);
1339}
1340
1341/*
1342 *@@ doshDeleteDir:
1343 * deletes a directory. As opposed to DosDeleteDir,
1344 * this removes empty subdirectories and/or files
1345 * as well.
1346 *
1347 * flFlags can be any combination of the following:
1348 *
1349 * -- DOSHDELDIR_RECURSE: recurse into subdirectories.
1350 *
1351 * -- DOSHDELDIR_DELETEFILES: delete all regular files
1352 * which are found on the way.
1353 *
1354 * THIS IS NOT IMPLEMENTED YET.
1355 *
1356 * If 0 is specified, this effectively behaves just as
1357 * DosDeleteDir.
1358 *
1359 * If you specify DOSHDELDIR_RECURSE only, only empty
1360 * subdirectories are deleted as well.
1361 *
1362 * If you specify DOSHDELDIR_RECURSE | DOSHDELDIR_DELETEFILES,
1363 * this removes an entire directory tree, including all
1364 * subdirectories and files.
1365 *
1366 *@@added V0.9.4 (2000-07-01) [umoeller]
1367 */
1368
1369APIRET doshDeleteDir(const char *pcszDir,
1370 ULONG flFlags,
1371 PULONG pulDirs, // out: directories found
1372 PULONG pulFiles) // out: files found
1373{
1374 APIRET arc = NO_ERROR,
1375 arcReturn = NO_ERROR;
1376
1377 HDIR hdirFindHandle = HDIR_CREATE;
1378 FILEFINDBUF3 ffb3 = {0}; // returned from FindFirst/Next
1379 ULONG ulResultBufLen = sizeof(FILEFINDBUF3);
1380 ULONG ulFindCount = 1; // look for 1 file at a time
1381
1382 CHAR szFileMask[2*CCHMAXPATH];
1383 sprintf(szFileMask, "%s\\*", pcszDir);
1384
1385 // find files
1386 arc = DosFindFirst(szFileMask,
1387 &hdirFindHandle, // directory search handle
1388 FILE_ARCHIVED | FILE_DIRECTORY | FILE_SYSTEM
1389 | FILE_HIDDEN | FILE_READONLY,
1390 // search attributes; include all, even dirs
1391 &ffb3, // result buffer
1392 ulResultBufLen, // result buffer length
1393 &ulFindCount, // number of entries to find
1394 FIL_STANDARD); // return level 1 file info
1395
1396 if (arc == NO_ERROR)
1397 {
1398 // keep finding the next file until there are no more files
1399 while (arc == NO_ERROR) // != ERROR_NO_MORE_FILES
1400 {
1401 if (ffb3.attrFile & FILE_DIRECTORY)
1402 {
1403 // we found a directory:
1404
1405 // ignore the pseudo-directories
1406 if ( (strcmp(ffb3.achName, ".") != 0)
1407 && (strcmp(ffb3.achName, "..") != 0)
1408 )
1409 {
1410 // real directory:
1411 if (flFlags & DOSHDELDIR_RECURSE)
1412 {
1413 // recurse!
1414 CHAR szSubDir[2*CCHMAXPATH];
1415 sprintf(szSubDir, "%s\\%s", pcszDir, ffb3.achName);
1416 arcReturn = doshDeleteDir(szSubDir,
1417 flFlags,
1418 pulDirs,
1419 pulFiles);
1420 // this removes ffb3.achName as well
1421 }
1422 else
1423 {
1424 // directory, but no recursion:
1425 // report "access denied"
1426 // (this is what OS/2 reports with DosDeleteDir as well)
1427 arcReturn = ERROR_ACCESS_DENIED; // 5
1428 (*pulDirs)++;
1429 }
1430 }
1431 }
1432 else
1433 {
1434 // it's a file:
1435 arcReturn = ERROR_ACCESS_DENIED;
1436 (*pulFiles)++;
1437 }
1438
1439 if (arc == NO_ERROR)
1440 {
1441 ulFindCount = 1; // reset find count
1442 arc = DosFindNext(hdirFindHandle, // directory handle
1443 &ffb3, // result buffer
1444 ulResultBufLen, // result buffer length
1445 &ulFindCount); // number of entries to find
1446 }
1447 } // endwhile
1448
1449 DosFindClose(hdirFindHandle); // close our find handle
1450 }
1451
1452 if (arcReturn == NO_ERROR)
1453 // success so far:
1454 // delete our directory now
1455 arc = DosDeleteDir((PSZ)pcszDir);
1456
1457 return (arcReturn);
1458}
1459
1460/*
1461 *@@category: Helpers\Control program helpers\Process management
1462 */
1463
1464/* ******************************************************************
1465 * *
1466 * Process helpers *
1467 * *
1468 ********************************************************************/
1469
1470/*
1471 *@@ doshExecVIO:
1472 * executes cmd.exe with the /c parameter
1473 * and pcszExecWithArgs. This is equivalent
1474 * to the C library system() function,
1475 * except that an OS/2 error code is returned
1476 * and that this works with the VAC subsystem
1477 * library.
1478 *
1479 * This uses DosExecPgm and handles the sick
1480 * argument passing.
1481 *
1482 * If NO_ERROR is returned, *plExitCode receives
1483 * the exit code of the process. If the process
1484 * was terminated abnormally, *plExitCode receives:
1485 *
1486 * -- -1: hard error halt
1487 * -- -2: 16-bit trap
1488 * -- -3: DosKillProcess
1489 * -- -4: 32-bit exception
1490 *
1491 *@@added V0.9.4 (2000-07-27) [umoeller]
1492 */
1493
1494APIRET doshExecVIO(const char *pcszExecWithArgs,
1495 PLONG plExitCode) // out: exit code (ptr can be NULL)
1496{
1497 APIRET arc = NO_ERROR;
1498
1499 if (strlen(pcszExecWithArgs) > 255)
1500 arc = ERROR_INSUFFICIENT_BUFFER;
1501 {
1502 CHAR szObj[CCHMAXPATH];
1503 RESULTCODES res = {0};
1504 CHAR szBuffer[300];
1505
1506 // DosExecPgm expects two args in szBuffer:
1507 // -- cmd.exe\0
1508 // -- then the actual argument, terminated by two 0 bytes.
1509 memset(szBuffer, 0, sizeof(szBuffer));
1510 strcpy(szBuffer, "cmd.exe\0");
1511 sprintf(szBuffer + 8, "/c %s",
1512 pcszExecWithArgs);
1513
1514 arc = DosExecPgm(szObj, sizeof(szObj),
1515 EXEC_SYNC,
1516 szBuffer,
1517 0,
1518 &res,
1519 "cmd.exe");
1520 if ((arc == NO_ERROR) && (plExitCode))
1521 {
1522 if (res.codeTerminate == 0)
1523 // normal exit:
1524 *plExitCode = res.codeResult;
1525 else
1526 *plExitCode = -((LONG)res.codeTerminate);
1527 }
1528 }
1529
1530 return (arc);
1531}
1532
1533/*
1534 *@@ doshQuickStartSession:
1535 * this is a shortcut to DosStartSession w/out having to
1536 * deal with all the messy parameters.
1537 *
1538 * This one starts pszPath as a child session and passes
1539 * pszParams to it.
1540 *
1541 * In usPgmCtl, OR any or none of the following (V0.9.0):
1542 * -- SSF_CONTROL_NOAUTOCLOSE (0x0008): do not close automatically.
1543 * This bit is used only for VIO Windowable apps and ignored
1544 * for all other applications.
1545 * -- SSF_CONTROL_MINIMIZE (0x0004)
1546 * -- SSF_CONTROL_MAXIMIZE (0x0002)
1547 * -- SSF_CONTROL_INVISIBLE (0x0001)
1548 * -- SSF_CONTROL_VISIBLE (0x0000)
1549 *
1550 * Specifying 0 will therefore auto-close the session and make it
1551 * visible.
1552 *
1553 * If (fWait), this function will create a termination queue
1554 * and not return until the child session has ended. Otherwise
1555 * the function will return immediately, and the SID/PID of
1556 * the child session can be found in *pulSID and *ppid.
1557 *
1558 * Returns the error code of DosStartSession.
1559 *
1560 * Note: According to CPREF, calling DosStartSession calls
1561 * DosExecPgm in turn for all full-screen, VIO, and PM sessions.
1562 *
1563 *@@changed V0.9.0 [umoeller]: prototype changed to include usPgmCtl
1564 *@@changed V0.9.1 (99-12-30) [umoeller]: queue was sometimes not closed. Fixed.
1565 *@@changed V0.9.3 (2000-05-03) [umoeller]: added fForeground
1566 */
1567
1568APIRET doshQuickStartSession(const char *pcszPath, // in: program to start
1569 const char *pcszParams, // in: parameters for program
1570 BOOL fForeground, // in: if TRUE, session will be in foreground
1571 USHORT usPgmCtl, // in: STARTDATA.PgmControl
1572 BOOL fWait, // in: wait for termination?
1573 PULONG pulSID, // out: session ID (req.)
1574 PPID ppid) // out: process ID (req.)
1575{
1576 APIRET arc;
1577 // queue stuff
1578 const char *pcszQueueName = "\\queues\\kfgstart.que";
1579 HQUEUE hq = 0;
1580 PID qpid = 0;
1581 STARTDATA SData;
1582 CHAR szObjBuf[CCHMAXPATH];
1583
1584 if (fWait)
1585 {
1586 if ((arc = DosCreateQueue(&hq,
1587 QUE_FIFO | QUE_CONVERT_ADDRESS,
1588 (PSZ)pcszQueueName))
1589 != NO_ERROR)
1590 return (arc);
1591
1592 if ((arc = DosOpenQueue(&qpid, &hq, (PSZ)pcszQueueName)) != NO_ERROR)
1593 return (arc);
1594 }
1595
1596 SData.Length = sizeof(STARTDATA);
1597 SData.Related = SSF_RELATED_CHILD; //INDEPENDENT;
1598 SData.FgBg = (fForeground) ? SSF_FGBG_FORE : SSF_FGBG_BACK;
1599 // V0.9.3 (2000-05-03) [umoeller]
1600 SData.TraceOpt = SSF_TRACEOPT_NONE;
1601
1602 SData.PgmTitle = (PSZ)pcszPath; // title for window
1603 SData.PgmName = (PSZ)pcszPath;
1604 SData.PgmInputs = (PSZ)pcszParams;
1605
1606 SData.TermQ = (fWait) ? "\\queues\\kfgstart.que" : NULL;
1607 SData.Environment = 0;
1608 SData.InheritOpt = SSF_INHERTOPT_PARENT;
1609 SData.SessionType = SSF_TYPE_DEFAULT;
1610 SData.IconFile = 0;
1611 SData.PgmHandle = 0;
1612
1613 SData.PgmControl = usPgmCtl;
1614
1615 SData.InitXPos = 30;
1616 SData.InitYPos = 40;
1617 SData.InitXSize = 200;
1618 SData.InitYSize = 140;
1619 SData.Reserved = 0;
1620 SData.ObjectBuffer = (CHAR*)&szObjBuf;
1621 SData.ObjectBuffLen = (ULONG)sizeof(szObjBuf);
1622
1623 arc = DosStartSession(&SData, pulSID, ppid);
1624
1625 if (arc == NO_ERROR)
1626 {
1627 if (fWait)
1628 {
1629 REQUESTDATA rqdata;
1630 ULONG DataLength = 0;
1631 PULONG DataAddress;
1632 BYTE elpri;
1633
1634 rqdata.pid = qpid;
1635 DosReadQueue(hq, // in: queue handle
1636 &rqdata, // out: pid and ulData
1637 &DataLength, // out: size of data returned
1638 (PVOID*)&DataAddress, // out: data returned
1639 0, // in: remove first element in queue
1640 0, // in: wait for queue data (block thread)
1641 &elpri, // out: element's priority
1642 0); // in: event semaphore to be posted
1643 }
1644 }
1645
1646 if (hq)
1647 DosCloseQueue(hq);
1648
1649 return (arc);
1650}
1651
1652
Note: See TracBrowser for help on using the repository browser.