#include "mrklib_priv.h" typedef enum { TMODE_EOL, TMODE_PATH, TMODE_TEXT, TMODE_PATH_CP, TMODE_PATH_CP_LIST, TMODE_PATH_LIST, } Tag_Mode; typedef struct { const char *tag; Tag_Mode mode; } Tag_Type; static const Tag_Type tags[] = { {"PROJ:", TMODE_EOL}, {"PROJICON:", TMODE_PATH}, {"BRIEF:", TMODE_TEXT}, {"VERSION:", TMODE_EOL}, {"LICENSE:", TMODE_EOL}, {"COPYING:", TMODE_PATH_LIST}, {"NEEDS:", TMODE_EOL}, {"DOMAIN:", TMODE_PATH}, {"REPO:", TMODE_EOL}, {"DEVREPO:", TMODE_EOL}, {"CONTACT:", TMODE_TEXT}, {"CATEGORY:", TMODE_PATH_LIST}, {"TAGS:", TMODE_PATH_LIST}, {"BIN:", TMODE_PATH}, {"SRC:", TMODE_PATH_LIST}, {"DEPS:", TMODE_PATH_LIST}, {"INC:", TMODE_PATH_LIST}, {"DATA:", TMODE_PATH_CP_LIST}, {"DESKTOP:", TMODE_PATH_LIST}, {"ICON:", TMODE_PATH_LIST}, {"PODOMAIN:", TMODE_PATH}, {"PO:", TMODE_PATH_LIST}, {NULL, 0} // END OF LIST }; static char * parse_token(char **p, char *end) { char *tok, *seg; while ((*p < end) && (isspace(**p))) (*p)++; if (*p >= end) return NULL; tok = *p; while (*p < end) { if (isspace(**p)) goto token; (*p)++; } token: seg = malloc(*p - tok + 1); if (!seg) return NULL; memcpy(seg, tok, *p - tok); seg[*p - tok] = 0; return seg; } static char * parse_eol(char **p, char *end) { char *tok, *seg; while ((*p < end) && (isspace(**p))) (*p)++; if (*p >= end) return NULL; tok = *p; while (*p < end) { if (**p == '\n') goto token; (*p)++; } token: seg = malloc(*p - tok + 1); if (!seg) return NULL; memcpy(seg, tok, *p - tok); seg[*p - tok] = 0; return seg; } static char * path_check(char *tok) { // XXX: check me return strdup(tok); } static Mrk_Build * parse_content(char *mem, size_t size) { Mrk_Build *bld = NULL; char prevc = '\n'; char *end = mem + size; char *p = mem; int skipline = 0; int startline = 0; int line = 1; char *seg = NULL, *s; char *data1 = NULL, *data2 = NULL; int i; Tag_Mode mode = TMODE_TEXT; #define err(reason...) do { fprintf(stderr, ##reason); goto error; } while (0) bld = calloc(1, sizeof(Mrk_Build)); if (!bld) return NULL; while (p < end) { if (prevc == '\n') { line++; if (*p == '#') skipline = 1; else skipline = 0; startline = 1; } if (!skipline) { char *tok; char *prevp; prevp = p; tok = parse_token(&p, end); if (!tok) err("%i: token parse error\n", line); if (startline) { for (i = 0; tags[i].tag; i++) { if (!strcmp(tok, tags[i].tag)) { free(seg); seg = strdup(tok); mode = tags[i].mode; break; } } if (!tags[i].tag) goto not_tag; } else { not_tag: switch (mode) { case TMODE_EOL: case TMODE_TEXT: p = prevp; data1 = parse_eol(&p, end); if (!data1) err("%i: no content\n", line); break; case TMODE_PATH: case TMODE_PATH_LIST: data1 = path_check(tok); if (!data1) err("%i: path invalid\n", line); break; case TMODE_PATH_CP: case TMODE_PATH_CP_LIST: data1 = path_check(tok); if (!data1) err("%i: path invalid\n", line); s = parse_token(&p, end); if (!s) err("%i: missing > in path copy\n", line); if (!(!strcmp(s, ">"))) err("%i: copy token is not >\n", line); free(s); s = parse_token(&p, end); if (!s) err("%i: missing destination path in path copy\n", line); data2 = path_check(s); if (!data2) err("%i: destination path not valid\n", line); free(s); break; default: break; } if (seg) { if (!strcmp(seg, "PROJ:")) { if (!_mrk_util_plain_file_check(data1)) err("%i: name failed sanity check\n", line); eina_stringshare_del(bld->name); bld->name = eina_stringshare_add(data1); } else if (!strcmp(seg, "PROJICON:")) { eina_stringshare_del(bld->icon); bld->icon = eina_stringshare_add(data1); } else if (!strcmp(seg, "BRIEF:")) { if (!bld->brief) bld->brief = eina_stringshare_add(data1); else { s = malloc(strlen(bld->brief) + 1 + strlen(data1) + 1); if (s) { strcpy(s, bld->brief); strcat(s, " "); strcat(s, data1); eina_stringshare_del(bld->brief); bld->brief = s; } } } else if (!strcmp(seg, "VERSION:")) { eina_stringshare_del(bld->version); bld->version = eina_stringshare_add(data1); } else if (!strcmp(seg, "LICENSE:")) { eina_stringshare_del(bld->license); bld->license = eina_stringshare_add(data1); } else if (!strcmp(seg, "COPYING:")) { bld->copying = eina_list_append(bld->copying, eina_stringshare_add(data1)); } else if (!strcmp(seg, "NEEDS:")) { eina_stringshare_del(bld->needs); bld->license = eina_stringshare_add(data1); } else if (!strcmp(seg, "DOMAIN:")) { eina_stringshare_del(bld->domain); bld->domain = eina_stringshare_add(data1); } else if (!strcmp(seg, "REPO:")) { eina_stringshare_del(bld->repo); bld->repo = eina_stringshare_add(data1); } else if (!strcmp(seg, "DEVREPO:")) { eina_stringshare_del(bld->devrepo); bld->devrepo = eina_stringshare_add(data1); } else if (!strcmp(seg, "CATEGORY:")) { bld->categories = eina_list_append(bld->categories, eina_stringshare_add(data1)); } else if (!strcmp(seg, "TAGS:")) { bld->tags = eina_list_append(bld->tags, eina_stringshare_add(data1)); } else if (!strcmp(seg, "CONTACT:")) { if (!bld->contact) bld->contact = eina_stringshare_add(data1); else { s = malloc(strlen(bld->contact) + 1 + strlen(data1) + 1); if (s) { strcpy(s, bld->contact); strcat(s, " "); strcat(s, data1); eina_stringshare_del(bld->contact); bld->contact = s; } } } else if (!strcmp(seg, "BIN:")) { Mrk_Build_Bin *build_bin = calloc(1, sizeof(Mrk_Build_Bin)); if (build_bin) { build_bin->bin = eina_stringshare_add(data1); bld->bins = eina_list_append(bld->bins, build_bin); } } else if (!strcmp(seg, "SRC:")) { Mrk_Build_Bin *build_bin = eina_list_data_get(eina_list_last(bld->bins)); if (build_bin) { build_bin->srcs = eina_list_append(build_bin->srcs, eina_stringshare_add(data1)); } } else if (!strcmp(seg, "DEPS:")) { Mrk_Build_Bin *build_bin = eina_list_data_get(eina_list_last(bld->bins)); if (build_bin) { build_bin->deps = eina_list_append(build_bin->deps, eina_stringshare_add(data1)); } } else if (!strcmp(seg, "INC:")) { Mrk_Build_Bin *build_bin = eina_list_data_get(eina_list_last(bld->bins)); if (build_bin) { build_bin->incs = eina_list_append(build_bin->incs, eina_stringshare_add(data1)); } } else if (!strcmp(seg, "DATA:")) { Mrk_Build_Data *build_data = calloc(1, sizeof(Mrk_Build_Data)); if (build_data) { build_data->src = eina_stringshare_add(data1); build_data->dest = eina_stringshare_add(data2); bld->data = eina_list_append(bld->data, build_data); } } else if (!strcmp(seg, "DESKTOP:")) { bld->desktops = eina_list_append(bld->desktops, eina_stringshare_add(data1)); } else if (!strcmp(seg, "ICON:")) { bld->icons = eina_list_append(bld->icons, eina_stringshare_add(data1)); } else if (!strcmp(seg, "PO:")) { bld->po = eina_list_append(bld->po, eina_stringshare_add(data1)); } } free(data1); free(data2); data1 = NULL; data2 = NULL; } free(tok); prevc = *p; p++; } else { prevc = *p; p++; } startline = 0; } return bld; error: mrk_build_free(bld); return NULL; #undef err } EAPI Mrk_Build * mrk_build_load(const char *file) { Mrk_Build *bld; Eina_File *ef; char *mem; size_t size; int ret; ef = eina_file_open(file, EINA_FALSE); if (!ef) return NULL; size = eina_file_size_get(ef); mem = eina_file_map_all(ef, EINA_FILE_SEQUENTIAL); if ((size == 0) || (!mem)) return NULL; bld = parse_content(mem, size); eina_file_close(ef); return bld; } EAPI void mrk_build_free(Mrk_Build *bld) { const char *s; Mrk_Build_Bin *build_bin; Mrk_Build_Data *build_data; if (!bld) return; eina_stringshare_del(bld->name); eina_stringshare_del(bld->icon); eina_stringshare_del(bld->brief); eina_stringshare_del(bld->version); eina_stringshare_del(bld->license); eina_stringshare_del(bld->domain); eina_stringshare_del(bld->repo); eina_stringshare_del(bld->devrepo); eina_stringshare_del(bld->contact); EINA_LIST_FREE(bld->tags, s) eina_stringshare_del(s); EINA_LIST_FREE(bld->categories, s) eina_stringshare_del(s); EINA_LIST_FREE(bld->copying, s) eina_stringshare_del(s); eina_stringshare_del(bld->needs); EINA_LIST_FREE(bld->desktops, s) eina_stringshare_del(s); EINA_LIST_FREE(bld->bins, build_bin) { eina_stringshare_del(build_bin->bin); EINA_LIST_FREE(build_bin->srcs, s) eina_stringshare_del(s); EINA_LIST_FREE(build_bin->deps, s) eina_stringshare_del(s); EINA_LIST_FREE(build_bin->incs, s) eina_stringshare_del(s); free(build_bin); } EINA_LIST_FREE(bld->data, build_data) { eina_stringshare_del(build_data->src); eina_stringshare_del(build_data->dest); free(build_data); } EINA_LIST_FREE(bld->icons, s) eina_stringshare_del(s); EINA_LIST_FREE(bld->po, s) eina_stringshare_del(s); free(bld); } EAPI Eina_Bool mrk_build_do(Mrk_Build *bld, const char *tmpd) { Eina_List *l, *ll; Mrk_Build_Bin *bin; Mrk_Build_Data *data; Eina_Strbuf *buf; char *s, *extn, *s2; char tmp[4096]; char tmp2[4096]; const char *ss, *cc; #define err(reason) do { fprintf(stderr, "%s\n", reason); goto error; } while (0) EINA_LIST_FOREACH(bld->po, l, s) { snprintf(tmp, sizeof(tmp), "%s/share/locale/%s/LC_MESSAGES/", tmpd, s); ecore_file_mkpath(tmp); snprintf(tmp2, sizeof(tmp2), "po/%s.gmo", s); snprintf(tmp, sizeof(tmp), "%s/share/locale/%s/LC_MESSAGES/%s.mo", tmpd, s, bld->domain); ecore_file_cp(tmp2, tmp); } EINA_LIST_FOREACH(bld->data, l, data) { s = ecore_file_dir_get(data->dest); if (s) { snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, s); ecore_file_mkpath(tmp); free(s); } snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, data->dest); ecore_file_cp(data->src, tmp); } snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, "share/applications"); ecore_file_mkpath(tmp); EINA_LIST_FOREACH(bld->desktops, l, s) { ss = ecore_file_file_get(s); if (!(!strncmp(ss, bld->domain, strlen(bld->domain)))) err("destkop file wrong domain"); snprintf(tmp, sizeof(tmp), "%s/share/applications/%s", tmpd, ss); ecore_file_cp(s, tmp); } snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, "share/icons"); ecore_file_mkpath(tmp); EINA_LIST_FOREACH(bld->icons, l, s) { ss = ecore_file_file_get(s); if (!(!strncmp(ss, bld->domain, strlen(bld->domain)))) err("icon file wrong domain"); snprintf(tmp, sizeof(tmp), "%s/share/icons/%s", tmpd, ss); ecore_file_cp(s, tmp); } EINA_LIST_FOREACH(bld->copying, l, s) { if (strchr(s, '/')) { s2 = ecore_file_dir_get(s); snprintf(tmp, sizeof(tmp), "%s/share/licenses/%s", tmpd, s2); free(s2); } else snprintf(tmp, sizeof(tmp), "%s/share/licenses", tmpd); ecore_file_mkpath(tmp); snprintf(tmp, sizeof(tmp), "%s/share/licenses/%s", tmpd, s); ecore_file_cp(s, tmp); } EINA_LIST_FOREACH(bld->bins, l, bin) { if ((buf = eina_strbuf_new())) { s = ecore_file_dir_get(bin->bin); if (s) { snprintf(tmp, sizeof(tmp), "%s/%s", tmpd, s); ecore_file_mkpath(tmp); free(s); } cc = getenv("CC"); if (!cc) cc = "gcc"; eina_strbuf_append(buf, cc); eina_strbuf_append(buf, " -I. -lm -o "); eina_strbuf_append(buf, tmpd); eina_strbuf_append(buf, "/"); eina_strbuf_append(buf, bin->bin); eina_strbuf_append(buf, " -DLOCALEDIR=\\\"/tmp/X/share/locale\\\""); eina_strbuf_append(buf, " -DPACKAGE_BIN_DIR=\\\"/tmp/X/bin\\\""); eina_strbuf_append(buf, " -DPACKAGE_LIB_DIR=\\\"/tmp/X/lib\\\""); eina_strbuf_append(buf, " -DPACKAGE_DATA_DIR=\\\"/tmp/X/share/"); eina_strbuf_append(buf, bld->domain); eina_strbuf_append(buf, "\\\""); eina_strbuf_append(buf, " -DPACKAGE_NAME=\\\""); eina_strbuf_append(buf, bld->domain); eina_strbuf_append(buf, "\\\""); eina_strbuf_append(buf, " -DPACKAGE_VERSION=\\\""); eina_strbuf_append(buf, bld->version); eina_strbuf_append(buf, "\\\""); eina_strbuf_append(buf, " -D_REENTRANT -DHAVE_CONFIG_H -pthread "); eina_strbuf_append(buf, " $CFLAGS "); EINA_LIST_FOREACH(bin->srcs, ll, s) { extn = strrchr(s, '.'); if ((extn) && (!strcasecmp(extn, ".c"))) { eina_strbuf_append(buf, s); eina_strbuf_append(buf, " "); } } EINA_LIST_FOREACH(bin->deps, ll, s) { eina_strbuf_append(buf, " `pkg-config --cflags --libs "); eina_strbuf_append(buf, s); eina_strbuf_append(buf, "`"); } EINA_LIST_FOREACH(bin->incs, ll, s) { eina_strbuf_append(buf, " -I"); eina_strbuf_append(buf, s); eina_strbuf_append(buf, " "); } s = (char *)eina_strbuf_string_get(buf); if (s) system(s); eina_strbuf_free(buf); } } return EINA_TRUE; error: return EINA_FALSE; #undef err } static void package_file(Eet_File *ef, const char *file, const char *key) { Eina_File *enf = eina_file_open(file, EINA_FALSE); if (enf) { void *mem = eina_file_map_all(enf, EINA_FILE_SEQUENTIAL); if (mem) { size_t size = eina_file_size_get(enf); eet_write(ef, key, mem, size, EET_COMPRESSION_VERYFAST); } eina_file_close(enf); } } static void package_bin_iter(Eet_File *ef, const char *dir, const char *key) { Eina_List *files; Eina_File *enf; char *s; char tmp[4096]; char tmp2[4096]; files = ecore_file_ls(dir); EINA_LIST_FREE(files, s) { if (!strcmp(s, ".")) continue; else if (!strcmp(s, "..")) continue; snprintf(tmp, sizeof(tmp), "%s/%s", dir, s); snprintf(tmp2, sizeof(tmp2), "%s/%s", key, s); if (ecore_file_is_dir(tmp)) { if (ecore_file_can_exec(tmp)) tmp2[4] = 'D'; package_bin_iter(ef, tmp, tmp2); } else { if (ecore_file_can_exec(tmp)) tmp2[4] = 'X'; else tmp2[4] = 'f'; package_file(ef, tmp, tmp2); } free(s); } } EAPI Eina_Bool mrk_build_package_bin(Mrk_Build *bld, const char *file, const char *tmpd, const char *os, const char *arch) { Eet_File *ef; char tmp[4096]; Eina_List *l; char *s; int i; // snprintf(tmp, sizeof(tmp), "%s-%s.mkb", bld->name, bld->version); ef = eet_open(file, EET_FILE_MODE_WRITE); if (ef) { #define WRTS(key, var) \ if (var) eet_write(ef, key, var, strlen(var), EET_COMPRESSION_VERYFAST) WRTS("name", bld->name); if (bld->icon) package_file(ef, bld->icon, "icon"); WRTS("brief", bld->brief); WRTS("version", bld->version); WRTS("license", bld->license); WRTS("repo", bld->repo); WRTS("devrepo", bld->devrepo); WRTS("contact", bld->contact); WRTS("needs", bld->needs); snprintf(tmp, sizeof(tmp), "%s-%s", os, arch); WRTS("arch", tmp); i = 0; EINA_LIST_FOREACH(bld->tags, l, s) { snprintf(tmp, sizeof(tmp), "tag/%i", i++); WRTS(tmp, s); } i = 0; EINA_LIST_FOREACH(bld->categories, l, s) { snprintf(tmp, sizeof(tmp), "category/%i", i++); WRTS(tmp, s); } package_bin_iter(ef, tmpd, "bin/f"); eet_close(ef); return EINA_TRUE; } return EINA_FALSE; } EAPI Eina_Bool mrk_build_package_src(Mrk_Build *bld, const char *buildfile, const char *file) { Eet_File *ef; char tmp[4096]; char tmp2[4096]; // snprintf(tmp, sizeof(tmp), "%s-%s.mks", bld->name, bld->version); ef = eet_open(file, EET_FILE_MODE_WRITE); if (ef) { Eina_File *enf; Eina_List *l, *ll; void *mem; size_t size; char *s; Mrk_Build_Bin *bin; Mrk_Build_Data *data; enf = eina_file_open(buildfile, EINA_FALSE); if (!enf) err("can't open build file"); mem = eina_file_map_all(enf, EINA_FILE_SEQUENTIAL); if (!mem) err("can't map build file"); size = eina_file_size_get(enf); eet_write(ef, "buildinfo", mem, size, EET_COMPRESSION_VERYFAST); eina_file_close(enf); EINA_LIST_FOREACH(bld->copying, l, s) { snprintf(tmp, sizeof(tmp), "src/%s", s); package_file(ef, s, tmp); } EINA_LIST_FOREACH(bld->desktops, l, s) { snprintf(tmp, sizeof(tmp), "src/%s", s); package_file(ef, s, tmp); } EINA_LIST_FOREACH(bld->icons, l, s) { snprintf(tmp, sizeof(tmp), "src/%s", s); package_file(ef, s, tmp); } EINA_LIST_FOREACH(bld->po, l, s) { snprintf(tmp2, sizeof(tmp2), "po/%s.gmo", s); snprintf(tmp, sizeof(tmp), "src/po/%s.gmo", s); package_file(ef, tmp2, tmp); } EINA_LIST_FOREACH(bld->bins, l, bin) { EINA_LIST_FOREACH(bin->srcs, ll, s) { snprintf(tmp, sizeof(tmp), "src/%s", s); package_file(ef, s, tmp); } } EINA_LIST_FOREACH(bld->data, l, data) { snprintf(tmp, sizeof(tmp), "src/%s", data->src); package_file(ef, data->src, tmp); } eet_close(ef); return EINA_TRUE; } return EINA_FALSE; }