Skip to content

Instantly share code, notes, and snippets.

@xeioex
Created February 19, 2019 18:06
Show Gist options
  • Save xeioex/4f4ab80ff7286324332c69cb04dae3fa to your computer and use it in GitHub Desktop.
Save xeioex/4f4ab80ff7286324332c69cb04dae3fa to your computer and use it in GitHub Desktop.
# HG changeset patch
# User Dmitry Volyntsev <[email protected]>
# Date 1550599519 -10800
# Tue Feb 19 21:05:19 2019 +0300
# Node ID 175bc9cc32830302cc65d589cd428d26d1bbe07d
# Parent bb8b8d00b96910dc55e958687d7258d312e05912
Introduced nxt_file_basename() and nxt_file_dirname().
diff --git a/njs/njs_shell.c b/njs/njs_shell.c
--- a/njs/njs_shell.c
+++ b/njs/njs_shell.c
@@ -216,7 +216,9 @@ main(int argc, char **argv)
if (!opts.quiet) {
if (opts.file != NULL) {
- nxt_file_name(&vm_options.file, opts.file);
+ vm_options.file.start = (u_char *) opts.file;
+ vm_options.file.length = strlen(opts.file);
+ nxt_file_basename(&vm_options.file, &vm_options.file);
} else {
vm_options.file = nxt_string_value("shell");
diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c
+++ b/njs/test/njs_unit_test.c
@@ -12009,6 +12009,96 @@ njs_vm_object_alloc_test(njs_vm_t * vm,
}
+static nxt_int_t
+nxt_file_basename_test(njs_vm_t * vm, nxt_bool_t disassemble,
+ nxt_bool_t verbose)
+{
+ nxt_str_t name;
+ nxt_bool_t success;
+ nxt_uint_t i;
+
+ static const struct {
+ nxt_str_t path;
+ nxt_str_t expected;
+ } tests[] = {
+ { nxt_string(""), nxt_string("") },
+ { nxt_string("/"), nxt_string("") },
+ { nxt_string("/a"), nxt_string("a") },
+ { nxt_string("///"), nxt_string("") },
+ { nxt_string("///a"), nxt_string("a") },
+ { nxt_string("///a/"), nxt_string("") },
+ { nxt_string("a"), nxt_string("a") },
+ { nxt_string("a/"), nxt_string("") },
+ { nxt_string("a//"), nxt_string("") },
+ { nxt_string("path/name"), nxt_string("name") },
+ { nxt_string("/path/name"), nxt_string("name") },
+ { nxt_string("/path/name/"), nxt_string("") },
+ };
+
+ for (i = 0; i < nxt_nitems(tests); i++) {
+ nxt_file_basename(&tests[i].path, &name);
+
+ success = nxt_strstr_eq(&tests[i].expected, &name);
+
+ if (!success) {
+ printf("nxt_file_basename_test(\"%.*s\"):\n"
+ "expected: \"%.*s\"\n got: \"%.*s\"\n",
+ (int) tests[i].path.length, tests[i].path.start,
+ (int) tests[i].expected.length, tests[i].expected.start,
+ (int) name.length, name.start);
+ return NXT_ERROR;
+ }
+ }
+
+ return NXT_OK;
+}
+
+
+static nxt_int_t
+nxt_file_dirname_test(njs_vm_t * vm, nxt_bool_t disassemble,
+ nxt_bool_t verbose)
+{
+ nxt_str_t name;
+ nxt_bool_t success;
+ nxt_uint_t i;
+
+ static const struct {
+ nxt_str_t path;
+ nxt_str_t expected;
+ } tests[] = {
+ { nxt_string(""), nxt_string("") },
+ { nxt_string("/"), nxt_string("/") },
+ { nxt_string("/a"), nxt_string("/") },
+ { nxt_string("///"), nxt_string("///") },
+ { nxt_string("///a"), nxt_string("///") },
+ { nxt_string("///a/"), nxt_string("///a") },
+ { nxt_string("a"), nxt_string("") },
+ { nxt_string("a/"), nxt_string("a") },
+ { nxt_string("a//"), nxt_string("a") },
+ { nxt_string("p1/p2/name"), nxt_string("p1/p2") },
+ { nxt_string("/p1/p2/name"), nxt_string("/p1/p2") },
+ { nxt_string("/p1/p2/name/"), nxt_string("/p1/p2/name") },
+ };
+
+ for (i = 0; i < nxt_nitems(tests); i++) {
+ nxt_file_dirname(&tests[i].path, &name);
+
+ success = nxt_strstr_eq(&tests[i].expected, &name);
+
+ if (!success) {
+ printf("nxt_file_dirname_test(\"%.*s\"):\n"
+ "expected: \"%.*s\"\n got: \"%.*s\"\n",
+ (int) tests[i].path.length, tests[i].path.start,
+ (int) tests[i].expected.length, tests[i].expected.start,
+ (int) name.length, name.start);
+ return NXT_ERROR;
+ }
+ }
+
+ return NXT_OK;
+}
+
+
typedef struct {
nxt_int_t (*test)(njs_vm_t *, nxt_bool_t, nxt_bool_t);
nxt_str_t name;
@@ -12024,10 +12114,13 @@ njs_api_test(nxt_bool_t disassemble, nxt
njs_vm_opt_t options;
njs_api_test_t *test;
- static njs_api_test_t njs_api_test[] =
- {
+ static njs_api_test_t njs_api_test[] = {
{ njs_vm_object_alloc_test,
- nxt_string("njs_vm_object_alloc_test") }
+ nxt_string("njs_vm_object_alloc_test") },
+ { nxt_file_basename_test,
+ nxt_string("nxt_file_basename_test") },
+ { nxt_file_dirname_test,
+ nxt_string("nxt_file_dirname_test") },
};
rc = NXT_ERROR;
diff --git a/nxt/nxt_file.c b/nxt/nxt_file.c
--- a/nxt/nxt_file.c
+++ b/nxt/nxt_file.c
@@ -14,20 +14,70 @@
void
-nxt_file_name(nxt_str_t *name, char *path)
+nxt_file_basename(const nxt_str_t *path, nxt_str_t *name)
{
- char *p;
- size_t length;
+ const u_char *p, *end;
- length = strlen(path);
+ end = path->start + path->length;
+ p = end - 1;
- for (p = path + length; p >= path; p--) {
- if (*p == '/') {
- p++;
- break;
+ /* Stripping dir prefix. */
+
+ while (p >= path->start && *p != '/') { p--; }
+
+ p++;
+
+ name->start = (u_char *) p;
+ name->length = end - p;
+}
+
+
+void
+nxt_file_dirname(const nxt_str_t *path, nxt_str_t *name)
+{
+ const u_char *p, *end;
+
+ if (path->length == 0) {
+ *name = nxt_string_value("");
+ return;
+ }
+
+ p = path->start + path->length - 1;
+
+ if (*p == '/') {
+
+ /* Stripping trailing slashes. */
+
+ while (p >= path->start && *p == '/') { p--; }
+
+ end = p + 1;
+
+ if (end == path->start) {
+ *name = *path;
+ return;
+ }
+
+ } else {
+
+ /* Stripping basename. */
+
+ while (p >= path->start && *p != '/') { p--; }
+
+ end = p + 1;
+
+ if (end == path->start) {
+ *name = nxt_string_value("");
+ return;
+ }
+
+ while (p >= path->start && *p == '/') { p--; }
+
+ if (p != path->start - 1) {
+ /* Parent dir exists: stripping last slash. */
+ end--;
}
}
- name->start = (u_char *) p;
- name->length = length - (p - path);
+ name->start = path->start;
+ name->length = end - path->start;
}
diff --git a/nxt/nxt_file.h b/nxt/nxt_file.h
--- a/nxt/nxt_file.h
+++ b/nxt/nxt_file.h
@@ -8,7 +8,8 @@
#define _NXT_FILE_H_INCLUDED_
-void nxt_file_name(nxt_str_t *name, char *path);
+void nxt_file_basename(const nxt_str_t *path, nxt_str_t *name);
+void nxt_file_dirname(const nxt_str_t *path, nxt_str_t *name);
#endif /* _NXT_FILE_H_INCLUDED_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment