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

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

Initial checkin of helpers code which used to be in WarpIN.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 52.6 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 switch (arc)
468 {
469 case ERROR_NETWORK_ACCESS_DENIED: // 65
470 // added V0.9.3 (2000-03-27) [umoeller];
471 // according to user reports, this is returned
472 // by all network drives, which apparently don't
473 // support DASD DosOpen
474 case ERROR_ACCESS_DENIED: // 5
475 // added V0.9.4 (2000-07-10) [umoeller]
476 // LAN drives still didn't work... apparently
477 // the above only works for NFS drives
478 case ERROR_PATH_NOT_FOUND: // 3
479 // added V0.9.4 (2000-08-03) [umoeller]:
480 // this is returned by some other network types...
481 // sigh...
482 case ERROR_NOT_SUPPORTED: // 50
483 {
484 // this is returned by file systems which don't
485 // support DASD DosOpen;
486 // use some other method then, this isn't likely
487 // to fail -- V0.9.1 (2000-02-09) [umoeller]
488 FSALLOCATE fsa;
489 arc = DosQueryFSInfo(ulLogicalDrive,
490 FSIL_ALLOC,
491 &fsa,
492 sizeof(fsa));
493 break; }
494
495 case NO_ERROR:
496 DosClose(hfDrive);
497 break;
498 }
499
500 return (arc);
501
502 /* FSALLOCATE fsa;
503 APIRET arc = NO_ERROR;
504
505 if (fSuppress)
506 {
507 DosError(FERR_DISABLEHARDERR | FERR_DISABLEEXCEPTION);
508 DosEnterCritSec();
509 }
510
511 arc = DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa));
512
513 if (fSuppress)
514 {
515 DosError(FERR_ENABLEHARDERR | FERR_ENABLEEXCEPTION);
516 DosExitCritSec();
517 }
518
519 return (arc); */
520}
521
522/*
523 *@@ doshQueryDiskFree:
524 * returns the number of bytes remaining on the disk
525 * specified by the given logical drive, or -1 upon errors.
526 *
527 * Note: This returns a "double" value, because a ULONG
528 * can only hold values of some 4 billion, which would
529 * lead to funny results for drives > 4 GB.
530 *
531 *@@changed V0.9.0 [umoeller]: fixed another > 4 GB bug (thanks to Rdiger Ihle)
532 */
533
534double doshQueryDiskFree(ULONG ulLogicalDrive) // in: 1 for A:, 2 for B:, 3 for C:, ...
535{
536 FSALLOCATE fsa;
537 double dbl = -1;
538
539 if (ulLogicalDrive)
540 if (DosQueryFSInfo(ulLogicalDrive, FSIL_ALLOC, &fsa, sizeof(fsa))
541 == NO_ERROR)
542 dbl = ((double)fsa.cSectorUnit * fsa.cbSector * fsa.cUnitAvail);
543 // ^ fixed V0.9.0
544
545 return (dbl);
546}
547
548/*
549 *@@ doshQueryDiskFSType:
550 * copies the file-system type of the given disk object
551 * (HPFS, FAT, CDFS etc.) to pszBuf.
552 * Returns the DOS error code.
553 *
554 *@@changed V0.9.1 (99-12-12) [umoeller]: added cbBuf to prototype
555 */
556
557APIRET doshQueryDiskFSType(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
558 PSZ pszBuf, // out: buffer for FS type
559 ULONG cbBuf) // in: size of that buffer
560{
561 APIRET arc = NO_ERROR;
562 CHAR szName[5];
563
564 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
565 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
566 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
567
568 // compose "D:"-type string from logical drive letter
569 szName[0] = G_acDriveLetters[ulLogicalDrive];
570 szName[1] = ':';
571 szName[2] = '\0';
572
573 arc = DosQueryFSAttach(szName, // logical drive of attached FS ("D:"-style)
574 0, // ulOrdinal, ignored for FSAIL_QUERYNAME
575 FSAIL_QUERYNAME, // return name for a drive or device
576 pfsqBuffer, // buffer for returned data
577 &cbBuffer); // sizeof(*pfsqBuffer)
578
579 if (arc == NO_ERROR)
580 {
581 if (pszBuf)
582 {
583 // The data for the last three fields in the FSQBUFFER2
584 // structure are stored at the offset of fsqBuffer.szName.
585 // Each data field following fsqBuffer.szName begins
586 // immediately after the previous item.
587 strcpy(pszBuf,
588 (CHAR*)(&pfsqBuffer->szName) + pfsqBuffer->cbName + 1);
589 }
590 }
591
592 return (arc);
593}
594
595/*
596 *@@ doshIsFixedDisk:
597 * checks whether a disk is fixed or removeable.
598 * ulLogicalDrive must be 1 for drive A:, 2 for B:, ...
599 * The result is stored in *pfFixed.
600 * Returns DOS error code.
601 *
602 * Warning: This uses DosDevIOCtl, which has proved
603 * to cause problems with some device drivers for
604 * removeable disks.
605 */
606
607APIRET doshIsFixedDisk(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
608 PBOOL pfFixed) // out: TRUE for fixed disks
609{
610 APIRET arc = ERROR_INVALID_DRIVE;
611
612 if (ulLogicalDrive)
613 {
614 // parameter packet
615 #pragma pack(1)
616 struct {
617 UCHAR command, drive;
618 } parms;
619 #pragma pack()
620
621 // data packet
622 UCHAR ucNonRemoveable;
623
624 ULONG ulParmSize = sizeof(parms);
625 ULONG ulDataSize = sizeof(ucNonRemoveable);
626
627 parms.drive = (UCHAR)(ulLogicalDrive-1);
628 arc = DosDevIOCtl((HFILE)-1,
629 IOCTL_DISK,
630 DSK_BLOCKREMOVABLE,
631 &parms,
632 ulParmSize,
633 &ulParmSize,
634 &ucNonRemoveable,
635 ulDataSize,
636 &ulDataSize);
637
638 if (arc == NO_ERROR)
639 *pfFixed = (BOOL)ucNonRemoveable;
640 }
641
642 return (arc);
643}
644
645/*
646 *@@ doshQueryDiskParams:
647 * this retrieves more information about a given drive,
648 * which is stored in the specified DRIVEPARAMS structure
649 * (dosh.h).
650 *
651 * Warning: This uses DosDevIOCtl, which has proved
652 * to cause problems with some device drivers for
653 * removeable disks.
654 *
655 * This returns the DOS error code of DosDevIOCtl.
656 *
657 *@@added V0.9.0 [umoeller]
658 */
659
660APIRET doshQueryDiskParams(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
661 PDRIVEPARAMS pdp) // out: drive parameters
662{
663 APIRET arc = ERROR_INVALID_DRIVE;
664
665 if (ulLogicalDrive)
666 {
667 #pragma pack(1)
668 // parameter packet
669 struct {
670 UCHAR command, drive;
671 } parms;
672 #pragma pack()
673
674 ULONG ulParmSize = sizeof(parms);
675 ULONG ulDataSize = sizeof(DRIVEPARAMS);
676
677 parms.command = 1; // read currently inserted media
678 parms.drive=(UCHAR)(ulLogicalDrive-1);
679
680 arc = DosDevIOCtl((HFILE)-1,
681 IOCTL_DISK,
682 DSK_GETDEVICEPARAMS,
683 // parameter packet:
684 &parms, ulParmSize, &ulParmSize,
685 // data packet: DRIVEPARAMS structure
686 pdp, ulDataSize, &ulDataSize);
687 }
688
689 return (arc);
690}
691
692/*
693 *@@ doshQueryDiskLabel:
694 * this returns the label of a disk into
695 * *pszVolumeLabel, which must be 12 bytes
696 * in size.
697 *
698 * This function was added because the Toolkit
699 * information for DosQueryFSInfo is only partly
700 * correct. On OS/2 2.x, that function does not
701 * take an FSINFO structure as input, but a VOLUMELABEL.
702 * On Warp, this does take an FSINFO.
703 *
704 * DosSetFSInfo is even worse. See doshSetDiskLabel.
705 *
706 * See http://zebra.asta.fh-weingarten.de/os2/Snippets/Bugi6787.HTML
707 * for details.
708 *
709 *@@added V0.9.0 [umoeller]
710 */
711
712APIRET doshQueryDiskLabel(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
713 PSZ pszVolumeLabel) // out: volume label (must be 12 chars in size)
714{
715 APIRET arc;
716
717 #ifdef __OS2V2X__
718 VOLUMELABEL FSInfoBuf;
719 #else
720 FSINFO FSInfoBuf;
721 #endif
722
723 arc = DosQueryFSInfo(ulLogicalDrive,
724 FSIL_VOLSER,
725 &FSInfoBuf,
726 sizeof(FSInfoBuf)); // depends
727
728 #ifdef __OS2V2X__
729 strcpy(pszVolumeLabel, FSInfoBuf.szVolLabel);
730 #else
731 strcpy(pszVolumeLabel, FSInfoBuf.vol.szVolLabel);
732 #endif
733
734 return (arc);
735}
736
737/*
738 *@@ doshSetDiskLabel:
739 * this sets the label of a disk.
740 *
741 * This function was added because the Toolkit
742 * information for DosSetFSInfo is flat out wrong.
743 * That function does not take an FSINFO structure
744 * as input, but a VOLUMELABEL. As a result, using
745 * that function with the Toolkit's calling specs
746 * results in ERROR_LABEL_TOO_LONG always.
747 *
748 * See http://zebra.asta.fh-weingarten.de/os2/Snippets/Bugi6787.HTML
749 * for details.
750 *
751 *@@added V0.9.0 [umoeller]
752 */
753
754APIRET doshSetDiskLabel(ULONG ulLogicalDrive, // in: 1 for A:, 2 for B:, 3 for C:, ...
755 PSZ pszNewLabel)
756{
757 VOLUMELABEL FSInfoBuf;
758
759 // check length; 11 chars plus null byte allowed
760 FSInfoBuf.cch = (BYTE)strlen(pszNewLabel);
761 if (FSInfoBuf.cch < sizeof(FSInfoBuf.szVolLabel))
762 {
763 strcpy(FSInfoBuf.szVolLabel, pszNewLabel);
764
765 return (DosSetFSInfo(ulLogicalDrive,
766 FSIL_VOLSER,
767 &FSInfoBuf,
768 sizeof(FSInfoBuf)));
769 }
770 else
771 return (ERROR_LABEL_TOO_LONG);
772}
773
774/*
775 *@@category: Helpers\Control program helpers\File management
776 */
777
778/* ******************************************************************
779 * *
780 * File helpers *
781 * *
782 ********************************************************************/
783
784/*
785 *@@ doshGetExtension:
786 * finds the file name extension of pszFilename,
787 * which can be a file name only or a fully
788 * qualified filename.
789 *
790 * This returns a pointer into pszFilename to
791 * the character after the last dot.
792 *
793 * Returns NULL if not found (e.g. if the filename
794 * has no dot in it).
795 *
796 *@@added V0.9.6 (2000-10-16) [umoeller]
797 */
798
799PSZ doshGetExtension(const char *pcszFilename)
800{
801 PSZ pszExtension = 0;
802
803 if (pcszFilename)
804 {
805 // find filename
806 PSZ p2 = strrchr(pcszFilename + 2, '\\'),
807 // works on "C:\blah" or "\\unc\blah"
808 p3 = NULL;
809
810 if (!p2)
811 // no backslash found: then this is not qualified...
812 // use start of filename
813 p2 = (PSZ)pcszFilename;
814
815 // find last dot in filename
816 p3 = strrchr(p2 + 1, '.');
817 if (p3)
818 pszExtension = p3 + 1;
819 }
820
821 return (pszExtension);
822}
823
824/*
825 *@@ doshIsFileOnFAT:
826 * returns TRUE if pszFileName resides on
827 * a FAT drive. Note that pszFileName must
828 * be fully qualified (i.e. the drive letter
829 * must be the first character), or this will
830 * return garbage.
831 */
832
833BOOL doshIsFileOnFAT(const char* pcszFileName)
834{
835 BOOL brc = FALSE;
836 CHAR szName[5];
837
838 APIRET rc = NO_ERROR; // return code
839 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
840 ULONG cbBuffer = sizeof(fsqBuffer); // Buffer length)
841 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2)fsqBuffer;
842
843 szName[0] = pcszFileName[0]; // copy drive letter
844 szName[1] = ':';
845 szName[2] = '\0';
846
847 rc = DosQueryFSAttach(szName, // logical drive of attached FS
848 0, // ulOrdinal, ignored for FSAIL_QUERYNAME
849 FSAIL_QUERYNAME, // return data for a Drive or Device
850 pfsqBuffer, // returned data
851 &cbBuffer); // returned data length
852
853 if (rc == NO_ERROR)
854 {
855 // The data for the last three fields in the FSQBUFFER2
856 // structure are stored at the offset of fsqBuffer.szName.
857 // Each data field following fsqBuffer.szName begins
858 // immediately after the previous item.
859 if (strncmp((PSZ)&(pfsqBuffer->szName) + pfsqBuffer->cbName + 1,
860 "FAT",
861 3)
862 == 0)
863 brc = TRUE;
864 }
865
866 return (brc);
867}
868
869/*
870 *@@ doshQueryFileSize:
871 * returns the size of an already opened file
872 * or 0 upon errors.
873 * Use doshQueryPathSize to query the size of
874 * any file.
875 */
876
877ULONG doshQueryFileSize(HFILE hFile)
878{
879 FILESTATUS3 fs3;
880 if (DosQueryFileInfo(hFile, FIL_STANDARD, &fs3, sizeof(fs3)))
881 return (0);
882 else
883 return (fs3.cbFile);
884}
885
886/*
887 *@@ doshQueryPathSize:
888 * returns the size of any file,
889 * or 0 if the file could not be
890 * found.
891 * Use doshQueryFileSize instead to query the
892 * size if you have a HFILE.
893 */
894
895ULONG doshQueryPathSize(PSZ pszFile)
896{
897 FILESTATUS3 fs3;
898 if (DosQueryPathInfo(pszFile, FIL_STANDARD, &fs3, sizeof(fs3)))
899 return (0);
900 else
901 return (fs3.cbFile);
902}
903
904/*
905 *@@ doshQueryPathAttr:
906 * returns the file attributes of pszFile,
907 * which can be fully qualified. The
908 * attributes will be stored in *pulAttr.
909 * pszFile can also specify a directory,
910 * although not all attributes make sense
911 * for directories.
912 *
913 * fAttr can be:
914 * -- FILE_ARCHIVED
915 * -- FILE_READONLY
916 * -- FILE_SYSTEM
917 * -- FILE_HIDDEN
918 *
919 * This returns the APIRET of DosQueryPathAttr.
920 * *pulAttr is only valid if NO_ERROR is
921 * returned.
922 *
923 *@@added V0.9.0 [umoeller]
924 */
925
926APIRET doshQueryPathAttr(const char* pcszFile, // in: file or directory name
927 PULONG pulAttr) // out: attributes
928{
929 FILESTATUS3 fs3;
930 APIRET arc = DosQueryPathInfo((PSZ)pcszFile,
931 FIL_STANDARD,
932 &fs3,
933 sizeof(fs3));
934 if (arc == NO_ERROR)
935 {
936 if (pulAttr)
937 *pulAttr = fs3.attrFile;
938 else
939 arc = ERROR_INVALID_PARAMETER;
940 }
941
942 return (arc);
943}
944
945/*
946 *@@ doshSetPathAttr:
947 * sets the file attributes of pszFile,
948 * which can be fully qualified.
949 * pszFile can also specify a directory,
950 * although not all attributes make sense
951 * for directories.
952 *
953 * fAttr can be:
954 * -- FILE_ARCHIVED
955 * -- FILE_READONLY
956 * -- FILE_SYSTEM
957 * -- FILE_HIDDEN
958 *
959 * Note that this simply sets all the given
960 * attributes; the existing attributes
961 * are lost.
962 *
963 * This returns the APIRET of DosQueryPathInfo.
964 */
965
966APIRET doshSetPathAttr(const char* pcszFile, // in: file or directory name
967 ULONG ulAttr) // in: new attributes
968{
969 FILESTATUS3 fs3;
970 APIRET rc = DosQueryPathInfo((PSZ)pcszFile,
971 FIL_STANDARD,
972 &fs3,
973 sizeof(fs3));
974
975 if (rc == NO_ERROR)
976 {
977 fs3.attrFile = ulAttr;
978 rc = DosSetPathInfo((PSZ)pcszFile,
979 FIL_STANDARD,
980 &fs3,
981 sizeof(fs3),
982 DSPI_WRTTHRU);
983 }
984 return (rc);
985}
986
987/*
988 *@@ doshReadTextFile:
989 * reads a text file from disk, allocates memory
990 * via malloc() and sets a pointer to this
991 * buffer (or NULL upon errors).
992 *
993 * This returns the APIRET of DosOpen and DosRead.
994 * If any error occured, no buffer was allocated.
995 * Otherwise, you should free() the buffer when
996 * no longer needed.
997 */
998
999APIRET doshReadTextFile(PSZ pszFile, // in: file name to read
1000 PSZ* ppszContent) // out: newly allocated buffer with file's content
1001{
1002 ULONG ulSize,
1003 ulBytesRead = 0,
1004 ulAction, ulLocal;
1005 HFILE hFile;
1006 PSZ pszContent = NULL;
1007
1008 APIRET arc = DosOpen(pszFile,
1009 &hFile,
1010 &ulAction, // action taken
1011 5000L, // primary allocation size
1012 FILE_ARCHIVED | FILE_NORMAL, // file attribute
1013 OPEN_ACTION_OPEN_IF_EXISTS, // open flags
1014 OPEN_FLAGS_NOINHERIT
1015 | OPEN_SHARE_DENYNONE
1016 | OPEN_ACCESS_READONLY, // read-only mode
1017 NULL); // no EAs
1018
1019 if (arc == NO_ERROR)
1020 {
1021 ulSize = doshQueryFileSize(hFile);
1022 pszContent = (PSZ)malloc(ulSize+1);
1023 arc = DosSetFilePtr(hFile,
1024 0L,
1025 FILE_BEGIN,
1026 &ulLocal);
1027 arc = DosRead(hFile,
1028 pszContent,
1029 ulSize,
1030 &ulBytesRead);
1031 DosClose(hFile);
1032 *(pszContent+ulBytesRead) = 0;
1033
1034 // set output buffer pointer
1035 *ppszContent = pszContent;
1036 }
1037 else
1038 *ppszContent = 0;
1039
1040 return (arc);
1041}
1042
1043/*
1044 *@@ doshCreateBackupFileName:
1045 * creates a valid backup filename of pszExisting
1046 * with a numerical file name extension which does
1047 * not exist in the directory where pszExisting
1048 * resides.
1049 * Returns a PSZ to a new buffer which was allocated
1050 * using malloc().
1051 *
1052 * <B>Example:</B> returns "C:\CONFIG.002" for input
1053 * "C:\CONFIG.SYS" if "C:\CONFIG.001" already exists.
1054 *
1055 *@@changed V0.9.1 (99-12-13) [umoeller]: this crashed if pszExisting had no file extension
1056 */
1057
1058PSZ doshCreateBackupFileName(const char* pszExisting)
1059{
1060 CHAR szFilename[CCHMAXPATH];
1061 PSZ pszLastDot;
1062 ULONG ulCount = 1;
1063 CHAR szCount[5];
1064
1065 strcpy(szFilename, pszExisting);
1066 pszLastDot = strrchr(szFilename, '.');
1067 if (!pszLastDot)
1068 // no dot in filename:
1069 pszLastDot = szFilename + strlen(szFilename);
1070 do
1071 {
1072 sprintf(szCount, ".%03d", ulCount);
1073 strcpy(pszLastDot, szCount);
1074 ulCount++;
1075 } while (doshQueryPathSize(szFilename) != 0);
1076
1077 return (strdup(szFilename));
1078}
1079
1080/*
1081 *@@ doshWriteTextFile:
1082 * writes a text file to disk; pszFile must contain the
1083 * whole path and filename.
1084 *
1085 * An existing file will be backed up if (pszBackup != NULL),
1086 * using doshCreateBackupFileName. In that case, pszBackup
1087 * receives the name of the backup created, so that buffer
1088 * should be CCHMAXPATH in size.
1089 *
1090 * If (pszbackup == NULL), an existing file will be overwritten.
1091 *
1092 * On success (NO_ERROR returned), *pulWritten receives
1093 * the no. of bytes written.
1094 *
1095 *@@changed V0.9.3 (2000-05-01) [umoeller]: optimized DosOpen; added error checking; changed prototype
1096 *@@changed V0.9.3 (2000-05-12) [umoeller]: added pszBackup
1097 */
1098
1099APIRET doshWriteTextFile(const char* pszFile, // in: file name
1100 const char* pszContent, // in: text to write
1101 PULONG pulWritten, // out: bytes written (ptr can be NULL)
1102 PSZ pszBackup) // in/out: create-backup?
1103{
1104 APIRET arc = NO_ERROR;
1105 ULONG ulWritten = 0;
1106
1107 if ((!pszFile) || (!pszContent))
1108 arc = ERROR_INVALID_PARAMETER;
1109 else
1110 {
1111 ULONG ulAction = 0,
1112 ulLocal = 0;
1113 HFILE hFile = 0;
1114
1115 ULONG ulSize = strlen(pszContent); // exclude 0 byte
1116
1117 if (pszBackup)
1118 {
1119 PSZ pszBackup2 = doshCreateBackupFileName(pszFile);
1120 DosCopy((PSZ)pszFile,
1121 pszBackup2,
1122 DCPY_EXISTING); // delete existing
1123 strcpy(pszBackup, pszBackup2);
1124 free(pszBackup2);
1125 }
1126
1127 arc = DosOpen((PSZ)pszFile,
1128 &hFile,
1129 &ulAction, // action taken
1130 ulSize, // primary allocation size
1131 FILE_ARCHIVED | FILE_NORMAL, // file attribute
1132 OPEN_ACTION_CREATE_IF_NEW
1133 | OPEN_ACTION_REPLACE_IF_EXISTS, // open flags
1134 OPEN_FLAGS_NOINHERIT
1135 | OPEN_FLAGS_SEQUENTIAL // sequential, not random access
1136 | OPEN_SHARE_DENYWRITE // deny write mode
1137 | OPEN_ACCESS_WRITEONLY, // write mode
1138 NULL); // no EAs
1139
1140 if (arc == NO_ERROR)
1141 {
1142 arc = DosSetFilePtr(hFile,
1143 0L,
1144 FILE_BEGIN,
1145 &ulLocal);
1146 if (arc == NO_ERROR)
1147 {
1148 arc = DosWrite(hFile,
1149 (PVOID)pszContent,
1150 ulSize,
1151 &ulWritten);
1152 if (arc == NO_ERROR)
1153 arc = DosSetFileSize(hFile, ulSize);
1154 }
1155
1156 DosClose(hFile);
1157 }
1158 } // end if ((pszFile) && (pszContent))
1159
1160 if (pulWritten)
1161 *pulWritten = ulWritten;
1162
1163 return (arc);
1164}
1165
1166/*
1167 *@@ doshOpenLogFile:
1168 * this opens a log file in the root directory of
1169 * the boot drive; it is titled pszFilename, and
1170 * the file handle is returned.
1171 */
1172
1173HFILE doshOpenLogFile(const char* pcszFilename)
1174{
1175 APIRET rc;
1176 CHAR szFileName[CCHMAXPATH];
1177 HFILE hfLog;
1178 ULONG ulAction;
1179 ULONG ibActual;
1180
1181 sprintf(szFileName, "%c:\\%s", doshQueryBootDrive(), pcszFilename);
1182 rc = DosOpen(szFileName,
1183 &hfLog,
1184 &ulAction,
1185 0, // file size
1186 FILE_NORMAL,
1187 OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
1188 OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE,
1189 (PEAOP2)NULL);
1190 if (rc == NO_ERROR)
1191 {
1192 DosSetFilePtr(hfLog, 0, FILE_END, &ibActual);
1193 return (hfLog);
1194 }
1195 else
1196 return (0);
1197}
1198
1199/*
1200 * doshWriteToLogFile
1201 * writes a string to a log file, adding a
1202 * leading timestamp.
1203 */
1204
1205APIRET doshWriteToLogFile(HFILE hfLog, const char* pcsz)
1206{
1207 if (hfLog)
1208 {
1209 DATETIME dt;
1210 CHAR szTemp[2000];
1211 ULONG cbWritten;
1212 DosGetDateTime(&dt);
1213 sprintf(szTemp, "Time: %02d:%02d:%02d %s",
1214 dt.hours, dt.minutes, dt.seconds,
1215 pcsz);
1216 return (DosWrite(hfLog, (PVOID)szTemp, strlen(szTemp), &cbWritten));
1217 }
1218 else return (ERROR_INVALID_HANDLE);
1219}
1220
1221/*
1222 *@@category: Helpers\Control program helpers\Directory management
1223 */
1224
1225/* ******************************************************************
1226 * *
1227 * Directory helpers *
1228 * *
1229 ********************************************************************/
1230
1231/*
1232 *@@ doshQueryDirExist:
1233 * returns TRUE if the given directory
1234 * exists.
1235 */
1236
1237BOOL doshQueryDirExist(PSZ pszDir)
1238{
1239 FILESTATUS3 fs3;
1240 APIRET arc = DosQueryPathInfo(pszDir, FIL_STANDARD, &fs3, sizeof(fs3));
1241 if (arc == NO_ERROR)
1242 // file found:
1243 return ((fs3.attrFile & FILE_DIRECTORY) != 0);
1244 else
1245 return FALSE;
1246}
1247
1248/*
1249 *@@ doshCreatePath:
1250 * this creates the specified directory.
1251 * As opposed to DosCreateDir, this
1252 * function can create several directories
1253 * at the same time, if the parent
1254 * directories do not exist yet.
1255 */
1256
1257APIRET doshCreatePath(PSZ pszPath,
1258 BOOL fHidden) // in: if TRUE, the new directories will get FILE_HIDDEN
1259{
1260 APIRET arc0 = NO_ERROR;
1261 CHAR path[CCHMAXPATH];
1262 CHAR *cp, c;
1263 ULONG cbPath;
1264
1265 strcpy(path, pszPath);
1266 cbPath = strlen(path);
1267
1268 if (path[cbPath] != '\\')
1269 {
1270 path[cbPath] = '\\';
1271 path[cbPath+1] = 0;
1272 }
1273
1274 cp = path;
1275 // advance past the drive letter only if we have one
1276 if (*(cp+1) == ':')
1277 cp += 3;
1278
1279 // go!
1280 while (*cp != 0)
1281 {
1282 if (*cp == '\\')
1283 {
1284 c = *cp;
1285 *cp = 0;
1286 if (!doshQueryDirExist(path))
1287 {
1288 APIRET arc = DosCreateDir(path,
1289 0); // no EAs
1290 if (arc != NO_ERROR)
1291 {
1292 arc0 = arc;
1293 break;
1294 }
1295 else
1296 if (fHidden)
1297 {
1298 // hide the directory we just created
1299 doshSetPathAttr(path, FILE_HIDDEN);
1300 }
1301 }
1302 *cp = c;
1303 }
1304 cp++;
1305 }
1306 return (arc0);
1307}
1308
1309/*
1310 *@@ doshQueryCurrentDir:
1311 * writes the current directory into
1312 * the specified buffer, which should be
1313 * CCHMAXPATH in size.
1314 *
1315 * As opposed to DosQueryCurrentDir, this
1316 * includes the drive letter.
1317 *
1318 *@@added V0.9.4 (2000-07-22) [umoeller]
1319 */
1320
1321APIRET doshQueryCurrentDir(PSZ pszBuf)
1322{
1323 APIRET arc = NO_ERROR;
1324 ULONG ulCurDisk = 0;
1325 ULONG ulMap = 0;
1326 arc = DosQueryCurrentDisk(&ulCurDisk, &ulMap);
1327 if (arc == NO_ERROR)
1328 {
1329 ULONG cbBuf = CCHMAXPATH - 3;
1330 *pszBuf = G_acDriveLetters[ulCurDisk];
1331 *(pszBuf + 1) = ':';
1332 *(pszBuf + 2) = '\\';
1333 arc = DosQueryCurrentDir(0, pszBuf + 3, &cbBuf);
1334 }
1335
1336 return (arc);
1337}
1338
1339/*
1340 *@@ doshDeleteDir:
1341 * deletes a directory. As opposed to DosDeleteDir,
1342 * this removes empty subdirectories and/or files
1343 * as well.
1344 *
1345 * flFlags can be any combination of the following:
1346 *
1347 * -- DOSHDELDIR_RECURSE: recurse into subdirectories.
1348 *
1349 * -- DOSHDELDIR_DELETEFILES: delete all regular files
1350 * which are found on the way.
1351 *
1352 * THIS IS NOT IMPLEMENTED YET.
1353 *
1354 * If 0 is specified, this effectively behaves just as
1355 * DosDeleteDir.
1356 *
1357 * If you specify DOSHDELDIR_RECURSE only, only empty
1358 * subdirectories are deleted as well.
1359 *
1360 * If you specify DOSHDELDIR_RECURSE | DOSHDELDIR_DELETEFILES,
1361 * this removes an entire directory tree, including all
1362 * subdirectories and files.
1363 *
1364 *@@added V0.9.4 (2000-07-01) [umoeller]
1365 */
1366
1367APIRET doshDeleteDir(const char *pcszDir,
1368 ULONG flFlags,
1369 PULONG pulDirs, // out: directories found
1370 PULONG pulFiles) // out: files found
1371{
1372 APIRET arc = NO_ERROR,
1373 arcReturn = NO_ERROR;
1374
1375 HDIR hdirFindHandle = HDIR_CREATE;
1376 FILEFINDBUF3 ffb3 = {0}; // returned from FindFirst/Next
1377 ULONG ulResultBufLen = sizeof(FILEFINDBUF3);
1378 ULONG ulFindCount = 1; // look for 1 file at a time
1379
1380 CHAR szFileMask[2*CCHMAXPATH];
1381 sprintf(szFileMask, "%s\\*", pcszDir);
1382
1383 // find files
1384 arc = DosFindFirst(szFileMask,
1385 &hdirFindHandle, // directory search handle
1386 FILE_ARCHIVED | FILE_DIRECTORY | FILE_SYSTEM
1387 | FILE_HIDDEN | FILE_READONLY,
1388 // search attributes; include all, even dirs
1389 &ffb3, // result buffer
1390 ulResultBufLen, // result buffer length
1391 &ulFindCount, // number of entries to find
1392 FIL_STANDARD); // return level 1 file info
1393
1394 if (arc == NO_ERROR)
1395 {
1396 // keep finding the next file until there are no more files
1397 while (arc == NO_ERROR) // != ERROR_NO_MORE_FILES
1398 {
1399 if (ffb3.attrFile & FILE_DIRECTORY)
1400 {
1401 // we found a directory:
1402
1403 // ignore the pseudo-directories
1404 if ( (strcmp(ffb3.achName, ".") != 0)
1405 && (strcmp(ffb3.achName, "..") != 0)
1406 )
1407 {
1408 // real directory:
1409 if (flFlags & DOSHDELDIR_RECURSE)
1410 {
1411 // recurse!
1412 CHAR szSubDir[2*CCHMAXPATH];
1413 sprintf(szSubDir, "%s\\%s", pcszDir, ffb3.achName);
1414 arcReturn = doshDeleteDir(szSubDir,
1415 flFlags,
1416 pulDirs,
1417 pulFiles);
1418 // this removes ffb3.achName as well
1419 }
1420 else
1421 {
1422 // directory, but no recursion:
1423 // report "access denied"
1424 // (this is what OS/2 reports with DosDeleteDir as well)
1425 arcReturn = ERROR_ACCESS_DENIED; // 5
1426 (*pulDirs)++;
1427 }
1428 }
1429 }
1430 else
1431 {
1432 // it's a file:
1433 arcReturn = ERROR_ACCESS_DENIED;
1434 (*pulFiles)++;
1435 }
1436
1437 if (arc == NO_ERROR)
1438 {
1439 ulFindCount = 1; // reset find count
1440 arc = DosFindNext(hdirFindHandle, // directory handle
1441 &ffb3, // result buffer
1442 ulResultBufLen, // result buffer length
1443 &ulFindCount); // number of entries to find
1444 }
1445 } // endwhile
1446
1447 DosFindClose(hdirFindHandle); // close our find handle
1448 }
1449
1450 if (arcReturn == NO_ERROR)
1451 // success so far:
1452 // delete our directory now
1453 arc = DosDeleteDir((PSZ)pcszDir);
1454
1455 return (arcReturn);
1456}
1457
1458/*
1459 *@@category: Helpers\Control program helpers\Process management
1460 */
1461
1462/* ******************************************************************
1463 * *
1464 * Process helpers *
1465 * *
1466 ********************************************************************/
1467
1468/*
1469 *@@ doshExecVIO:
1470 * executes cmd.exe with the /c parameter
1471 * and pcszExecWithArgs. This is equivalent
1472 * to the C library system() function,
1473 * except that an OS/2 error code is returned
1474 * and that this works with the VAC subsystem
1475 * library.
1476 *
1477 * This uses DosExecPgm and handles the sick
1478 * argument passing.
1479 *
1480 * If NO_ERROR is returned, *plExitCode receives
1481 * the exit code of the process. If the process
1482 * was terminated abnormally, *plExitCode receives:
1483 *
1484 * -- -1: hard error halt
1485 * -- -2: 16-bit trap
1486 * -- -3: DosKillProcess
1487 * -- -4: 32-bit exception
1488 *
1489 *@@added V0.9.4 (2000-07-27) [umoeller]
1490 */
1491
1492APIRET doshExecVIO(const char *pcszExecWithArgs,
1493 PLONG plExitCode) // out: exit code (ptr can be NULL)
1494{
1495 APIRET arc = NO_ERROR;
1496
1497 if (strlen(pcszExecWithArgs) > 255)
1498 arc = ERROR_INSUFFICIENT_BUFFER;
1499 {
1500 CHAR szObj[CCHMAXPATH];
1501 RESULTCODES res = {0};
1502 CHAR szBuffer[300];
1503
1504 // DosExecPgm expects two args in szBuffer:
1505 // -- cmd.exe\0
1506 // -- then the actual argument, terminated by two 0 bytes.
1507 memset(szBuffer, 0, sizeof(szBuffer));
1508 strcpy(szBuffer, "cmd.exe\0");
1509 sprintf(szBuffer + 8, "/c %s",
1510 pcszExecWithArgs);
1511
1512 arc = DosExecPgm(szObj, sizeof(szObj),
1513 EXEC_SYNC,
1514 szBuffer,
1515 0,
1516 &res,
1517 "cmd.exe");
1518 if ((arc == NO_ERROR) && (plExitCode))
1519 {
1520 if (res.codeTerminate == 0)
1521 // normal exit:
1522 *plExitCode = res.codeResult;
1523 else
1524 *plExitCode = -((LONG)res.codeTerminate);
1525 }
1526 }
1527
1528 return (arc);
1529}
1530
1531/*
1532 *@@ doshQuickStartSession:
1533 * this is a shortcut to DosStartSession w/out having to
1534 * deal with all the messy parameters.
1535 *
1536 * This one starts pszPath as a child session and passes
1537 * pszParams to it.
1538 *
1539 * In usPgmCtl, OR any or none of the following (V0.9.0):
1540 * -- SSF_CONTROL_NOAUTOCLOSE (0x0008): do not close automatically.
1541 * This bit is used only for VIO Windowable apps and ignored
1542 * for all other applications.
1543 * -- SSF_CONTROL_MINIMIZE (0x0004)
1544 * -- SSF_CONTROL_MAXIMIZE (0x0002)
1545 * -- SSF_CONTROL_INVISIBLE (0x0001)
1546 * -- SSF_CONTROL_VISIBLE (0x0000)
1547 *
1548 * Specifying 0 will therefore auto-close the session and make it
1549 * visible.
1550 *
1551 * If (fWait), this function will create a termination queue
1552 * and not return until the child session has ended. Otherwise
1553 * the function will return immediately, and the SID/PID of
1554 * the child session can be found in *pulSID and *ppid.
1555 *
1556 * Returns the error code of DosStartSession.
1557 *
1558 * Note: According to CPREF, calling DosStartSession calls
1559 * DosExecPgm in turn for all full-screen, VIO, and PM sessions.
1560 *
1561 *@@changed V0.9.0 [umoeller]: prototype changed to include usPgmCtl
1562 *@@changed V0.9.1 (99-12-30) [umoeller]: queue was sometimes not closed. Fixed.
1563 *@@changed V0.9.3 (2000-05-03) [umoeller]: added fForeground
1564 */
1565
1566APIRET doshQuickStartSession(const char *pcszPath, // in: program to start
1567 const char *pcszParams, // in: parameters for program
1568 BOOL fForeground, // in: if TRUE, session will be in foreground
1569 USHORT usPgmCtl, // in: STARTDATA.PgmControl
1570 BOOL fWait, // in: wait for termination?
1571 PULONG pulSID, // out: session ID (req.)
1572 PPID ppid) // out: process ID (req.)
1573{
1574 APIRET arc;
1575 // queue stuff
1576 const char *pcszQueueName = "\\queues\\kfgstart.que";
1577 HQUEUE hq = 0;
1578 PID qpid = 0;
1579 STARTDATA SData;
1580 CHAR szObjBuf[CCHMAXPATH];
1581
1582 if (fWait)
1583 {
1584 if ((arc = DosCreateQueue(&hq,
1585 QUE_FIFO | QUE_CONVERT_ADDRESS,
1586 (PSZ)pcszQueueName))
1587 != NO_ERROR)
1588 return (arc);
1589
1590 if ((arc = DosOpenQueue(&qpid, &hq, (PSZ)pcszQueueName)) != NO_ERROR)
1591 return (arc);
1592 }
1593
1594 SData.Length = sizeof(STARTDATA);
1595 SData.Related = SSF_RELATED_CHILD; //INDEPENDENT;
1596 SData.FgBg = (fForeground) ? SSF_FGBG_FORE : SSF_FGBG_BACK;
1597 // V0.9.3 (2000-05-03) [umoeller]
1598 SData.TraceOpt = SSF_TRACEOPT_NONE;
1599
1600 SData.PgmTitle = (PSZ)pcszPath; // title for window
1601 SData.PgmName = (PSZ)pcszPath;
1602 SData.PgmInputs = (PSZ)pcszParams;
1603
1604 SData.TermQ = (fWait) ? "\\queues\\kfgstart.que" : NULL;
1605 SData.Environment = 0;
1606 SData.InheritOpt = SSF_INHERTOPT_PARENT;
1607 SData.SessionType = SSF_TYPE_DEFAULT;
1608 SData.IconFile = 0;
1609 SData.PgmHandle = 0;
1610
1611 SData.PgmControl = usPgmCtl;
1612
1613 SData.InitXPos = 30;
1614 SData.InitYPos = 40;
1615 SData.InitXSize = 200;
1616 SData.InitYSize = 140;
1617 SData.Reserved = 0;
1618 SData.ObjectBuffer = (CHAR*)&szObjBuf;
1619 SData.ObjectBuffLen = (ULONG)sizeof(szObjBuf);
1620
1621 arc = DosStartSession(&SData, pulSID, ppid);
1622
1623 if (arc == NO_ERROR)
1624 {
1625 if (fWait)
1626 {
1627 REQUESTDATA rqdata;
1628 ULONG DataLength = 0;
1629 PULONG DataAddress;
1630 BYTE elpri;
1631
1632 rqdata.pid = qpid;
1633 DosReadQueue(hq, // in: queue handle
1634 &rqdata, // out: pid and ulData
1635 &DataLength, // out: size of data returned
1636 (PVOID*)&DataAddress, // out: data returned
1637 0, // in: remove first element in queue
1638 0, // in: wait for queue data (block thread)
1639 &elpri, // out: element's priority
1640 0); // in: event semaphore to be posted
1641 }
1642 }
1643
1644 if (hq)
1645 DosCloseQueue(hq);
1646
1647 return (arc);
1648}
1649
1650
Note: See TracBrowser for help on using the repository browser.