]>
Commit | Line | Data |
---|---|---|
252b5132 RH |
1 | /* MPW-Unix compatibility library. |
2 | Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of the libiberty library. | |
5 | Libiberty is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Library General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2 of the License, or (at your option) any later version. | |
9 | ||
10 | Libiberty is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with libiberty; see the file COPYING.LIB. If | |
17 | not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | /* This should only be compiled and linked under MPW. */ | |
21 | ||
22 | #include "mpw.h" | |
23 | ||
24 | #include <stdlib.h> | |
25 | ||
26 | #ifndef USE_MW_HEADERS | |
27 | #include <sys/time.h> | |
28 | #include <sys/resource.h> | |
29 | #endif | |
30 | ||
31 | #include <Types.h> | |
32 | #include <Files.h> | |
33 | ||
34 | #include <Timer.h> | |
35 | ||
36 | /* Initialize to 0 at first, then set to errno_max() later. */ | |
37 | ||
38 | int sys_nerr = 0; | |
39 | ||
40 | /* Debug flag for pathname hacking. Set this to one and rebuild. */ | |
41 | ||
42 | int DebugPI = -1; | |
43 | ||
44 | void | |
45 | mpwify_filename(char *unixname, char *macname) | |
46 | { | |
47 | int i, j; | |
48 | ||
49 | /* (should truncate 255 chars from end of name, not beginning) */ | |
50 | if (strlen (unixname) > 255) | |
51 | { | |
52 | fprintf (stderr, "Pathname \"%s\" is too long for Macs, truncating\n", | |
53 | unixname); | |
54 | } | |
55 | j = 0; | |
56 | /* If you're going to end up with one or more colons in the middle of a | |
57 | path after an all-Unix relative path is translated, you must add a | |
58 | colon on the front, so that the first component is not thought to be | |
59 | a disk name. */ | |
60 | if (unixname[0] != '/' && ! strchr (unixname, ':') && strchr (unixname, '/')) | |
61 | { | |
62 | macname[j++] = ':'; | |
63 | } | |
64 | for (i = 0; unixname[i] != '\0' && i < 255; ++i) | |
65 | { | |
66 | if (i == 0 && unixname[i] == '/') | |
67 | { | |
68 | if (strncmp (unixname, "/tmp/", 5) == 0) | |
69 | { | |
70 | /* A temporary name, make a more Mac-flavored tmpname. */ | |
71 | /* A better choice would be {Boot}Trash:foo, but | |
72 | that would require being able to identify the | |
73 | boot disk's and trashcan's name. Another option | |
74 | would be to have an env var, so user can point it | |
75 | at a ramdisk. */ | |
76 | macname[j++] = ':'; | |
77 | macname[j++] = 't'; | |
78 | macname[j++] = 'm'; | |
79 | macname[j++] = 'p'; | |
80 | macname[j++] = '_'; | |
81 | i += 4; | |
82 | } | |
83 | else | |
84 | { | |
85 | /* Don't copy the leading slash. */ | |
86 | } | |
87 | } | |
88 | else if (unixname[i] == ':' && unixname[i+1] == '/') | |
89 | { | |
90 | macname[j++] = ':'; | |
91 | i += 1; | |
92 | } | |
93 | else if (unixname[i] == '.' && unixname[i+1] == '/') | |
94 | { | |
95 | macname[j++] = ':'; | |
96 | i += 1; | |
97 | } | |
98 | else if (unixname[i] == '.' && unixname[i+1] == '.' && unixname[i+2] == '/') | |
99 | { | |
100 | macname[j++] = ':'; | |
101 | macname[j++] = ':'; | |
102 | i += 2; | |
103 | } | |
104 | else if (unixname[i] == '/') | |
105 | { | |
106 | macname[j++] = ':'; | |
107 | } | |
108 | else | |
109 | { | |
110 | macname[j++] = unixname[i]; | |
111 | } | |
112 | } | |
113 | macname[j] = '\0'; | |
114 | /* Allow for getting the debug flag from an env var; quite useful. */ | |
115 | if (DebugPI < 0) | |
116 | DebugPI = (*(getenv ("DEBUG_PATHNAMES")) == '1' ? 1 : 0); | |
117 | if (DebugPI) | |
118 | { | |
119 | fprintf (stderr, "# Made \"%s\"\n", unixname); | |
120 | fprintf (stderr, "# into \"%s\"\n", macname); | |
121 | } | |
122 | } | |
123 | ||
124 | /* MPW-flavored basename finder. */ | |
125 | ||
126 | char * | |
127 | mpw_basename (name) | |
128 | char *name; | |
129 | { | |
130 | char *base = name; | |
131 | ||
132 | while (*name) | |
133 | { | |
134 | if (*name++ == ':') | |
135 | { | |
136 | base = name; | |
137 | } | |
138 | } | |
139 | return base; | |
140 | } | |
141 | ||
142 | /* Mixed MPW/Unix basename finder. This can be led astray by | |
143 | filenames with slashes in them and come up with a basename that | |
144 | either corresponds to no file or (worse) to some other file, so | |
145 | should only be tried if other methods of finding a file via a | |
146 | basename have failed. */ | |
147 | ||
148 | char * | |
149 | mpw_mixed_basename (name) | |
150 | char *name; | |
151 | { | |
152 | char *base = name; | |
153 | ||
154 | while (*name) | |
155 | { | |
156 | if (*name == '/' || *name == ':') | |
157 | { | |
158 | base = name + 1; | |
159 | } | |
160 | ++name; | |
161 | } | |
162 | return base; | |
163 | } | |
164 | ||
165 | /* This function is fopen() modified to create files that are type TEXT | |
166 | or 'BIN ', and always of type 'MPS '. */ | |
167 | ||
168 | FILE * | |
169 | mpw_fopen (char *name, char *mode) | |
170 | { | |
171 | #undef fopen | |
172 | int errnum; | |
173 | FILE *fp; | |
174 | char tmpname[256]; | |
175 | ||
176 | mpwify_filename (name, tmpname); | |
177 | PROGRESS (1); | |
178 | fp = fopen (tmpname, mode); | |
179 | errnum = errno; | |
180 | ||
181 | /* If writing, need to set type and creator usefully. */ | |
182 | if (strchr (mode, 'w')) | |
183 | { | |
184 | char *pname = (char *) malloc (strlen (tmpname) + 2); | |
185 | OSErr e; | |
186 | struct FInfo fi; | |
187 | ||
188 | pname[0] = strlen (tmpname); | |
189 | strcpy (pname+1, tmpname); | |
190 | ||
191 | e = GetFInfo ((ConstStr255Param) pname, 0, &fi); | |
192 | /* should do spiffier error handling */ | |
193 | if (e != 0) | |
194 | fprintf(stderr, "GetFInfo returns %d\n", e); | |
195 | if (strchr (mode, 'b')) | |
196 | { | |
197 | fi.fdType = (OSType) 'BIN '; | |
198 | } | |
199 | else | |
200 | { | |
201 | fi.fdType = (OSType) 'TEXT'; | |
202 | } | |
203 | fi.fdCreator = (OSType) 'MPS '; | |
204 | e = SetFInfo ((ConstStr255Param) pname, 0, &fi); | |
205 | if (e != 0) | |
206 | fprintf(stderr, "SetFInfo returns %d\n", e); | |
207 | free (pname); | |
208 | } | |
209 | if (fp == NULL) | |
210 | errno = errnum; | |
211 | return fp; | |
212 | } | |
213 | ||
214 | /* This is a version of fseek() modified to fill the file with zeros | |
215 | if seeking past the end of it. */ | |
216 | ||
217 | #define ZEROBLKSIZE 4096 | |
218 | ||
219 | char zeros[ZEROBLKSIZE]; | |
220 | ||
221 | int | |
222 | mpw_fseek (FILE *fp, int offset, int whence) | |
223 | { | |
224 | #undef fseek | |
225 | int cursize, numleft; | |
226 | ||
227 | PROGRESS (1); | |
228 | if (whence == SEEK_SET) | |
229 | { | |
230 | fseek (fp, 0, SEEK_END); | |
231 | cursize = ftell (fp); | |
232 | if (offset > cursize) | |
233 | { | |
234 | numleft = offset - cursize; | |
235 | while (numleft > ZEROBLKSIZE) | |
236 | { | |
237 | /* This might fail, should check for that. */ | |
238 | PROGRESS (1); | |
239 | fwrite (zeros, 1, ZEROBLKSIZE, fp); | |
240 | numleft -= ZEROBLKSIZE; | |
241 | } | |
242 | PROGRESS (1); | |
243 | fwrite (zeros, 1, numleft, fp); | |
244 | fflush (fp); | |
245 | } | |
246 | } | |
247 | return fseek (fp, offset, whence); | |
248 | } | |
249 | ||
250 | int | |
251 | mpw_fread (char *ptr, int size, int nitems, FILE *stream) | |
252 | { | |
253 | #undef fread | |
254 | int rslt; | |
255 | ||
256 | PROGRESS (1); | |
257 | rslt = fread (ptr, size, nitems, stream); | |
258 | PROGRESS (1); | |
259 | return rslt; | |
260 | } | |
261 | ||
262 | int | |
263 | mpw_fwrite (char *ptr, int size, int nitems, FILE *stream) | |
264 | { | |
265 | #undef fwrite | |
266 | int rslt; | |
267 | ||
268 | PROGRESS (1); | |
269 | rslt = fwrite (ptr, size, nitems, stream); | |
270 | PROGRESS (1); | |
271 | return rslt; | |
272 | } | |
273 | ||
274 | int | |
275 | link () | |
276 | { | |
277 | fprintf (stderr, "link not available!\n"); | |
278 | mpw_abort (); | |
279 | } | |
280 | ||
281 | int | |
282 | fork () | |
283 | { | |
284 | fprintf (stderr, "fork not available!\n"); | |
285 | mpw_abort (); | |
286 | } | |
287 | ||
288 | int | |
289 | vfork () | |
290 | { | |
291 | fprintf (stderr, "vfork not available!\n"); | |
292 | mpw_abort (); | |
293 | return (-1); | |
294 | } | |
295 | ||
296 | int | |
297 | pipe (int *fd) | |
298 | { | |
299 | fprintf (stderr, "pipe not available!\n"); | |
300 | mpw_abort (); | |
301 | return (-1); | |
302 | } | |
303 | ||
304 | #ifndef USE_MW_HEADERS | |
305 | int | |
306 | execvp (char *file, char **argv) | |
307 | { | |
308 | fprintf (stderr, "execvp not available!\n"); | |
309 | mpw_abort (); | |
310 | return (-1); | |
311 | } | |
312 | ||
313 | int | |
314 | execv (char *path, char **argv) | |
315 | { | |
316 | fprintf (stderr, "execv not available!\n"); | |
317 | mpw_abort (); | |
318 | return (-1); | |
319 | } | |
320 | #endif | |
321 | ||
322 | int | |
323 | kill (int pid, int sig) | |
324 | { | |
325 | fprintf (stderr, "kill not available!\n"); | |
326 | mpw_abort (); | |
327 | return (-1); | |
328 | } | |
329 | ||
330 | int | |
331 | wait (int *status) | |
332 | { | |
333 | *status = 0; | |
334 | return 0; | |
335 | } | |
336 | ||
337 | #ifndef USE_MW_HEADERS | |
338 | int | |
339 | sleep (int seconds) | |
340 | { | |
341 | unsigned long start_time, now; | |
342 | ||
343 | time (&start_time); | |
344 | ||
345 | while (1) | |
346 | { | |
347 | PROGRESS (1); | |
348 | time (&now); | |
349 | if (now > start_time + seconds) | |
350 | return 0; | |
351 | } | |
352 | } | |
353 | #endif | |
354 | ||
355 | void | |
356 | putenv (char *str) | |
357 | { | |
358 | /* The GCC driver calls this to do things for collect2, but we | |
359 | don't care about collect2. */ | |
360 | } | |
361 | ||
362 | int | |
363 | chmod (char *path, int mode) | |
364 | { | |
365 | /* Pretend it was all OK. */ | |
366 | return 0; | |
367 | } | |
368 | ||
369 | #ifndef USE_MW_HEADERS | |
370 | int | |
371 | getuid () | |
372 | { | |
373 | /* One value is as good as another... */ | |
374 | return 0; | |
375 | } | |
376 | ||
377 | int | |
378 | getgid () | |
379 | { | |
380 | /* One value is as good as another... */ | |
381 | return 0; | |
382 | } | |
383 | #endif | |
384 | ||
385 | /* Instead of coredumping, which is not a normal Mac facility, we | |
386 | drop into Macsbug. If we then "g" from Macsbug, the program will | |
387 | exit cleanly. */ | |
388 | ||
389 | void | |
390 | mpw_abort () | |
391 | { | |
392 | /* Make sure no output still buffered up, then zap into MacsBug. */ | |
393 | fflush(stdout); | |
394 | fflush(stderr); | |
395 | printf("## Abort! ##\n"); | |
396 | #ifdef MPW_SADE | |
397 | SysError(8005); | |
398 | #else | |
399 | Debugger(); | |
400 | #endif | |
401 | /* "g" in MacsBug will then cause a regular error exit. */ | |
402 | exit (1); | |
403 | } | |
404 | ||
405 | /* Imitation getrusage based on the ANSI clock() function. */ | |
406 | ||
407 | int | |
408 | getrusage (int who, struct rusage *rusage) | |
409 | { | |
410 | int clk = clock (); | |
411 | ||
412 | #if 0 | |
413 | rusage->ru_utime.tv_sec = clk / CLOCKS_PER_SEC; | |
414 | rusage->ru_utime.tv_usec = ((clk * 1000) / CLOCKS_PER_SEC) * 1000; | |
415 | rusage->ru_stime.tv_sec = 0; | |
416 | rusage->ru_stime.tv_usec = 0; | |
417 | #endif | |
418 | } | |
419 | ||
420 | int | |
421 | sbrk () | |
422 | { | |
423 | return 0; | |
424 | } | |
425 | ||
426 | #ifndef USE_MW_HEADERS | |
427 | int | |
428 | isatty (int fd) | |
429 | { | |
430 | return 0; | |
431 | } | |
432 | ||
433 | /* This is inherited from Timothy Murray's Posix library. */ | |
434 | ||
435 | #include "utime.h" | |
436 | ||
437 | int | |
438 | utime (char *filename, struct utimbuf *times) | |
439 | { | |
440 | CInfoPBRec cipbr; | |
441 | HFileInfo *fpb = (HFileInfo *) &cipbr; | |
442 | DirInfo *dpb = (DirInfo *) &cipbr; | |
443 | unsigned char pname[256]; | |
444 | short err; | |
445 | ||
446 | strcpy ((char *) pname, filename); | |
447 | c2pstr (pname); | |
448 | ||
449 | dpb->ioDrDirID = 0L; | |
450 | fpb->ioNamePtr = pname; | |
451 | fpb->ioVRefNum = 0; | |
452 | fpb->ioFDirIndex = 0; | |
453 | fpb->ioFVersNum = 0; | |
454 | err = PBGetCatInfo (&cipbr, 0); | |
455 | if (err != noErr) { | |
456 | errno = ENOENT; | |
457 | return -1; | |
458 | } | |
459 | dpb->ioDrDirID = 0L; | |
460 | fpb->ioFlMdDat = times->modtime; | |
461 | fpb->ioFlCrDat = times->actime; | |
462 | err = PBSetCatInfo (&cipbr, 0); | |
463 | if (err != noErr) { | |
464 | errno = EACCES; | |
465 | return -1; | |
466 | } | |
467 | return 0; | |
468 | } | |
469 | ||
470 | int | |
471 | mkdir (char *path, int mode) | |
472 | { | |
473 | errno = ENOSYS; | |
474 | return -1; | |
475 | } | |
476 | ||
477 | int | |
478 | rmdir () | |
479 | { | |
480 | errno = ENOSYS; | |
481 | return -1; | |
482 | } | |
483 | #endif | |
484 | ||
485 | chown () | |
486 | { | |
487 | errno = ENOSYS; | |
488 | return -1; | |
489 | } | |
490 | ||
491 | char *myenviron[] = {NULL}; | |
492 | ||
493 | char **environ = myenviron; | |
494 | ||
495 | #ifndef USE_MW_HEADERS | |
496 | ||
497 | /* Minimal 'stat' emulation: tells directories from files and | |
498 | gives length and mtime. | |
499 | ||
500 | Derived from code written by Guido van Rossum, CWI, Amsterdam | |
501 | and placed by him in the public domain. */ | |
502 | ||
503 | extern int __uid, __gid; | |
504 | ||
505 | int __uid = 0; | |
506 | int __gid = 0; | |
507 | ||
508 | /* Bits in ioFlAttrib: */ | |
509 | #define LOCKBIT (1<<0) /* File locked */ | |
510 | #define DIRBIT (1<<4) /* It's a directory */ | |
511 | ||
512 | /* Macified "stat" in which filename is given relative to a directory, | |
513 | specified by long DirID. */ | |
514 | ||
515 | static int | |
516 | _stat (char *name, long dirid, struct stat *buf) | |
517 | { | |
518 | CInfoPBRec cipbr; | |
519 | HFileInfo *fpb = (HFileInfo*) &cipbr; | |
520 | DirInfo *dpb = (DirInfo*) &cipbr; | |
521 | Str255 pname; | |
522 | short err; | |
523 | ||
524 | /* Make a temp copy of the name and pascalize. */ | |
525 | strcpy ((char *) pname, name); | |
526 | c2pstr (pname); | |
527 | ||
528 | cipbr.dirInfo.ioDrDirID = dirid; | |
529 | cipbr.hFileInfo.ioNamePtr = pname; | |
530 | cipbr.hFileInfo.ioVRefNum = 0; | |
531 | cipbr.hFileInfo.ioFDirIndex = 0; | |
532 | cipbr.hFileInfo.ioFVersNum = 0; | |
533 | err = PBGetCatInfo (&cipbr, 0); | |
534 | if (err != noErr) | |
535 | { | |
536 | errno = ENOENT; | |
537 | return -1; | |
538 | } | |
539 | /* Mac files are readable if they can be accessed at all. */ | |
540 | buf->st_mode = 0444; | |
541 | /* Mark unlocked files as writeable. */ | |
542 | if (!(fpb->ioFlAttrib & LOCKBIT)) | |
543 | buf->st_mode |= 0222; | |
544 | if (fpb->ioFlAttrib & DIRBIT) | |
545 | { | |
546 | /* Mark directories as "executable". */ | |
547 | buf->st_mode |= 0111 | S_IFDIR; | |
548 | buf->st_size = dpb->ioDrNmFls; | |
549 | buf->st_rsize = 0; | |
550 | } | |
551 | else | |
552 | { | |
553 | buf->st_mode |= S_IFREG; | |
554 | /* Mark apps as "executable". */ | |
555 | if (fpb->ioFlFndrInfo.fdType == 'APPL') | |
556 | buf->st_mode |= 0111; | |
557 | /* Fill in the sizes of data and resource forks. */ | |
558 | buf->st_size = fpb->ioFlLgLen; | |
559 | buf->st_rsize = fpb->ioFlRLgLen; | |
560 | } | |
561 | /* Fill in various times. */ | |
562 | buf->st_atime = fpb->ioFlCrDat; | |
563 | buf->st_mtime = fpb->ioFlMdDat; | |
564 | buf->st_ctime = fpb->ioFlCrDat; | |
565 | /* Set up an imitation inode number. */ | |
566 | buf->st_ino = (unsigned short) fpb->ioDirID; | |
567 | /* Set up an imitation device. */ | |
568 | GetVRefNum (buf->st_ino, &buf->st_dev); | |
569 | buf->st_uid = __uid; | |
570 | buf->st_gid = __gid; | |
571 | /* buf->st_FlFndrInfo = fpb->ioFlFndrInfo; */ | |
572 | return 0; | |
573 | } | |
574 | ||
575 | /* stat() sets up an empty dirid. */ | |
576 | ||
577 | int | |
578 | stat (char *path, struct stat *buf) | |
579 | { | |
580 | long rslt, errnum; | |
581 | char tmpname[256]; | |
582 | ||
583 | mpwify_filename (path, tmpname); | |
584 | if (DebugPI) | |
585 | fprintf (stderr, "# stat (%s, %x)", tmpname, buf); | |
586 | PROGRESS (1); | |
587 | rslt = _stat (tmpname, 0L, buf); | |
588 | errnum = errno; | |
589 | if (DebugPI) | |
590 | { | |
591 | fprintf (stderr, " -> %d", rslt); | |
592 | if (rslt != 0) | |
593 | fprintf (stderr, " (errno is %d)", errnum); | |
594 | fprintf (stderr, "\n"); | |
595 | fflush (stderr); | |
596 | } | |
597 | if (rslt != 0) | |
598 | errno = errnum; | |
599 | return rslt; | |
600 | } | |
601 | ||
602 | int | |
603 | fstat (int fd, struct stat *buf) | |
604 | { | |
605 | FCBPBRec fcb; | |
606 | FILE *fp; | |
607 | Str255 pathname; | |
608 | long dirid = 0L, temp; | |
609 | long rslt, errnum; | |
610 | short err; | |
611 | ||
612 | if (DebugPI < 0) | |
613 | DebugPI = (*(getenv ("DEBUG_PATHNAMES")) == '1' ? 1 : 0); | |
614 | if (DebugPI) | |
615 | fprintf (stderr, "# fstat (%d, %x)", fd, buf); | |
616 | PROGRESS (1); | |
617 | pathname[0] = 0; | |
618 | #ifdef FIOFNAME | |
619 | /* Use an MPW-specific ioctl to get the pathname associated with | |
620 | the file descriptor. */ | |
621 | ioctl (fd, FIOFNAME, (long *) pathname); | |
622 | #else | |
623 | you lose | |
624 | #endif | |
625 | if (DebugPI) | |
626 | fprintf (stderr, " (name is %s)", pathname); | |
627 | dirid = 0L /* fcb.ioFCBParID */ ; | |
628 | rslt = _stat ((char *) pathname, dirid, buf); | |
629 | errnum = errno; | |
630 | if (DebugPI) | |
631 | { | |
632 | fprintf (stderr, " -> %d", rslt); | |
633 | if (rslt != 0) | |
634 | fprintf (stderr, " (errno is %d)", errnum); | |
635 | fprintf (stderr, "\n"); | |
636 | fflush (stderr); | |
637 | } | |
638 | if (rslt != 0) | |
639 | errno = errnum; | |
640 | return rslt; | |
641 | } | |
642 | ||
643 | #endif /* n USE_MW_HEADERS */ | |
644 | ||
645 | chdir () | |
646 | { | |
647 | errno = ENOSYS; | |
648 | return (-1); | |
649 | } | |
650 | ||
651 | char * | |
652 | getcwd (char *buf, int size) | |
653 | { | |
654 | if (buf == NULL) | |
655 | buf = (char *) malloc (size); | |
656 | strcpy(buf, ":"); | |
657 | return buf; | |
658 | } | |
659 | ||
660 | /* This should probably be more elaborate for MPW. */ | |
661 | ||
662 | char * | |
663 | getpwd () | |
664 | { | |
665 | return ":"; | |
666 | } | |
667 | ||
668 | int | |
669 | mpw_open (char *filename, int arg2, int arg3) | |
670 | { | |
671 | #undef open | |
672 | int fd, errnum = 0; | |
673 | char tmpname[256]; | |
674 | ||
675 | mpwify_filename (filename, tmpname); | |
676 | fd = open (tmpname, arg2); | |
677 | errnum = errno; | |
678 | ||
679 | if (DebugPI) | |
680 | { | |
681 | fprintf (stderr, "# open (%s, %d, %d)", tmpname, arg2, arg3); | |
682 | fprintf (stderr, " -> %d", fd); | |
683 | if (fd == -1) | |
684 | fprintf (stderr, " (errno is %d)", errnum); | |
685 | fprintf (stderr, "\n"); | |
686 | } | |
687 | if (fd == -1) | |
688 | errno = errnum; | |
689 | return fd; | |
690 | } | |
691 | ||
692 | int | |
693 | mpw_access (char *filename, unsigned int cmd) | |
694 | { | |
695 | #undef access | |
696 | ||
697 | int rslt, errnum = 0; | |
698 | struct stat st; | |
699 | char tmpname[256]; | |
700 | ||
701 | mpwify_filename (filename, tmpname); | |
702 | if (cmd & R_OK || cmd & X_OK) | |
703 | { | |
704 | rslt = stat (tmpname, &st); | |
705 | errnum = errno; | |
706 | if (rslt >= 0) | |
707 | { | |
708 | if ((((st.st_mode & 004) == 0) && (cmd & R_OK)) | |
709 | || (((st.st_mode & 002) == 0) && (cmd & W_OK)) | |
710 | || (((st.st_mode & 001) == 0) && (cmd & X_OK))) | |
711 | { | |
712 | rslt = -1; | |
713 | errnum = EACCES; | |
714 | } | |
715 | } | |
716 | } | |
717 | if (DebugPI) | |
718 | { | |
719 | fprintf (stderr, "# mpw_access (%s, %d)", tmpname, cmd); | |
720 | fprintf (stderr, " -> %d", rslt); | |
721 | if (rslt != 0) | |
722 | fprintf (stderr, " (errno is %d)", errnum); | |
723 | fprintf (stderr, "\n"); | |
724 | } | |
725 | if (rslt != 0) | |
726 | errno = errnum; | |
727 | return rslt; | |
728 | } | |
729 | ||
730 | /* The MPW library creat() has no mode argument. */ | |
731 | ||
732 | int | |
733 | mpw_creat (char *path, /* mode_t */ int mode) | |
734 | { | |
735 | #undef creat | |
736 | ||
737 | #ifdef USE_MW_HEADERS | |
738 | return creat (path, mode); | |
739 | #else | |
740 | return creat (path); | |
741 | #endif | |
742 | } | |
743 | ||
744 | /* This is a hack to get control in an MPW tool before it crashes the | |
745 | machine. */ | |
746 | ||
747 | mpw_special_init (name) | |
748 | char *name; | |
749 | { | |
750 | if (strstr (name, "DEBUG")) | |
751 | DebugStr("\pat beginning of program"); | |
752 | } | |
753 | ||
754 | static int current_umask; | |
755 | ||
756 | int | |
757 | umask(int mask) | |
758 | { | |
759 | int oldmask = current_umask; | |
760 | ||
761 | current_umask = mask; | |
762 | return oldmask; | |
763 | } | |
764 | ||
765 | /* Cursor-spinning stuff that includes metering of spin rate and delays. */ | |
766 | ||
767 | /* Nonzero when cursor spinning has been set up properly. */ | |
768 | ||
769 | int cursor_inited; | |
770 | ||
771 | /* Nonzero if spin should be measured and excessive delays reported. */ | |
772 | ||
773 | int measure_spin; | |
774 | ||
775 | /* Nonzero if spin histogram and rate data should be written out. */ | |
776 | ||
777 | int dump_spin_data; | |
778 | ||
779 | long warning_threshold = 400000; | |
780 | ||
781 | long bucket_size = 1024; | |
782 | ||
783 | long bucket_power = 10; | |
784 | ||
785 | long numbuckets = 300; | |
786 | ||
787 | int *delay_counts; | |
788 | ||
789 | int overflow_count; | |
790 | ||
791 | char *current_progress; | |
792 | ||
793 | static UnsignedWide last_microseconds; | |
794 | ||
795 | static char *last_spin_file = ""; | |
796 | ||
797 | static int last_spin_line; | |
798 | ||
799 | void | |
800 | warn_if_spin_delay (char *file, int line) | |
801 | { | |
802 | long diff, ix; | |
803 | UnsignedWide now; | |
804 | ||
805 | Microseconds(&now); | |
806 | ||
807 | diff = now.lo - last_microseconds.lo; | |
808 | ||
809 | if (diff > warning_threshold) | |
810 | fprintf (stderr, "# %s: %ld.%06ld sec delay getting from %s:%d to %s:%d\n", | |
811 | (current_progress ? current_progress : ""), | |
812 | diff / 1000000, diff % 1000000, | |
813 | last_spin_file, last_spin_line, file, line); | |
814 | if (dump_spin_data) | |
815 | { | |
816 | if (diff >= 0) | |
817 | { | |
818 | ix = diff >> bucket_power; | |
819 | if (ix >= 0 && ix < numbuckets && delay_counts != NULL) | |
820 | ++delay_counts[ix]; | |
821 | else | |
822 | ++overflow_count; | |
823 | } | |
824 | else | |
825 | fprintf (stderr, "raw diff is %ld (?)\n", diff); | |
826 | } | |
827 | } | |
828 | ||
829 | void | |
830 | record_for_spin_delay (char *file, int line) | |
831 | { | |
832 | Microseconds (&last_microseconds); | |
833 | last_spin_file = file; | |
834 | last_spin_line = line; | |
835 | } | |
836 | ||
837 | void | |
838 | mpw_start_progress (char *str, int n, char *file, int line) | |
839 | { | |
840 | int i; | |
841 | char *measure, *threshold; | |
842 | ||
843 | if (!cursor_inited) | |
844 | { | |
845 | InitCursorCtl (nil); | |
846 | cursor_inited = 1; | |
847 | record_for_spin_delay (file, line); | |
848 | measure = getenv ("MEASURE_SPIN"); | |
849 | if (measure != NULL && measure[0] != '\0') | |
850 | { | |
851 | measure_spin = 1; | |
852 | if (strcmp (measure, "all") == 0) | |
853 | dump_spin_data = 1; | |
854 | } | |
855 | threshold = getenv ("SPIN_WARN_THRESHOLD"); | |
856 | if (threshold != NULL && threshold[0] != '\0') | |
857 | warning_threshold = atol (threshold); | |
858 | if (dump_spin_data) | |
859 | { | |
860 | if (delay_counts == NULL) | |
861 | delay_counts = (int *) malloc (numbuckets * sizeof (int)); | |
862 | for (i = 0; i < numbuckets; ++i) | |
863 | delay_counts[i] = 0; | |
864 | overflow_count = 0; | |
865 | } | |
866 | } | |
867 | current_progress = str; | |
868 | ||
869 | sys_nerr = errno_max (); | |
870 | ||
871 | mpw_special_init (str); | |
872 | } | |
873 | ||
874 | void | |
875 | mpw_progress (int n) | |
876 | { | |
877 | SpinCursor (32); | |
878 | } | |
879 | ||
880 | void | |
881 | mpw_progress_measured (int n, char *file, int line) | |
882 | { | |
883 | if (measure_spin) | |
884 | warn_if_spin_delay (file, line); | |
885 | SpinCursor (32); | |
886 | if (measure_spin) | |
887 | record_for_spin_delay (file, line); | |
888 | } | |
889 | ||
890 | void | |
891 | mpw_end_progress (char *str, char *file, int line) | |
892 | { | |
893 | long i, delay, count = 0, sum = 0, avgdelay, spinrate; | |
894 | long curpower = 0, curgroup = 0; | |
895 | ||
896 | /* Warn if it's been a while since the last spin. */ | |
897 | if (measure_spin) | |
898 | warn_if_spin_delay (file, line); | |
899 | ||
900 | /* Dump all the nonzero delay counts and an approximation of the delay. */ | |
901 | if (dump_spin_data && delay_counts != NULL) | |
902 | { | |
903 | for (i = 0; i < numbuckets; ++i) | |
904 | { | |
905 | delay = (i + 1) * bucket_size; | |
906 | sum += delay_counts[i] * (i + 1); | |
907 | count += delay_counts[i]; | |
908 | if (delay <= (1 << curpower)) | |
909 | { | |
910 | curgroup += delay_counts[i]; | |
911 | } | |
912 | else | |
913 | { | |
914 | if (curgroup > 0) | |
915 | fprintf (stderr, | |
916 | "# %s: %d delays between %ld.%06ld and %ld.%06ld sec\n", | |
917 | (str ? str : ""), | |
918 | curgroup, | |
919 | (1 << curpower) / 1000000, | |
920 | (1 << curpower) % 1000000, | |
921 | (1 << (curpower + 1)) / 1000000, | |
922 | (1 << (curpower + 1)) % 1000000); | |
923 | ++curpower; | |
924 | curgroup = 0; | |
925 | } | |
926 | } | |
927 | if (count > 0) | |
928 | { | |
929 | avgdelay = (sum * bucket_size) / count; | |
930 | spinrate = 1000000 / avgdelay; | |
931 | fprintf (stderr, "# %s: Average spin rate is %d times/sec\n", | |
932 | (str ? str : ""), spinrate); | |
933 | } | |
934 | } | |
935 | } | |
936 | ||
937 | #ifdef PROGRESS_TEST | |
938 | ||
939 | /* Test program. */ | |
940 | ||
941 | main () | |
942 | { | |
943 | int i, j; | |
944 | double x = 1.0, y = 2.4; | |
945 | long start = Microseconds (), tm; FIXME | |
946 | ||
947 | START_PROGRESS ("hi", 0); | |
948 | ||
949 | for (i = 0; i < 1000; ++i) | |
950 | { | |
951 | PROGRESS (1); | |
952 | ||
953 | for (j = 0; j < (i * 100); ++j) | |
954 | { | |
955 | x += (x * y) / j; | |
956 | } | |
957 | } | |
958 | ||
959 | END_PROGRESS ("hi"); | |
960 | ||
961 | tm = Microseconds () - start; | |
962 | ||
963 | printf ("Total time is %d.%d secs\n", tm / 1000000, tm % 1000000); | |
964 | } | |
965 | ||
966 | #endif | |
967 | ||
968 | #ifdef USE_MW_HEADERS | |
969 | /* Empty definitions for Metrowerks' SIOUX console library. */ | |
970 | ||
971 | #ifndef __CONSOLE__ | |
972 | #include <console.h> | |
973 | #endif | |
974 | ||
975 | short | |
976 | InstallConsole(short fd) | |
977 | { | |
978 | #pragma unused (fd) | |
979 | return 0; | |
980 | } | |
981 | ||
982 | void | |
983 | RemoveConsole(void) | |
984 | { | |
985 | } | |
986 | ||
987 | long | |
988 | WriteCharsToConsole(char *buf, long n) | |
989 | { | |
990 | #pragma unused (buf, n) | |
991 | return 0; | |
992 | } | |
993 | ||
994 | long ReadCharsFromConsole(char *buf, long n) | |
995 | { | |
996 | #pragma unused (buf, n) | |
997 | return 0; | |
998 | } | |
999 | ||
1000 | extern char * | |
1001 | __ttyname(long fd) | |
1002 | { | |
1003 | static char *__devicename = "null device"; | |
1004 | ||
1005 | if (fd >= 0 && fd <= 2) | |
1006 | return (__devicename); | |
1007 | return NULL; | |
1008 | } | |
1009 | ||
1010 | #endif |