aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Veresov <aleksey@veresov.pro>2023-12-06 19:54:42 +0300
committerAleksey Veresov <aleksey@veresov.pro>2023-12-06 19:54:42 +0300
commit9c5e4f5d0a736574bc09bb0817becde62eb56e00 (patch)
tree459e00a23281ecaacb4ebffe8186faebd1fb87db
parent41af7aebf4cd86bacee211aa0a5dbba3196f6fdc (diff)
downloadmagi-master.tar
magi-master.tar.xz
magi-master.zip
Add more practical examplesHEADmaster
lang.c example automatically redirects to a particular website version, based on the language prefernces of the user. style.c cycles through a range of CSS styles.
-rw-r--r--examples/lang.c69
-rw-r--r--examples/style.c131
2 files changed, 200 insertions, 0 deletions
diff --git a/examples/lang.c b/examples/lang.c
new file mode 100644
index 0000000..eb6336e
--- /dev/null
+++ b/examples/lang.c
@@ -0,0 +1,69 @@
+#include <magi.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static char *scat(const char *a, const char *b)
+{
+ int alen = a ? strlen(a) : 0;
+ int blen = b ? strlen(b) : 0;
+ char *res = malloc(alen + blen + 1);
+ memcpy(res, a, alen);
+ memcpy(res + alen, b, blen);
+ res[alen + blen] = 0;
+ return res;
+}
+
+
+static const char *determ(const char *langprefs)
+{
+ int i;
+ const char *langs[] = { "en", "ru" };
+ const int langslen = 2;
+ const char *min = 0;
+ int minid = 0;
+ for (i = 0; i != langslen; ++i) {
+ const char *res = strstr(langprefs, langs[i]);
+ if (min == 0 || res < min) {
+ min = res;
+ minid = i;
+ }
+ }
+ return langs[minid];
+}
+
+static void response(struct magi_request *req)
+{
+ struct magi_response res;
+ const char *lang = getenv("HTTP_ACCEPT_LANGUAGE");
+ char *a = scat(req->script, req->path);
+ char *b = scat(determ(lang), a);
+ free(a);
+ a = scat("/", b);
+ free(b);
+ b = scat(req->host, a);
+ free(a);
+ a = scat("https://", b);
+ free(b);
+ magi_response_init(&res);
+ magi_response_status(&res, 302, "Moved Temporarily");
+ magi_response_header(&res, "Location", a);
+ free(a);
+ magi_response_send(&res);
+ magi_response_free(&res);
+}
+
+
+int main()
+{
+ struct magi_request request;
+ magi_request_init(&request);
+ if (magi_parse(&request)) {
+ response(&request);
+ } else {
+ magi_error_response(request.error);
+ }
+ magi_request_free(&request);
+ return 0;
+}
diff --git a/examples/style.c b/examples/style.c
new file mode 100644
index 0000000..abaef57
--- /dev/null
+++ b/examples/style.c
@@ -0,0 +1,131 @@
+#include <magi.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static int emptyurl(const char *url)
+{
+ return !url || !*url || (url[0] == '/' && !url[1]);
+}
+
+static int equrl(const char *a, const char *b)
+{
+ if (!a) return !b;
+ if (!b) return 0;
+ while (*a && *b && *a == *b) {
+ ++a;
+ ++b;
+ }
+ return emptyurl(a) && emptyurl(b);
+}
+
+static char *scopy(const char *s)
+{
+ int len = s ? strlen(s) : 0;
+ char *res = malloc(len + 1);
+ if (s) memcpy(res, s, len);
+ res[len] = 0;
+ return res;
+}
+
+static char *scat(const char *a, const char *b)
+{
+ int alen = a ? strlen(a) : 0;
+ int blen = b ? strlen(b) : 0;
+ char *res = malloc(alen + blen + 1);
+ memcpy(res, a, alen);
+ memcpy(res + alen, b, blen);
+ res[alen + blen] = 0;
+ return res;
+}
+
+
+static char *nextstyle(const char *curstyle)
+{
+ DIR *d = opendir("/var/web/veresov.pro/public/styles");
+ struct dirent *de;
+ struct dirent *res = readdir(d);
+ while (res->d_name[0] == '.') res = readdir(d);
+ while ((de = readdir(d)) != 0) {
+ if (de->d_name[0] == '.') continue;
+ if (strcmp(de->d_name, curstyle)) {
+ if (de->d_name[0] != '.') res = de;
+ else break;
+ }
+ }
+ closedir(d);
+ return scopy(res->d_name);
+}
+
+static void switchstyle(const char *style, const char *script, const char *r)
+{
+ struct magi_cookie stl = { 0, 0, 0, 0, 0 };
+ struct magi_response res;
+ magi_response_init(&res);
+ stl.name = scopy("style");
+ stl.data = nextstyle(style);
+ stl.path = scopy(script);
+ magi_response_cookie_complex(&res, &stl);
+ if (r) {
+ magi_response_status(&res, 302, "Moved Temporarily");
+ magi_response_header(&res, "Location", r);
+ }
+ magi_response_send(&res);
+ magi_response_free(&res);
+ free(stl.name);
+ free(stl.data);
+ free(stl.path);
+}
+
+static void getstyle(const char *style, const char *script)
+{
+ char c;
+ char *p = scat("/var/web/veresov.pro/public/styles/", style);
+ FILE *f = fopen(p, "r");
+ struct magi_cookie stl = { 0, 0, 0, 0, 0 };
+ struct magi_response res;
+ magi_response_init(&res);
+ stl.name = scopy("style");
+ stl.data = scopy(style);
+ stl.path = scopy(script);
+ magi_response_cookie_complex(&res, &stl);
+ magi_response_content_type(&res, "text/css");
+ magi_response_send(&res);
+ magi_response_free(&res);
+ while (fread(&c, 1, 1, f) == 1) {
+ fwrite(&c, 1, 1, stdout);
+ }
+ fclose(f);
+ free(p);
+ free(stl.name);
+ free(stl.data);
+ free(stl.path);
+}
+
+
+static void response(struct magi_request *req)
+{
+ const char *curstyle = magi_request_cookie(req, "style");
+ if (!curstyle) curstyle = "default.css";
+ if (equrl(req->path, "/switch")) {
+ switchstyle(curstyle, req->script, magi_request_param(req, "r"));
+ } else if (equrl(req->path, "/style.css")) {
+ getstyle(curstyle, req->script);
+ }
+}
+
+
+int main()
+{
+ struct magi_request request;
+ magi_request_init(&request);
+ if (magi_parse(&request)) {
+ response(&request);
+ } else {
+ magi_error_response(request.error);
+ }
+ magi_request_free(&request);
+ return 0;
+}