- converted 1st stage setup stub from message box style to property sheet style
[reactos.git] / rosapps / applications / mc / pc / util_os2.c
1 /* Various utilities - OS/2 versions
2 Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
3
4 Written 1994, 1995, 1996 by:
5 Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
6 Jakub Jelinek, Mauricio Plaza.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 #include <config.h>
23
24 #define INCL_DOS
25 #define INCL_PM
26 #define INCL_DOSPROCESS
27 #define INCL_DOSFILEMGR
28 #define INCL_DOSDEVICES /* Device values */
29 #define INCL_DOSDATETIME
30 #define INCL_DOSERRORS
31 #include <os2.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <ctype.h>
37 #include <sys/stat.h>
38 #include <errno.h>
39 #include <io.h>
40 #include <fcntl.h>
41 #include <signal.h> /* my_system */
42 #include <limits.h> /* INT_MAX */
43 #include <sys/time.h> /* select: timeout */
44 #include <sys/param.h>
45 #include <sys/stat.h>
46 #include <stdarg.h>
47 #include <process.h>
48 #include "../src/fs.h"
49 #include "../src/util.h"
50 #include "../src/dialog.h"
51
52 #ifndef ENOTEMPTY
53 #define ENOTEMPTY ERROR_DIR_NOT_EMPTY
54 #endif
55
56 char *
57 get_owner (int uid)
58 {
59 return "none";
60 }
61
62 char *
63 get_group (int gid)
64 {
65 return "none";
66 }
67
68 /* Pipes are guaranteed to be able to hold at least 4096 bytes */
69 /* More than that would be unportable */
70 #define MAX_PIPE_SIZE 4096
71
72 static int error_pipe[2]; /* File descriptors of error pipe */
73 static int old_error; /* File descriptor of old standard error */
74
75 /* Creates a pipe to hold standard error for a later analysis. */
76 /* The pipe can hold 4096 bytes. Make sure no more is written */
77 /* or a deadlock might occur. */
78 void
79 open_error_pipe (void)
80 {
81 return;
82 }
83
84 void
85 close_error_pipe (int error, char *text)
86 {
87 return;
88 }
89
90 void
91 check_error_pipe (void)
92 {
93 char error[MAX_PIPE_SIZE];
94 int len = 0;
95 if (old_error >= 0){
96 while (len < MAX_PIPE_SIZE)
97 {
98 int rvalue;
99
100 rvalue = read (error_pipe[0], error + len, 1);
101 len ++;
102 if (rvalue <= 0)
103 break;
104 }
105 error[len] = 0;
106 close (error_pipe[0]);
107 }
108 if (len > 0)
109 message (0, " Warning ", error);
110 }
111
112
113 static int
114 StartWindowsProg (char *name, SHORT type)
115 {
116 #if 0 /* FIXME: PM DDL's should be loaded (or not loaded) at run time */
117 PROGDETAILS pDetails;
118
119 memset(&pDetails, 0, sizeof(PROGDETAILS)) ;
120 pDetails.Length = sizeof(pDetails);
121 pDetails.pszExecutable = name; /* program name */
122 pDetails.pszStartupDir = NULL; /* default directory for new app. */
123 pDetails.pszParameters = NULL; /* command line */
124 pDetails.progt.fbVisible = SHE_VISIBLE ;
125 pDetails.pszEnvironment = NULL;
126
127 switch (type) {
128 case 0:
129 /* Win Standard */
130 pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ;
131 break;
132 case 1:
133 /* Win 3.1 Protect */
134 pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ;
135 break;
136 case 2:
137 /* Win 3.1 Enh. Protect */
138 pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ;
139 break;
140 default:
141 pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ;
142 break;
143 }
144 WinStartApp(NULLHANDLE,
145 &pDetails,
146 NULL,
147 NULL,
148 SAF_INSTALLEDCMDLINE|SAF_STARTCHILDAPP) ;
149 #endif
150 return 0;
151 }
152
153
154 static int
155 os2_system (int as_shell_command, const char *shell, const char *command, char *parm);
156
157 /*
158 as_shell_command = 1: If a program is started during input line, CTRL-O
159 or RETURN
160 = 0: F3, F4
161 */
162 int
163 my_system (int as_shell_command, const char *shell, const char *command)
164 {
165 char *sh; /* This is the shell -- always! */
166 char *cmd; /* This is the command (only the command) */
167 char *parm; /* This is the parameter (can be more than one) */
168 register int length, i;
169 char temp[4096]; /* That's enough! */
170
171 sh = get_default_shell();
172 if (strcmp(sh, shell)) {
173 /*
174 Not equal -- That means: shell is the program and command is the
175 parameter
176 */
177 cmd = (char *) shell;
178 parm = (char *) command;
179 } else {
180 /* look into the command and take out the program */
181 if (command) {
182 strcpy(temp, command);
183 length = strlen(command);
184 for (i=length-1; i>=0; i--) {
185 if (command[i] == ' ') {
186 temp[i] = (char) 0;
187 length--;
188 } else
189 break;
190 }
191 if (i==-1) {
192 /* only blanks */
193 return -1;
194 }
195 if (parm = strchr(temp, (char) ' ')) {
196 *parm = (char) 0;
197 parm++;
198 }
199 cmd = (char *) temp;
200 } else {
201 /* command is NULL */
202 cmd = parm = NULL;
203 }
204 }
205 return os2_system (as_shell_command, sh, cmd, parm);
206 }
207
208 static int
209 ux_startp (const char *shell, const char *command, const char *parm)
210 {
211 if (parm) {
212 spawnlp (P_WAIT,
213 (char *) shell,
214 (char *) shell,
215 "/c",
216 (char *) command,
217 (char *) parm,
218 (char *) 0);
219 } else {
220 spawnlp (P_WAIT,
221 (char *) shell,
222 (char *) shell,
223 "/c",
224 (char *) command,
225 (char *) 0);
226 }
227 return 0;
228 }
229
230
231 static int
232 os2_system (int as_shell_command, const char *shell, const char *command, char *parm)
233 {
234 register int i, j;
235 ULONG AppType = 0; /* Application type flags (returned) */
236 APIRET rc = NO_ERROR; /* Return Code */
237 char pathValue[5] = "PATH"; /* For DosSearchPath */
238 UCHAR searchResult[MC_MAXPATHLEN * 2 + 1]; /* For DosSearchPath */
239
240 char *cmdString;
241 char *postFix[3];
242 char *line;
243 /* ------------------------------------------------------- */
244 STARTDATA StartData;
245 CHAR ObjBuf[100];
246 ULONG SessionID;
247 PID pid;
248
249 if (command == NULL) {
250 /* .ado: just start a shell, we don't need the parameter */
251 spawnl (P_WAIT,
252 (char *) shell,
253 (char *) shell,
254 (char *) command, (char *) 0);
255 return 0;
256 }
257
258 memset(&StartData, 0, sizeof(StartData)) ;
259 StartData.Length = sizeof(StartData);
260 StartData.Related = SSF_RELATED_CHILD;
261 StartData.FgBg = SSF_FGBG_BACK;
262 StartData.TraceOpt = SSF_TRACEOPT_NONE;
263 StartData.PgmTitle = NULL;
264 StartData.TermQ = NULL;
265 StartData.InheritOpt = SSF_INHERTOPT_PARENT;
266 StartData.IconFile = 0;
267 StartData.PgmHandle = 0;
268 StartData.PgmControl = SSF_CONTROL_VISIBLE ;
269 StartData.ObjectBuffer = ObjBuf;
270 StartData.ObjectBuffLen = 100;
271 StartData.PgmInputs = parm;
272
273 postFix[0] = ".exe";
274 postFix[1] = ".cmd";
275 postFix[2] = ".bat";
276
277 i = strlen(command);
278 if (command[i-1] == ' ') {
279 /* The user has used ALT-RETURN */
280 i--;
281 }
282 cmdString = (char *) malloc(i+1);
283 for (j=0; j<i; j++) {
284 cmdString[j] = command[j];
285 }
286 cmdString[j] = (char) 0;
287
288 if ((i < 5) || ((i > 4) && (cmdString[i-4]) != '.')) {
289 /* without Extension */
290 line = (char *) malloc(i+5);
291 rc = 1;
292 for (i=0; (i<3 && rc); i++) {
293 /* Search for the file */
294 strcpy(line, cmdString);
295 strcat(line, postFix[i]);
296 rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY),
297 (PSZ) pathValue,
298 line,
299 searchResult,
300 sizeof(searchResult));
301 }
302 free (line);
303 } else {
304 /* Just search */
305 rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY),
306 (PSZ) pathValue,
307 cmdString,
308 searchResult,
309 sizeof(searchResult));
310 }
311 free(cmdString);
312 if (rc != 0) {
313 /* Internal command or the program was written with absolut path */
314 return ux_startp(shell, command, parm);
315 }
316
317 /* Application to be started */
318 StartData.PgmName = searchResult;
319 StartData.Environment = NULL;
320 rc = DosQueryAppType(searchResult, &AppType);
321 if (rc == NO_ERROR) {
322 StartData.SessionType = PROG_WINDOWABLEVIO;
323 if ((AppType & 0x00000007) == FAPPTYP_WINDOWAPI) {
324 /* Window API */
325 StartData.SessionType = PROG_PM;
326 return DosStartSession(&StartData, &SessionID, &pid);
327 }
328 if ((AppType & 0x00000007) == FAPPTYP_WINDOWCOMPAT) {
329 /* Window compat */
330 return ux_startp(shell, command, parm);
331 }
332 if (AppType & 0x0000ffff & FAPPTYP_DOS) {
333 /* PC/DOS Format */
334 StartData.SessionType = PROG_WINDOWEDVDM;
335 return DosStartSession(&StartData, &SessionID, &pid);
336 }
337 if (AppType & 0x0000ffff & FAPPTYP_WINDOWSREAL) {
338 /* Windows real mode app */
339 return StartWindowsProg(searchResult, 0);
340 }
341 if (AppType & 0x0000ffff & FAPPTYP_WINDOWSPROT) {
342 /* Windows Protect mode app*/
343 return StartWindowsProg(searchResult, 1);
344 }
345 if (AppType & 0x0000ffff & FAPPTYP_WINDOWSPROT31) {
346 /* Windows 3.1 Protect mode app*/
347 return StartWindowsProg(searchResult, 2);
348 }
349 rc = DosStartSession(&StartData, &SessionID, &pid) ;
350 } else {
351 /* It's not a known exe type or it's a CMD/BAT file */
352 i = strlen(searchResult);
353 if ((toupper(searchResult[--i]) == 'T') &&
354 (toupper(searchResult[--i]) == 'A') &&
355 (toupper(searchResult[--i]) == 'B') &&
356 (searchResult[--i] == '.') ) {
357 StartData.SessionType = PROG_WINDOWEDVDM;
358 rc = DosStartSession(&StartData, &SessionID, &pid) ;
359 } else {
360 rc = ux_startp (shell, command, parm);
361 }
362 }
363 return rc;
364 }
365
366 char *tilde_expand (char *directory)
367 {
368 return strdup (directory);
369 }
370
371
372 /* Canonicalize path, and return a new path. Do everything in situ.
373 The new path differs from path in:
374 Multiple BACKSLASHs are collapsed to a single BACKSLASH.
375 Leading `./'s and trailing `/.'s are removed.
376 Trailing BACKSLASHs are removed.
377 Non-leading `../'s and trailing `..'s are handled by removing
378 portions of the path. */
379 char *
380 canonicalize_pathname (char *path)
381 {
382 int i, start;
383 char stub_char;
384
385 stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
386
387 /* Walk along path looking for things to compact. */
388 i = 0;
389 for (;;) {
390 if (!path[i])
391 break;
392
393 while (path[i] && path[i] != PATH_SEP)
394 i++;
395
396 start = i++;
397
398 /* If we didn't find any slashes, then there is nothing left to do. */
399 if (!path[start])
400 break;
401
402 /* Handle multiple BACKSLASHs in a row. */
403 while (path[i] == PATH_SEP)
404 i++;
405
406 if ((start + 1) != i) {
407 strcpy (path + start + 1, path + i);
408 i = start + 1;
409 }
410
411 /* Handle backquoted BACKSLASH. */
412 /* if (start > 0 && path[start - 1] == '\\')
413 continue; */
414
415 /* Check for trailing BACKSLASH. */
416 if (start && !path[i]) {
417 zero_last:
418 path[--i] = '\0';
419 break;
420 }
421
422 /* Check for `../', `./' or trailing `.' by itself. */
423 if (path[i] == '.') {
424 /* Handle trailing `.' by itself. */
425 if (!path[i + 1])
426 goto zero_last;
427
428 /* Handle `./'. */
429 if (path[i + 1] == PATH_SEP) {
430 strcpy (path + i, path + i + 1);
431 i = start;
432 continue;
433 }
434
435 /* Handle `../' or trailing `..' by itself.
436 Remove the previous ?/ part with the exception of
437 ../, which we should leave intact. */
438 if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
439 while (--start > -1 && path[start] != PATH_SEP);
440 if (!strncmp (path + start + 1, "..\\", 3))
441 continue;
442 strcpy (path + start + 1, path + i + 2);
443 i = start;
444 continue;
445 }
446 }
447 }
448
449 if (!*path) {
450 *path = stub_char;
451 path[1] = '\0';
452 }
453 return path;
454 }
455
456
457 void
458 my_statfs (struct my_statfs *myfs_stats, char *path)
459 {
460 PFSALLOCATE pBuf;
461 PFSINFO pFsInfo;
462 ULONG lghBuf;
463
464 ULONG diskNum = 0;
465 ULONG logical = 0;
466
467 UCHAR szDeviceName[3] = "A:";
468 PBYTE pszFSDName = NULL; /* pointer to FS name */
469 APIRET rc = NO_ERROR; /* Return code */
470 BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
471 ULONG cbBuffer = sizeof(fsqBuffer); /* Buffer length) */
472 PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2) fsqBuffer;
473
474 int i, len = 0;
475
476 /* ------------------------------------------------------------------ */
477
478 lghBuf = sizeof(FSALLOCATE);
479 pBuf = (PFSALLOCATE) malloc(lghBuf);
480
481 /* Get the free number of Bytes */
482 rc = DosQueryFSInfo(0L, FSIL_ALLOC, (PVOID) pBuf, lghBuf);
483 /* KBytes available */
484 myfs_stats->avail = pBuf->cSectorUnit * pBuf->cUnitAvail * pBuf->cbSector / 1024;
485 /* KBytes total */
486 myfs_stats->total = pBuf->cSectorUnit * pBuf->cUnit * pBuf->cbSector / 1024;
487 myfs_stats->nfree = pBuf->cUnitAvail;
488 myfs_stats->nodes = pBuf->cbSector;
489
490 lghBuf = sizeof(FSINFO);
491 pFsInfo = (PFSINFO) malloc(lghBuf);
492 rc = DosQueryFSInfo(0L,
493 FSIL_VOLSER,
494 (PVOID) pFsInfo,
495 lghBuf);
496 /* Get name */
497 myfs_stats->device = strdup(pFsInfo->vol.szVolLabel); /* Label of the Disk */
498
499 /* Get the current disk for DosQueryFSAttach */
500 rc = DosQueryCurrentDisk(&diskNum, &logical);
501
502 szDeviceName[0] = (UCHAR) (diskNum + (ULONG) 'A' - 1);
503 /* Now get the type of the disk */
504 rc = DosQueryFSAttach(szDeviceName,
505 0L,
506 FSAIL_QUERYNAME,
507 pfsqBuffer,
508 &cbBuffer);
509
510 pszFSDName = pfsqBuffer->szName + pfsqBuffer->cbName + 1;
511 myfs_stats->mpoint = strdup(pszFSDName); /* FAT, HPFS ... */
512
513 myfs_stats->type = pBuf->idFileSystem;
514 /* What is about 3 ?*/
515 if (myfs_stats->type == 0) {
516 myfs_stats->typename = (char *) malloc(11);
517 strcpy(myfs_stats->typename, "Local Disk");
518 } else {
519 myfs_stats->typename = (char *) malloc(13);
520 strcpy(myfs_stats->typename, "Other Device");
521 }
522
523 free(pBuf);
524 free(pFsInfo);
525 }
526
527 int
528 gettimeofday (struct timeval* tvp, void *p)
529 {
530 DATETIME pdt = {0};
531 if (p != NULL) /* what is "p"? */
532 return 0;
533
534 /* Since MC only calls this func from get_random_hint we return
535 * some value, not exactly the "correct" one
536 */
537 DosGetDateTime(&pdt);
538 tvp->tv_usec = (pdt.hours * 60 + pdt.minutes) * 60 + pdt.seconds;
539 /* Number of milliseconds since Windows started */
540 tvp->tv_sec = tvp->tv_usec * 1000 + pdt.hundredths * 10;
541 return 0;
542 }
543
544 /* FAKE functions */
545
546 int
547 look_for_exe(const char* pathname)
548 {
549 int j;
550 char *p;
551 int lgh = strlen(pathname);
552
553 if (lgh < 4) {
554 return 0;
555 } else {
556 p = (char *) pathname;
557 for (j=0; j<lgh-4; j++) {
558 p++;
559 }
560 if (!stricmp(p, ".exe") ||
561 !stricmp(p, ".bat") ||
562 !stricmp(p, ".com") ||
563 !stricmp(p, ".cmd")) {
564 return 1;
565 }
566 }
567 return 0;
568 }
569
570 int
571 lstat (const char* pathname, struct stat *buffer)
572 {
573 int rc = stat (pathname, buffer);
574 #ifdef __BORLANDC__
575 if (rc == 0) {
576 if (!(buffer->st_mode & S_IFDIR)) {
577 if (!look_for_exe(pathname)) {
578 buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
579 }
580 }
581 }
582 #endif
583 return rc;
584 }
585
586 int
587 getuid ()
588 {
589 return 0;
590 }
591
592 int
593 getgid ()
594 {
595 return 0;
596 }
597
598 int
599 readlink (char* path, char* buf, int size)
600 {
601 return -1;
602 }
603
604 int
605 symlink (char *n1, char *n2)
606 {
607 return -1;
608 }
609
610 int
611 link (char *p1, char *p2)
612 {
613 return -1;
614 }
615
616 int
617 chown (char *path, int owner, int group)
618 {
619 return -1;
620 }
621
622 int
623 mknod (char *path, int mode, int dev)
624 {
625 return -1;
626 }
627
628 void
629 init_uid_gid_cache (void)
630 {
631 return;
632 }
633
634 int
635 mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
636 {
637 return 0;
638 }
639
640 int
641 mc_doublepclose (int pipe, pid_t pid)
642 {
643 return 0;
644 }
645
646 /*hacks to get it compile, remove these after vfs works */
647 char *
648 vfs_get_current_dir (void)
649 {
650 return NULL;
651 }
652
653 int
654 vfs_current_is_extfs (void)
655 {
656 return 0;
657 }
658
659 int
660 vfs_file_is_ftp (char *filename)
661 {
662 return 0;
663 }
664
665 int
666 mc_utime (char *path, void *times)
667 {
668 return 0;
669 }
670
671
672 void
673 extfs_run (char *file)
674 {
675 return;
676 }
677
678 int
679 geteuid(void)
680 {
681 return 0;
682 }
683
684
685 int
686 mc_chdir(char *pathname)
687 {
688 APIRET ret;
689 register int lgh = strlen(pathname);
690
691 /* Set the current drive */
692 if (lgh == 0) {
693 return -1;
694 } else {
695 /* First set the default drive */
696 if (lgh > 1) {
697 if (pathname[1] == ':') {
698 ret = DosSetDefaultDisk(toupper(pathname[0]) - 'A' + 1);
699 }
700 }
701 /* After that, set the current dir! */
702 ret = DosSetCurrentDir(pathname);
703 }
704 return ret;
705 }
706
707 int
708 mc_chmod(char *pathName, int unxmode)
709 {
710 /* OS/2 does not need S_REG */
711 int os2Mode = unxmode & 0x0FFF;
712 return chmod(pathName, os2Mode);
713 }
714
715 static int
716 conv_os2_unx_rc(int os2rc)
717 {
718 int errCode;
719 switch (os2rc) {
720 case ERROR_FILE_NOT_FOUND:
721 case ERROR_PATH_NOT_FOUND:
722 case ERROR_FILENAME_EXCED_RANGE:
723 errCode = ENOENT;
724 break;
725 case ERROR_NOT_DOS_DISK:
726 case ERROR_SHARING_VIOLATION:
727 case ERROR_SHARING_BUFFER_EXCEEDED:
728 case ERROR_ACCESS_DENIED:
729 errCode = EACCES;
730 break;
731 case ERROR_INVALID_PARAMETER:
732 errCode = EINVAL;
733 break;
734 default:
735 errCode = EINVAL;
736 break;
737 }
738 return errCode;
739 }
740
741 int
742 mc_open (char *file, int flags, int pmode)
743 {
744 return open(file, (flags | O_BINARY), pmode);
745 }
746
747 int
748 mc_unlink(char *pathName)
749 {
750 /* Use OS/2 API to delete a file, if the file is set as read-only,
751 the file will be deleted without asking the user! */
752 APIRET rc;
753 rc = DosDelete(pathName);
754 if (!rc) {
755 return 0;
756 }
757 if (rc == ERROR_ACCESS_DENIED) {
758 chmod(pathName, (S_IREAD|S_IWRITE));
759 rc = DosDelete(pathName);
760 if (rc) {
761 errno = conv_os2_unx_rc(rc) ;
762 return -1;
763 } else {
764 return 0;
765 }
766 } else {
767 errno = conv_os2_unx_rc(rc) ;
768 return -1;
769 }
770 }
771
772 char *
773 get_default_editor (void)
774 {
775 char *tmp;
776 APIRET rc;
777 char pathValue[5] = "PATH";
778 UCHAR searchResult[MC_MAXPATHLEN + 1];
779
780 /* EPM is not always be installed */
781 rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY),
782 (PSZ) pathValue,
783 "EPM.EXE",
784 searchResult,
785 sizeof(searchResult));
786 if (rc != 0) {
787 /* The system editor is always there */
788 return strdup("e.exe");
789 } else {
790 /* Let it be searched from my_system */
791 return strdup("epm.exe");
792 }
793 }
794
795 /* get_default_shell
796 Get the default shell for the current hardware platform
797 TODO: Get the value of %OS2_SHELL% or %SHELL%: which one?
798 */
799 char *
800 get_default_shell()
801 {
802 return getenv ("COMSPEC");
803 }
804
805 int
806 errno_dir_not_empty (int err)
807 {
808 if (err == ENOTEMPTY)
809 return 1;
810 return 0;
811 }
812
813 /* The MC library directory is by default the directory where mc.exe
814 is situated. It is recommended to specify this directory via MCHOME
815 environment variable, otherwise you will be unable to rename mc.exe */
816 char *
817 get_mc_lib_dir ()
818 {
819 HMODULE mc_hm;
820 int rc;
821 char *cur = NULL;
822 char *mchome = getenv("MCHOME");
823
824 if (mchome && *mchome)
825 return mchome;
826 mchome = malloc(MC_MAXPATHLEN);
827 rc = DosQueryModuleHandle ("MC.EXE", &mc_hm);
828 if (!rc)
829 rc = DosQueryModuleName (mc_hm, MC_MAXPATHLEN, mchome);
830 if (!rc)
831 {
832 for (cur = mchome + strlen(mchome); \
833 (cur > mchome) && (*cur != PATH_SEP); cur--);
834 *cur = 0;
835 cur = strdup(mchome);
836 free(mchome);
837 }
838 if (!cur || !*cur) {
839 free(cur);
840 return "C:\\MC";
841 }
842 return cur;
843 }
844
845 int get_user_rights (struct stat *buf)
846 {
847 return 2;
848 }
849 void init_groups (void)
850 {
851 }
852 void delete_groups (void)
853 {
854 }