this repo has no description
1/*
2 This file is part of Darling.
3
4 Copyright (C) 2019-2020 Lubos Dolezel
5
6 Darling is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 Darling is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Darling. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include <stdio.h>
21#include <string.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <getopt.h>
27#include <stdbool.h>
28
29#import <Foundation/NSArray.h>
30#import <Foundation/NSString.h>
31#import <Foundation/NSURL.h>
32#import <AppKit/NSWorkspace.h>
33#include <CoreServices/CoreServices.h>
34
35static void usage(void);
36
37int main(int argc, char *argv[])
38{
39 bool fresh = false;
40 bool reveal = false;
41 bool wait = false;
42 bool _new = false;
43 bool hide = false;
44 bool background = false;
45 bool header = false;
46 bool useDefTextEditor = false;
47 bool readStdin = false;
48
49 const char* sdk = NULL;
50 const char* bundle = NULL;
51 const char* appname = NULL;
52 NSArray<NSString*>* arguments = nil;
53 NSArray<NSURL*>* filenames = nil;
54 FSRef fsref;
55 bool hasFSRef = false;
56 CFURLRef appURL = NULL;
57
58 for (int i = 1; i < argc; i++)
59 {
60 if (strcmp(argv[i], "--args") == 0)
61 {
62 int count = argc-i-1;
63 NSString** strings = (NSString**) malloc(count * sizeof(NSString*));
64
65 for (int j = 0; j < count; j++)
66 strings[j] = [NSString stringWithCString: argv[j+i+1] encoding: NSUTF8StringEncoding];
67
68 arguments = [NSArray arrayWithObjects: strings count: count];
69 free(strings);
70
71 argv[i] = NULL;
72 argc = i;
73 break;
74 }
75 }
76
77 while (true)
78 {
79 static struct option long_options[] = {
80 { "fresh", no_argument, 0, 'F' },
81 { "reveal", no_argument, 0, 'R' },
82 { "wait-apps", no_argument, 0, 'W' },
83 { "new", no_argument, 0, 'n' },
84 { "hide", no_argument, 0, 'j' },
85 { "background", no_argument, 0, 'g' },
86 { "header", no_argument, 0, 'h' },
87 { NULL, 0, 0, 0 }
88 };
89 int c = getopt_long(argc, argv, "a:b:etfFRWnjghs:", long_options, NULL);
90
91 if (c == -1)
92 break;
93
94 switch (c)
95 {
96 case 'a':
97 appname = optarg;
98 break;
99 case 'b':
100 bundle = optarg;
101 break;
102 case 'e':
103 bundle = "com.apple.TextEdit";
104 break;
105 case 't':
106 useDefTextEditor = true;
107 break;
108 case 'f':
109 readStdin = true;
110 break;
111 case 'F':
112 fresh = true;
113 break;
114 case 'R':
115 reveal = true;
116 break;
117 case 'W':
118 wait = true;
119 break;
120 case 'n':
121 _new = true;
122 break;
123 case 'j':
124 hide = true;
125 break;
126 case 'g':
127 background = true;
128 break;
129 case 'h':
130 header = true;
131 break;
132 case 's':
133 sdk = optarg;
134 break;
135 default:
136 usage();
137 return EXIT_FAILURE;
138 }
139 }
140
141 if (header || reveal || readStdin)
142 {
143 fprintf(stderr, "This operation is not implemented yet. Sorry.\n");
144 return EXIT_FAILURE;
145 }
146
147 if (optind < argc)
148 {
149 int count = argc - optind;
150 NSURL** urls = (NSURL**) malloc(count * sizeof(NSURL*));
151
152 for (int i = 0; i < count; i++)
153 urls[i] = [NSURL URLWithString:[NSString stringWithCString: argv[optind+i] encoding: NSUTF8StringEncoding]];
154
155 filenames = [NSArray arrayWithObjects: urls count: count];
156 free(urls);
157 }
158
159 OSStatus result = noErr;
160 if (useDefTextEditor)
161 {
162 result = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("txt"), kLSRolesEditor, &fsref, &appURL);
163 hasFSRef = true;
164 }
165 else if (bundle != NULL)
166 {
167 result = LSFindApplicationForInfo(kLSUnknownCreator, (CFStringRef) [NSString stringWithCString:bundle encoding:NSUTF8StringEncoding], NULL, &fsref, &appURL);
168 hasFSRef = true;
169 }
170 else if (appname != NULL)
171 {
172 NSString* appPath = [[NSWorkspace sharedWorkspace] fullPathForApplication: [NSString stringWithCString:appname encoding:NSUTF8StringEncoding]];
173 if (appPath == nil)
174 {
175 fprintf(stderr, "Cannot find required application: %s\n", appname);
176 return EXIT_FAILURE;
177 }
178
179 appURL = (CFURLRef) [NSURL URLWithString: appPath];
180 result = FSPathMakeRef((const UInt8*) [appPath UTF8String], &fsref, NULL);
181 }
182
183 if (result != noErr)
184 {
185 fprintf(stderr, "Cannot find required application: %d\n", result);
186 return EXIT_FAILURE;
187 }
188
189 NSArray<NSURL*>* urlsToOpen;
190 LSApplicationParameters params;
191
192 memset(¶ms, 0, sizeof(params));
193
194 if (hasFSRef)
195 params.application = &fsref;
196 params.argv = (CFArrayRef) arguments;
197
198 if (_new)
199 params.flags |= kLSLaunchNewInstance;
200 if (background)
201 params.flags |= kLSLaunchDontSwitch;
202 if (hide)
203 params.flags |= kLSLaunchAndHide;
204
205 if (filenames)
206 {
207 urlsToOpen = filenames;
208 }
209 else if (appURL)
210 {
211 urlsToOpen = [NSArray arrayWithObjects: (const id*) &appURL count: 1];
212 }
213 else
214 {
215 usage();
216 return EXIT_FAILURE;
217 }
218
219 // TODO: Apple Events, PSNs (for waiting)
220 result = LSOpenURLsWithRole((CFArrayRef) urlsToOpen, kLSRolesAll, NULL, ¶ms, NULL, 0);
221
222 if (result != noErr)
223 {
224 fprintf(stderr, "Failed to launch: %d\n", result);
225 return EXIT_FAILURE;
226 }
227
228 return EXIT_SUCCESS;
229}
230
231static void usage(void)
232{
233 printf("Usage: open [filenames]\n"
234 "Help: Use open to open files, folders, and URLs from the command line.\n");
235}