/* Parse one revision specification. Return pointer to character after revision, or NULL if the revision is invalid. Modifies str, so make sure to pass a copy of anything precious. Uses POOL for temporary allocation. */ static char *parse_one_rev(svn_opt_revision_t *revision, char *str, apr_pool_t *pool) { char *end, save; /* Allow any number of 'r's to prefix a revision number, because that way if a script pastes svn output into another svn command (like "svn log -r${REV_COPIED_FROM_OUTPUT}"), it'll Just Work, even when compounded. As it happens, none of our special revision words begins with "r". If any ever do, then this code will have to get smarter. Incidentally, this allows "r{DATE}". We could avoid that with some trivial code rearrangement, but it's not clear what would be gained by doing so. */ while (*str == 'r') str++; if (*str == '{') { svn_boolean_t matched; apr_time_t tm; svn_error_t *err; /* Brackets denote a date. */ str++; end = strchr(str, '}'); if (!end) return NULL; *end = '\0'; err = svn_parse_date(&matched, &tm, str, apr_time_now(), pool); if (err) { svn_error_clear(err); return NULL; } if (!matched) return NULL; revision->kind = svn_opt_revision_date; revision->value.date = tm; return end + 1; } else if (svn_ctype_isdigit(*str)) { /* It's a number. */ end = str + 1; while (svn_ctype_isdigit(*end)) end++; save = *end; *end = '\0'; revision->kind = svn_opt_revision_number; revision->value.number = SVN_STR_TO_REV(str); *end = save; return end; } else if (svn_ctype_isalpha(*str)) { end = str + 1; while (svn_ctype_isalpha(*end)) end++; save = *end; *end = '\0'; if (revision_from_word(revision, str) != 0) return NULL; *end = save; return end; } else return NULL; }
/* Standard svn test program */ int main(int argc, const char *argv[]) { const char *prog_name; int i; svn_boolean_t got_error = FALSE; apr_pool_t *pool, *test_pool; svn_boolean_t ran_a_test = FALSE; svn_boolean_t list_mode = FALSE; int opt_id; apr_status_t apr_err; apr_getopt_t *os; svn_error_t *err; char errmsg[200]; /* How many tests are there? */ int array_size = get_array_size(); svn_test_opts_t opts = { NULL }; opts.fs_type = DEFAULT_FS_TYPE; /* Initialize APR (Apache pools) */ if (apr_initialize() != APR_SUCCESS) { printf("apr_initialize() failed.\n"); exit(1); } /* set up the global pool. Use a separate allocator to limit memory * usage but make it thread-safe to allow for multi-threaded tests. */ pool = apr_allocator_owner_get(svn_pool_create_allocator(TRUE)); /* Remember the command line */ test_argc = argc; test_argv = argv; err = svn_cmdline__getopt_init(&os, argc, argv, pool); os->interleave = TRUE; /* Let options and arguments be interleaved */ /* Strip off any leading path components from the program name. */ prog_name = strrchr(argv[0], '/'); if (prog_name) prog_name++; else { /* Just check if this is that weird platform that uses \ instead of / for the path separator. */ prog_name = strrchr(argv[0], '\\'); if (prog_name) prog_name++; else prog_name = argv[0]; } if (err) return svn_cmdline_handle_exit_error(err, pool, prog_name); while (1) { const char *opt_arg; /* Parse the next option. */ apr_err = apr_getopt_long(os, cl_options, &opt_id, &opt_arg); if (APR_STATUS_IS_EOF(apr_err)) break; else if (apr_err && (apr_err != APR_BADCH)) { /* Ignore invalid option error to allow passing arbitary options */ fprintf(stderr, "apr_getopt_long failed : [%d] %s\n", apr_err, apr_strerror(apr_err, errmsg, sizeof(errmsg))); exit(1); } switch (opt_id) { case cleanup_opt: cleanup_mode = TRUE; break; case config_opt: opts.config_file = apr_pstrdup(pool, opt_arg); break; case fstype_opt: opts.fs_type = apr_pstrdup(pool, opt_arg); break; case list_opt: list_mode = TRUE; break; case mode_filter_opt: if (svn_cstring_casecmp(opt_arg, "PASS") == 0) mode_filter = svn_test_pass; else if (svn_cstring_casecmp(opt_arg, "XFAIL") == 0) mode_filter = svn_test_xfail; else if (svn_cstring_casecmp(opt_arg, "SKIP") == 0) mode_filter = svn_test_skip; else if (svn_cstring_casecmp(opt_arg, "ALL") == 0) mode_filter = svn_test_all; else { fprintf(stderr, "FAIL: Invalid --mode-filter option. Try "); fprintf(stderr, " PASS, XFAIL, SKIP or ALL.\n"); exit(1); } break; case verbose_opt: verbose_mode = TRUE; break; case quiet_opt: quiet_mode = TRUE; break; case allow_segfault_opt: allow_segfaults = TRUE; break; case server_minor_version_opt: { char *end; opts.server_minor_version = (int) strtol(opt_arg, &end, 10); if (end == opt_arg || *end != '\0') { fprintf(stderr, "FAIL: Non-numeric minor version given\n"); exit(1); } if ((opts.server_minor_version < 3) || (opts.server_minor_version > 6)) { fprintf(stderr, "FAIL: Invalid minor version given\n"); exit(1); } } } } /* Disable sleeping for timestamps, to speed up the tests. */ apr_env_set( "SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_SLEEP_FOR_TIMESTAMPS", "yes", pool); /* You can't be both quiet and verbose. */ if (quiet_mode && verbose_mode) { fprintf(stderr, "FAIL: --verbose and --quiet are mutually exclusive\n"); exit(1); } /* Create an iteration pool for the tests */ cleanup_pool = svn_pool_create(pool); test_pool = svn_pool_create(pool); if (!allow_segfaults) svn_error_set_malfunction_handler(svn_error_raise_on_malfunction); if (argc >= 2) /* notice command-line arguments */ { if (! strcmp(argv[1], "list") || list_mode) { const char *header_msg; ran_a_test = TRUE; /* run all tests with MSG_ONLY set to TRUE */ header_msg = "Test # Mode Test Description\n" "------ ----- ----------------\n"; for (i = 1; i <= array_size; i++) { if (do_test_num(prog_name, i, TRUE, &opts, &header_msg, test_pool)) got_error = TRUE; /* Clear the per-function pool */ svn_pool_clear(test_pool); svn_pool_clear(cleanup_pool); } } else { for (i = 1; i < argc; i++) { if (svn_ctype_isdigit(argv[i][0]) || argv[i][0] == '-') { int test_num = atoi(argv[i]); if (test_num == 0) /* A --option argument, most likely. */ continue; ran_a_test = TRUE; if (do_test_num(prog_name, test_num, FALSE, &opts, NULL, test_pool)) got_error = TRUE; /* Clear the per-function pool */ svn_pool_clear(test_pool); svn_pool_clear(cleanup_pool); } } } } if (! ran_a_test) { /* just run all tests */ for (i = 1; i <= array_size; i++) { if (do_test_num(prog_name, i, FALSE, &opts, NULL, test_pool)) got_error = TRUE; /* Clear the per-function pool */ svn_pool_clear(test_pool); svn_pool_clear(cleanup_pool); } } /* Clean up APR */ svn_pool_destroy(pool); /* takes test_pool with it */ apr_terminate(); return got_error; }
/* Read and parse an old-style 'entries' file in the administrative area of PATH, filling in ENTRIES with the contents. The results will be allocated in RESULT_POOL, and temporary allocations will be made in SCRATCH_POOL. */ svn_error_t * svn_wc__read_entries_old(apr_hash_t **entries, const char *dir_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { char *curp; const char *endp; svn_wc_entry_t *entry; svn_stream_t *stream; svn_string_t *buf; *entries = apr_hash_make(result_pool); /* Open the entries file. */ SVN_ERR(svn_wc__open_adm_stream(&stream, dir_abspath, SVN_WC__ADM_ENTRIES, scratch_pool, scratch_pool)); SVN_ERR(svn_string_from_stream(&buf, stream, scratch_pool, scratch_pool)); /* We own the returned data; it is modifiable, so cast away... */ curp = (char *)buf->data; endp = buf->data + buf->len; /* If the first byte of the file is not a digit, then it is probably in XML format. */ if (curp != endp && !svn_ctype_isdigit(*curp)) SVN_ERR(parse_entries_xml(dir_abspath, *entries, buf->data, buf->len, result_pool, scratch_pool)); else { int entryno, entries_format; const char *val; /* Read the format line from the entries file. In case we're in the middle of upgrading a working copy, this line will contain the original format pre-upgrade. */ SVN_ERR(read_val(&val, &curp, endp)); if (val) entries_format = (int)apr_strtoi64(val, NULL, 0); else return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, _("Invalid version line in entries file " "of '%s'"), svn_dirent_local_style(dir_abspath, scratch_pool)); entryno = 1; while (curp != endp) { svn_error_t *err = read_entry(&entry, &curp, endp, entries_format, result_pool); if (! err) { /* We allow extra fields at the end of the line, for extensibility. */ curp = memchr(curp, '\f', endp - curp); if (! curp) err = svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Missing entry terminator")); if (! err && (curp == endp || *(++curp) != '\n')) err = svn_error_create(SVN_ERR_WC_CORRUPT, NULL, _("Invalid entry terminator")); } if (err) return svn_error_createf(err->apr_err, err, _("Error at entry %d in entries file for " "'%s':"), entryno, svn_dirent_local_style(dir_abspath, scratch_pool)); ++curp; ++entryno; svn_hash_sets(*entries, entry->name, entry); } } /* Fill in any implied fields. */ return svn_error_trace(resolve_to_defaults(*entries, result_pool)); }