Fix #70112 RFE Allow dirname to go up various times
authorRemi Collet <fedora@famillecollet.com>
Sat, 25 Jul 2015 14:58:36 +0000 (16:58 +0200)
committerRemi Collet <remi@php.net>
Mon, 27 Jul 2015 13:23:04 +0000 (15:23 +0200)
ext/standard/basic_functions.c
ext/standard/string.c
ext/standard/tests/strings/dirname_error.phpt
ext/standard/tests/strings/dirname_multi.phpt [new file with mode: 0644]

index 488b71b900e4b2f6de73dc8edd195123aa31893c..3f03275aa59252f037504d407e5dafbd9d35905d 100644 (file)
@@ -2213,8 +2213,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_basename, 0, 0, 1)
        ZEND_ARG_INFO(0, suffix)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO(arginfo_dirname, 0)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_dirname, 0, 0, 1)
        ZEND_ARG_INFO(0, path)
+       ZEND_ARG_INFO(0, levels)
 ZEND_END_ARG_INFO()
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_pathinfo, 0, 0, 1)
index 2a9ddb2a180b85feca3de464ff9aa54afb71e361..143c6f636c3c5451e8913fea4eddc67b9d39452b 100644 (file)
@@ -1648,21 +1648,36 @@ PHPAPI size_t php_dirname(char *path, size_t len)
 }
 /* }}} */
 
-/* {{{ proto string dirname(string path)
+/* {{{ proto string dirname(string path[, int levels])
    Returns the directory name component of the path */
 PHP_FUNCTION(dirname)
 {
        char *str;
        zend_string *ret;
        size_t str_len;
+       zend_long levels = 1;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &levels) == FAILURE) {
                return;
        }
 
        ret = zend_string_init(str, str_len, 0);
-       ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len);
 
+       if (levels == 1) {
+               /* Defaut case */
+               ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len);
+
+       } else if (levels < 1) {
+               php_error_docref(NULL, E_WARNING, "Invalid argument, levels must be >= 1");
+               return;
+
+
+       } else {
+               /* Some levels up */
+               do {
+                       ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len=ZSTR_LEN(ret));
+               } while (ZSTR_LEN(ret)<str_len && --levels>0);
+       }
        RETURN_NEW_STR(ret);
 }
 /* }}} */
index bf6310283b47bae577328c6f458b40aebae5072b..303a59b2d57c601476fcfc867a53a6420839785b 100644 (file)
@@ -9,17 +9,23 @@ echo "*** Testing error conditions ***\n";
 // zero arguments 
 var_dump( dirname() );
 
+// Bad arg
+var_dump( dirname("/var/tmp/bar.gz", 0) );
+
 // more than expected no. of arguments
-var_dump( dirname("/var/tmp/bar.gz", ".gz") );
+var_dump( dirname("/var/tmp/bar.gz", 1, ".gz") );
 
 echo "Done\n";
 ?>
 --EXPECTF--
 *** Testing error conditions ***
 
-Warning: dirname() expects exactly 1 parameter, 0 given in %s on line %d
+Warning: dirname() expects at least 1 parameter, 0 given in %s on line %d
+NULL
+
+Warning: dirname(): Invalid argument, levels must be >= 1 in %s on line %d
 NULL
 
-Warning: dirname() expects exactly 1 parameter, 2 given in %s on line %d
+Warning: dirname() expects at most 2 parameters, 3 given in %s on line %d
 NULL
 Done
diff --git a/ext/standard/tests/strings/dirname_multi.phpt b/ext/standard/tests/strings/dirname_multi.phpt
new file mode 100644 (file)
index 0000000..d0fdfac
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Test dirname() function : usage variations
+--FILE--
+<?php
+/* Prototype: string dirname ( string $path [, int nb]);
+   Description: Returns directory name component of path.
+*/
+for ($i=1 ; $i<5 ; $i++) {
+       var_dump(dirname("/foo/bar/baz", $i));
+}
+var_dump(dirname("/foo/bar/baz", PHP_INT_MAX));
+?>
+Done
+--EXPECT--
+string(8) "/foo/bar"
+string(4) "/foo"
+string(1) "/"
+string(1) "/"
+string(1) "/"
+Done