Mercurial > vim
comparison src/os_mac.c @ 7:3fc0f57ecb91 v7.0001
updated for version 7.0001
author | vimboss |
---|---|
date | Sun, 13 Jun 2004 20:20:40 +0000 |
parents | |
children | 4102fb4ea781 |
comparison
equal
deleted
inserted
replaced
6:c2daee826b8f | 7:3fc0f57ecb91 |
---|---|
1 /* vi:set ts=8 sts=4 sw=4: | |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * | |
5 * Do ":help uganda" in Vim to read copying and usage conditions. | |
6 * Do ":help credits" in Vim to see a list of people who contributed. | |
7 * See README.txt for an overview of the Vim source code. | |
8 */ | |
9 | |
10 /* | |
11 * os_mac.c -- code for the MacOS | |
12 * | |
13 * This file is mainly based on os_unix.c. | |
14 */ | |
15 | |
16 #include "vim.h" | |
17 | |
18 #if defined(__MRC__) || defined(__SC__) /* for Apple MPW Compilers */ | |
19 | |
20 #include "StandardFile.h" | |
21 | |
22 /* | |
23 * Implements the corresponding unix function | |
24 */ | |
25 int | |
26 stat( | |
27 char *p, | |
28 struct stat *p_st) | |
29 { | |
30 /* | |
31 TODO: Use functions which fill the FileParam struct (Files.h) | |
32 and copy these contents to our self-defined stat struct | |
33 */ | |
34 return 0; | |
35 } | |
36 #endif | |
37 | |
38 /* | |
39 * change the current working directory | |
40 */ | |
41 int | |
42 mch_chdir(char *p_name) | |
43 { | |
44 #if defined(__MRC__) || defined(__SC__) /* for Apple MPW Compilers */ | |
45 /* TODO */ | |
46 return FAIL; | |
47 #else | |
48 return chdir(p_name); | |
49 #endif | |
50 } | |
51 | |
52 | |
53 /* | |
54 * Recursively build up a list of files in "gap" matching the first wildcard | |
55 * in `path'. Called by mch_expandpath(). | |
56 * "path" has backslashes before chars that are not to be expanded. | |
57 */ | |
58 int | |
59 mac_expandpath( | |
60 garray_T *gap, | |
61 char_u *path, | |
62 int flags, /* EW_* flags */ | |
63 short start_at, | |
64 short as_full) | |
65 { | |
66 /* | |
67 * TODO: | |
68 * +Get Volumes (when looking for files in current dir) | |
69 * +Make it work when working dir not on select volume | |
70 * +Cleanup | |
71 */ | |
72 short index = 1; | |
73 OSErr gErr; | |
74 char_u dirname[256]; | |
75 char_u cfilename[256]; | |
76 long dirID; | |
77 char_u *new_name; | |
78 CInfoPBRec gMyCPB; | |
79 HParamBlockRec gMyHPBlock; | |
80 FSSpec usedDir; | |
81 | |
82 char_u *buf; | |
83 char_u *p, *s, *e, dany; | |
84 int start_len, c; | |
85 char_u *pat; | |
86 regmatch_T regmatch; | |
87 | |
88 start_len = gap->ga_len; | |
89 buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */ | |
90 if (buf == NULL) | |
91 return 0; | |
92 | |
93 /* | |
94 * Find the first part in the path name that contains a wildcard. | |
95 * Copy it into buf, including the preceding characters. | |
96 */ | |
97 p = buf; | |
98 s = buf; | |
99 e = NULL; | |
100 #if 1 | |
101 STRNCPY(buf, path, start_at); | |
102 p += start_at; | |
103 path += start_at; | |
104 #endif | |
105 | |
106 while (*path) | |
107 { | |
108 if (*path == ':') | |
109 { | |
110 if (e) | |
111 break; | |
112 else | |
113 s = p + 1; | |
114 } | |
115 /* should use WILCARDLIST but what about ` */ | |
116 /* if (vim_strchr((char_u *)"*?[{~$", *path) != NULL)*/ | |
117 else if (vim_strchr((char_u *)WILDCHAR_LIST, *path) != NULL) | |
118 e = p; | |
119 #ifdef FEAT_MBYTE | |
120 if (has_mbyte) | |
121 { | |
122 int len = (*mb_ptr2len_check)(path); | |
123 | |
124 STRNCPY(p, path, len); | |
125 p += len; | |
126 path += len; | |
127 } | |
128 else | |
129 #endif | |
130 *p++ = *path++; | |
131 } | |
132 e = p; | |
133 | |
134 /* now we have one wildcard component between s and e */ | |
135 *e = NUL; | |
136 | |
137 #if 1 | |
138 dany = *s; | |
139 *s = NUL; | |
140 backslash_halve(buf); | |
141 *s = dany; | |
142 #endif | |
143 | |
144 /* convert the file pattern to a regexp pattern */ | |
145 pat = file_pat_to_reg_pat(s, e, NULL, FALSE); | |
146 if (pat == NULL) | |
147 { | |
148 vim_free(buf); | |
149 return 0; | |
150 } | |
151 | |
152 /* compile the regexp into a program */ | |
153 regmatch.rm_ic = FALSE; /* Don't ever ignore case */ | |
154 regmatch.regprog = vim_regcomp(pat, RE_MAGIC); | |
155 vim_free(pat); | |
156 | |
157 if (regmatch.regprog == NULL) | |
158 { | |
159 vim_free(buf); | |
160 return 0; | |
161 } | |
162 | |
163 /* open the directory for scanning */ | |
164 c = *s; | |
165 *s = NUL; | |
166 | |
167 if (*buf == NUL) | |
168 { | |
169 as_full = TRUE; | |
170 #if 0 | |
171 (void) mch_dirname (&dirname[1], 254); | |
172 dirname[0] = STRLEN(&dirname[1]); | |
173 #endif | |
174 } | |
175 else | |
176 { | |
177 if (*buf == ':') /* relative path */ | |
178 { | |
179 (void)mch_dirname(&dirname[1], 254); | |
180 new_name = concat_fnames(&dirname[1], buf+1, TRUE); | |
181 STRCPY(&dirname[1], new_name); | |
182 dirname[0] = STRLEN(new_name); | |
183 vim_free(new_name); | |
184 } | |
185 else | |
186 { | |
187 STRCPY(&dirname[1], buf); | |
188 backslash_halve(&dirname[1]); | |
189 dirname[0] = STRLEN(buf); | |
190 } | |
191 } | |
192 *s = c; | |
193 | |
194 FSMakeFSSpec (0, 0, dirname, &usedDir); | |
195 | |
196 gMyCPB.dirInfo.ioNamePtr = dirname; | |
197 gMyCPB.dirInfo.ioVRefNum = usedDir.vRefNum; | |
198 gMyCPB.dirInfo.ioFDirIndex = 0; | |
199 gMyCPB.dirInfo.ioDrDirID = 0; | |
200 | |
201 gErr = PBGetCatInfo(&gMyCPB, false); | |
202 | |
203 gMyCPB.dirInfo.ioCompletion = NULL; | |
204 dirID = gMyCPB.dirInfo.ioDrDirID; | |
205 do | |
206 { | |
207 gMyCPB.hFileInfo.ioFDirIndex = index; | |
208 gMyCPB.hFileInfo.ioDirID = dirID; | |
209 | |
210 gErr = PBGetCatInfo(&gMyCPB,false); | |
211 | |
212 if (gErr == noErr) | |
213 { | |
214 STRNCPY (cfilename, &dirname[1], dirname[0]); | |
215 cfilename[dirname[0]] = 0; | |
216 if (vim_regexec(®match, cfilename, (colnr_T)0)) | |
217 { | |
218 if (s[-1] != ':') | |
219 { | |
220 /* TODO: need to copy with cleaned name */ | |
221 STRCPY(s+1, cfilename); | |
222 s[0] = ':'; | |
223 } | |
224 else | |
225 { /* TODO: need to copy with cleeaned name */ | |
226 STRCPY(s, cfilename); | |
227 } | |
228 start_at = STRLEN(buf); | |
229 STRCAT(buf, path); | |
230 if (mch_has_exp_wildcard(path)) /* handle more wildcards */ | |
231 (void)mac_expandpath(gap, buf, flags, start_at, FALSE); | |
232 else | |
233 { | |
234 #ifdef DONT_ADD_PATHSEP_TO_DIR | |
235 if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 ) | |
236 STRCAT(buf, PATHSEPSTR); | |
237 #endif | |
238 addfile(gap, buf, flags); | |
239 } | |
240 } | |
241 if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 ) | |
242 { | |
243 } | |
244 else | |
245 { | |
246 } | |
247 } | |
248 index++; | |
249 } | |
250 while (gErr == noErr); | |
251 | |
252 if (as_full) | |
253 { | |
254 index = 1; | |
255 do | |
256 { | |
257 gMyHPBlock.volumeParam.ioNamePtr = (char_u *) dirname; | |
258 gMyHPBlock.volumeParam.ioVRefNum =0; | |
259 gMyHPBlock.volumeParam.ioVolIndex = index; | |
260 | |
261 gErr = PBHGetVInfo (&gMyHPBlock,false); | |
262 if (gErr == noErr) | |
263 { | |
264 STRNCPY (cfilename, &dirname[1], dirname[0]); | |
265 cfilename[dirname[0]] = 0; | |
266 if (vim_regexec(®match, cfilename, (colnr_T)0)) | |
267 { | |
268 STRCPY(s, cfilename); | |
269 STRCAT(buf, path); | |
270 if (mch_has_exp_wildcard(path)) /* handle more wildcards */ | |
271 (void)mac_expandpath(gap, s, flags, 0, FALSE); | |
272 else | |
273 { | |
274 #ifdef DONT_ADD_PATHSEP_TO_DIR | |
275 /* if ((gMyCPB.hFileInfo.ioFlAttrib & ioDirMask) !=0 ) | |
276 */ STRCAT(buf, PATHSEPSTR); | |
277 #endif | |
278 addfile(gap, s, flags); | |
279 } | |
280 #if 0 | |
281 STRCAT(cfilename, PATHSEPSTR); | |
282 addfile (gap, cfilename, flags); | |
283 #endif | |
284 } | |
285 } | |
286 index++; | |
287 } | |
288 while (gErr == noErr); | |
289 } | |
290 | |
291 vim_free(regmatch.regprog); | |
292 | |
293 return gap->ga_len - start_len; | |
294 } | |
295 | |
296 | |
297 #ifdef USE_UNIXFILENAME | |
298 static int | |
299 pstrcmp(a, b) | |
300 const void *a, *b; | |
301 { | |
302 return (pathcmp(*(char **)a, *(char **)b)); | |
303 } | |
304 | |
305 static int | |
306 unix_expandpath(gap, path, wildoff, flags) | |
307 garray_T *gap; | |
308 char_u *path; | |
309 int wildoff; | |
310 int flags; /* EW_* flags */ | |
311 { | |
312 char_u *buf; | |
313 char_u *path_end; | |
314 char_u *p, *s, *e; | |
315 int start_len, c; | |
316 char_u *pat; | |
317 DIR *dirp; | |
318 regmatch_T regmatch; | |
319 struct dirent *dp; | |
320 int starts_with_dot; | |
321 int matches; | |
322 int len; | |
323 | |
324 start_len = gap->ga_len; | |
325 buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */ | |
326 if (buf == NULL) | |
327 return 0; | |
328 | |
329 /* | |
330 * Find the first part in the path name that contains a wildcard. | |
331 * Copy it into buf, including the preceding characters. | |
332 */ | |
333 p = buf; | |
334 s = buf; | |
335 e = NULL; | |
336 path_end = path; | |
337 while (*path_end) | |
338 { | |
339 /* May ignore a wildcard that has a backslash before it */ | |
340 if (path_end >= path + wildoff && rem_backslash(path_end)) | |
341 *p++ = *path_end++; | |
342 else if (*path_end == '/') | |
343 { | |
344 if (e != NULL) | |
345 break; | |
346 else | |
347 s = p + 1; | |
348 } | |
349 else if (vim_strchr((char_u *)"*?[{~$", *path_end) != NULL) | |
350 e = p; | |
351 #ifdef FEAT_MBYTE | |
352 if (has_mbyte) | |
353 { | |
354 len = (*mb_ptr2len_check)(path_end); | |
355 STRNCPY(p, path_end, len); | |
356 p += len; | |
357 path_end += len; | |
358 } | |
359 else | |
360 #endif | |
361 *p++ = *path_end++; | |
362 } | |
363 e = p; | |
364 *e = NUL; | |
365 | |
366 /* now we have one wildcard component between s and e */ | |
367 /* Remove backslashes between "wildoff" and the start of the wildcard | |
368 * component. */ | |
369 for (p = buf + wildoff; p < s; ++p) | |
370 if (rem_backslash(p)) | |
371 { | |
372 STRCPY(p, p + 1); | |
373 --e; | |
374 --s; | |
375 } | |
376 | |
377 /* convert the file pattern to a regexp pattern */ | |
378 starts_with_dot = (*s == '.'); | |
379 pat = file_pat_to_reg_pat(s, e, NULL, FALSE); | |
380 if (pat == NULL) | |
381 { | |
382 vim_free(buf); | |
383 return 0; | |
384 } | |
385 | |
386 /* compile the regexp into a program */ | |
387 #ifdef MACOS_X | |
388 /* We want to behave like Terminal.app */ | |
389 regmatch.rm_ic = TRUE; | |
390 #else | |
391 regmatch.rm_ic = FALSE; /* Don't ever ignore case */ | |
392 #endif | |
393 regmatch.regprog = vim_regcomp(pat, RE_MAGIC); | |
394 vim_free(pat); | |
395 | |
396 if (regmatch.regprog == NULL) | |
397 { | |
398 vim_free(buf); | |
399 return 0; | |
400 } | |
401 | |
402 /* open the directory for scanning */ | |
403 c = *s; | |
404 *s = NUL; | |
405 dirp = opendir(*buf == NUL ? "." : (char *)buf); | |
406 *s = c; | |
407 | |
408 /* Find all matching entries */ | |
409 if (dirp != NULL) | |
410 { | |
411 for (;;) | |
412 { | |
413 dp = readdir(dirp); | |
414 if (dp == NULL) | |
415 break; | |
416 if ((dp->d_name[0] != '.' || starts_with_dot) | |
417 && vim_regexec(®match, (char_u *)dp->d_name, (colnr_T)0)) | |
418 { | |
419 STRCPY(s, dp->d_name); | |
420 len = STRLEN(buf); | |
421 STRCPY(buf + len, path_end); | |
422 if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */ | |
423 { | |
424 /* need to expand another component of the path */ | |
425 /* remove backslashes for the remaining components only */ | |
426 (void)unix_expandpath(gap, buf, len + 1, flags); | |
427 } | |
428 else | |
429 { | |
430 /* no more wildcards, check if there is a match */ | |
431 /* remove backslashes for the remaining components only */ | |
432 if (*path_end) | |
433 backslash_halve(buf + len + 1); | |
434 if (mch_getperm(buf) >= 0) /* add existing file */ | |
435 addfile(gap, buf, flags); | |
436 } | |
437 } | |
438 } | |
439 | |
440 closedir(dirp); | |
441 } | |
442 | |
443 vim_free(buf); | |
444 vim_free(regmatch.regprog); | |
445 | |
446 matches = gap->ga_len - start_len; | |
447 if (matches) | |
448 qsort(((char_u **)gap->ga_data) + start_len, matches, | |
449 sizeof(char_u *), pstrcmp); | |
450 return matches; | |
451 } | |
452 #endif | |
453 | |
454 /* | |
455 * Recursively build up a list of files in "gap" matching the first wildcard | |
456 * in `path'. Called by expand_wildcards(). | |
457 * "pat" has backslashes before chars that are not to be expanded. | |
458 */ | |
459 int | |
460 mch_expandpath( | |
461 garray_T *gap, | |
462 char_u *path, | |
463 int flags) /* EW_* flags */ | |
464 { | |
465 #ifdef USE_UNIXFILENAME | |
466 return unix_expandpath(gap, path, 0, flags); | |
467 #else | |
468 char_u first = *path; | |
469 short scan_volume; | |
470 | |
471 slash_n_colon_adjust(path); | |
472 | |
473 scan_volume = (first != *path); | |
474 | |
475 return mac_expandpath(gap, path, flags, 0, scan_volume); | |
476 #endif | |
477 } | |
478 | |
479 void | |
480 fname_case(name, len) | |
481 char_u *name; | |
482 int len; /* buffer size, ignored here */ | |
483 { | |
484 /* | |
485 * TODO: get the real casing for the file | |
486 * make it called | |
487 * with USE_FNAME_CASE & USE_LONG_FNAME | |
488 * CASE_INSENSITIVE_FILENAME | |
489 * within setfname, fix_fname, do_ecmd | |
490 */ | |
491 #ifdef USE_UNIXFILENAME | |
492 OSStatus status; | |
493 FSRef refFile; | |
494 UInt32 pathSize = STRLEN(name) + 1; | |
495 char_u *path; | |
496 Boolean isDirectory; | |
497 | |
498 path = alloc(pathSize); | |
499 if (path == NULL) | |
500 return; | |
501 | |
502 status = FSPathMakeRef((UInt8 *)name, &refFile, &isDirectory); | |
503 if (status) | |
504 return; | |
505 | |
506 status = FSRefMakePath(&refFile, (UInt8 *)path, pathSize); | |
507 if (status) | |
508 return; | |
509 | |
510 /* Paranoid: Update the name if only the casing differ.*/ | |
511 if (STRICMP(name, path) == 0) | |
512 STRCPY(name, path); | |
513 #endif | |
514 } | |
515 static char_u *oldtitle = (char_u *) "gVim"; | |
516 | |
517 /* | |
518 * check for an "interrupt signal": CTRL-break or CTRL-C | |
519 */ | |
520 void | |
521 mch_breakcheck() | |
522 { | |
523 /* | |
524 * TODO: Scan event for a CTRL-C or COMMAND-. and do: got_int=TRUE; | |
525 * or only go proccess event? | |
526 * or do nothing | |
527 */ | |
528 EventRecord theEvent; | |
529 | |
530 if (EventAvail (keyDownMask, &theEvent)) | |
531 if ((theEvent.message & charCodeMask) == Ctrl_C && ctrl_c_interrupts) | |
532 got_int = TRUE; | |
533 #if 0 | |
534 short i = 0; | |
535 Boolean found = false; | |
536 EventRecord theEvent; | |
537 | |
538 while ((i < 10) && (!found)) | |
539 { | |
540 found = EventAvail (keyDownMask, &theEvent); | |
541 if (found) | |
542 { | |
543 if ((theEvent.modifiers & controlKey) != 0) | |
544 found = false; | |
545 if ((theEvent.what == keyDown)) | |
546 found = false; | |
547 if ((theEvent.message & charCodeMask) == Ctrl_C) | |
548 { | |
549 found = false; | |
550 got_int = TRUE; | |
551 } | |
552 } | |
553 i++; | |
554 } | |
555 #endif | |
556 | |
557 } | |
558 | |
559 /* | |
560 * Return amount of memory currently available. | |
561 */ | |
562 long_u | |
563 mch_avail_mem(special) | |
564 int special; | |
565 { | |
566 /* | |
567 * TODO: Use MaxBlock, FreeMeM, PurgeSpace, MaxBlockSys FAQ-266 | |
568 * figure out what the special is for | |
569 * | |
570 * FreeMem -> returns all avail memory is application heap | |
571 * MaxBlock -> returns the biggest contigeous block in application heap | |
572 * PurgeSpace -> | |
573 */ | |
574 return MaxBlock(); | |
575 } | |
576 | |
577 void | |
578 mch_delay(msec, ignoreinput) | |
579 long msec; | |
580 int ignoreinput; | |
581 { | |
582 #if (defined(__MWERKS__) && __MWERKS__ >= 0x2000) \ | |
583 || defined(__MRC__) || defined(__SC__) | |
584 unsigned | |
585 #endif | |
586 long finalTick; | |
587 | |
588 if (ignoreinput) | |
589 Delay (60*msec/1000, &finalTick); | |
590 else | |
591 /* even thougth we should call gui stuff from here | |
592 it the simplest way to be safe */ | |
593 gui_mch_wait_for_chars(msec); | |
594 } | |
595 | |
596 void | |
597 mch_init() | |
598 { | |
599 /* | |
600 * TODO: Verify if needed, or override later. | |
601 */ | |
602 Columns = 80; | |
603 Rows = 24; | |
604 } | |
605 | |
606 /* | |
607 * Check_win checks whether we have an interactive stdout. | |
608 */ | |
609 int | |
610 mch_check_win(argc, argv) | |
611 int argc; | |
612 char **argv; | |
613 { | |
614 /* | |
615 * TODO: Maybe to be remove through NO_CONSOLE | |
616 */ | |
617 return OK; | |
618 } | |
619 | |
620 /* | |
621 * Return TRUE if the input comes from a terminal, FALSE otherwise. | |
622 */ | |
623 int | |
624 mch_input_isatty() | |
625 { | |
626 /* | |
627 * TODO: Maybe to be remove through NO_CONSOLE | |
628 */ | |
629 return OK; | |
630 } | |
631 | |
632 #ifdef FEAT_TITLE | |
633 /* | |
634 * Set the window title and icon. | |
635 * (The icon is not taken care of). | |
636 */ | |
637 void | |
638 mch_settitle(title, icon) | |
639 char_u *title; | |
640 char_u *icon; | |
641 { | |
642 gui_mch_settitle(title, icon); | |
643 } | |
644 | |
645 /* | |
646 * Restore the window/icon title. | |
647 * which is one of: | |
648 * 1 Just restore title | |
649 * 2 Just restore icon | |
650 * 3 Restore title and icon | |
651 * but don't care about the icon. | |
652 */ | |
653 void | |
654 mch_restore_title(which) | |
655 int which; | |
656 { | |
657 mch_settitle((which & 1) ? oldtitle : NULL, NULL); | |
658 } | |
659 #endif | |
660 | |
661 /* | |
662 * Insert user name in s[len]. | |
663 * Return OK if a name found. | |
664 */ | |
665 int | |
666 mch_get_user_name(s, len) | |
667 char_u *s; | |
668 int len; | |
669 { | |
670 #if !(defined(__MRC__) || defined(__SC__)) /* No solution yet */ | |
671 /* | |
672 * TODO: clean up and try getlogin () | |
673 */ | |
674 #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID) | |
675 struct passwd *pw; | |
676 #endif | |
677 uid_t uid; | |
678 | |
679 uid = getuid(); | |
680 #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID) | |
681 if ((pw = getpwuid(uid)) != NULL | |
682 && pw->pw_name != NULL && *(pw->pw_name) != NUL) | |
683 { | |
684 STRNCPY(s, pw->pw_name, len); | |
685 return OK; | |
686 } | |
687 #endif | |
688 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */ | |
689 #endif | |
690 return FAIL; /* a number is not a name */ | |
691 } | |
692 | |
693 /* | |
694 * Copy host name into s[len]. | |
695 */ | |
696 void | |
697 mch_get_host_name(s, len) | |
698 char_u *s; | |
699 int len; | |
700 { | |
701 #if defined(__MRC__) || defined(__SC__) || defined(__APPLE_CC__) | |
702 STRNCPY(s, "Mac", len); /* TODO: use Gestalt information */ | |
703 #else | |
704 struct utsname vutsname; | |
705 | |
706 if (uname(&vutsname) < 0) | |
707 *s = NUL; | |
708 else | |
709 STRNCPY(s, vutsname.nodename, len); | |
710 #endif | |
711 s[len - 1] = NUL; /* make sure it's terminated */ | |
712 } | |
713 | |
714 /* | |
715 * return process ID | |
716 */ | |
717 long | |
718 mch_get_pid() | |
719 { | |
720 return (long)getpid(); | |
721 } | |
722 | |
723 /* | |
724 * Get name of current directory into buffer 'buf' of length 'len' bytes. | |
725 * Return OK for success, FAIL for failure. | |
726 */ | |
727 int | |
728 mch_dirname(buf, len) | |
729 char_u *buf; | |
730 int len; | |
731 { | |
732 #if defined(__MRC__) || defined(__SC__) | |
733 return FAIL; /* No solution yet */ | |
734 #else | |
735 /* The last : is already put by getcwd */ | |
736 if (getcwd((char *)buf, len) == NULL) | |
737 { | |
738 STRCPY(buf, strerror(errno)); | |
739 return FAIL; | |
740 } | |
741 # ifndef USE_UNIXFILENAME | |
742 else if (*buf != NUL && buf[STRLEN(buf) - 1] == ':') | |
743 buf[STRLEN(buf) - 1] = NUL; /* remove trailing ':' */ | |
744 # endif | |
745 return OK; | |
746 #endif | |
747 } | |
748 | |
749 void | |
750 slash_to_colon(p) | |
751 char_u *p; | |
752 { | |
753 for ( ; *p; ++p) | |
754 if (*p == '/') | |
755 *p = ':'; | |
756 } | |
757 | |
758 char_u * | |
759 slash_to_colon_save (p) | |
760 char_u *p; | |
761 { | |
762 char_u *res; | |
763 | |
764 res = vim_strsave(p); | |
765 if (res == NULL) | |
766 return p; | |
767 slash_to_colon(res); | |
768 return res; | |
769 } | |
770 | |
771 void | |
772 slash_n_colon_adjust (buf) | |
773 char_u *buf; | |
774 { | |
775 /* | |
776 * TODO: Make it faster | |
777 */ | |
778 #ifndef USE_UNIXFILENAME | |
779 char_u temp[MAXPATHL]; | |
780 char_u *first_colon = vim_strchr(buf, ':'); | |
781 char_u *first_slash = vim_strchr(buf, '/'); | |
782 int full = TRUE; | |
783 char_u *scanning; | |
784 char_u *filling; | |
785 char_u last_copied = NUL; | |
786 | |
787 if (*buf == NUL) | |
788 return ; | |
789 | |
790 if ((first_colon == NULL) && (first_slash == NULL)) | |
791 full = FALSE; | |
792 if ((first_slash == NULL) && (first_colon != NULL)) | |
793 full = TRUE; | |
794 if ((first_colon == NULL) && (first_slash != NULL)) | |
795 full = FALSE; | |
796 if ((first_slash < first_colon) && (first_slash != NULL)) | |
797 full = FALSE; | |
798 if ((first_colon < first_slash) && (first_colon != NULL)) | |
799 full = TRUE; | |
800 if (first_slash == buf) | |
801 full = TRUE; | |
802 if (first_colon == buf) | |
803 full = FALSE; | |
804 | |
805 scanning = buf; | |
806 filling = temp; | |
807 | |
808 while (*scanning != NUL) | |
809 { | |
810 if (*scanning == '/') | |
811 { | |
812 if ((scanning[1] != '/') && (scanning[-1] != ':')) | |
813 { | |
814 *filling++ = ':'; | |
815 scanning++; | |
816 } | |
817 else | |
818 scanning++; | |
819 } | |
820 else if (*scanning == '.') | |
821 { | |
822 if ((scanning[1] == NUL) || scanning[1] == '/') | |
823 { | |
824 if (scanning[1] == NUL) | |
825 scanning += 1; | |
826 else | |
827 scanning += 2; | |
828 } | |
829 else if (scanning[1] == '.') | |
830 { | |
831 if ((scanning[2] == NUL) || scanning[2] == '/') | |
832 { | |
833 *filling++ = ':'; | |
834 if (scanning[2] == NUL) | |
835 scanning +=2; | |
836 else | |
837 scanning += 3; | |
838 } | |
839 else | |
840 { | |
841 *filling++ = *scanning++; | |
842 } | |
843 } | |
844 else | |
845 { | |
846 *filling++ = *scanning++; | |
847 } | |
848 | |
849 } | |
850 else | |
851 { | |
852 *filling++ = *scanning++; | |
853 } | |
854 | |
855 } | |
856 | |
857 *filling = 0; | |
858 filling = temp; | |
859 | |
860 if (!full) | |
861 { | |
862 if (buf[0] != ':') | |
863 { | |
864 buf[0] = ':'; | |
865 buf[1] = NUL; | |
866 } | |
867 else | |
868 buf[0] = NUL; | |
869 } | |
870 else | |
871 { | |
872 buf[0] = NUL; | |
873 if (filling[0] == ':') | |
874 filling++; | |
875 } | |
876 | |
877 STRCAT (buf, filling); | |
878 #endif | |
879 } | |
880 | |
881 /* | |
882 * Get absolute filename into buffer 'buf' of length 'len' bytes. | |
883 * | |
884 * return FAIL for failure, OK for success | |
885 */ | |
886 int | |
887 mch_FullName(fname, buf, len, force) | |
888 char_u *fname, *buf; | |
889 int len; | |
890 int force; /* also expand when already absolute path name */ | |
891 { | |
892 /* | |
893 * TODO: Find what TODO | |
894 */ | |
895 int l; | |
896 char_u olddir[MAXPATHL]; | |
897 char_u newdir[MAXPATHL]; | |
898 char_u *p; | |
899 char_u c; | |
900 int retval = OK; | |
901 | |
902 if (force || !mch_isFullName(fname)) | |
903 { | |
904 /* | |
905 * Forced or not an absolute path. | |
906 * If the file name has a path, change to that directory for a moment, | |
907 * and then do the getwd() (and get back to where we were). | |
908 * This will get the correct path name with "../" things. | |
909 */ | |
910 if ((p = vim_strrchr(fname, ':')) != NULL) | |
911 { | |
912 p++; | |
913 if (mch_dirname(olddir, MAXPATHL) == FAIL) | |
914 { | |
915 p = NULL; /* can't get current dir: don't chdir */ | |
916 retval = FAIL; | |
917 } | |
918 else | |
919 { | |
920 c = *p; | |
921 *p = NUL; | |
922 if (mch_chdir((char *)fname)) | |
923 retval = FAIL; | |
924 else | |
925 fname = p; /* + 1;*/ | |
926 *p = c; | |
927 } | |
928 } | |
929 if (mch_dirname(buf, len) == FAIL) | |
930 { | |
931 retval = FAIL; | |
932 *newdir = NUL; | |
933 } | |
934 l = STRLEN(buf); | |
935 if (STRCMP(fname, ".") != 0) | |
936 { | |
937 #ifdef USE_UNIXFILENAME | |
938 if (l > 0 && buf[l - 1] != '/' && *fname != NUL) | |
939 STRCAT(buf, "/"); | |
940 #else | |
941 if (l > 0 && buf[l - 1] != ':' && *fname != NUL) | |
942 STRCAT(buf, ":"); | |
943 #endif | |
944 } | |
945 if (p != NULL) | |
946 mch_chdir((char *)olddir); | |
947 if (STRCMP(fname, ".") != 0) | |
948 STRCAT(buf, fname); | |
949 } | |
950 else | |
951 { | |
952 STRNCPY(buf, fname, len); | |
953 buf[len - 1] = NUL; | |
954 slash_n_colon_adjust(buf); | |
955 } | |
956 | |
957 return retval; | |
958 } | |
959 | |
960 /* | |
961 * Return TRUE if "fname" does not depend on the current directory. | |
962 */ | |
963 int | |
964 mch_isFullName(fname) | |
965 char_u *fname; | |
966 { | |
967 #ifdef USE_UNIXFILENAME | |
968 return ((fname[0] == '/') || (fname[0] == '~')); | |
969 #else | |
970 /* | |
971 * TODO: Make sure fname is always of mac still | |
972 * i.e: passed throught slash_n_colon_adjust | |
973 */ | |
974 char_u *first_colon = vim_strchr(fname, ':'); | |
975 char_u *first_slash = vim_strchr(fname, '/'); | |
976 | |
977 if (first_colon == fname) | |
978 return FALSE; | |
979 if (first_slash == fname) | |
980 return TRUE; | |
981 if ((first_colon < first_slash) && (first_colon != NULL)) | |
982 return TRUE; | |
983 if ((first_slash < first_colon) && (first_slash != NULL)) | |
984 return FALSE; | |
985 if ((first_colon == NULL) && (first_slash != NULL)) | |
986 return FALSE; | |
987 if ((first_slash == NULL) && (first_colon != NULL)) | |
988 return TRUE; | |
989 if ((first_colon == NULL) && (first_slash == NULL)) | |
990 return FALSE; | |
991 return TRUE; | |
992 #endif | |
993 } | |
994 | |
995 /* | |
996 * Replace all slashes by colons. | |
997 */ | |
998 void | |
999 slash_adjust(p) | |
1000 char_u *p; | |
1001 { | |
1002 #ifndef USE_UNIXFILENAME | |
1003 /* | |
1004 * TODO: keep escaped '/' | |
1005 */ | |
1006 | |
1007 while (*p) | |
1008 { | |
1009 if (*p == '/') | |
1010 *p = ':'; | |
1011 #ifdef FEAT_MBYTE | |
1012 if (has_mbyte) | |
1013 p += (*mb_ptr2len_check)(p); | |
1014 else | |
1015 #endif | |
1016 ++p; | |
1017 } | |
1018 #endif | |
1019 } | |
1020 | |
1021 /* | |
1022 * Get file permissions for 'name'. | |
1023 * Returns -1 when it doesn't exist. | |
1024 */ | |
1025 long | |
1026 mch_getperm(name) | |
1027 char_u *name; | |
1028 { | |
1029 /* | |
1030 * TODO: Maybe use AppleShare info?? | |
1031 * Use locked for non writable | |
1032 */ | |
1033 | |
1034 struct stat statb; | |
1035 | |
1036 if (stat((char *)name, &statb)) | |
1037 return -1; | |
1038 return statb.st_mode; | |
1039 } | |
1040 | |
1041 /* | |
1042 * set file permission for 'name' to 'perm' | |
1043 * | |
1044 * return FAIL for failure, OK otherwise | |
1045 */ | |
1046 int | |
1047 mch_setperm(name, perm) | |
1048 char_u *name; | |
1049 long perm; | |
1050 { | |
1051 /* | |
1052 * TODO: Maybe use AppleShare info?? | |
1053 * Use locked for non writable | |
1054 */ | |
1055 return (OK); | |
1056 } | |
1057 | |
1058 /* | |
1059 * Set hidden flag for "name". | |
1060 */ | |
1061 void | |
1062 mch_hide(name) | |
1063 char_u *name; | |
1064 { | |
1065 /* | |
1066 * TODO: Hide the file throught FileManager FAQ 8-34 | |
1067 * | |
1068 * *name is mac style start with : for relative | |
1069 */ | |
1070 } | |
1071 | |
1072 | |
1073 /* | |
1074 * return TRUE if "name" is a directory | |
1075 * return FALSE if "name" is not a directory | |
1076 * return FALSE for error | |
1077 */ | |
1078 int | |
1079 mch_isdir(name) | |
1080 char_u *name; | |
1081 { | |
1082 /* | |
1083 * TODO: Find out by FileManager calls ... | |
1084 */ | |
1085 struct stat statb; | |
1086 | |
1087 #if defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON | |
1088 /* For some reason the name is sometimes empty, | |
1089 * (such as for a not yet named file). An empty | |
1090 * filename is interpreted by the MacOS version | |
1091 * of stat (at least under Codewarrior) as the | |
1092 * current directory. | |
1093 */ | |
1094 /* AK 20020413 | |
1095 * This is required for Carbon but breaks the | |
1096 * explorer plugin in Classic | |
1097 */ | |
1098 if (name[0] == NULL) | |
1099 return FALSE; | |
1100 #endif | |
1101 | |
1102 if (stat((char *)name, &statb)) | |
1103 return FALSE; | |
1104 #if defined(__MRC__) || defined(__SC__) | |
1105 return FALSE; /* definitely TODO */ | |
1106 #else | |
1107 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE); | |
1108 #endif | |
1109 } | |
1110 | |
1111 #if defined(FEAT_EVAL) || defined(PROTO) | |
1112 /* | |
1113 * Return 1 if "name" can be executed, 0 if not. | |
1114 * Return -1 if unknown. | |
1115 */ | |
1116 int | |
1117 mch_can_exe(name) | |
1118 char_u *name; | |
1119 { | |
1120 /* TODO */ | |
1121 return -1; | |
1122 } | |
1123 #endif | |
1124 | |
1125 /* | |
1126 * Check what "name" is: | |
1127 * NODE_NORMAL: file or directory (or doesn't exist) | |
1128 * NODE_WRITABLE: writable device, socket, fifo, etc. | |
1129 * NODE_OTHER: non-writable things | |
1130 */ | |
1131 int | |
1132 mch_nodetype(name) | |
1133 char_u *name; | |
1134 { | |
1135 /* TODO */ | |
1136 return NODE_NORMAL; | |
1137 } | |
1138 | |
1139 void | |
1140 mch_early_init() | |
1141 { | |
1142 } | |
1143 | |
1144 void | |
1145 mch_exit(r) | |
1146 int r; | |
1147 { | |
1148 display_errors(); | |
1149 | |
1150 ml_close_all(TRUE); /* remove all memfiles */ | |
1151 exit(r); | |
1152 } | |
1153 | |
1154 | |
1155 void | |
1156 mch_settmode(tmode) | |
1157 int tmode; | |
1158 { | |
1159 /* | |
1160 * TODO: remove the needs of it. | |
1161 */ | |
1162 } | |
1163 | |
1164 #ifdef FEAT_MOUSE | |
1165 /* | |
1166 * set mouse clicks on or off (only works for xterms) | |
1167 */ | |
1168 void | |
1169 mch_setmouse(on) | |
1170 int on; | |
1171 { | |
1172 /* | |
1173 * TODO: remove the needs of it. | |
1174 */ | |
1175 } | |
1176 #endif | |
1177 | |
1178 /* | |
1179 * set screen mode, always fails. | |
1180 */ | |
1181 int | |
1182 mch_screenmode(arg) | |
1183 char_u *arg; | |
1184 { | |
1185 EMSG(_(e_screenmode)); | |
1186 return FAIL; | |
1187 } | |
1188 | |
1189 int | |
1190 mch_call_shell(cmd, options) | |
1191 char_u *cmd; | |
1192 int options; /* SHELL_*, see vim.h */ | |
1193 { | |
1194 /* | |
1195 * TODO: find a shell or pseudo-shell to call | |
1196 * for some simple useful command | |
1197 */ | |
1198 | |
1199 return (-1); | |
1200 } | |
1201 | |
1202 /* | |
1203 * Return TRUE if "p" contains a wildcard that can be expanded by | |
1204 * mch_expandpath(). | |
1205 */ | |
1206 int | |
1207 mch_has_exp_wildcard(p) | |
1208 char_u *p; | |
1209 { | |
1210 for ( ; *p; ++p) | |
1211 { | |
1212 if (*p == '\\' && p[1] != NUL) | |
1213 ++p; | |
1214 else if (vim_strchr((char_u *)WILDCHAR_LIST, *p) != NULL) | |
1215 return TRUE; | |
1216 #ifdef FEAT_MBYTE | |
1217 if (has_mbyte) | |
1218 p += (*mb_ptr2len_check)(p) - 1; | |
1219 #endif | |
1220 } | |
1221 return FALSE; | |
1222 } | |
1223 | |
1224 int | |
1225 mch_has_wildcard(p) | |
1226 char_u *p; | |
1227 { | |
1228 #ifdef USE_UNIXFILENAME | |
1229 if (*p == '~' && p[1] != NUL) | |
1230 return TRUE; | |
1231 #endif | |
1232 return mch_has_exp_wildcard(p); | |
1233 } | |
1234 | |
1235 | |
1236 /* | |
1237 * This procedure duplicate a file, it is used in order to keep | |
1238 * the footprint of the previous file, when some info can be easily | |
1239 * restored with set_perm(). | |
1240 * | |
1241 * Return -1 for failure, 0 for success. | |
1242 */ | |
1243 int | |
1244 mch_copy_file(from, to) | |
1245 char_u *from; | |
1246 char_u *to; | |
1247 { | |
1248 char_u from_str[256]; | |
1249 char_u to_str[256]; | |
1250 char_u to_name[256]; | |
1251 | |
1252 HParamBlockRec paramBlock; | |
1253 char_u *char_ptr; | |
1254 int len; | |
1255 | |
1256 /* | |
1257 * Convert C string to Pascal string | |
1258 */ | |
1259 char_ptr = from; | |
1260 len = 1; | |
1261 for (; (*char_ptr != 0) && (len < 255); len++, char_ptr++) | |
1262 from_str[len] = *char_ptr; | |
1263 from_str[0] = len-1; | |
1264 | |
1265 char_ptr = to; | |
1266 len = 1; | |
1267 for (; (*char_ptr != 0) && (len < 255); len++, char_ptr++) | |
1268 to_str[len] = *char_ptr; | |
1269 to_str[0] = len-1; | |
1270 | |
1271 paramBlock.copyParam.ioCompletion = NULL; | |
1272 paramBlock.copyParam.ioNamePtr = from_str; | |
1273 /* paramBlock.copyParam.ioVRefnum = overided by ioFilename; */ | |
1274 /* paramBlock.copyParam.ioDirI = overided by ioFilename; */ | |
1275 | |
1276 paramBlock.copyParam.ioNewName = to_str; | |
1277 paramBlock.copyParam.ioCopyName = to_name; /* NIL */ | |
1278 /* paramBlock.copyParam.ioDstVRefNum = overided by ioNewName; */ | |
1279 /* paramBlock.copyParam.ioNewDirID = overided by ioNewName; */ | |
1280 | |
1281 | |
1282 | |
1283 /* | |
1284 * First delete the "to" file, this is required on some systems to make | |
1285 * the rename() work, on other systems it makes sure that we don't have | |
1286 * two files when the rename() fails. | |
1287 */ | |
1288 mch_remove(to); | |
1289 | |
1290 /* | |
1291 * First try a normal rename, return if it works. | |
1292 */ | |
1293 (void) PBHCopyFile(¶mBlock, false); | |
1294 return 0; | |
1295 | |
1296 } | |
1297 | |
1298 | |
1299 int | |
1300 mch_copy_file_attribute(from, to) | |
1301 char_u *from; | |
1302 char_u *to; | |
1303 { | |
1304 FSSpec frFSSpec; | |
1305 FSSpec toFSSpec; | |
1306 FInfo fndrInfo; | |
1307 Str255 name; | |
1308 ResType type; | |
1309 ResType sink; | |
1310 Handle resource; | |
1311 short idxTypes; | |
1312 short nbTypes; | |
1313 short idxResources; | |
1314 short nbResources; | |
1315 short ID; | |
1316 short frRFid; | |
1317 short toRFid; | |
1318 short attrs_orig; | |
1319 short attrs_copy; | |
1320 short temp; | |
1321 | |
1322 /* TODO: Handle error */ | |
1323 (void) GetFSSpecFromPath (from, &frFSSpec); | |
1324 (void) GetFSSpecFromPath (to , &toFSSpec); | |
1325 | |
1326 /* Copy resource fork */ | |
1327 temp = 0; | |
1328 | |
1329 #if 1 | |
1330 frRFid = FSpOpenResFile (&frFSSpec, fsCurPerm); | |
1331 | |
1332 if (frRFid != -1) | |
1333 { | |
1334 FSpCreateResFile(&toFSSpec, 'TEXT', UNKNOWN_CREATOR, 0); | |
1335 toRFid = FSpOpenResFile (&toFSSpec, fsRdWrPerm); | |
1336 | |
1337 UseResFile (frRFid); | |
1338 | |
1339 nbTypes = Count1Types(); | |
1340 | |
1341 for (idxTypes = 1; idxTypes <= nbTypes; idxTypes++) | |
1342 { | |
1343 Get1IndType (&type, idxTypes); | |
1344 nbResources = Count1Resources(type); | |
1345 | |
1346 for (idxResources = 1; idxResources <= nbResources; idxResources++) | |
1347 { | |
1348 attrs_orig = 0; /* in case GetRes fails */ | |
1349 attrs_copy = 0; /* in case GetRes fails */ | |
1350 resource = Get1IndResource(type, idxResources); | |
1351 GetResInfo (resource, &ID, &sink, name); | |
1352 HLock (resource); | |
1353 attrs_orig = GetResAttrs (resource); | |
1354 DetachResource (resource); | |
1355 | |
1356 | |
1357 UseResFile (toRFid); | |
1358 AddResource (resource, type, ID, name); | |
1359 attrs_copy = GetResAttrs (resource); | |
1360 attrs_copy = (attrs_copy & 0x2) | (attrs_orig & 0xFD); | |
1361 SetResAttrs (resource, attrs_copy); | |
1362 WriteResource (resource); | |
1363 UpdateResFile (toRFid); | |
1364 | |
1365 temp = GetResAttrs (resource); | |
1366 | |
1367 /*SetResAttrs (resource, 0);*/ | |
1368 HUnlock(resource); | |
1369 ReleaseResource (resource); | |
1370 UseResFile (frRFid); | |
1371 } | |
1372 } | |
1373 CloseResFile (toRFid); | |
1374 CloseResFile (frRFid); | |
1375 } | |
1376 #endif | |
1377 /* Copy Finder Info */ | |
1378 (void) FSpGetFInfo (&frFSSpec, &fndrInfo); | |
1379 (void) FSpSetFInfo (&toFSSpec, &fndrInfo); | |
1380 | |
1381 return (temp == attrs_copy); | |
1382 } | |
1383 | |
1384 int | |
1385 mch_has_resource_fork (file) | |
1386 char_u *file; | |
1387 { | |
1388 FSSpec fileFSSpec; | |
1389 short fileRFid; | |
1390 | |
1391 /* TODO: Handle error */ | |
1392 (void) GetFSSpecFromPath (file, &fileFSSpec); | |
1393 fileRFid = FSpOpenResFile (&fileFSSpec, fsCurPerm); | |
1394 if (fileRFid != -1) | |
1395 CloseResFile (fileRFid); | |
1396 | |
1397 return (fileRFid != -1); | |
1398 } | |
1399 | |
1400 int | |
1401 mch_get_shellsize(void) | |
1402 { | |
1403 /* never used */ | |
1404 return OK; | |
1405 } | |
1406 | |
1407 void | |
1408 mch_set_shellsize(void) | |
1409 { | |
1410 /* never used */ | |
1411 } | |
1412 | |
1413 /* | |
1414 * Rows and/or Columns has changed. | |
1415 */ | |
1416 void | |
1417 mch_new_shellsize(void) | |
1418 { | |
1419 /* never used */ | |
1420 } | |
1421 | |
1422 /* | |
1423 * Those function were set as #define before, but in order | |
1424 * to allow an easier us of os_unix.c for the MacOS X port, | |
1425 * they are change to procedure. Thec ompile whould optimize | |
1426 * them out. | |
1427 */ | |
1428 | |
1429 int | |
1430 mch_can_restore_title() | |
1431 { | |
1432 return TRUE; | |
1433 } | |
1434 | |
1435 int | |
1436 mch_can_restore_icon() | |
1437 { | |
1438 return TRUE; | |
1439 } | |
1440 | |
1441 /* | |
1442 * If the machine has job control, use it to suspend the program, | |
1443 * otherwise fake it by starting a new shell. | |
1444 */ | |
1445 void | |
1446 mch_suspend() | |
1447 { | |
1448 /* TODO: get calle in #ifndef NO_CONSOLE */ | |
1449 gui_mch_iconify(); | |
1450 }; | |
1451 |