]> git.armaanb.net Git - mmenu.git/blobdiff - mmenu.c
Add installation instructions to README
[mmenu.git] / mmenu.c
diff --git a/mmenu.c b/mmenu.c
index b00af5af1b2d7ee11962f2c003fb7559b50c53f4..a21ba80f6b2e2009795413b0223277b780cfe115 100644 (file)
--- a/mmenu.c
+++ b/mmenu.c
@@ -1,28 +1,35 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdbool.h>
+#include <string.h>
+#include <strings.h>
 
+#include <Xm/Xm.h>
 #include <Xm/Text.h>
+#include <Xm/RowColumn.h>
+#include <Xm/List.h>
+
 #include <curl/curl.h>
 
-struct MemoryStruct {
+struct memstruct {
        char *memory;
        size_t size;
 };
 
+char *days[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
+
 int
 memfail(void)
 {
        printf("ERROR: Out of memory\n");
-       exit(4);
+       exit(2);
 }
 
-
 static size_t
 memback(void *contents, size_t size, size_t nmemb, void *userp)
 {
        size_t realsize = size * nmemb;
-       struct MemoryStruct *mem = (struct MemoryStruct *)userp;
+       struct memstruct *mem = (struct memstruct *)userp;
 
        char *ptr = realloc(mem->memory, mem->size + realsize + 1);
        if (!ptr) memfail();
@@ -35,10 +42,9 @@ memback(void *contents, size_t size, size_t nmemb, void *userp)
        return realsize;
 }
 
-int
-main(int argc, char *argv[])
+char *
+getmenu(char *date)
 {
-       // Get webpage
        CURL *curl = curl_easy_init();
        CURLcode res;
 
@@ -47,23 +53,29 @@ main(int argc, char *argv[])
                exit(1);
        }
 
-       struct MemoryStruct chunk;
+       struct memstruct chunk;
        chunk.memory = malloc(1); // Grown as needed by the realloc in memback()
        chunk.size = 0; // No data yet
 
-       curl_easy_setopt(curl, CURLOPT_URL,
-                       "https://nobilis.nobles.edu/skyworld/castlemenu.php");
+       const char *baseurl =
+               "https://nobilis.nobles.edu/skyworld/castlemenu.php?Date=";
+       int len = strlen(baseurl) + strlen(date) + 1;
+       char *url = (char *) malloc(len);
+       snprintf(url, len, "%s%s", baseurl, date);
+       printf("INFO: Using URL %s\n", url);
+       curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memback);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
 
-       printf("INFO: Fetching wepage\n");
+       printf("INFO: Fetching webpage\n");
        res = curl_easy_perform(curl);
+       free(url);
 
        if (res != CURLE_OK) {
-               fprintf(stderr,"ERROR: Could not fetch webpage\n%s\n",
-                               curl_easy_strerror(res));
-               exit(2);
+               fprintf(stderr,"ERROR: Could not fetch webpage:\n%s\n",
+                                               curl_easy_strerror(res));
+               exit(1);
        }
 
        curl_easy_cleanup(curl);
@@ -76,51 +88,129 @@ main(int argc, char *argv[])
 
        // Extract text from between HTML tags
        int j = 1;
-       for (int i = 345; i < strlen(chunk.memory); i++) {
+       char next[2];
+       next[1] = '\0';
+       for (int i = 345; chunk.memory[i]; i++) {
                char c = chunk.memory[i];
                if (c == '<') intag = true;
                if (!intag) {
                        j++;
                        outp = (char *) realloc(outp, j);
                        if (!outp) memfail();
-                       strncat(outp, &c, 1);
+                       next[0] = c;
+                       strncat(outp, next, 2);
                }
                if (c == '>') intag = false;
        }
 
+       free(chunk.memory);
+
        // Strip empty newlines
        char *nl = (char *) calloc(1, sizeof(char));
        if (!nl) memfail();
 
-       for (int i = 0; i < strlen(outp) - 1; i++) {
-               if (outp[i] == '\n' && outp[i+1] == '\n') i+=4;
-               nl = (char *) realloc(nl, i);
-               if (!nl) memfail();
-               strncat(nl, &outp[i], 1);
+       j = 1;
+       for (int i = 0; outp[i]; i++) {
+               j++;
+               if (!((outp[i] == '\n' && outp[i+1] == '\n') ||
+                               (outp[i] == ' ' && outp[i+1] == ' '))) {
+                       nl = (char *) realloc(nl, j);
+                       if (!nl) memfail();
+                       next[0] = outp[i+1];
+                       strncat(nl, next, 2);
+               }
+       }
+
+       free(outp);
+       return nl;
+}
+
+void
+dayback(Widget unused, XtPointer client_data, XtPointer call_data)
+{
+       (void)unused;
+       Widget disp = (Widget) client_data;
+       XmListCallbackStruct *list_cbs = (XmListCallbackStruct *) call_data;
+       char *nl = getmenu(days[list_cbs->item_position - 1]);
+       char *oldtext = XmTextGetString(disp) ;
+       XmTextReplace((Widget) disp, 0, strlen(oldtext), nl);
+       free(nl);
+       free(oldtext);
+}
+
+// Convert an array of strings to an array of compound strings
+XmStringTable
+ArgvToXmStringTable (int argc, char **argv)
+{
+       XmStringTable new =
+               (XmStringTable) XtMalloc((argc+1) * sizeof (XmString));
+       if (!new) return (XmStringTable) 0;
+
+       new[argc] = (XmString) 0;
+       while (--argc >= 0) {
+               new[argc] = XmStringGenerate ((XtPointer) argv[argc], "tag2",
+                               XmCHARSET_TEXT, NULL);
+       }
+
+       return new;
+}
+
+int
+main(int argc, char *argv[])
+{
+       // Parse CLI arguments
+       bool showUsage = false;
+       if (argc == 2) {
+               showUsage = true;
+               for (int i = 0; i < 5; i++) {
+                       if (strcasecmp(argv[1], days[i]) == 0) {
+                               showUsage = false;
+                               break;
+                       }
+               }
+       }
+
+       if (argc > 2 || showUsage) {
+               printf("Usage: %s [optional: day of the week]\n", argv[0]);
+               exit(3);
        }
 
        // Initialize motif
-       Widget       toplevel;
-       XtAppContext app;
-       Widget       text_w;
-       Arg          args[4];
+       Widget         toplevel, rowcol, daysel, disp;
+       XmStringTable  strs;
+       XtAppContext   app;
+       Arg            args[0];
 
        XtSetLanguageProc(NULL, NULL, NULL);
-       toplevel = XtVaOpenApplication (&app, "Castle Menu", NULL, 0, &argc, argv,
-                       NULL, sessionShellWidgetClass, NULL);
+       toplevel = XtVaOpenApplication(&app, "Castle Menu", NULL, 0, &argc, argv,
+                                                                                                                                NULL, sessionShellWidgetClass, NULL);
 
-       // Set textbox settings
        int n = 0;
-       XtSetArg(args[n], XmNvalue, nl);                    n++;
-       XtSetArg(args[n], XmNeditable, False);              n++;
-       XtSetArg(args[n], XmNcolumns, 80);                  n++;
+       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
+       rowcol = XmCreateRowColumn(toplevel, "rowcol", args, n);
+       XtManageChild(rowcol);
+
+       // Create text widget to display menu
+       n = 0;
+       char *nl = getmenu((argv[1]) ? argv[1] : "");
+       XtSetArg(args[n], XmNvalue, nl); n++;
+       XtSetArg(args[n], XmNeditable, False); n++;
+       XtSetArg(args[n], XmNcolumns, 80); n++;
+       XtSetArg(args[n], XmNrows, 20); n++;
+       XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
        XtSetArg(args[n], XmNcursorPositionVisible, False); n++;
-       text_w = XmCreateScrolledText(toplevel, "text", args, n);
-       free(outp);
+       disp = XmCreateScrolledText(rowcol, "text", args, n);
+       XtManageChild(disp);
        free(nl);
 
+       // Create day selector
+       strs = ArgvToXmStringTable(XtNumber(days), days);
+       daysel = XmCreateScrolledList(rowcol, "list", NULL, 0);
+       XtVaSetValues(daysel, XmNitems, strs, XmNitemCount, XtNumber(days), NULL);
+       XtAddCallback(daysel, XmNbrowseSelectionCallback, dayback, (XtPointer) disp);
+       XtManageChild(daysel);
+
        // Display everything
-       XtManageChild(text_w);
        XtRealizeWidget(toplevel);
        XtAppMainLoop(app);
 }