char * jb_variable_evaluate (JBVariable *variable) { static GSList *evaluation_stack = NULL; char *str; char *value; g_return_val_if_fail(variable != NULL, NULL); if (evaluation_stack != NULL && evaluation_stack->data == variable) jb_error("variable \"%s\" references itself", variable->name); if (g_slist_find(evaluation_stack, variable) != NULL) jb_error("variable \"%s\" indirectly references itself", variable->name); evaluation_stack = g_slist_prepend(evaluation_stack, variable); str = jb_variable_to_string(variable); value = expand_real(str, NULL); g_free(str); evaluation_stack = g_slist_delete_link(evaluation_stack, evaluation_stack); return value; }
void jb_log (const char *format, ...) { static gboolean logging = FALSE; static GIOChannel *log_channel = NULL; static char *current_log_file = NULL; va_list args; char *message; char *with_nl; GError *err = NULL; gsize bytes_written; g_return_if_fail(format != NULL); g_return_if_fail(log_file != NULL); if (logging) return; logging = TRUE; if (log_channel != NULL) { if (strcmp(current_log_file, log_file)) { if (g_io_channel_shutdown(log_channel, TRUE, &err) != G_IO_STATUS_NORMAL) jb_error("unable to write to %s: %s", current_log_file, err->message); g_io_channel_unref(log_channel); log_channel = NULL; g_free(current_log_file); } } if (log_channel == NULL) { current_log_file = g_strdup(log_file); log_channel = g_io_channel_new_file(log_file, "w", &err); if (log_channel == NULL) jb_error("unable to open %s for writing: %s", log_file, err->message); } va_start(args, format); message = g_strdup_vprintf(format, args); va_end(args); with_nl = g_strdup_printf("%s\n", message); g_free(message); if (g_io_channel_write_chars(log_channel, with_nl, -1, &bytes_written, &err) != G_IO_STATUS_NORMAL || g_io_channel_flush(log_channel, &err) != G_IO_STATUS_NORMAL) jb_error("unable to write to %s: %s", log_file, err->message); g_free(with_nl); logging = FALSE; }
static void gnome_help_check_dir (const char *name, const char *description, const char *scrollkeeper_config_arg) { const char *dir; char *result; dir = jb_variable_get_string(name); if (strcmp(dir, "autodetect")) return; jb_require_program("scrollkeeper-config"); jb_message_checking("for the %s", description); if (jb_exec_expand(&result, NULL, "$scrollkeeper-config $arg", "arg", scrollkeeper_config_arg, NULL)) { jb_message_result_string(result); jb_variable_set_string(name, result); } else { jb_message_result_string("not found"); jb_error("unable to autodetect the %s", description); } g_free(result); }
static void gconf_configure (void) { JBVariable *variable; jb_require_program("gconftool-2"); if (! strcmp(jb_variable_get_string("gconf-config-source"), "autodetect")) { char *config_source; if (! jb_exec_expand(&config_source, NULL, "$gconftool-2 --get-default-source", NULL)) jb_error("unable to detect the GConf configuration source address"); jb_variable_set_string("gconf-config-source", config_source); g_free(config_source); } /* fix the default schemas dir on Ubuntu */ variable = jb_variable_get_variable_or_error("gconf-schemas-dir"); if (! variable->user_set) { static const char *ubuntu_dir = "$datadir/gconf/schemas"; char *expanded; expanded = jb_variable_expand(ubuntu_dir, NULL); if (g_file_test(expanded, G_FILE_TEST_IS_DIR)) jb_variable_set_string("gconf-schemas-dir", ubuntu_dir); g_free(expanded); } }
void jb_chdir (const char *path) { g_return_if_fail(path != NULL); if (chdir(path) < 0) jb_error("cannot change directory to %s: %s", path, g_strerror(errno)); }
void jb_mkdir (const char *pathname) { g_return_if_fail(pathname != NULL); if (g_mkdir_with_parents(pathname, 0755) < 0) jb_error("cannot create directory %s: %s", pathname, g_strerror(errno)); }
void jb_chmod (const char *path, mode_t mode) { g_return_if_fail(path != NULL); if (chmod(path, mode) < 0) jb_error("cannot chmod %s to " JB_MODE_FORMAT ": %s", path, (unsigned int) mode, g_strerror(errno)); }
void jb_require_program (const char *name) { g_return_if_fail(name != NULL); if (! jb_check_program(name)) jb_error("required program \"%s\" not found", name); }
void jb_write_file_or_exit (const char *filename, const char *contents) { GError *err = NULL; if (! jb_write_file(filename, contents, &err)) jb_error("cannot write %s: %s", filename, err->message); }
void jb_rename (const char *oldpath, const char *newpath) { g_return_if_fail(oldpath != NULL); g_return_if_fail(newpath != NULL); if (rename(oldpath, newpath) < 0) jb_error("cannot rename %s to %s: %s", oldpath, newpath, g_strerror(errno)); }
char * jb_read_file_or_exit (const char *filename) { GError *err = NULL; char *contents; contents = jb_read_file(filename, &err); if (contents == NULL) jb_error("cannot read %s: %s", filename, err->message); return contents; }
static void gettext_configure (void) { static const char *functions = "ngettext dgettext bind_textdomain_codeset"; if (jb_check_functions(functions, NULL)) jb_variable_set_package_flags("gettext", NULL, "-DENABLE_NLS", NULL, NULL); else if (jb_check_functions(functions, "intl")) jb_variable_set_package_flags("gettext", NULL, "-DENABLE_NLS", NULL, "-lintl"); else jb_error("gettext found neither in libc nor in libintl"); jb_require_program("msgfmt"); }
void jb_check_host_system (void) { char *output; gboolean status = FALSE; if (jb_variable_get_variable("host-cpu") != NULL) return; /* already checked */ jb_message_checking("the host system type"); if (jb_exec(&output, NULL, "jbsrc/tools/config.sub `jbsrc/tools/config.guess`")) { char **fields; int len; fields = g_strsplit(output, "-", 0); len = g_strv_length(fields); if (len == 3) { jb_variable_set_string("host-cpu", fields[0]); jb_variable_set_string("host-manufacturer", fields[1]); jb_variable_set_string("host-kernel", NULL); jb_variable_set_string("host-os", fields[2]); status = TRUE; } else if (len == 4) { jb_variable_set_string("host-cpu", fields[0]); jb_variable_set_string("host-manufacturer", fields[1]); jb_variable_set_string("host-kernel", fields[2]); jb_variable_set_string("host-os", fields[3]); status = TRUE; } g_strfreev(fields); } if (status) jb_message_result_string(output); else jb_message_result_string("unknown"); g_free(output); if (! status) jb_error("unable to determine host system type"); }
void jb_package_configure (void) { if (lm_glibc_check()) { /* * We need -std=c99 for lround(), ... * We need _BSD_SOURCE (which requires -lbsd-compat) for struct icmp, ... * We need _POSIX_C_SOURCE for struct addrinfo, clock_gettime(), ... */ jb_variable_set_string("glibc-cflags", "-std=c99 -D_BSD_SOURCE -D_POSIX_C_SOURCE=199309L"); jb_variable_set_string("glibc-cppflags", ""); // jb_variable_set_string("glibc-ldflags", "-lbsd-compat"); jb_variable_set_string("glibc-ldflags", ""); } else { jb_variable_set_string("glibc-cflags", ""); jb_variable_set_string("glibc-cppflags", ""); jb_variable_set_string("glibc-ldflags", ""); } if (jb_check_functions("clock_gettime", "rt")) jb_variable_set_string("clock-gettime-ldflags", "-lrt"); else if (jb_check_functions("clock_gettime", NULL)) jb_variable_set_string("clock-gettime-ldflags", ""); else jb_error("clock_gettime() found neither in librt nor in libc"); jb_check_reentrant_dns_resolver(); jb_require_packages("GNOME", "gnome", "gthread-2.0 gtk+-3.0 libpanelapplet-4.0 gmodule-2.0"); if (jb_variable_get_bool("geoip")) { if (lm_geoip_check()) { if (! lm_gdk_pixbuf_loader_check("art/flags/fr.svg", "image/svg+xml")) jb_warning("GTK+ cannot load image/svg+xml images, country flags will not be displayed"); } else { jb_warning("disabling option \"geoip\" since GeoIP was not found"); jb_variable_set_bool("geoip", FALSE); } } report_invalid_prefix(); }
static void handle_variable (const char *pair) { char *name; char *value; JBVariable *variable; GError *err = NULL; if (! parse_variable(pair, &name, &value)) jb_error("invalid variable specification \"%s\"", pair); variable = jb_variable_get_variable(name); if (variable == NULL || (variable->flags & JB_VARIABLE_USER_SETTABLE) == 0) jb_error("unknown variable \"%s\"", name); if (! jb_variable_set_from_string(variable, value, &err)) jb_error("invalid value \"%s\" for %s variable \"%s\": %s", value, variable->type->name, name, err->message); variable->user_set = TRUE; }
void jb_error_expand (const char *str, ...) { va_list args; char *message; g_assert(str != NULL); va_start(args, str); message = jb_variable_expandv(str, args); va_end(args); jb_error("%s", message); g_free(message); }
static void intltool_configure (void) { jb_require_program("perl"); if (jb_intltool_use_xml) { gboolean result; jb_message_checking("for XML::Parser"); result = jb_exec_expand(NULL, NULL, "$perl -e 'require XML::Parser'", NULL); jb_message_result_bool(result); if (! result) jb_error("intltool requires the XML::Parser Perl module"); } }
static char * get_expansion (const char *varname, GHashTable *extra_variables) { JBVariable *variable; if (extra_variables != NULL) { const char *extra_value; if (g_hash_table_lookup_extended(extra_variables, varname, NULL, (gpointer) &extra_value)) return g_strdup(extra_value != NULL ? extra_value : ""); } variable = jb_variable_get_variable(varname); if (variable != NULL) return jb_variable_evaluate(variable); jb_error("unknown variable \"%s\"", varname); }
static void parse_args (int argc, char **argv) { GSList *group_names; int i = 1; if (argc >= 2) { if (! strcmp(argv[1], "help") || ! strcmp(argv[1], "--help") || ! strcmp(argv[1], "-h") || ! strcmp(argv[1], "-?")) { if (argc != 2) jb_error("too many arguments for \"help\" action; run \"./jb help\" for an usage summary"); jb_action_help(); } else if (! strcmp(argv[1], "configure")) { for (i++; i < argc; i++) handle_variable(argv[i]); jb_action_configure(); } else if (! strcmp(argv[1], "build")) { group_names = parse_group_args(argc - 2, argv + 2); jb_action_build(group_names); } else if (! strcmp(argv[1], "install")) { group_names = parse_group_args(argc - 2, argv + 2); jb_action_install(group_names); } else if (! strcmp(argv[1], "makedist")) { if (argc != 2) jb_error("too many arguments for \"makedist\" action; run \"./jb help\" for an usage summary"); jb_action_makedist(); } else if (! strcmp(argv[1], "clean")) { group_names = parse_group_args(argc - 2, argv + 2); jb_action_clean(group_names); } else if (! strcmp(argv[1], "distclean")) { group_names = parse_group_args(argc - 2, argv + 2); jb_action_distclean(group_names); } else if (! strcmp(argv[1], "maintainerclean")) { group_names = parse_group_args(argc - 2, argv + 2); jb_action_maintainerclean(group_names); } else jb_error("unknown action \"%s\"; run \"./jb help\" for an usage summary", argv[1]); } else jb_error("not enough arguments; run \"./jb help\" for an usage summary"); }
/* * Returns TRUE if the command exited with status 0. * * The trailing newline of @standard_output and @standard_error will * be stripped. * * @standard_output and @standard_error will be set even if FALSE is * returned, since a command can produce an output even if it exits * with a non-zero status. */ gboolean jb_exec (char **standard_output, char **standard_error, const char *format, ...) { char *command; va_list args; int command_status; gboolean status = FALSE; char *_stdout; char *_stderr; char *converted_stdout = NULL; char *converted_stderr = NULL; char *shell_argv[4]; GError *err = NULL; g_return_val_if_fail(format != NULL, FALSE); va_start(args, format); command = g_strdup_vprintf(format, args); va_end(args); shell_argv[0] = "/bin/sh"; shell_argv[1] = "-c"; shell_argv[2] = command; shell_argv[3] = NULL; if (g_spawn_sync(NULL, shell_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &_stdout, &_stderr, &command_status, &err)) { converted_stdout = convert_process_output(_stdout); g_free(_stdout); converted_stderr = convert_process_output(_stderr); g_free(_stderr); if (WIFEXITED(command_status)) { int exit_status; exit_status = WEXITSTATUS(command_status); if (exit_status == 0) { jb_log("command \"%s\" succeeded", command); status = TRUE; } else jb_log("command \"%s\" failed with status %i", command, exit_status); if (*converted_stdout != '\0') { jb_log("standard output:"); jb_log("%s", converted_stdout); jb_log(JB_SEPARATOR); } if (*converted_stderr != '\0') { jb_log("standard error output:"); jb_log("%s", converted_stderr); jb_log(JB_SEPARATOR); } } else jb_log("command exited abnormally"); } else /* fatal error: it should not happend since we exec the shell */ jb_error("cannot execute command \"%s\": %s", command, err->message); g_free(command); if (standard_output) *standard_output = converted_stdout; else g_free(converted_stdout); if (standard_error) *standard_error = converted_stderr; else g_free(converted_stderr); return status; }
static char * expand_real (const char *str, GHashTable *extra_variables) { GString *result; const char *p; g_return_val_if_fail(str != NULL, NULL); result = g_string_new(NULL); for (p = str; *p != '\0';) { char c = *p; if (c == '$') { char *name; char *value; char *expanded_value; if (p[1] == '$') { g_string_append_c(result, '$'); p += 2; continue; } if (p[1] == '{') { char *end; p += 2; end = strchr(p, '}'); if (end == NULL) jb_error("unterminated variable reference"); if (end == p + 1) jb_error("empty variable reference"); name = g_strndup(p, end - p); p = end + 1; } else { const char *end; p++; end = p + 1; while (g_ascii_isalnum(*end) || *end == '-') end++; if (end == p) jb_error("empty variable reference"); name = g_strndup(p, end - p); p = end; } value = get_expansion(name, extra_variables); /* do not pass the extra variables to the recursive expansion */ expanded_value = expand_real(value, NULL); g_free(value); g_string_append(result, expanded_value); g_free(expanded_value); } else { g_string_append_c(result, c); p++; } } return g_string_free(result, FALSE); }