1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24: #include <config.h>
25:
26: #include <stdio.h>
27: #include <errno.h>
28:
29: #include "lisp.h"
30: #include "process.h"
31: #ifdef MAC_OSX
32: #undef select
33: #endif
34: #include "systime.h"
35: #include "sysselect.h"
36: #include "blockinput.h"
37:
38: #include "macterm.h"
39:
40: #include "charset.h"
41: #include "coding.h"
42: #if !TARGET_API_MAC_CARBON
43: #include <Files.h>
44: #include <MacTypes.h>
45: #include <TextUtils.h>
46: #include <Folders.h>
47: #include <Resources.h>
48: #include <Aliases.h>
49: #include <Timer.h>
50: #include <OSA.h>
51: #include <AppleScript.h>
52: #include <Events.h>
53: #include <Processes.h>
54: #include <EPPC.h>
55: #include <MacLocales.h>
56: #include <Endian.h>
57: #endif
58:
59: #include <utime.h>
60: #include <dirent.h>
61: #include <sys/types.h>
62: #include <sys/stat.h>
63: #include <pwd.h>
64: #include <grp.h>
65: #include <sys/param.h>
66: #include <fcntl.h>
67: #if __MWERKS__
68: #include <unistd.h>
69: #endif
70:
71:
72: static int mac_system_script_code;
73:
74:
75: static Lisp_Object Vmac_system_locale;
76:
77:
78: static ComponentInstance as_scripting_component;
79:
80: static OSAID as_script_context;
81:
82: #if TARGET_API_MAC_CARBON
83: static int wakeup_from_rne_enabled_p = 0;
84: #define ENABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 1)
85: #define DISABLE_WAKEUP_FROM_RNE (wakeup_from_rne_enabled_p = 0)
86: #else
87: #define ENABLE_WAKEUP_FROM_RNE 0
88: #define DISABLE_WAKEUP_FROM_RNE 0
89: #endif
90:
91: #ifndef MAC_OSX
92: static OSErr posix_pathname_to_fsspec P_ ((const char *, FSSpec *));
93: static OSErr fsspec_to_posix_pathname P_ ((const FSSpec *, char *, int));
94: #endif
95:
96:
97:
98:
99:
100:
101: void
102: string_cat_and_replace (char *s1, const char *s2, int n, char a, char b)
103: {
104: int l1 = strlen (s1);
105: int l2 = strlen (s2);
106: char *p = s1 + l1;
107: int i;
108:
109: strncat (s1, s2, n);
110: for (i = 0; i < l2; i++)
111: {
112: if (*p == a)
113: *p = b;
114: p++;
115: }
116: }
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128: int
129: mac_to_posix_pathname (const char *mfn, char *ufn, int ufnbuflen)
130: {
131: const char *p, *q, *pe;
132:
133: strcpy (ufn, "");
134:
135: if (*mfn == '\0')
136: return 1;
137:
138: p = strchr (mfn, ':');
139: if (p != 0 && p != mfn)
140: strcat (ufn, "/");
141:
142: p = mfn;
143: if (*p == ':')
144: p++;
145:
146: pe = mfn + strlen (mfn);
147: while (p < pe)
148: {
149: q = strchr (p, ':');
150: if (q)
151: {
152: if (q == p)
153: {
154: if (strlen (ufn) + 3 >= ufnbuflen)
155: return 0;
156: strcat (ufn, "../");
157: }
158: else
159: {
160: if (strlen (ufn) + (q - p) + 1 >= ufnbuflen)
161: return 0;
162: string_cat_and_replace (ufn, p, q - p, '/', ':');
163: strcat (ufn, "/");
164: }
165: p = q + 1;
166: }
167: else
168: {
169: if (strlen (ufn) + (pe - p) >= ufnbuflen)
170: return 0;
171: string_cat_and_replace (ufn, p, pe - p, '/', ':');
172:
173: p = pe;
174: }
175: }
176:
177: return 1;
178: }
179:
180:
181: extern char *get_temp_dir_name ();
182:
183:
184:
185:
186:
187: int
188: posix_to_mac_pathname (const char *ufn, char *mfn, int mfnbuflen)
189: {
190: const char *p, *q, *pe;
191: char expanded_pathname[MAXPATHLEN+1];
192:
193: strcpy (mfn, "");
194:
195: if (*ufn == '\0')
196: return 1;
197:
198: p = ufn;
199:
200:
201:
202: if (*p == '/' && strchr (p+1, '/') == NULL && strcmp (p, "/.emacs") != 0)
203: {
204: if (strlen (p) + 1 > mfnbuflen)
205: return 0;
206: strcpy (mfn, p+1);
207: strcat (mfn, ":");
208: return 1;
209: }
210:
211:
212: if (strncmp (p, "~emacs/", 7) == 0)
213: {
214: struct passwd *pw = getpwnam ("emacs");
215: p += 7;
216: if (strlen (pw->pw_dir) + strlen (p) > MAXPATHLEN)
217: return 0;
218: strcpy (expanded_pathname, pw->pw_dir);
219: strcat (expanded_pathname, p);
220: p = expanded_pathname;
221:
222: }
223: else if (strncmp (p, "/tmp/", 5) == 0)
224: {
225: char *t = get_temp_dir_name ();
226: p += 5;
227: if (strlen (t) + strlen (p) > MAXPATHLEN)
228: return 0;
229: strcpy (expanded_pathname, t);
230: strcat (expanded_pathname, p);
231: p = expanded_pathname;
232:
233: }
234: else if (*p != '/')
235: strcat (mfn, ":");
236:
237: if (*p == '/')
238: p++;
239:
240: pe = p + strlen (p);
241: while (p < pe)
242: {
243: q = strchr (p, '/');
244: if (q)
245: {
246: if (q - p == 2 && *p == '.' && *(p+1) == '.')
247: {
248: if (strlen (mfn) + 1 >= mfnbuflen)
249: return 0;
250: strcat (mfn, ":");
251: }
252: else
253: {
254: if (strlen (mfn) + (q - p) + 1 >= mfnbuflen)
255: return 0;
256: string_cat_and_replace (mfn, p, q - p, ':', '/');
257: strcat (mfn, ":");
258: }
259: p = q + 1;
260: }
261: else
262: {
263: if (strlen (mfn) + (pe - p) >= mfnbuflen)
264: return 0;
265: string_cat_and_replace (mfn, p, pe - p, ':', '/');
266: p = pe;
267: }
268: }
269:
270: return 1;
271: }
272:
273: ^L
274:
275:
276:
277:
278: static Lisp_Object Qundecoded_file_name;
279:
280: static struct {
281: AEKeyword keyword;
282: char *name;
283: Lisp_Object symbol;
284: } ae_attr_table [] =
285: {{keyTransactionIDAttr, "transaction-id"},
286: {keyReturnIDAttr, "return-id"},
287: {keyEventClassAttr, "event-class"},
288: {keyEventIDAttr, "event-id"},
289: {keyAddressAttr, "address"},
290: {keyOptionalKeywordAttr, "optional-keyword"},
291: {keyTimeoutAttr, "timeout"},
292: {keyInteractLevelAttr, "interact-level"},
293: {keyEventSourceAttr, "event-source"},
294:
295: {keyOriginalAddressAttr, "original-address"},
296: {keyReplyRequestedAttr, "reply-requested"},
297: {KEY_EMACS_SUSPENSION_ID_ATTR, "emacs-suspension-id"}
298: };
299:
300: static Lisp_Object
301: mac_aelist_to_lisp (desc_list)
302: const AEDescList *desc_list;
303: {
304: OSErr err;
305: long count;
306: Lisp_Object result, elem;
307: DescType desc_type;
308: Size size;
309: AEKeyword keyword;
310: AEDesc desc;
311: int attribute_p = 0;
312:
313: err = AECountItems (desc_list, &count);
314: if (err != noErr)
315: return Qnil;
316: result = Qnil;
317:
318: again:
319: while (count > 0)
320: {
321: if (attribute_p)
322: {
323: keyword = ae_attr_table[count - 1].keyword;
324: err = AESizeOfAttribute (desc_list, keyword, &desc_type, &size);
325: }
326: else
327: err = AESizeOfNthItem (desc_list, count, &desc_type, &size);
328:
329: if (err == noErr)
330: switch (desc_type)
331: {
332: case typeAEList:
333: case typeAERecord:
334: case typeAppleEvent:
335: if (attribute_p)
336: err = AEGetAttributeDesc (desc_list, keyword, typeWildCard,
337: &desc);
338: else
339: err = AEGetNthDesc (desc_list, count, typeWildCard,
340: &keyword, &desc);
341: if (err != noErr)
342: break;
343: elem = mac_aelist_to_lisp (&desc);
344: AEDisposeDesc (&desc);
345: break;
346:
347: default:
348: if (desc_type == typeNull)
349: elem = Qnil;
350: else
351: {
352: elem = make_uninit_string (size);
353: if (attribute_p)
354: err = AEGetAttributePtr (desc_list, keyword, typeWildCard,
355: &desc_type, SDATA (elem),
356: size, &size);
357: else
358: err = AEGetNthPtr (desc_list, count, typeWildCard, &keyword,
359: &desc_type, SDATA (elem), size, &size);
360: }
361: if (err != noErr)
362: break;
363: desc_type = EndianU32_NtoB (desc_type);
364: elem = Fcons (make_unibyte_string ((char *) &desc_type, 4), elem);
365: break;
366: }
367:
368: if (err == noErr || desc_list->descriptorType == typeAEList)
369: {
370: if (err != noErr)
371: elem = Qnil;
372: else if (desc_list->descriptorType != typeAEList)
373: {
374: if (attribute_p)
375: elem = Fcons (ae_attr_table[count-1].symbol, elem);
376: else
377: {
378: keyword = EndianU32_NtoB (keyword);
379: elem = Fcons (make_unibyte_string ((char *) &keyword, 4),
380: elem);
381: }
382: }
383:
384: result = Fcons (elem, result);
385: }
386:
387: count--;
388: }
389:
390: if (desc_list->descriptorType == typeAppleEvent && !attribute_p)
391: {
392: attribute_p = 1;
393: count = sizeof (ae_attr_table) / sizeof (ae_attr_table[0]);
394: goto again;
395: }
396:
397: desc_type = EndianU32_NtoB (desc_list->descriptorType);
398: return Fcons (make_unibyte_string ((char *) &desc_type, 4), result);
399: }
400:
401: Lisp_Object
402: mac_aedesc_to_lisp (desc)
403: const AEDesc *desc;
404: {
405: OSErr err = noErr;
406: DescType desc_type = desc->descriptorType;
407: Lisp_Object result;
408:
409: switch (desc_type)
410: {
411: case typeNull:
412: result = Qnil;
413: break;
414:
415: case typeAEList:
416: case typeAERecord:
417: case typeAppleEvent:
418: return mac_aelist_to_lisp (desc);
419: #if 0
420:
421:
422: {
423: long count;
424: Lisp_Object elem;
425: AEKeyword keyword;
426: AEDesc desc1;
427:
428: err = AECountItems (desc, &count);
429: if (err != noErr)
430: break;
431: result = Qnil;
432: while (count > 0)
433: {
434: err = AEGetNthDesc (desc, count, typeWildCard, &keyword, &desc1);
435: if (err != noErr)
436: break;
437: elem = mac_aedesc_to_lisp (&desc1);
438: AEDisposeDesc (&desc1);
439: if (desc_type != typeAEList)
440: {
441: keyword = EndianU32_NtoB (keyword);
442: elem = Fcons (make_unibyte_string ((char *) &keyword, 4), elem);
443: }
444: result = Fcons (elem, result);
445: count--;
446: }
447: }
448: #endif
449: break;
450:
451: default:
452: #if TARGET_API_MAC_CARBON
453: result = make_uninit_string (AEGetDescDataSize (desc));
454: err = AEGetDescData (desc, SDATA (result), SBYTES (result));
455: #else
456: result = make_uninit_string (GetHandleSize (desc->dataHandle));
457: memcpy (SDATA (result), *(desc->dataHandle), SBYTES (result));
458: #endif
459: break;
460: }
461:
462: if (err != noErr)
463: return Qnil;
464:
465: desc_type = EndianU32_NtoB (desc_type);
466: return Fcons (make_unibyte_string ((char *) &desc_type, 4), result);
467: }
468:
469: OSErr
470: mac_ae_put_lisp (desc, keyword_or_index, obj)
471: AEDescList *desc;
472: UInt32 keyword_or_index;
473: Lisp_Object obj;
474: {
475: OSErr err;
476:
477: if (!(desc->descriptorType == typeAppleEvent
478: || desc->descriptorType == typeAERecord
479: || desc->descriptorType == typeAEList))
480: return errAEWrongDataType;
481:
482: if (CONSP (obj) && STRINGP (XCAR (obj)) && SBYTES (XCAR (obj)) == 4)
483: {
484: DescType desc_type1 = EndianU32_BtoN (*((UInt32 *) SDATA (XCAR (obj))));
485: Lisp_Object data = XCDR (obj), rest;
486: AEDesc desc1;
487:
488: switch (desc_type1)
489: {
490: case typeNull:
491: case typeAppleEvent:
492: break;
493:
494: case typeAEList:
495: case typeAERecord:
496: err = AECreateList (NULL, 0, desc_type1 == typeAERecord, &desc1);
497: if (err == noErr)
498: {
499: for (rest = data; CONSP (rest); rest = XCDR (rest))
500: {
501: UInt32 keyword_or_index1 = 0;
502: Lisp_Object elem = XCAR (rest);
503:
504: if (desc_type1 == typeAERecord)
505: {
506: if (CONSP (elem) && STRINGP (XCAR (elem))
507: && SBYTES (XCAR (elem)) == 4)
508: {
509: keyword_or_index1 =
510: EndianU32_BtoN (*((UInt32 *)
511: SDATA (XCAR (elem))));
512: elem = XCDR (elem);
513: }
514: else
515: continue;
516: }
517:
518: err = mac_ae_put_lisp (&desc1, keyword_or_index1, elem);
519: if (err != noErr)
520: break;
521: }
522:
523: if (err == noErr)
524: {
525: if (desc->descriptorType == typeAEList)
526: err = AEPutDesc (desc, keyword_or_index, &desc1);
527: else
528: err = AEPutParamDesc (desc, keyword_or_index, &desc1);
529: }
530:
531: AEDisposeDesc (&desc1);
532: }
533: return err;
534:
535: default:
536: if (!STRINGP (data))
537: break;
538: if (desc->descriptorType == typeAEList)
539: err = AEPutPtr (desc, keyword_or_index, desc_type1,
540: SDATA (data), SBYTES (data));
541: else
542: err = AEPutParamPtr (desc, keyword_or_index, desc_type1,
543: SDATA (data), SBYTES (data));
544: return err;
545: }
546: }
547:
548: if (desc->descriptorType == typeAEList)
549: err = AEPutPtr (desc, keyword_or_index, typeNull, NULL, 0);
550: else
551: err = AEPutParamPtr (desc, keyword_or_index, typeNull, NULL, 0);
552:
553: return err;
554: }
555:
556: static pascal OSErr
557: mac_coerce_file_name_ptr (type_code, data_ptr, data_size,
558: to_type, handler_refcon, result)
559: DescType type_code;
560: const void *data_ptr;
561: Size data_size;
562: DescType to_type;
563: long handler_refcon;
564: AEDesc *result;
565: {
566: OSErr err;
567:
568: if (type_code == typeNull)
569: err = errAECoercionFail;
570: else if (type_code == to_type || to_type == typeWildCard)
571: err = AECreateDesc (TYPE_FILE_NAME, data_ptr, data_size, result);
572: else if (type_code == TYPE_FILE_NAME)
573:
574: {
575: #ifdef MAC_OSX
576: CFStringRef str;
577: CFURLRef url = NULL;
578: CFDataRef data = NULL;
579:
580: str = CFStringCreateWithBytes (NULL, data_ptr, data_size,
581: kCFStringEncodingUTF8, false);
582: if (str)
583: {
584: url = CFURLCreateWithFileSystemPath (NULL, str,
585: kCFURLPOSIXPathStyle, false);
586: CFRelease (str);
587: }
588: if (url)
589: {
590: data = CFURLCreateData (NULL, url, kCFStringEncodingUTF8, true);
591: CFRelease (url);
592: }
593: if (data)
594: {
595: err = AECoercePtr (typeFileURL, CFDataGetBytePtr (