Ignore:
Timestamp:
12/14/02 06:50:34 (21 years ago)
Author:
Nicholas Riley
Message:

launch 1.0b1.

  • accept "slack" (default http) URLs and email addresses with -l
  • accept input from stdin with '-'
  • open URLs with arbitrary applications when specified without -l
  • builds without compiler warnings
  • added a CFRelease
  • updated README with 10.2 info and new features
Location:
trunk/launch/launch
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/launch/launch

    • Property svn:ignore set to
      build
      .*
  • trunk/launch/launch/main.c

    r3 r52  
    2323- Does -X work at all?  What does it return if it fails?
    2424
    25 - Create blank document ˆ la my existing BBEdit alias?  Use
    26 template/stationery?
    27 
    28 - Allow piping (like BBEdit, again?)
    29 
    3025- Launching as root: use authentication framework - doesn't work.
     26
     27- launch URL with specified URL handler (done, except for IC)
    3128
    3229- launch apps by IC protocol handler (esp. editor)
     
    4643
    4744#include <unistd.h>
     45#include <sys/stat.h>
    4846#include <Carbon/Carbon.h>
    4947#include <CoreServices/CoreServices.h>
     
    5856const char *APP_NAME;
    5957
    60 #define VERSION "1.0a9"
     58#define VERSION "1.0b1"
    6159
    6260#define STRBUF_LEN 1024
     
    7876
    7977LSLaunchURLSpec LSPEC = {NULL, NULL, NULL, DEFAULT_LAUNCH_FLAGS, NULL};
     78
     79char *TEMPFILE = NULL;
    8080
    8181typedef struct {
     
    107107
    108108void usage() {
    109     fprintf(stderr, "usage: %s [-npswbmhCX] [-c creator] [-i bundleID] [-u URL] [-a name] [document ...]\n"
     109    fprintf(stderr, "usage: %s [-npswbmhCX] [-c creator] [-i bundleID] [-u URL] [-a name] [item ...] [-]\n"
    110110                    "   or: %s [-npflswbmhCX] item ...\n", APP_NAME, APP_NAME);
    111111    fprintf(stderr,
     
    140140    errRec *rec;
    141141    const char *errDesc = "unknown error";
    142     const char *failedStr = "(unable to retrieve error message)";
     142    char * const failedStr = "(unable to retrieve error message)";
    143143    static char *str = NULL;
    144144    size_t len;
     
    152152    str = (char *)malloc(len);
    153153    if (str != NULL)
    154         snprintf(str, len, "%s (%d)", errDesc, (long)err);
     154        snprintf(str, len, "%s (%ld)", errDesc, err);
    155155    else
    156156        str = failedStr;
     
    242242#endif
    243243
    244 void getargs(int argc, const char *argv[]) {
     244CFURLRef normalizedURLFromString(CFStringRef str) {
     245    CFURLRef url = CFURLCreateWithString(NULL, str, NULL);
     246    if (url != NULL) {
     247        CFURLRef absURL = CFURLCopyAbsoluteURL(url);
     248        CFRelease(url);
     249        url = NULL;
     250        if (absURL != NULL) {
     251            CFStringRef scheme = CFURLCopyScheme(absURL);
     252            url = absURL;
     253            if (scheme == NULL) {
     254                CFRelease(url);
     255                url = NULL;
     256            }
     257        }
     258    }
     259    return url;
     260}
     261
     262CFURLRef normalizedURLFromPrefixSlack(CFStringRef prefix, CFStringRef slackStr) {
     263    CFStringRef str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"),
     264                                               prefix, slackStr);
     265    CFURLRef normalizedURL = normalizedURLFromString(str);
     266    CFRelease(str);
     267    return normalizedURL;
     268}
     269
     270char *tempFile(int *fd) {
     271    char *tmpDir = getenv("TMPDIR");
     272    const char * const tempTemplate = "/launch-stationery-XXXXXXXX";
     273    char *tempPath;
     274    OSStatus err;
     275    FSRef fsr;
     276    FSCatalogInfo catalogInfo;
     277    FileInfo *fInfo;
     278
     279    // create temporary file
     280    if (tmpDir == NULL) tmpDir = "/tmp";
     281    tempPath = (char *)malloc(strlen(tmpDir) + strlen(tempTemplate) + 1);
     282    if (tempPath == NULL) errexit("can't allocate memory");
     283    strcpy(tempPath, tmpDir);
     284    strcat(tempPath, tempTemplate);
     285    if ( (*fd = mkstemp(tempPath)) == -1)
     286        errexit("can't create temporary file '%s'", tempPath);
     287    // mark file as stationery
     288    err = FSPathMakeRef(tempPath, &fsr, NULL);
     289    if (err != noErr) osstatusexit(err, "can't find '%s'", tempPath);
     290    err = FSGetCatalogInfo(&fsr, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL);
     291    if (err != noErr) osstatusexit(err, "can't get information for '%s'", tempPath);
     292    fInfo = (FileInfo *)&(catalogInfo.finderInfo);
     293    fInfo->finderFlags |= kIsStationery;
     294    err = FSSetCatalogInfo(&fsr, kFSCatInfoFinderInfo, &catalogInfo);
     295    if (err != noErr) osstatusexit(err, "can't set information for '%s'", tempPath);
     296   
     297    return tempPath;
     298}
     299
     300char *stdinAsTempFile() {
     301    unsigned char *buf;
     302    int bufsize;
     303    // Actual number of characters read, and therefore written.
     304    ssize_t charCount;
     305    int fd;
     306    struct stat stat_buf;
     307    char *tempFilePath;
     308
     309    tempFilePath = tempFile(&fd);
     310
     311    if (fstat(fd, &stat_buf) == -1)
     312        errexit("can't fstat temporary file '%s'", tempFilePath);
     313
     314    bufsize = stat_buf.st_blksize;
     315    if ( (buf = (unsigned char *)malloc(bufsize * sizeof(unsigned char))) == NULL)
     316        errexit("can't allocate %ld bytes of buffer memory",
     317                bufsize * sizeof(unsigned char));
     318
     319    // Loop until the end of the file.
     320    while (1) {
     321        // Read a block of input.
     322        charCount = read(STDIN_FILENO, buf, bufsize);
     323        if (charCount < 0) {
     324            errexit("can't read from standard input");
     325        }
     326        // End of this file?
     327        if (charCount == 0)
     328            break;
     329        // Write this block out.
     330        if (write(fd, buf, charCount) != charCount)
     331            errexit("error writing to file '%s'", tempFilePath);
     332    }
     333    free(buf);
     334    return tempFilePath;
     335}
     336
     337void getargs(int argc, char * const argv[]) {
    245338    extern char *optarg;
    246339    extern int optind;
     
    311404            break;
    312405        case 'u':
    313             LSPEC.appURL = CFURLCreateWithString(NULL,
    314                 CFStringCreateWithCString(NULL, optarg, CFStringGetSystemEncoding()), NULL);
     406            { CFStringRef str = CFStringCreateWithCString(NULL, optarg, CFStringGetSystemEncoding());
     407              LSPEC.appURL = CFURLCreateWithString(NULL, str, NULL);
     408              if (str != NULL) CFRelease(str);
     409            }
    315410            if (LSPEC.appURL == NULL) {
    316411                errexit("invalid URL (argument of -u)");
     
    354449
    355450    if (OPTS.action == ACTION_LAUNCH_URLS && appSpecified)
    356         errexit("sorry, launching URLs with a given application is not yet supported"); // XXX
     451        errexit("launching URLs with a given application is not supported; try without -l");
    357452
    358453    if (OPTS.action == ACTION_INFO_ITEMS && appSpecified)
     
    365460        int i;
    366461        OSStatus err;
    367         CFStringRef pathstr;
     462        CFStringRef argStr;
    368463        CFURLRef itemURL;
    369464        LSItemInfoRecord docInfo;
     
    375470        LSPEC.itemURLs = CFArrayCreateMutable(NULL, argc, NULL);
    376471        for (i = 0 ; i < argc ; i++) {
    377             pathstr = CFStringCreateWithCString(NULL, argv[i], CFStringGetSystemEncoding());
    378             itemURL = NULL;
    379             if (OPTS.action == ACTION_FIND_ITEMS || OPTS.action == ACTION_OPEN_ITEMS ||
    380                 OPTS.action == ACTION_LAUNCH_URLS || OPTS.action == ACTION_INFO_ITEMS) { // check for URLs
    381                 itemURL = CFURLCreateWithString(NULL, pathstr, NULL);
    382                 if (itemURL != NULL) {
    383                     CFURLRef absURL = CFURLCopyAbsoluteURL(itemURL);
    384                     CFRelease(itemURL);
    385                     itemURL = NULL;
    386                     if (absURL != NULL) {
    387                         CFStringRef scheme = CFURLCopyScheme(absURL);
    388                         itemURL = absURL;
    389                         if (scheme == NULL) {
    390                             CFRelease(itemURL);
    391                             itemURL = NULL;
    392                         }
    393                     }
     472            argStr = NULL;
     473            if (strcmp(argv[i], "-") == 0) {
     474                TEMPFILE = stdinAsTempFile();
     475                itemURL = CFURLCreateFromFileSystemRepresentation(NULL, TEMPFILE, strlen(TEMPFILE), false);
     476                LSPEC.launchFlags ^= kLSLaunchAsync;
     477            } else {
     478                argStr = CFStringCreateWithCString(NULL, argv[i], CFStringGetSystemEncoding());
     479                // check for URLs
     480                itemURL = normalizedURLFromString(argStr);
     481                if (itemURL == NULL && OPTS.action == ACTION_LAUNCH_URLS) {
     482                    // check for email addresses
     483                    if (strchr(argv[i], '@') != NULL && strchr(argv[i], '/') == NULL)
     484                        itemURL = normalizedURLFromPrefixSlack(CFSTR("mailto:"), argStr);
     485                    // check for "slack" URLs
     486                    if (itemURL == NULL && strchr(argv[i], '.') != NULL && strchr(argv[i], '/') != argv[i])
     487                        itemURL = normalizedURLFromPrefixSlack(CFSTR("http://"), argStr);
     488                }
     489                if (itemURL == NULL) {
     490                    // check for file paths
     491                    itemURL = CFURLCreateWithFileSystemPath(NULL, argStr, kCFURLPOSIXPathStyle, false);
     492                    err = LSCopyItemInfoForURL(itemURL, kLSRequestExtensionFlagsOnly, &docInfo);
     493                    if (err != noErr) osstatusexit(err, "unable to locate '%s'", argv[i]);
    394494                }
    395495            }
    396             if (itemURL == NULL) {
    397                 itemURL = CFURLCreateWithFileSystemPath(NULL, pathstr, kCFURLPOSIXPathStyle, false);
    398                 err = LSCopyItemInfoForURL(itemURL, kLSRequestExtensionFlagsOnly, &docInfo);
    399                 if (err != noErr) osstatusexit(err, "unable to locate '%s'", argv[i]);
    400             }
    401496            CFArrayAppendValue((CFMutableArrayRef)LSPEC.itemURLs, itemURL);
    402             CFRelease(pathstr);
     497            // don't CFRelease the itemURL because CFArray doesn't retain it by default
     498            if (argStr != NULL) CFRelease(argStr);
    403499        }
    404500    }
     
    616712}
    617713
    618 int main (int argc, const char *argv[]) {
     714int main (int argc, char * const argv[]) {
    619715    OSStatus err;
    620716   
     
    670766    }
    671767
     768    if (TEMPFILE != NULL) {
     769        // the application may take a while to finish opening the temporary file
     770        daemon(0, 0);
     771        sleep(60);
     772        unlink(TEMPFILE);
     773    }
     774
    672775    return 0;
    673776}
Note: See TracChangeset for help on using the changeset viewer.