LIBUPCOREAPI int create_directory(wchar_t const* p) noexcept { BOOL result; wchar_t* pext; size_t plen; if (!p) { errno = EINVAL; return -1; } plen = wcslen(p); if (plen >= 248) { pext = static_cast<wchar_t*>(malloca((plen + 16) * sizeof(wchar_t))); if (!pext) { return -1; } wcscpy(pext, L"\\\\?\\"); wcscpy(pext + 4, p); result = ::CreateDirectoryW(pext, NULL); freea(pext); } else { result = ::CreateDirectoryW(p, NULL); } if (!result) { set_errno_with_last_oserror(); return -1; } return 0; }
static int message_list_hash_insert_entry (hash_table *htable, message_ty *mp) { char *alloced_key; const char *key; size_t keylen; int found; if (mp->msgctxt != NULL) { /* Concatenate mp->msgctxt and mp->msgid, to form the hash table key. */ size_t msgctxt_len = strlen (mp->msgctxt); size_t msgid_len = strlen (mp->msgid); keylen = msgctxt_len + 1 + msgid_len + 1; alloced_key = (char *) xmalloca (keylen); memcpy (alloced_key, mp->msgctxt, msgctxt_len); alloced_key[msgctxt_len] = MSGCTXT_SEPARATOR; memcpy (alloced_key + msgctxt_len + 1, mp->msgid, msgid_len + 1); key = alloced_key; } else { alloced_key = NULL; key = mp->msgid; keylen = strlen (mp->msgid) + 1; } found = (hash_insert_entry (htable, key, keylen, mp) == NULL); if (mp->msgctxt != NULL) freea (alloced_key); return found; }
static int execute_csharp_using_sscli (const char *assembly_path, const char * const *libdirs, unsigned int libdirs_count, const char * const *args, unsigned int nargs, bool verbose, bool quiet, execute_fn *executer, void *private_data) { static bool clix_tested; static bool clix_present; if (!clix_tested) { /* Test for presence of clix: "clix >/dev/null 2>/dev/null ; test $? = 1" */ char *argv[2]; int exitstatus; argv[0] = "clix"; argv[1] = NULL; exitstatus = execute ("clix", "clix", argv, false, false, true, true, true, false, NULL); clix_present = (exitstatus == 0 || exitstatus == 1); clix_tested = true; } if (clix_present) { char *old_clixpath; char **argv = (char **) xmalloca ((2 + nargs + 1) * sizeof (char *)); unsigned int i; bool err; /* Set clix' PATH variable. */ old_clixpath = set_clixpath (libdirs, libdirs_count, false, verbose); argv[0] = "clix"; argv[1] = (char *) assembly_path; for (i = 0; i <= nargs; i++) argv[2 + i] = (char *) args[i]; if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } err = executer ("clix", "clix", argv, private_data); /* Reset clix' PATH variable. */ reset_clixpath (old_clixpath); freea (argv); return err; } else return -1; }
static void do_allocation (int n) { void *ptr = malloca (n); freea (ptr); ptr = safe_alloca (n); }
int rpl_setenv (const char *name, const char *value, int replace) { int result; if (!name || !*name || strchr (name, '=')) { errno = EINVAL; return -1; } /* Call the real setenv even if replace is 0, in case implementation has underlying data to update, such as when environ changes. */ result = setenv (name, value, replace); if (result == 0 && replace && *value == '=') { char *tmp = getenv (name); if (!STREQ (tmp, value)) { int saved_errno; size_t len = strlen (value); tmp = malloca (len + 2); /* Since leading '=' is eaten, double it up. */ *tmp = '='; memcpy (tmp + 1, value, len + 1); result = setenv (name, tmp, replace); saved_errno = errno; freea (tmp); errno = saved_errno; } } return result; }
message_ty * message_list_search (message_list_ty *mlp, const char *msgctxt, const char *msgid) { if (mlp->use_hashtable) { char *alloced_key; const char *key; size_t keylen; if (msgctxt != NULL) { /* Concatenate the msgctxt and msgid, to form the hash table key. */ size_t msgctxt_len = strlen (msgctxt); size_t msgid_len = strlen (msgid); keylen = msgctxt_len + 1 + msgid_len + 1; alloced_key = (char *) xmalloca (keylen); memcpy (alloced_key, msgctxt, msgctxt_len); alloced_key[msgctxt_len] = MSGCTXT_SEPARATOR; memcpy (alloced_key + msgctxt_len + 1, msgid, msgid_len + 1); key = alloced_key; } else { alloced_key = NULL; key = msgid; keylen = strlen (msgid) + 1; } { void *htable_value; int found = !hash_find_entry (&mlp->htable, key, keylen, &htable_value); if (msgctxt != NULL) freea (alloced_key); if (found) return (message_ty *) htable_value; else return NULL; } } else { size_t j; for (j = 0; j < mlp->nitems; ++j) { message_ty *mp; mp = mlp->item[j]; if ((msgctxt != NULL ? mp->msgctxt != NULL && strcmp (msgctxt, mp->msgctxt) == 0 : mp->msgctxt == NULL) && strcmp (msgid, mp->msgid) == 0) return mp; } return NULL; } }
/* File open routine that understands `-' as stdin/stdout and `|cmd' as a pipe to command `cmd'. Returns resultant FILE on success, NULL on failure. If NULL is returned then errno is set to a sensible value. */ FILE * fn_open (const char *fn, const char *mode) { assert (mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a'); if (mode[0] == 'r') { if (!strcmp (fn, "stdin") || !strcmp (fn, "-")) return stdin; } else { if (!strcmp (fn, "stdout") || !strcmp (fn, "-")) return stdout; if (!strcmp (fn, "stderr")) return stderr; } #if HAVE_POPEN if (fn[0] == '|') { if (settings_get_safer_mode ()) return safety_violation (fn); return popen (&fn[1], mode[0] == 'r' ? "r" : "w"); } else if (*fn && fn[strlen (fn) - 1] == '|') { char *s; FILE *f; if (settings_get_safer_mode ()) return safety_violation (fn); s = xmalloca (strlen (fn)); memcpy (s, fn, strlen (fn) - 1); s[strlen (fn) - 1] = 0; f = popen (s, mode[0] == 'r' ? "r" : "w"); freea (s); return f; } else #endif return fopen (fn, mode); }
int mem_iconveha (const char *src, size_t srclen, const char *from_codeset, const char *to_codeset, bool transliterate, enum iconv_ilseq_handler handler, size_t *offsets, char **resultp, size_t *lengthp) { if (srclen == 0) { /* Nothing to convert. */ *lengthp = 0; return 0; } /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, we want to use transliteration. */ #if (((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2) \ && !defined __UCLIBC__) \ || _LIBICONV_VERSION >= 0x0105 if (transliterate) { int retval; size_t len = strlen (to_codeset); char *to_codeset_suffixed = (char *) malloca (len + 10 + 1); memcpy (to_codeset_suffixed, to_codeset, len); memcpy (to_codeset_suffixed + len, "//TRANSLIT", 10 + 1); retval = mem_iconveha_notranslit (src, srclen, from_codeset, to_codeset_suffixed, handler, offsets, resultp, lengthp); freea (to_codeset_suffixed); return retval; } else #endif return mem_iconveha_notranslit (src, srclen, from_codeset, to_codeset, handler, offsets, resultp, lengthp); }
char * str_iconveha (const char *src, const char *from_codeset, const char *to_codeset, bool transliterate, enum iconv_ilseq_handler handler) { if (*src == '\0' || c_strcasecmp (from_codeset, to_codeset) == 0) { char *result = strdup (src); if (result == NULL) errno = ENOMEM; return result; } /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, we want to use transliteration. */ #if (((__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2) \ && !defined __UCLIBC__) \ || _LIBICONV_VERSION >= 0x0105 if (transliterate) { char *result; size_t len = strlen (to_codeset); char *to_codeset_suffixed = (char *) malloca (len + 10 + 1); memcpy (to_codeset_suffixed, to_codeset, len); memcpy (to_codeset_suffixed + len, "//TRANSLIT", 10 + 1); result = str_iconveha_notranslit (src, from_codeset, to_codeset_suffixed, handler); freea (to_codeset_suffixed); return result; } else #endif return str_iconveha_notranslit (src, from_codeset, to_codeset, handler); }
LIBUPCOREAPI ssize_t absolute_path(char* d, size_t dsz, char const* p, char const* base) noexcept { wchar_t* native_d = nullptr, * native_p = nullptr, * native_base = nullptr; ssize_t retval = -1; size_t length; if (dsz) { native_d = static_cast<wchar_t *>(malloca(dsz * sizeof(wchar_t))); if (!native_d) { return -1; } } native_p = transcode(p); if (!native_p) { goto error; } if (base) { native_base = transcode(base); if (!native_base) { goto error; } } retval = absolute_path(native_d, dsz, native_p, native_base); if (!retval) { length = static_cast<size_t>(retval); retval = transcode(d, dsz, native_d, length); } error: free(native_base); free(native_p); freea(native_d); return retval; }
/* Return true if a format is a valid messageFormatPattern. Extracts argument type information into spec. */ static bool message_format_parse (const char *format, char *fdi, struct spec *spec, char **invalid_reason) { const char *const format_start = format; bool quoting = false; for (;;) { HANDLE_QUOTE; if (!quoting && *format == '{') { unsigned int depth; const char *element_start; const char *element_end; size_t n; char *element_alloced; char *element; unsigned int number; enum format_arg_type type; FDI_SET (format, FMTDIR_START); spec->directives++; element_start = ++format; depth = 0; for (; *format != '\0'; format++) { if (*format == '{') depth++; else if (*format == '}') { if (depth == 0) break; else depth--; } } if (*format == '\0') { *invalid_reason = xstrdup (_("The string ends in the middle of a directive: found '{' without matching '}'.")); FDI_SET (format - 1, FMTDIR_ERROR); return false; } element_end = format++; n = element_end - element_start; element = element_alloced = (char *) xmalloca (n + 1); memcpy (element, element_start, n); element[n] = '\0'; if (!c_isdigit (*element)) { *invalid_reason = xasprintf (_("In the directive number %u, '{' is not followed by an argument number."), spec->directives); FDI_SET (format - 1, FMTDIR_ERROR); freea (element_alloced); return false; } number = 0; do { number = 10 * number + (*element - '0'); element++; } while (c_isdigit (*element)); type = FAT_OBJECT; if (*element == '\0') ; else if (strncmp (element, ",time", 5) == 0 || strncmp (element, ",date", 5) == 0) { type = FAT_DATE; element += 5; if (*element == '\0') ; else if (*element == ',') { element++; if (strcmp (element, "short") == 0 || strcmp (element, "medium") == 0 || strcmp (element, "long") == 0 || strcmp (element, "full") == 0 || date_format_parse (element)) ; else { *invalid_reason = xasprintf (_("In the directive number %u, the substring \"%s\" is not a valid date/time style."), spec->directives, element); FDI_SET (format - 1, FMTDIR_ERROR); freea (element_alloced); return false; } } else { *element = '\0'; element -= 4; *invalid_reason = xasprintf (_("In the directive number %u, \"%s\" is not followed by a comma."), spec->directives, element); FDI_SET (format - 1, FMTDIR_ERROR); freea (element_alloced); return false; } } else if (strncmp (element, ",number", 7) == 0) { type = FAT_NUMBER; element += 7; if (*element == '\0') ; else if (*element == ',') { element++; if (strcmp (element, "currency") == 0 || strcmp (element, "percent") == 0 || strcmp (element, "integer") == 0 || number_format_parse (element)) ; else { *invalid_reason = xasprintf (_("In the directive number %u, the substring \"%s\" is not a valid number style."), spec->directives, element); FDI_SET (format - 1, FMTDIR_ERROR); freea (element_alloced); return false; } } else { *element = '\0'; element -= 6; *invalid_reason = xasprintf (_("In the directive number %u, \"%s\" is not followed by a comma."), spec->directives, element); FDI_SET (format - 1, FMTDIR_ERROR); freea (element_alloced); return false; } } else if (strncmp (element, ",choice", 7) == 0) { type = FAT_NUMBER; /* because ChoiceFormat extends NumberFormat */ element += 7; if (*element == '\0') ; else if (*element == ',') { element++; if (choice_format_parse (element, spec, invalid_reason)) ; else { FDI_SET (format - 1, FMTDIR_ERROR); freea (element_alloced); return false; } } else { *element = '\0'; element -= 6; *invalid_reason = xasprintf (_("In the directive number %u, \"%s\" is not followed by a comma."), spec->directives, element); FDI_SET (format - 1, FMTDIR_ERROR); freea (element_alloced); return false; } } else { *invalid_reason = xasprintf (_("In the directive number %u, the argument number is not followed by a comma and one of \"%s\", \"%s\", \"%s\", \"%s\"."), spec->directives, "time", "date", "number", "choice"); FDI_SET (format - 1, FMTDIR_ERROR); freea (element_alloced); return false; } freea (element_alloced); if (spec->allocated == spec->numbered_arg_count) { spec->allocated = 2 * spec->allocated + 1; spec->numbered = (struct numbered_arg *) xrealloc (spec->numbered, spec->allocated * sizeof (struct numbered_arg)); } spec->numbered[spec->numbered_arg_count].number = number; spec->numbered[spec->numbered_arg_count].type = type; spec->numbered_arg_count++; FDI_SET (format - 1, FMTDIR_END); } /* The doc says "ab}de" is invalid. Even though JDK accepts it. */ else if (!quoting && *format == '}') { FDI_SET (format, FMTDIR_START); *invalid_reason = xstrdup (_("The string starts in the middle of a directive: found '}' without matching '{'.")); FDI_SET (format, FMTDIR_ERROR); return false; } else if (*format != '\0') format++; else break; } return true; }
static int compile_csharp_using_mono (const char * const *sources, unsigned int sources_count, const char * const *libdirs, unsigned int libdirs_count, const char * const *libraries, unsigned int libraries_count, const char *output_file, bool output_is_library, bool optimize, bool debug, bool verbose) { static bool mcs_tested; static bool mcs_present; if (!mcs_tested) { /* Test for presence of mcs: "mcs --version >/dev/null 2>/dev/null" and (to exclude an unrelated 'mcs' program on QNX 6) "mcs --version 2>/dev/null | grep Mono >/dev/null" */ char *argv[3]; pid_t child; int fd[1]; int exitstatus; argv[0] = "mcs"; argv[1] = "--version"; argv[2] = NULL; child = create_pipe_in ("mcs", "mcs", argv, DEV_NULL, true, true, false, fd); mcs_present = false; if (child != -1) { /* Read the subprocess output, and test whether it contains the string "Mono". */ char c[4]; size_t count = 0; while (safe_read (fd[0], &c[count], 1) > 0) { count++; if (count == 4) { if (memcmp (c, "Mono", 4) == 0) mcs_present = true; c[0] = c[1]; c[1] = c[2]; c[2] = c[3]; count--; } } close (fd[0]); /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = wait_subprocess (child, "mcs", false, true, true, false, NULL); if (exitstatus != 0) mcs_present = false; } mcs_tested = true; } if (mcs_present) { unsigned int argc; char **argv; char **argp; pid_t child; int fd[1]; FILE *fp; char *line[2]; size_t linesize[2]; size_t linelen[2]; unsigned int l; int exitstatus; unsigned int i; argc = 1 + (output_is_library ? 1 : 0) + 1 + libdirs_count + libraries_count + (debug ? 1 : 0) + sources_count; argv = (char **) xmalloca ((argc + 1) * sizeof (char *)); argp = argv; *argp++ = "mcs"; if (output_is_library) *argp++ = "-target:library"; { char *option = (char *) xmalloca (5 + strlen (output_file) + 1); memcpy (option, "-out:", 5); strcpy (option + 5, output_file); *argp++ = option; } for (i = 0; i < libdirs_count; i++) { char *option = (char *) xmalloca (5 + strlen (libdirs[i]) + 1); memcpy (option, "-lib:", 5); strcpy (option + 5, libdirs[i]); *argp++ = option; } for (i = 0; i < libraries_count; i++) { char *option = (char *) xmalloca (11 + strlen (libraries[i]) + 4 + 1); memcpy (option, "-reference:", 11); memcpy (option + 11, libraries[i], strlen (libraries[i])); strcpy (option + 11 + strlen (libraries[i]), ".dll"); *argp++ = option; } if (debug) *argp++ = "-debug"; for (i = 0; i < sources_count; i++) { const char *source_file = sources[i]; if (strlen (source_file) >= 10 && memcmp (source_file + strlen (source_file) - 10, ".resources", 10) == 0) { char *option = (char *) xmalloca (10 + strlen (source_file) + 1); memcpy (option, "-resource:", 10); strcpy (option + 10, source_file); *argp++ = option; } else *argp++ = (char *) source_file; } *argp = NULL; /* Ensure argv length was correctly calculated. */ if (argp - argv != argc) abort (); if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } child = create_pipe_in ("mcs", "mcs", argv, NULL, false, true, true, fd); /* Read the subprocess output, copying it to stderr. Drop the last line if it starts with "Compilation succeeded". */ fp = fdopen (fd[0], "r"); if (fp == NULL) error (EXIT_FAILURE, errno, _("fdopen() failed")); line[0] = NULL; linesize[0] = 0; line[1] = NULL; linesize[1] = 0; l = 0; for (;;) { linelen[l] = getline (&line[l], &linesize[l], fp); if (linelen[l] == (size_t)(-1)) break; l = (l + 1) % 2; if (line[l] != NULL) fwrite (line[l], 1, linelen[l], stderr); } l = (l + 1) % 2; if (line[l] != NULL && !(linelen[l] >= 21 && memcmp (line[l], "Compilation succeeded", 21) == 0)) fwrite (line[l], 1, linelen[l], stderr); if (line[0] != NULL) free (line[0]); if (line[1] != NULL) free (line[1]); fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = wait_subprocess (child, "mcs", false, false, true, true, NULL); for (i = 1 + (output_is_library ? 1 : 0); i < 1 + (output_is_library ? 1 : 0) + 1 + libdirs_count + libraries_count; i++) freea (argv[i]); for (i = 0; i < sources_count; i++) if (argv[argc - sources_count + i] != sources[i]) freea (argv[argc - sources_count + i]); freea (argv); return (exitstatus != 0); } else return -1; }
/* Return true if a format is a valid choiceFormatPattern. Extracts argument type information into spec. */ static bool choice_format_parse (const char *format, struct spec *spec, char **invalid_reason) { /* Pattern syntax: pattern := | choice | choice '|' pattern choice := number separator messageformat separator := '<' | '#' | '\u2264' Single-quote starts a quoted section, to be terminated at the next single-quote or string end. Double single-quote gives a single single-quote. */ bool quoting = false; HANDLE_QUOTE; if (*format == '\0') return true; for (;;) { /* Don't bother looking too precisely into the syntax of the number. It can contain various Unicode characters. */ bool number_nonempty; char *msgformat; char *mp; bool msgformat_valid; /* Parse number. */ number_nonempty = false; while (*format != '\0' && !(!quoting && (*format == '<' || *format == '#' || strncmp (format, "\\u2264", 6) == 0 || *format == '|'))) { if (format[0] == '\\') { if (format[1] == 'u' && c_isxdigit (format[2]) && c_isxdigit (format[3]) && c_isxdigit (format[4]) && c_isxdigit (format[5])) format += 6; else format += 2; } else format += 1; number_nonempty = true; HANDLE_QUOTE; } /* Short clause at end of pattern is valid and is ignored! */ if (*format == '\0') break; if (!number_nonempty) { *invalid_reason = xasprintf (_("In the directive number %u, a choice contains no number."), spec->directives); return false; } if (*format == '<' || *format == '#') format += 1; else if (strncmp (format, "\\u2264", 6) == 0) format += 6; else { *invalid_reason = xasprintf (_("In the directive number %u, a choice contains a number that is not followed by '<', '#' or '%s'."), spec->directives, "\\u2264"); return false; } HANDLE_QUOTE; msgformat = (char *) xmalloca (strlen (format) + 1); mp = msgformat; while (*format != '\0' && !(!quoting && *format == '|')) { *mp++ = *format++; HANDLE_QUOTE; } *mp = '\0'; msgformat_valid = message_format_parse (msgformat, NULL, spec, invalid_reason); freea (msgformat); if (!msgformat_valid) return false; if (*format == '\0') break; format++; HANDLE_QUOTE; } return true; }
static int execute_csharp_using_pnet (const char *assembly_path, const char * const *libdirs, unsigned int libdirs_count, const char * const *args, unsigned int nargs, bool verbose, bool quiet, execute_fn *executer, void *private_data) { static bool ilrun_tested; static bool ilrun_present; if (!ilrun_tested) { /* Test for presence of ilrun: "ilrun --version >/dev/null 2>/dev/null" */ char *argv[3]; int exitstatus; argv[0] = "ilrun"; argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("ilrun", "ilrun", argv, false, false, true, true, true, false, NULL); ilrun_present = (exitstatus == 0); ilrun_tested = true; } if (ilrun_present) { unsigned int argc; char **argv; char **argp; unsigned int i; bool err; argc = 1 + 2 * libdirs_count + 1 + nargs; argv = (char **) xmalloca ((argc + 1) * sizeof (char *)); argp = argv; *argp++ = "ilrun"; for (i = 0; i < libdirs_count; i++) { *argp++ = "-L"; *argp++ = (char *) libdirs[i]; } *argp++ = (char *) assembly_path; for (i = 0; i < nargs; i++) *argp++ = (char *) args[i]; *argp = NULL; /* Ensure argv length was correctly calculated. */ if (argp - argv != argc) abort (); if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } err = executer ("ilrun", "ilrun", argv, private_data); freea (argv); return err; } else return -1; }
/* Knuth-Morris-Pratt algorithm. See http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm Return a boolean indicating success: Return true and set *RESULTP if the search was completed. Return false if it was aborted because not enough memory was available. */ static bool knuth_morris_pratt_multibyte (const char *haystack, const char *needle, const char **resultp) { size_t m = mbslen (needle); mbchar_t *needle_mbchars; size_t *table; /* Allocate room for needle_mbchars and the table. */ char *memory = (char *) nmalloca (m, sizeof (mbchar_t) + sizeof (size_t)); if (memory == NULL) return false; needle_mbchars = (mbchar_t *) memory; table = (size_t *) (memory + m * sizeof (mbchar_t)); /* Fill needle_mbchars. */ { mbui_iterator_t iter; size_t j; j = 0; for (mbui_init (iter, needle); mbui_avail (iter); mbui_advance (iter), j++) mb_copy (&needle_mbchars[j], &mbui_cur (iter)); } /* Fill the table. For 0 < i < m: 0 < table[i] <= i is defined such that forall 0 < x < table[i]: needle[x..i-1] != needle[0..i-1-x], and table[i] is as large as possible with this property. This implies: 1) For 0 < i < m: If table[i] < i, needle[table[i]..i-1] = needle[0..i-1-table[i]]. 2) For 0 < i < m: rhaystack[0..i-1] == needle[0..i-1] and exists h, i <= h < m: rhaystack[h] != needle[h] implies forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1]. table[0] remains uninitialized. */ { size_t i, j; /* i = 1: Nothing to verify for x = 0. */ table[1] = 1; j = 0; for (i = 2; i < m; i++) { /* Here: j = i-1 - table[i-1]. The inequality needle[x..i-1] != needle[0..i-1-x] is known to hold for x < table[i-1], by induction. Furthermore, if j>0: needle[i-1-j..i-2] = needle[0..j-1]. */ mbchar_t *b = &needle_mbchars[i - 1]; for (;;) { /* Invariants: The inequality needle[x..i-1] != needle[0..i-1-x] is known to hold for x < i-1-j. Furthermore, if j>0: needle[i-1-j..i-2] = needle[0..j-1]. */ if (mb_equal (*b, needle_mbchars[j])) { /* Set table[i] := i-1-j. */ table[i] = i - ++j; break; } /* The inequality needle[x..i-1] != needle[0..i-1-x] also holds for x = i-1-j, because needle[i-1] != needle[j] = needle[i-1-x]. */ if (j == 0) { /* The inequality holds for all possible x. */ table[i] = i; break; } /* The inequality needle[x..i-1] != needle[0..i-1-x] also holds for i-1-j < x < i-1-j+table[j], because for these x: needle[x..i-2] = needle[x-(i-1-j)..j-1] != needle[0..j-1-(x-(i-1-j))] (by definition of table[j]) = needle[0..i-2-x], hence needle[x..i-1] != needle[0..i-1-x]. Furthermore needle[i-1-j+table[j]..i-2] = needle[table[j]..j-1] = needle[0..j-1-table[j]] (by definition of table[j]). */ j = j - table[j]; } /* Here: j = i - table[i]. */ } } /* Search, using the table to accelerate the processing. */ { size_t j; mbui_iterator_t rhaystack; mbui_iterator_t phaystack; *resultp = NULL; j = 0; mbui_init (rhaystack, haystack); mbui_init (phaystack, haystack); /* Invariant: phaystack = rhaystack + j. */ while (mbui_avail (phaystack)) if (mb_equal (needle_mbchars[j], mbui_cur (phaystack))) { j++; mbui_advance (phaystack); if (j == m) { /* The entire needle has been found. */ *resultp = mbui_cur_ptr (rhaystack); break; } } else if (j > 0) { /* Found a match of needle[0..j-1], mismatch at needle[j]. */ size_t count = table[j]; j -= count; for (; count > 0; count--) { if (!mbui_avail (rhaystack)) abort (); mbui_advance (rhaystack); } } else { /* Found a mismatch at needle[0] already. */ if (!mbui_avail (rhaystack)) abort (); mbui_advance (rhaystack); mbui_advance (phaystack); } } freea (memory); return true; }
static int execute_csharp_using_mono (const char *assembly_path, const char * const *libdirs, unsigned int libdirs_count, const char * const *args, unsigned int nargs, bool verbose, bool quiet, execute_fn *executer, void *private_data) { static bool mono_tested; static bool mono_present; if (!mono_tested) { /* Test for presence of mono: "mono --version >/dev/null 2>/dev/null" */ char *argv[3]; int exitstatus; argv[0] = "mono"; argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("mono", "mono", argv, false, false, true, true, true, false, NULL); mono_present = (exitstatus == 0); mono_tested = true; } if (mono_present) { char *old_monopath; char **argv = (char **) xmalloca ((2 + nargs + 1) * sizeof (char *)); unsigned int i; bool err; /* Set MONO_PATH. */ old_monopath = set_monopath (libdirs, libdirs_count, false, verbose); argv[0] = "mono"; argv[1] = (char *) assembly_path; for (i = 0; i <= nargs; i++) argv[2 + i] = (char *) args[i]; if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } err = executer ("mono", "mono", argv, private_data); /* Reset MONO_PATH. */ reset_monopath (old_monopath); freea (argv); return err; } else return -1; }
char * __realpath (const char *name, char *resolved) { char *rpath, *dest, *extra_buf = NULL; const char *start, *end, *rpath_limit; long int path_max; #if HAVE_READLINK int num_links = 0; #endif if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if either parameter is a null pointer. We extend this to allow the RESOLVED parameter to be NULL in case the we are expected to allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf (name, _PC_PATH_MAX); if (path_max <= 0) path_max = 1024; #endif if (resolved == NULL) { rpath = malloc (path_max); if (rpath == NULL) { /* It's easier to set errno to ENOMEM than to rely on the 'malloc-posix' gnulib module. */ errno = ENOMEM; return NULL; } } else rpath = resolved; rpath_limit = rpath + path_max; if (name[0] != '/') { if (!__getcwd (rpath, path_max)) { rpath[0] = '\0'; goto error; } dest = strchr (rpath, '\0'); } else { rpath[0] = '/'; dest = rpath + 1; } for (start = end = name; *start; start = end) { #ifdef _LIBC struct stat64 st; #else struct stat st; #endif /* Skip sequence of multiple path-separators. */ while (*start == '/') ++start; /* Find end of path component. */ for (end = start; *end && *end != '/'; ++end) /* Nothing. */; if (end - start == 0) break; else if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } else { size_t new_size; if (dest[-1] != '/') *dest++ = '/'; if (dest + (end - start) >= rpath_limit) { ptrdiff_t dest_offset = dest - rpath; char *new_rpath; if (resolved) { __set_errno (ENAMETOOLONG); if (dest > rpath + 1) dest--; *dest = '\0'; goto error; } new_size = rpath_limit - rpath; if (end - start + 1 > path_max) new_size += end - start + 1; else new_size += path_max; new_rpath = (char *) realloc (rpath, new_size); if (new_rpath == NULL) { /* It's easier to set errno to ENOMEM than to rely on the 'realloc-posix' gnulib module. */ errno = ENOMEM; goto error; } rpath = new_rpath; rpath_limit = rpath + new_size; dest = rpath + dest_offset; } #ifdef _LIBC dest = __mempcpy (dest, start, end - start); #else memcpy (dest, start, end - start); dest += end - start; #endif *dest = '\0'; #ifdef _LIBC if (__lxstat64 (_STAT_VER, rpath, &st) < 0) #else if (lstat (rpath, &st) < 0) #endif goto error; #if HAVE_READLINK if (S_ISLNK (st.st_mode)) { char *buf; size_t len; int n; if (++num_links > MAXSYMLINKS) { __set_errno (ELOOP); goto error; } buf = malloca (path_max); if (!buf) { errno = ENOMEM; goto error; } n = __readlink (rpath, buf, path_max - 1); if (n < 0) { int saved_errno = errno; freea (buf); errno = saved_errno; goto error; } buf[n] = '\0'; if (!extra_buf) { extra_buf = malloca (path_max); if (!extra_buf) { freea (buf); errno = ENOMEM; goto error; } } len = strlen (end); if ((long int) (n + len) >= path_max) { freea (buf); __set_errno (ENAMETOOLONG); goto error; } /* Careful here, end may be a pointer into extra_buf... */ memmove (&extra_buf[n], end, len + 1); name = end = memcpy (extra_buf, buf, n); if (buf[0] == '/') dest = rpath + 1; /* It's an absolute symlink */ else /* Back up to previous component, ignore if at root already: */ if (dest > rpath + 1) while ((--dest)[-1] != '/'); } #endif } } if (dest > rpath + 1 && dest[-1] == '/') --dest; *dest = '\0'; if (extra_buf) freea (extra_buf); return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath; error: { int saved_errno = errno; if (extra_buf) freea (extra_buf); if (resolved) strcpy (resolved, rpath); else free (rpath); errno = saved_errno; } return NULL; }
bool execute_java_class (const char *class_name, const char * const *classpaths, unsigned int classpaths_count, bool use_minimal_classpath, const char *exe_dir, const char * const *args, bool verbose, bool quiet, execute_fn *executer, void *private_data) { bool err = false; unsigned int nargs; char *old_JAVA_HOME; /* Count args. */ { const char * const *arg; for (nargs = 0, arg = args; *arg != NULL; nargs++, arg++) ; } /* First, try a class compiled to a native code executable. */ if (exe_dir != NULL) { char *exe_pathname = concatenated_filename (exe_dir, class_name, EXEEXT); char *old_classpath; char **argv = (char **) xmalloca ((1 + nargs + 1) * sizeof (char *)); unsigned int i; /* Set CLASSPATH. */ old_classpath = set_classpath (classpaths, classpaths_count, use_minimal_classpath, verbose); argv[0] = exe_pathname; for (i = 0; i <= nargs; i++) argv[1 + i] = (char *) args[i]; if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } err = executer (class_name, exe_pathname, argv, private_data); /* Reset CLASSPATH. */ reset_classpath (old_classpath); freea (argv); goto done1; } { const char *java = getenv ("JAVA"); if (java != NULL && java[0] != '\0') { /* Because $JAVA may consist of a command and options, we use the shell. Because $JAVA has been set by the user, we leave all all environment variables in place, including JAVA_HOME, and we don't erase the user's CLASSPATH. */ char *old_classpath; unsigned int command_length; char *command; char *argv[4]; const char * const *arg; char *p; /* Set CLASSPATH. */ old_classpath = set_classpath (classpaths, classpaths_count, false, verbose); command_length = strlen (java); command_length += 1 + shell_quote_length (class_name); for (arg = args; *arg != NULL; arg++) command_length += 1 + shell_quote_length (*arg); command_length += 1; command = (char *) xmalloca (command_length); p = command; /* Don't shell_quote $JAVA, because it may consist of a command and options. */ memcpy (p, java, strlen (java)); p += strlen (java); *p++ = ' '; p = shell_quote_copy (p, class_name); for (arg = args; *arg != NULL; arg++) { *p++ = ' '; p = shell_quote_copy (p, *arg); } *p++ = '\0'; /* Ensure command_length was correctly calculated. */ if (p - command > command_length) abort (); if (verbose) printf ("%s\n", command); argv[0] = "/bin/sh"; argv[1] = "-c"; argv[2] = command; argv[3] = NULL; err = executer (java, "/bin/sh", argv, private_data); freea (command); /* Reset CLASSPATH. */ reset_classpath (old_classpath); goto done1; } } /* Unset the JAVA_HOME environment variable. */ old_JAVA_HOME = getenv ("JAVA_HOME"); if (old_JAVA_HOME != NULL) { old_JAVA_HOME = xstrdup (old_JAVA_HOME); unsetenv ("JAVA_HOME"); } { static bool gij_tested; static bool gij_present; if (!gij_tested) { /* Test for presence of gij: "gij --version > /dev/null" */ char *argv[3]; int exitstatus; argv[0] = "gij"; argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("gij", "gij", argv, false, false, true, true, true, false); gij_present = (exitstatus == 0); gij_tested = true; } if (gij_present) { char *old_classpath; char **argv = (char **) xmalloca ((2 + nargs + 1) * sizeof (char *)); unsigned int i; /* Set CLASSPATH. */ old_classpath = set_classpath (classpaths, classpaths_count, use_minimal_classpath, verbose); argv[0] = "gij"; argv[1] = (char *) class_name; for (i = 0; i <= nargs; i++) argv[2 + i] = (char *) args[i]; if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } err = executer ("gij", "gij", argv, private_data); /* Reset CLASSPATH. */ reset_classpath (old_classpath); freea (argv); goto done2; } } { static bool java_tested; static bool java_present; if (!java_tested) { /* Test for presence of java: "java -version 2> /dev/null" */ char *argv[3]; int exitstatus; argv[0] = "java"; argv[1] = "-version"; argv[2] = NULL; exitstatus = execute ("java", "java", argv, false, false, true, true, true, false); java_present = (exitstatus == 0); java_tested = true; } if (java_present) { char *old_classpath; char **argv = (char **) xmalloca ((2 + nargs + 1) * sizeof (char *)); unsigned int i; /* Set CLASSPATH. We don't use the "-classpath ..." option because in JDK 1.1.x its argument should also contain the JDK's classes.zip, but we don't know its location. (In JDK 1.3.0 it would work.) */ old_classpath = set_classpath (classpaths, classpaths_count, use_minimal_classpath, verbose); argv[0] = "java"; argv[1] = (char *) class_name; for (i = 0; i <= nargs; i++) argv[2 + i] = (char *) args[i]; if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } err = executer ("java", "java", argv, private_data); /* Reset CLASSPATH. */ reset_classpath (old_classpath); freea (argv); goto done2; } } { static bool jre_tested; static bool jre_present; if (!jre_tested) { /* Test for presence of jre: "jre 2> /dev/null ; test $? = 1" */ char *argv[2]; int exitstatus; argv[0] = "jre"; argv[1] = NULL; exitstatus = execute ("jre", "jre", argv, false, false, true, true, true, false); jre_present = (exitstatus == 0 || exitstatus == 1); jre_tested = true; } if (jre_present) { char *old_classpath; char **argv = (char **) xmalloca ((2 + nargs + 1) * sizeof (char *)); unsigned int i; /* Set CLASSPATH. We don't use the "-classpath ..." option because in JDK 1.1.x its argument should also contain the JDK's classes.zip, but we don't know its location. */ old_classpath = set_classpath (classpaths, classpaths_count, use_minimal_classpath, verbose); argv[0] = "jre"; argv[1] = (char *) class_name; for (i = 0; i <= nargs; i++) argv[2 + i] = (char *) args[i]; if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } err = executer ("jre", "jre", argv, private_data); /* Reset CLASSPATH. */ reset_classpath (old_classpath); freea (argv); goto done2; } } #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ /* Win32, Cygwin */ { static bool jview_tested; static bool jview_present; if (!jview_tested) { /* Test for presence of jview: "jview -? >nul ; test $? = 1" */ char *argv[3]; int exitstatus; argv[0] = "jview"; argv[1] = "-?"; argv[2] = NULL; exitstatus = execute ("jview", "jview", argv, false, false, true, true, true, false); jview_present = (exitstatus == 0 || exitstatus == 1); jview_tested = true; } if (jview_present) { char *old_classpath; char **argv = (char **) xmalloca ((2 + nargs + 1) * sizeof (char *)); unsigned int i; /* Set CLASSPATH. */ old_classpath = set_classpath (classpaths, classpaths_count, use_minimal_classpath, verbose); argv[0] = "jview"; argv[1] = (char *) class_name; for (i = 0; i <= nargs; i++) argv[2 + i] = (char *) args[i]; if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } err = executer ("jview", "jview", argv, private_data); /* Reset CLASSPATH. */ reset_classpath (old_classpath); freea (argv); goto done2; } } #endif if (!quiet) error (0, 0, _("Java virtual machine not found, try installing gij or set $JAVA")); err = true; done2: if (old_JAVA_HOME != NULL) { xsetenv ("JAVA_HOME", old_JAVA_HOME, 1); free (old_JAVA_HOME); } done1: return err; }
char * __realpath (const char *name, char *resolved) { char *rpath, *dest, *extra_buf = NULL; const char *start, *end, *rpath_limit; long int path_max; int num_links = 0; size_t prefix_len; if (name == NULL) { /* As per Single Unix Specification V2 we must return an error if either parameter is a null pointer. We extend this to allow the RESOLVED parameter to be NULL in case the we are expected to allocate the room for the return value. */ __set_errno (EINVAL); return NULL; } if (name[0] == '\0') { /* As per Single Unix Specification V2 we must return an error if the name argument points to an empty string. */ __set_errno (ENOENT); return NULL; } #ifdef PATH_MAX path_max = PATH_MAX; #else path_max = pathconf (name, _PC_PATH_MAX); if (path_max <= 0) path_max = 8192; #endif if (resolved == NULL) { rpath = malloc (path_max); if (rpath == NULL) { /* It's easier to set errno to ENOMEM than to rely on the 'malloc-posix' gnulib module. */ errno = ENOMEM; return NULL; } } else rpath = resolved; rpath_limit = rpath + path_max; /* This is always zero for Posix hosts, but can be 2 for MS-Windows and MS-DOS X:/foo/bar file names. */ prefix_len = FILE_SYSTEM_PREFIX_LEN (name); if (!IS_ABSOLUTE_FILE_NAME (name)) { if (!__getcwd (rpath, path_max)) { rpath[0] = '\0'; goto error; } dest = strchr (rpath, '\0'); start = name; prefix_len = FILE_SYSTEM_PREFIX_LEN (rpath); } else { dest = rpath; if (prefix_len) { memcpy (rpath, name, prefix_len); dest += prefix_len; } *dest++ = '/'; if (DOUBLE_SLASH_IS_DISTINCT_ROOT) { if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len) *dest++ = '/'; *dest = '\0'; } start = name + prefix_len; } for (end = start; *start; start = end) { #ifdef _LIBC struct stat64 st; #else struct stat st; #endif int n; /* Skip sequence of multiple path-separators. */ while (ISSLASH (*start)) ++start; /* Find end of path component. */ for (end = start; *end && !ISSLASH (*end); ++end) /* Nothing. */; if (end - start == 0) break; else if (end - start == 1 && start[0] == '.') /* nothing */; else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ if (dest > rpath + prefix_len + 1) for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest) continue; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; } else { size_t new_size; if (!ISSLASH (dest[-1])) *dest++ = '/'; if (dest + (end - start) >= rpath_limit) { ptrdiff_t dest_offset = dest - rpath; char *new_rpath; if (resolved) { __set_errno (ENAMETOOLONG); if (dest > rpath + prefix_len + 1) dest--; *dest = '\0'; goto error; } new_size = rpath_limit - rpath; if (end - start + 1 > path_max) new_size += end - start + 1; else new_size += path_max; new_rpath = (char *) realloc (rpath, new_size); if (new_rpath == NULL) { /* It's easier to set errno to ENOMEM than to rely on the 'realloc-posix' gnulib module. */ errno = ENOMEM; goto error; } rpath = new_rpath; rpath_limit = rpath + new_size; dest = rpath + dest_offset; } #ifdef _LIBC dest = __mempcpy (dest, start, end - start); #else memcpy (dest, start, end - start); dest += end - start; #endif *dest = '\0'; #ifdef _LIBC if (__lxstat64 (_STAT_VER, rpath, &st) < 0) #else if (lstat (rpath, &st) < 0) #endif goto error; if (S_ISLNK (st.st_mode)) { char *buf; size_t len; if (++num_links > MAXSYMLINKS) { __set_errno (ELOOP); goto error; } buf = malloca (path_max); if (!buf) { errno = ENOMEM; goto error; } n = __readlink (rpath, buf, path_max - 1); if (n < 0) { int saved_errno = errno; freea (buf); errno = saved_errno; goto error; } buf[n] = '\0'; if (!extra_buf) { extra_buf = malloca (path_max); if (!extra_buf) { freea (buf); errno = ENOMEM; goto error; } } len = strlen (end); if ((long int) (n + len) >= path_max) { freea (buf); __set_errno (ENAMETOOLONG); goto error; } /* Careful here, end may be a pointer into extra_buf... */ memmove (&extra_buf[n], end, len + 1); name = end = memcpy (extra_buf, buf, n); if (IS_ABSOLUTE_FILE_NAME (buf)) { size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf); if (pfxlen) memcpy (rpath, buf, pfxlen); dest = rpath + pfxlen; *dest++ = '/'; /* It's an absolute symlink */ if (DOUBLE_SLASH_IS_DISTINCT_ROOT) { if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen) *dest++ = '/'; *dest = '\0'; } /* Install the new prefix to be in effect hereafter. */ prefix_len = pfxlen; } else { /* Back up to previous component, ignore if at root already: */ if (dest > rpath + prefix_len + 1) for (--dest; dest > rpath && !ISSLASH (dest[-1]); --dest) continue; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len) dest++; } } else if (!S_ISDIR (st.st_mode) && *end != '\0') { __set_errno (ENOTDIR); goto error; } } } if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1])) --dest; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; *dest = '\0'; if (extra_buf) freea (extra_buf); return rpath; error: { int saved_errno = errno; if (extra_buf) freea (extra_buf); if (resolved == NULL) free (rpath); errno = saved_errno; } return NULL; }
int mbmemcasecoll (const char *s1, size_t s1len, const char *s2, size_t s2len, bool hard_LC_COLLATE) { char *t1; size_t t1len; char *t2; size_t t2len; char *memory; int cmp; if (MB_CUR_MAX > 1) { /* Application of towlower grows each character by a factor 2 at most. */ t1len = 2 * s1len; t2len = 2 * s2len; } else { /* Application of tolower doesn't change the size. */ t1len = s1len; t2len = s2len; } /* Allocate memory for t1 and t2. */ memory = (char *) malloca (t1len + 1 + t2len + 1); if (memory == NULL) { errno = ENOMEM; return 0; } t1 = memory; t2 = memory + t1len + 1; /* Csae-fold the two argument strings. */ if (MB_CUR_MAX > 1) { t1len = apply_towlower (s1, s1len, t1, t1len); t2len = apply_towlower (s2, s2len, t2, t2len); } else { apply_tolower (s1, t1, s1len); apply_tolower (s2, t2, s2len); } /* Compare the two case-folded strings. */ if (hard_LC_COLLATE) cmp = memcoll (t1, t1len, t2, t2len); else { cmp = memcmp2 (t1, t1len, t2, t2len); errno = 0; } { int saved_errno = errno; freea (memory); errno = saved_errno; } return cmp; }
int rpl_stat (char const *name, struct stat *buf) { #ifdef WINDOWS_NATIVE /* Fill the fields ourselves, because the original stat function returns values for st_atime, st_mtime, st_ctime that depend on the current time zone. See <https://lists.gnu.org/r/bug-gnulib/2017-04/msg00134.html> */ /* XXX Should we convert to wchar_t* and prepend '\\?\', in order to work around length limitations <https://msdn.microsoft.com/en-us/library/aa365247.aspx> ? */ /* POSIX <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13> specifies: "More than two leading <slash> characters shall be treated as a single <slash> character." */ if (ISSLASH (name[0]) && ISSLASH (name[1]) && ISSLASH (name[2])) { name += 2; while (ISSLASH (name[1])) name++; } size_t len = strlen (name); size_t drive_prefix_len = (HAS_DEVICE (name) ? 2 : 0); /* Remove trailing slashes (except the very first one, at position drive_prefix_len), but remember their presence. */ size_t rlen; bool check_dir = false; rlen = len; while (rlen > drive_prefix_len && ISSLASH (name[rlen-1])) { check_dir = true; if (rlen == drive_prefix_len + 1) break; rlen--; } /* Handle '' and 'C:'. */ if (!check_dir && rlen == drive_prefix_len) { errno = ENOENT; return -1; } /* Handle '\\'. */ if (rlen == 1 && ISSLASH (name[0]) && len >= 2) { errno = ENOENT; return -1; } const char *rname; char *malloca_rname; if (rlen == len) { rname = name; malloca_rname = NULL; } else { malloca_rname = malloca (rlen + 1); if (malloca_rname == NULL) { errno = ENOMEM; return -1; } memcpy (malloca_rname, name, rlen); malloca_rname[rlen] = '\0'; rname = malloca_rname; } /* There are two ways to get at the requested information: - by scanning the parent directory and examining the relevant directory entry, - by opening the file directly. The first approach fails for root directories (e.g. 'C:\') and UNC root directories (e.g. '\\server\share'). The second approach fails for some system files (e.g. 'C:\pagefile.sys' and 'C:\hiberfil.sys'): ERROR_SHARING_VIOLATION. The second approach gives more information (in particular, correct st_dev, st_ino, st_nlink fields). So we use the second approach and, as a fallback except for root and UNC root directories, also the first approach. */ { int ret; { /* Approach based on the file. */ /* Open a handle to the file. CreateFile <https://msdn.microsoft.com/en-us/library/aa363858.aspx> <https://msdn.microsoft.com/en-us/library/aa363874.aspx> */ HANDLE h = CreateFile (rname, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, /* FILE_FLAG_POSIX_SEMANTICS (treat file names that differ only in case as different) makes sense only when applied to *all* filesystem operations. */ FILE_FLAG_BACKUP_SEMANTICS /* | FILE_FLAG_POSIX_SEMANTICS */, NULL); if (h != INVALID_HANDLE_VALUE) { ret = _gl_fstat_by_handle (h, rname, buf); CloseHandle (h); goto done; } } /* Test for root and UNC root directories. */ if ((rlen == drive_prefix_len + 1 && ISSLASH (rname[drive_prefix_len])) || is_unc_root (rname)) goto failed; /* Fallback. */ { /* Approach based on the directory entry. */ if (strchr (rname, '?') != NULL || strchr (rname, '*') != NULL) { /* Other Windows API functions would fail with error ERROR_INVALID_NAME. */ if (malloca_rname != NULL) freea (malloca_rname); errno = ENOENT; return -1; } /* Get the details about the directory entry. This can be done through FindFirstFile <https://msdn.microsoft.com/en-us/library/aa364418.aspx> <https://msdn.microsoft.com/en-us/library/aa365740.aspx> or through FindFirstFileEx with argument FindExInfoBasic <https://msdn.microsoft.com/en-us/library/aa364419.aspx> <https://msdn.microsoft.com/en-us/library/aa364415.aspx> <https://msdn.microsoft.com/en-us/library/aa365740.aspx> */ WIN32_FIND_DATA info; HANDLE h = FindFirstFile (rname, &info); if (h == INVALID_HANDLE_VALUE) goto failed; /* Test for error conditions before starting to fill *buf. */ if (sizeof (buf->st_size) <= 4 && info.nFileSizeHigh > 0) { FindClose (h); if (malloca_rname != NULL) freea (malloca_rname); errno = EOVERFLOW; return -1; } # if _GL_WINDOWS_STAT_INODES buf->st_dev = 0; # if _GL_WINDOWS_STAT_INODES == 2 buf->st_ino._gl_ino[0] = buf->st_ino._gl_ino[1] = 0; # else /* _GL_WINDOWS_STAT_INODES == 1 */ buf->st_ino = 0; # endif # else /* st_ino is not wide enough for identifying a file on a device. Without st_ino, st_dev is pointless. */ buf->st_dev = 0; buf->st_ino = 0; # endif /* st_mode. */ unsigned int mode = /* XXX How to handle FILE_ATTRIBUTE_REPARSE_POINT ? */ ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? _S_IFDIR | S_IEXEC_UGO : _S_IFREG) | S_IREAD_UGO | ((info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? 0 : S_IWRITE_UGO); if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { /* Determine whether the file is executable by looking at the file name suffix. */ if (info.nFileSizeHigh > 0 || info.nFileSizeLow > 0) { const char *last_dot = NULL; const char *p; for (p = info.cFileName; *p != '\0'; p++) if (*p == '.') last_dot = p; if (last_dot != NULL) { const char *suffix = last_dot + 1; if (_stricmp (suffix, "exe") == 0 || _stricmp (suffix, "bat") == 0 || _stricmp (suffix, "cmd") == 0 || _stricmp (suffix, "com") == 0) mode |= S_IEXEC_UGO; } } } buf->st_mode = mode; /* st_nlink. Ignore hard links here. */ buf->st_nlink = 1; /* There's no easy way to map the Windows SID concept to an integer. */ buf->st_uid = 0; buf->st_gid = 0; /* st_rdev is irrelevant for normal files and directories. */ buf->st_rdev = 0; /* st_size. */ if (sizeof (buf->st_size) <= 4) /* Range check already done above. */ buf->st_size = info.nFileSizeLow; else buf->st_size = ((long long) info.nFileSizeHigh << 32) | (long long) info.nFileSizeLow; /* st_atime, st_mtime, st_ctime. */ # if _GL_WINDOWS_STAT_TIMESPEC buf->st_atim = _gl_convert_FILETIME_to_timespec (&info.ftLastAccessTime); buf->st_mtim = _gl_convert_FILETIME_to_timespec (&info.ftLastWriteTime); buf->st_ctim = _gl_convert_FILETIME_to_timespec (&info.ftCreationTime); # else buf->st_atime = _gl_convert_FILETIME_to_POSIX (&info.ftLastAccessTime); buf->st_mtime = _gl_convert_FILETIME_to_POSIX (&info.ftLastWriteTime); buf->st_ctime = _gl_convert_FILETIME_to_POSIX (&info.ftCreationTime); # endif FindClose (h); ret = 0; } done: if (ret >= 0 && check_dir && !S_ISDIR (buf->st_mode)) { errno = ENOTDIR; ret = -1; } if (malloca_rname != NULL) { int saved_errno = errno; freea (malloca_rname); errno = saved_errno; } return ret; } failed: { DWORD error = GetLastError (); #if 0 fprintf (stderr, "rpl_stat error 0x%x\n", (unsigned int) error); #endif if (malloca_rname != NULL) freea (malloca_rname); switch (error) { /* Some of these errors probably cannot happen with the specific flags that we pass to CreateFile. But who knows... */ case ERROR_FILE_NOT_FOUND: /* The last component of rname does not exist. */ case ERROR_PATH_NOT_FOUND: /* Some directory component in rname does not exist. */ case ERROR_BAD_PATHNAME: /* rname is such as '\\server'. */ case ERROR_BAD_NET_NAME: /* rname is such as '\\server\nonexistentshare'. */ case ERROR_INVALID_NAME: /* rname contains wildcards, misplaced colon, etc. */ case ERROR_DIRECTORY: errno = ENOENT; break; case ERROR_ACCESS_DENIED: /* rname is such as 'C:\System Volume Information\foo'. */ case ERROR_SHARING_VIOLATION: /* rname is such as 'C:\pagefile.sys' (second approach only). */ /* XXX map to EACCESS or EPERM? */ errno = EACCES; break; case ERROR_OUTOFMEMORY: errno = ENOMEM; break; case ERROR_WRITE_PROTECT: errno = EROFS; break; case ERROR_WRITE_FAULT: case ERROR_READ_FAULT: case ERROR_GEN_FAILURE: errno = EIO; break; case ERROR_BUFFER_OVERFLOW: case ERROR_FILENAME_EXCED_RANGE: errno = ENAMETOOLONG; break; case ERROR_DELETE_PENDING: /* XXX map to EACCESS or EPERM? */ errno = EPERM; break; default: errno = EINVAL; break; } return -1; } #else int result = orig_stat (name, buf); if (result == 0) { # if REPLACE_FUNC_STAT_FILE /* Solaris 9 mistakenly succeeds when given a non-directory with a trailing slash. */ if (!S_ISDIR (buf->st_mode)) { size_t len = strlen (name); if (ISSLASH (name[len - 1])) { errno = ENOTDIR; return -1; } } # endif /* REPLACE_FUNC_STAT_FILE */ result = stat_time_normalize (result, buf); } return result; #endif }
internal_function _nl_init_domain_conv (struct loaded_l10nfile *domain_file, struct loaded_domain *domain, struct binding *domainbinding) { /* Find out about the character set the file is encoded with. This can be found (in textual form) in the entry "". If this entry does not exist or if this does not contain the `charset=' information, we will assume the charset matches the one the current locale and we don't have to perform any conversion. */ char *nullentry; size_t nullentrylen; /* Preinitialize fields, to avoid recursion during _nl_find_msg. */ domain->codeset_cntr = (domainbinding != NULL ? domainbinding->codeset_cntr : 0); #ifdef _LIBC domain->conv = (__gconv_t) -1; #else # if HAVE_ICONV domain->conv = (iconv_t) -1; # endif #endif domain->conv_tab = NULL; /* Get the header entry. */ nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen); if (nullentry != NULL) { #if defined _LIBC || HAVE_ICONV const char *charsetstr; charsetstr = strstr (nullentry, "charset="); if (charsetstr != NULL) { size_t len; char *charset; const char *outcharset; charsetstr += strlen ("charset="); len = strcspn (charsetstr, " \t\n"); charset = (char *) alloca (len + 1); # if defined _LIBC || HAVE_MEMPCPY *((char *) mempcpy (charset, charsetstr, len)) = '\0'; # else memcpy (charset, charsetstr, len); charset[len] = '\0'; # endif /* The output charset should normally be determined by the locale. But sometimes the locale is not used or not correctly set up, so we provide a possibility for the user to override this. Moreover, the value specified through bind_textdomain_codeset overrides both. */ if (domainbinding != NULL && domainbinding->codeset != NULL) outcharset = domainbinding->codeset; else { outcharset = getenv ("OUTPUT_CHARSET"); if (outcharset == NULL || outcharset[0] == '\0') { # ifdef _LIBC outcharset = _NL_CURRENT (LC_CTYPE, CODESET); # else # if HAVE_ICONV extern const char *locale_charset (void); outcharset = locale_charset (); # endif # endif } } # ifdef _LIBC /* We always want to use transliteration. */ outcharset = norm_add_slashes (outcharset, "TRANSLIT"); charset = norm_add_slashes (charset, NULL); if (__gconv_open (outcharset, charset, &domain->conv, GCONV_AVOID_NOCONV) != __GCONV_OK) domain->conv = (__gconv_t) -1; # else # if HAVE_ICONV /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5, we want to use transliteration. */ # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \ || _LIBICONV_VERSION >= 0x0105 if (strchr (outcharset, '/') == NULL) { char *tmp; len = strlen (outcharset); tmp = (char *) alloca (len + 10 + 1); memcpy (tmp, outcharset, len); memcpy (tmp + len, "//TRANSLIT", 10 + 1); outcharset = tmp; domain->conv = iconv_open (outcharset, charset); freea (outcharset); } else # endif domain->conv = iconv_open (outcharset, charset); # endif # endif freea (charset); } #endif /* _LIBC || HAVE_ICONV */ } return nullentry; }
static int compile_csharp_using_sscli (const char * const *sources, unsigned int sources_count, const char * const *libdirs, unsigned int libdirs_count, const char * const *libraries, unsigned int libraries_count, const char *output_file, bool output_is_library, bool optimize, bool debug, bool verbose) { static bool csc_tested; static bool csc_present; if (!csc_tested) { /* Test for presence of csc: "csc -help >/dev/null 2>/dev/null \ && ! { csc -help 2>/dev/null | grep -i chicken > /dev/null; }" */ char *argv[3]; pid_t child; int fd[1]; int exitstatus; argv[0] = "csc"; argv[1] = "-help"; argv[2] = NULL; child = create_pipe_in ("csc", "csc", argv, DEV_NULL, true, true, false, fd); csc_present = false; if (child != -1) { /* Read the subprocess output, and test whether it contains the string "chicken". */ char c[7]; size_t count = 0; csc_present = true; while (safe_read (fd[0], &c[count], 1) > 0) { if (c[count] >= 'A' && c[count] <= 'Z') c[count] += 'a' - 'A'; count++; if (count == 7) { if (memcmp (c, "chicken", 7) == 0) csc_present = false; c[0] = c[1]; c[1] = c[2]; c[2] = c[3]; c[3] = c[4]; c[4] = c[5]; c[5] = c[6]; count--; } } close (fd[0]); /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = wait_subprocess (child, "csc", false, true, true, false, NULL); if (exitstatus != 0) csc_present = false; } csc_tested = true; } if (csc_present) { unsigned int argc; char **argv; char **argp; int exitstatus; unsigned int i; argc = 1 + 1 + 1 + libdirs_count + libraries_count + (optimize ? 1 : 0) + (debug ? 1 : 0) + sources_count; argv = (char **) xmalloca ((argc + 1) * sizeof (char *)); argp = argv; *argp++ = "csc"; *argp++ = (char *) (output_is_library ? "-target:library" : "-target:exe"); { char *option = (char *) xmalloca (5 + strlen (output_file) + 1); memcpy (option, "-out:", 5); strcpy (option + 5, output_file); *argp++ = option; } for (i = 0; i < libdirs_count; i++) { char *option = (char *) xmalloca (5 + strlen (libdirs[i]) + 1); memcpy (option, "-lib:", 5); strcpy (option + 5, libdirs[i]); *argp++ = option; } for (i = 0; i < libraries_count; i++) { char *option = (char *) xmalloca (11 + strlen (libraries[i]) + 4 + 1); memcpy (option, "-reference:", 11); memcpy (option + 11, libraries[i], strlen (libraries[i])); strcpy (option + 11 + strlen (libraries[i]), ".dll"); *argp++ = option; } if (optimize) *argp++ = "-optimize+"; if (debug) *argp++ = "-debug+"; for (i = 0; i < sources_count; i++) { const char *source_file = sources[i]; if (strlen (source_file) >= 10 && memcmp (source_file + strlen (source_file) - 10, ".resources", 10) == 0) { char *option = (char *) xmalloca (10 + strlen (source_file) + 1); memcpy (option, "-resource:", 10); strcpy (option + 10, source_file); *argp++ = option; } else *argp++ = (char *) source_file; } *argp = NULL; /* Ensure argv length was correctly calculated. */ if (argp - argv != argc) abort (); if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } exitstatus = execute ("csc", "csc", argv, false, false, false, false, true, true, NULL); for (i = 2; i < 3 + libdirs_count + libraries_count; i++) freea (argv[i]); for (i = 0; i < sources_count; i++) if (argv[argc - sources_count + i] != sources[i]) freea (argv[argc - sources_count + i]); freea (argv); return (exitstatus != 0); } else return -1; }
msgdomain_list_ty * msgdomain_read_tcl (const char *locale_name, const char *directory) { const char *gettextdatadir; char *tclscript; size_t len; char *frobbed_locale_name; char *p; char *file_name; char *argv[4]; pid_t child; int fd[1]; FILE *fp; msgdomain_list_ty *mdlp; int exitstatus; size_t k; /* Make it possible to override the msgunfmt.tcl location. This is necessary for running the testsuite before "make install". */ gettextdatadir = getenv ("GETTEXTDATADIR"); if (gettextdatadir == NULL || gettextdatadir[0] == '\0') gettextdatadir = relocate (GETTEXTDATADIR); tclscript = xconcatenated_filename (gettextdatadir, "msgunfmt.tcl", NULL); /* Convert the locale name to lowercase and remove any encoding. */ len = strlen (locale_name); frobbed_locale_name = (char *) xmalloca (len + 1); memcpy (frobbed_locale_name, locale_name, len + 1); for (p = frobbed_locale_name; *p != '\0'; p++) if (*p >= 'A' && *p <= 'Z') *p = *p - 'A' + 'a'; else if (*p == '.') { *p = '\0'; break; } file_name = xconcatenated_filename (directory, frobbed_locale_name, ".msg"); freea (frobbed_locale_name); /* Prepare arguments. */ argv[0] = "tclsh"; argv[1] = tclscript; argv[2] = file_name; argv[3] = NULL; if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } /* Open a pipe to the Tcl interpreter. */ child = create_pipe_in ("tclsh", "tclsh", argv, DEV_NULL, false, true, true, fd); fp = fdopen (fd[0], "r"); if (fp == NULL) error (EXIT_FAILURE, errno, _("fdopen() failed")); /* Read the message list. */ mdlp = read_catalog_stream (fp, "(pipe)", "(pipe)", &input_format_po); fclose (fp); /* Remove zombie process from process list, and retrieve exit status. */ exitstatus = wait_subprocess (child, "tclsh", false, false, true, true, NULL); if (exitstatus != 0) { if (exitstatus == 2) /* Special exitcode provided by msgunfmt.tcl. */ error (EXIT_FAILURE, ENOENT, _("error while opening \"%s\" for reading"), file_name); else error (EXIT_FAILURE, 0, _("%s subprocess failed with exit code %d"), "tclsh", exitstatus); } free (tclscript); /* Move the header entry to the beginning. */ for (k = 0; k < mdlp->nitems; k++) { message_list_ty *mlp = mdlp->item[k]->messages; size_t j; for (j = 0; j < mlp->nitems; j++) if (is_header (mlp->item[j])) { /* Found the header entry. */ if (j > 0) { message_ty *header = mlp->item[j]; size_t i; for (i = j; i > 0; i--) mlp->item[i] = mlp->item[i - 1]; mlp->item[0] = header; } break; } } return mdlp; }
/* This function is used by `setenv' and `putenv'. The difference between the two functions is that for the former must create a new string which is then placed in the environment, while the argument of `putenv' must be used directly. This is all complicated by the fact that we try to reuse values once generated for a `setenv' call since we can never free the strings. */ int __add_to_environ (const char *name, const char *value, const char *combined, int replace) { register char **ep; register size_t size; const size_t namelen = strlen (name); const size_t vallen = value != NULL ? strlen (value) + 1 : 0; LOCK; /* We have to get the pointer now that we have the lock and not earlier since another thread might have created a new environment. */ ep = __environ; size = 0; if (ep != NULL) { for (; *ep != NULL; ++ep) if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') break; else ++size; } if (ep == NULL || *ep == NULL) { char **new_environ; #ifdef USE_TSEARCH char *new_value; #endif /* We allocated this space; we can extend it. */ new_environ = (char **) (last_environ == NULL ? malloc ((size + 2) * sizeof (char *)) : realloc (last_environ, (size + 2) * sizeof (char *))); if (new_environ == NULL) { UNLOCK; return -1; } /* If the whole entry is given add it. */ if (combined != NULL) /* We must not add the string to the search tree since it belongs to the user. */ new_environ[size] = (char *) combined; else { /* See whether the value is already known. */ #ifdef USE_TSEARCH # ifdef _LIBC new_value = (char *) alloca (namelen + 1 + vallen); __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), value, vallen); # else new_value = (char *) malloca (namelen + 1 + vallen); if (new_value == NULL) { __set_errno (ENOMEM); UNLOCK; return -1; } memcpy (new_value, name, namelen); new_value[namelen] = '='; memcpy (&new_value[namelen + 1], value, vallen); # endif new_environ[size] = KNOWN_VALUE (new_value); if (new_environ[size] == NULL) #endif { new_environ[size] = (char *) malloc (namelen + 1 + vallen); if (new_environ[size] == NULL) { #if defined USE_TSEARCH && !defined _LIBC freea (new_value); #endif __set_errno (ENOMEM); UNLOCK; return -1; } #ifdef USE_TSEARCH memcpy (new_environ[size], new_value, namelen + 1 + vallen); #else memcpy (new_environ[size], name, namelen); new_environ[size][namelen] = '='; memcpy (&new_environ[size][namelen + 1], value, vallen); #endif /* And save the value now. We cannot do this when we remove the string since then we cannot decide whether it is a user string or not. */ STORE_VALUE (new_environ[size]); } #if defined USE_TSEARCH && !defined _LIBC freea (new_value); #endif } if (__environ != last_environ) memcpy ((char *) new_environ, (char *) __environ, size * sizeof (char *)); new_environ[size + 1] = NULL; last_environ = __environ = new_environ; } else if (replace) { char *np; /* Use the user string if given. */ if (combined != NULL) np = (char *) combined; else { #ifdef USE_TSEARCH char *new_value; # ifdef _LIBC new_value = alloca (namelen + 1 + vallen); __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), value, vallen); # else new_value = malloca (namelen + 1 + vallen); if (new_value == NULL) { __set_errno (ENOMEM); UNLOCK; return -1; } memcpy (new_value, name, namelen); new_value[namelen] = '='; memcpy (&new_value[namelen + 1], value, vallen); # endif np = KNOWN_VALUE (new_value); if (np == NULL) #endif { np = malloc (namelen + 1 + vallen); if (np == NULL) { #if defined USE_TSEARCH && !defined _LIBC freea (new_value); #endif __set_errno (ENOMEM); UNLOCK; return -1; } #ifdef USE_TSEARCH memcpy (np, new_value, namelen + 1 + vallen); #else memcpy (np, name, namelen); np[namelen] = '='; memcpy (&np[namelen + 1], value, vallen); #endif /* And remember the value. */ STORE_VALUE (np); } #if defined USE_TSEARCH && !defined _LIBC freea (new_value); #endif } *ep = np; } UNLOCK; return 0; }
static int compile_csharp_using_pnet (const char * const *sources, unsigned int sources_count, const char * const *libdirs, unsigned int libdirs_count, const char * const *libraries, unsigned int libraries_count, const char *output_file, bool output_is_library, bool optimize, bool debug, bool verbose) { static bool cscc_tested; static bool cscc_present; if (!cscc_tested) { /* Test for presence of cscc: "cscc --version >/dev/null 2>/dev/null" */ char *argv[3]; int exitstatus; argv[0] = "cscc"; argv[1] = "--version"; argv[2] = NULL; exitstatus = execute ("cscc", "cscc", argv, false, false, true, true, true, false, NULL); cscc_present = (exitstatus == 0); cscc_tested = true; } if (cscc_present) { unsigned int argc; char **argv; char **argp; int exitstatus; unsigned int i; argc = 1 + (output_is_library ? 1 : 0) + 2 + 2 * libdirs_count + 2 * libraries_count + (optimize ? 1 : 0) + (debug ? 1 : 0) + sources_count; argv = (char **) xmalloca ((argc + 1) * sizeof (char *)); argp = argv; *argp++ = "cscc"; if (output_is_library) *argp++ = "-shared"; *argp++ = "-o"; *argp++ = (char *) output_file; for (i = 0; i < libdirs_count; i++) { *argp++ = "-L"; *argp++ = (char *) libdirs[i]; } for (i = 0; i < libraries_count; i++) { *argp++ = "-l"; *argp++ = (char *) libraries[i]; } if (optimize) *argp++ = "-O"; if (debug) *argp++ = "-g"; for (i = 0; i < sources_count; i++) { const char *source_file = sources[i]; if (strlen (source_file) >= 10 && memcmp (source_file + strlen (source_file) - 10, ".resources", 10) == 0) { char *option = (char *) xmalloca (12 + strlen (source_file) + 1); memcpy (option, "-fresources=", 12); strcpy (option + 12, source_file); *argp++ = option; } else *argp++ = (char *) source_file; } *argp = NULL; /* Ensure argv length was correctly calculated. */ if (argp - argv != argc) abort (); if (verbose) { char *command = shell_quote_argv (argv); printf ("%s\n", command); free (command); } exitstatus = execute ("cscc", "cscc", argv, false, false, false, false, true, true, NULL); for (i = 0; i < sources_count; i++) if (argv[argc - sources_count + i] != sources[i]) freea (argv[argc - sources_count + i]); freea (argv); return (exitstatus != 0); } else return -1; }
static bool knuth_morris_pratt_multibyte (const char *haystack, const char *needle, const char **resultp) { size_t m = mbslen (needle); mbchar_t *needle_mbchars; size_t *table; /* Allocate room for needle_mbchars and the table. */ char *memory = (char *) malloca (m * (sizeof (mbchar_t) + sizeof (size_t))); if (memory == NULL) return false; needle_mbchars = (mbchar_t *) memory; table = (size_t *) (memory + m * sizeof (mbchar_t)); /* Fill needle_mbchars. */ { mbui_iterator_t iter; size_t j; j = 0; for (mbui_init (iter, needle); mbui_avail (iter); mbui_advance (iter), j++) mb_copy (&needle_mbchars[j], &mbui_cur (iter)); } /* Fill the table. For 0 < i < m: 0 < table[i] <= i is defined such that rhaystack[0..i-1] == needle[0..i-1] and rhaystack[i] != needle[i] implies forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1], and table[i] is as large as possible with this property. table[0] remains uninitialized. */ { size_t i, j; table[1] = 1; j = 0; for (i = 2; i < m; i++) { mbchar_t *b = &needle_mbchars[i - 1]; for (;;) { if (mb_equal (*b, needle_mbchars[j])) { table[i] = i - ++j; break; } if (j == 0) { table[i] = i; break; } j = j - table[j]; } } } /* Search, using the table to accelerate the processing. */ { size_t j; mbui_iterator_t rhaystack; mbui_iterator_t phaystack; *resultp = NULL; j = 0; mbui_init (rhaystack, haystack); mbui_init (phaystack, haystack); /* Invariant: phaystack = rhaystack + j. */ while (mbui_avail (phaystack)) if (mb_equal (needle_mbchars[j], mbui_cur (phaystack))) { j++; mbui_advance (phaystack); if (j == m) { /* The entire needle has been found. */ *resultp = mbui_cur_ptr (rhaystack); break; } } else if (j > 0) { /* Found a match of needle[0..j-1], mismatch at needle[j]. */ size_t count = table[j]; j -= count; for (; count > 0; count--) { if (!mbui_avail (rhaystack)) abort (); mbui_advance (rhaystack); } } else { /* Found a mismatch at needle[0] already. */ if (!mbui_avail (rhaystack)) abort (); mbui_advance (rhaystack); mbui_advance (phaystack); } } freea (memory); return true; }
/* Load the message catalogs specified by FILENAME. If it is no valid message catalog do nothing. */ void internal_function _nl_load_domain (struct loaded_l10nfile *domain_file, struct binding *domainbinding) { int fd; size_t size; #ifdef _LIBC struct stat64 st; #else struct stat st; #endif struct mo_file_header *data = (struct mo_file_header *) -1; int use_mmap = 0; struct loaded_domain *domain; int revision; const char *nullentry; domain_file->decided = 1; domain_file->data = NULL; /* Note that it would be useless to store domainbinding in domain_file because domainbinding might be == NULL now but != NULL later (after a call to bind_textdomain_codeset). */ /* If the record does not represent a valid locale the FILENAME might be NULL. This can happen when according to the given specification the locale file name is different for XPG and CEN syntax. */ if (domain_file->filename == NULL) return; /* Try to open the addressed file. */ fd = open (domain_file->filename, O_RDONLY | O_BINARY); if (fd == -1) return; /* We must know about the size of the file. */ if ( #ifdef _LIBC __builtin_expect (fstat64 (fd, &st) != 0, 0) #else __builtin_expect (fstat (fd, &st) != 0, 0) #endif || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0) || __builtin_expect (size < sizeof (struct mo_file_header), 0)) { /* Something went wrong. */ close (fd); return; } #ifdef HAVE_MMAP /* Now we are ready to load the file. If mmap() is available we try this first. If not available or it failed we try to load it. */ data = (struct mo_file_header *) mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); if (__builtin_expect (data != (struct mo_file_header *) -1, 1)) { /* mmap() call was successful. */ close (fd); use_mmap = 1; } #endif /* If the data is not yet available (i.e. mmap'ed) we try to load it manually. */ if (data == (struct mo_file_header *) -1) { size_t to_read; char *read_ptr; data = (struct mo_file_header *) malloc (size); if (data == NULL) return; to_read = size; read_ptr = (char *) data; do { long int nb = (long int) read (fd, read_ptr, to_read); if (nb <= 0) { #ifdef EINTR if (nb == -1 && errno == EINTR) continue; #endif close (fd); return; } read_ptr += nb; to_read -= nb; } while (to_read > 0); close (fd); } /* Using the magic number we can test whether it really is a message catalog file. */ if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED, 0)) { /* The magic number is wrong: not a message catalog file. */ #ifdef HAVE_MMAP if (use_mmap) munmap ((caddr_t) data, size); else #endif free (data); return; } domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain)); if (domain == NULL) return; domain_file->data = domain; domain->data = (char *) data; domain->use_mmap = use_mmap; domain->mmap_size = size; domain->must_swap = data->magic != _MAGIC; domain->malloced = NULL; /* Fill in the information about the available tables. */ revision = W (domain->must_swap, data->revision); /* We support only the major revisions 0 and 1. */ switch (revision >> 16) { case 0: case 1: domain->nstrings = W (domain->must_swap, data->nstrings); domain->orig_tab = (const struct string_desc *) ((char *) data + W (domain->must_swap, data->orig_tab_offset)); domain->trans_tab = (const struct string_desc *) ((char *) data + W (domain->must_swap, data->trans_tab_offset)); domain->hash_size = W (domain->must_swap, data->hash_tab_size); domain->hash_tab = (domain->hash_size > 2 ? (const nls_uint32 *) ((char *) data + W (domain->must_swap, data->hash_tab_offset)) : NULL); domain->must_swap_hash_tab = domain->must_swap; /* Now dispatch on the minor revision. */ switch (revision & 0xffff) { case 0: domain->n_sysdep_strings = 0; domain->orig_sysdep_tab = NULL; domain->trans_sysdep_tab = NULL; break; case 1: default: { nls_uint32 n_sysdep_strings; if (domain->hash_tab == NULL) /* This is invalid. These minor revisions need a hash table. */ goto invalid; n_sysdep_strings = W (domain->must_swap, data->n_sysdep_strings); if (n_sysdep_strings > 0) { nls_uint32 n_sysdep_segments; const struct sysdep_segment *sysdep_segments; const char **sysdep_segment_values; const nls_uint32 *orig_sysdep_tab; const nls_uint32 *trans_sysdep_tab; nls_uint32 n_inmem_sysdep_strings; size_t memneed; char *mem; struct sysdep_string_desc *inmem_orig_sysdep_tab; struct sysdep_string_desc *inmem_trans_sysdep_tab; nls_uint32 *inmem_hash_tab; unsigned int i, j; /* Get the values of the system dependent segments. */ n_sysdep_segments = W (domain->must_swap, data->n_sysdep_segments); sysdep_segments = (const struct sysdep_segment *) ((char *) data + W (domain->must_swap, data->sysdep_segments_offset)); sysdep_segment_values = alloca (n_sysdep_segments * sizeof (const char *)); for (i = 0; i < n_sysdep_segments; i++) { const char *name = (char *) data + W (domain->must_swap, sysdep_segments[i].offset); nls_uint32 namelen = W (domain->must_swap, sysdep_segments[i].length); if (!(namelen > 0 && name[namelen - 1] == '\0')) { freea (sysdep_segment_values); goto invalid; } sysdep_segment_values[i] = get_sysdep_segment_value (name); } orig_sysdep_tab = (const nls_uint32 *) ((char *) data + W (domain->must_swap, data->orig_sysdep_tab_offset)); trans_sysdep_tab = (const nls_uint32 *) ((char *) data + W (domain->must_swap, data->trans_sysdep_tab_offset)); /* Compute the amount of additional memory needed for the system dependent strings and the augmented hash table. At the same time, also drop string pairs which refer to an undefined system dependent segment. */ n_inmem_sysdep_strings = 0; memneed = domain->hash_size * sizeof (nls_uint32); for (i = 0; i < n_sysdep_strings; i++) { int valid = 1; size_t needs[2]; for (j = 0; j < 2; j++) { const struct sysdep_string *sysdep_string = (const struct sysdep_string *) ((char *) data + W (domain->must_swap, j == 0 ? orig_sysdep_tab[i] : trans_sysdep_tab[i])); size_t need = 0; const struct segment_pair *p = sysdep_string->segments; if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END) for (p = sysdep_string->segments;; p++) { nls_uint32 sysdepref; need += W (domain->must_swap, p->segsize); sysdepref = W (domain->must_swap, p->sysdepref); if (sysdepref == SEGMENTS_END) break; if (sysdepref >= n_sysdep_segments) { /* Invalid. */ freea (sysdep_segment_values); goto invalid; } if (sysdep_segment_values[sysdepref] == NULL) { /* This particular string pair is invalid. */ valid = 0; break; } need += strlen (sysdep_segment_values[sysdepref]); } needs[j] = need; if (!valid) break; } if (valid) { n_inmem_sysdep_strings++; memneed += needs[0] + needs[1]; } } memneed += 2 * n_inmem_sysdep_strings * sizeof (struct sysdep_string_desc); if (n_inmem_sysdep_strings > 0) { unsigned int k; /* Allocate additional memory. */ mem = (char *) malloc (memneed); if (mem == NULL) goto invalid; domain->malloced = mem; inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem; mem += n_inmem_sysdep_strings * sizeof (struct sysdep_string_desc); inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem; mem += n_inmem_sysdep_strings * sizeof (struct sysdep_string_desc); inmem_hash_tab = (nls_uint32 *) mem; mem += domain->hash_size * sizeof (nls_uint32); /* Compute the system dependent strings. */ k = 0; for (i = 0; i < n_sysdep_strings; i++) { int valid = 1; for (j = 0; j < 2; j++) { const struct sysdep_string *sysdep_string = (const struct sysdep_string *) ((char *) data + W (domain->must_swap, j == 0 ? orig_sysdep_tab[i] : trans_sysdep_tab[i])); const struct segment_pair *p = sysdep_string->segments; if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END) for (p = sysdep_string->segments;; p++) { nls_uint32 sysdepref; sysdepref = W (domain->must_swap, p->sysdepref); if (sysdepref == SEGMENTS_END) break; if (sysdep_segment_values[sysdepref] == NULL) { /* This particular string pair is invalid. */ valid = 0; break; } } if (!valid) break; } if (valid) { for (j = 0; j < 2; j++) { const struct sysdep_string *sysdep_string = (const struct sysdep_string *) ((char *) data + W (domain->must_swap, j == 0 ? orig_sysdep_tab[i] : trans_sysdep_tab[i])); const char *static_segments = (char *) data + W (domain->must_swap, sysdep_string->offset); const struct segment_pair *p = sysdep_string->segments; /* Concatenate the segments, and fill inmem_orig_sysdep_tab[k] (for j == 0) and inmem_trans_sysdep_tab[k] (for j == 1). */ struct sysdep_string_desc *inmem_tab_entry = (j == 0 ? inmem_orig_sysdep_tab : inmem_trans_sysdep_tab) + k; if (W (domain->must_swap, p->sysdepref) == SEGMENTS_END) { /* Only one static segment. */ inmem_tab_entry->length = W (domain->must_swap, p->segsize); inmem_tab_entry->pointer = static_segments; } else { inmem_tab_entry->pointer = mem; for (p = sysdep_string->segments;; p++) { nls_uint32 segsize = W (domain->must_swap, p->segsize); nls_uint32 sysdepref = W (domain->must_swap, p->sysdepref); size_t n; if (segsize > 0) { memcpy (mem, static_segments, segsize); mem += segsize; static_segments += segsize; } if (sysdepref == SEGMENTS_END) break; n = strlen (sysdep_segment_values[sysdepref]); memcpy (mem, sysdep_segment_values[sysdepref], n); mem += n; } inmem_tab_entry->length = mem - inmem_tab_entry->pointer; } } k++; } } if (k != n_inmem_sysdep_strings) abort (); /* Compute the augmented hash table. */ for (i = 0; i < domain->hash_size; i++) inmem_hash_tab[i] = W (domain->must_swap_hash_tab, domain->hash_tab[i]); for (i = 0; i < n_inmem_sysdep_strings; i++) { const char *msgid = inmem_orig_sysdep_tab[i].pointer; nls_uint32 hash_val = hash_string (msgid); nls_uint32 idx = hash_val % domain->hash_size; nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2)); for (;;) { if (inmem_hash_tab[idx] == 0) { /* Hash table entry is empty. Use it. */ inmem_hash_tab[idx] = 1 + domain->nstrings + i; break; } if (idx >= domain->hash_size - incr) idx -= domain->hash_size - incr; else idx += incr; } } domain->n_sysdep_strings = n_inmem_sysdep_strings; domain->orig_sysdep_tab = inmem_orig_sysdep_tab; domain->trans_sysdep_tab = inmem_trans_sysdep_tab; domain->hash_tab = inmem_hash_tab; domain->must_swap_hash_tab = 0; } else { domain->n_sysdep_strings = 0; domain->orig_sysdep_tab = NULL; domain->trans_sysdep_tab = NULL; } freea (sysdep_segment_values); } else { domain->n_sysdep_strings = 0; domain->orig_sysdep_tab = NULL; domain->trans_sysdep_tab = NULL; } } break; } break; default: /* This is an invalid revision. */ invalid: /* This is an invalid .mo file. */ if (domain->malloced) free (domain->malloced); #ifdef HAVE_MMAP if (use_mmap) munmap ((caddr_t) data, size); else #endif free (data); free (domain); domain_file->data = NULL; return; } /* Now initialize the character set converter from the character set the file is encoded with (found in the header entry) to the domain's specified character set or the locale's character set. */ nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding); /* Also look for a plural specification. */ EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals); }
static bool knuth_morris_pratt_unibyte (const char *haystack, const char *needle, const char **resultp) { size_t m = strlen (needle); /* Allocate the table. */ size_t *table = (size_t *) malloca (m * sizeof (size_t)); if (table == NULL) return false; /* Fill the table. For 0 < i < m: 0 < table[i] <= i is defined such that rhaystack[0..i-1] == needle[0..i-1] and rhaystack[i] != needle[i] implies forall 0 <= x < table[i]: rhaystack[x..x+m-1] != needle[0..m-1], and table[i] is as large as possible with this property. table[0] remains uninitialized. */ { size_t i, j; table[1] = 1; j = 0; for (i = 2; i < m; i++) { unsigned char b = (unsigned char) needle[i - 1]; for (;;) { if (b == (unsigned char) needle[j]) { table[i] = i - ++j; break; } if (j == 0) { table[i] = i; break; } j = j - table[j]; } } } /* Search, using the table to accelerate the processing. */ { size_t j; const char *rhaystack; const char *phaystack; *resultp = NULL; j = 0; rhaystack = haystack; phaystack = haystack; /* Invariant: phaystack = rhaystack + j. */ while (*phaystack != '\0') if ((unsigned char) needle[j] == (unsigned char) *phaystack) { j++; phaystack++; if (j == m) { /* The entire needle has been found. */ *resultp = rhaystack; break; } } else if (j > 0) { /* Found a match of needle[0..j-1], mismatch at needle[j]. */ rhaystack += table[j]; j -= table[j]; } else { /* Found a mismatch at needle[0] already. */ rhaystack++; phaystack++; } } freea (table); return true; }