Command Line Subcommands in Cilk

Here’s the translation of the Go code to Cilk, formatted in Markdown suitable for Hugo:

Our first program will demonstrate command-line subcommands. Here’s the full source code:

#include <cilk/cilk.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>

void foo_command(int argc, char *argv[]) {
    int enable = 0;
    char *name = NULL;
    int c;

    while ((c = getopt(argc, argv, "en:")) != -1) {
        switch (c) {
            case 'e':
                enable = 1;
                break;
            case 'n':
                name = optarg;
                break;
            default:
                fprintf(stderr, "Usage: %s foo [-e] [-n name]\n", argv[0]);
                exit(1);
        }
    }

    printf("subcommand 'foo'\n");
    printf("  enable: %s\n", enable ? "true" : "false");
    printf("  name: %s\n", name ? name : "");
    printf("  tail:");
    for (int i = optind; i < argc; i++) {
        printf(" %s", argv[i]);
    }
    printf("\n");
}

void bar_command(int argc, char *argv[]) {
    int level = 0;
    int c;

    while ((c = getopt(argc, argv, "l:")) != -1) {
        switch (c) {
            case 'l':
                level = atoi(optarg);
                break;
            default:
                fprintf(stderr, "Usage: %s bar [-l level]\n", argv[0]);
                exit(1);
        }
    }

    printf("subcommand 'bar'\n");
    printf("  level: %d\n", level);
    printf("  tail:");
    for (int i = optind; i < argc; i++) {
        printf(" %s", argv[i]);
    }
    printf("\n");
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "expected 'foo' or 'bar' subcommands\n");
        exit(1);
    }

    if (strcmp(argv[1], "foo") == 0) {
        foo_command(argc - 1, argv + 1);
    } else if (strcmp(argv[1], "bar") == 0) {
        bar_command(argc - 1, argv + 1);
    } else {
        fprintf(stderr, "expected 'foo' or 'bar' subcommands\n");
        exit(1);
    }

    return 0;
}

This program demonstrates how to implement command-line subcommands in Cilk. We define two subcommands, ‘foo’ and ‘bar’, each with its own set of flags.

To compile the program:

$ cilk++ -o command-line-subcommands command-line-subcommands.cilk

First, let’s invoke the foo subcommand:

$ ./command-line-subcommands foo -e -n joe a1 a2
subcommand 'foo'
  enable: true
  name: joe
  tail: a1 a2

Now, let’s try the bar subcommand:

$ ./command-line-subcommands bar -l 8 a1
subcommand 'bar'
  level: 8
  tail: a1

But bar won’t accept foo’s flags:

$ ./command-line-subcommands bar -e a1
Usage: ./command-line-subcommands bar [-l level]

In this Cilk implementation, we use the getopt function to parse command-line arguments for each subcommand. The main function checks the first argument to determine which subcommand to execute.

While Cilk is primarily used for parallel computing, this example doesn’t utilize Cilk’s parallel features. It demonstrates how to structure a command-line program with subcommands in Cilk, which can be useful when building more complex parallel applications that need command-line interfaces.

Next, we’ll look at environment variables, another common way to parameterize programs.