#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(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) {
- /* out of memory! */
- printf("not enough memory (realloc returned NULL)\n");
- return 0;
- }
+ if (!ptr) memfail();
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
return realsize;
}
-int
-main(int argc, char *argv[])
+char *
+getmenu(char *date)
{
- // Get webpage
CURL *curl = curl_easy_init();
CURLcode res;
exit(1);
}
- struct MemoryStruct chunk;
- chunk.memory = malloc(1); // will be grown as needed by the realloc above
- chunk.size = 0; // no data at this point
-
- curl_easy_setopt(curl, CURLOPT_URL,
- "https://nobilis.nobles.edu/skyworld/castlemenu.php");
+ struct memstruct chunk;
+ chunk.memory = malloc(1); // Grown as needed by the realloc in memback()
+ chunk.size = 0; // No data yet
+
+ 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);
// Parse HTML
printf("INFO: Parsing HTML\n");
bool intag = false;
- char *outp = (char *) malloc(strlen(chunk.memory) + 1); // TODO: Realloc?
- strcpy(outp, "");
+ char *outp = (char *) calloc(1, sizeof(char));
+ if (!outp) memfail();
// Extract text from between HTML tags
- for (int i = 345; i < strlen(chunk.memory); i++) {
+ int j = 1;
+ 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) strncat(outp, &c, 1);
+ if (!intag) {
+ j++;
+ outp = (char *) realloc(outp, j);
+ if (!outp) memfail();
+ next[0] = c;
+ strncat(outp, next, 2);
+ }
if (c == '>') intag = false;
}
+ free(chunk.memory);
+
// Strip empty newlines
- char *nl = (char *) malloc(strlen(outp));
- strncpy(nl, "\0", 1);
- for (int i = 0; i < strlen(outp) - 1; i++) {
- if (outp[i] == '\n' && outp[i+1] == '\n') i+=4;
- strncat(nl, &outp[i], 1);
+ char *nl = (char *) calloc(1, sizeof(char));
+ if (!nl) memfail();
+
+ 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);
+ XtSetLanguageProc(NULL, NULL, 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);
}