Index: global/global.c
===================================================================
RCS file: /sources/global/global/global/global.c,v
retrieving revision 1.295
diff -c -r1.295 global.c
*** global/global.c	9 Apr 2015 23:03:42 -0000	1.295
--- global/global.c	28 May 2015 14:12:36 -0000
***************
*** 86,91 ****
--- 86,92 ----
  int Lflag;				/* [option]		*/
  int Mflag;				/* [option]		*/
  int nflag;				/* [option]		*/
+ int Nflag;				/* [option]		*/
  int oflag;				/* [option]		*/
  int Oflag;				/* [option]		*/
  int pflag;				/* command		*/
***************
*** 104,109 ****
--- 105,111 ----
  int show_help;
  int nofilter;
  int nosource;				/**< undocumented command */
+ int nearsort;				/**< nearness sort */
  int debug;
  int literal;				/**< 1: literal search	*/
  int print0;				/**< @OPTION{-print0} option	*/
***************
*** 175,180 ****
--- 177,183 ----
  	{"file-list", required_argument, NULL, 'L'},
  	{"match-case", no_argument, NULL, 'M'},
  	{"nofilter", optional_argument, NULL, 'n'},
+ 	{"nearest", optional_argument, NULL, 'N'},
  	{"grep", no_argument, NULL, 'g'},
  	{"basic-regexp", no_argument, NULL, 'G'},
  	{"ignore-case", no_argument, NULL, 'i'},
***************
*** 204,209 ****
--- 207,213 ----
  	{"gtagslabel", required_argument, NULL, OPT_GTAGSLABEL},
  	{"literal", no_argument, &literal, 1},
  	{"match-part", required_argument, NULL, OPT_MATCH_PART},
+ 	{"near-sort", no_argument, &nearsort, 1},
  	{"path-style", required_argument, NULL, OPT_PATH_STYLE},
  	{"path-convert", required_argument, NULL, OPT_PATH_CONVERT},
  	{"print0", no_argument, &print0, 1},
***************
*** 391,397 ****
  	openconf(root);
  	setenv_from_config();
  	logging_arguments(argc, argv);
! 	while ((optchar = getopt_long(argc, argv, "acde:EifFgGIlL:MnoOpPqrsS:tTuvVx", long_options, &option_index)) != EOF) {
  		switch (optchar) {
  		case 0:
  			break;
--- 395,401 ----
  	openconf(root);
  	setenv_from_config();
  	logging_arguments(argc, argv);
! 	while ((optchar = getopt_long(argc, argv, "acde:EifFgGIlL:MnNoOpPqrsS:tTuvVx", long_options, &option_index)) != EOF) {
  		switch (optchar) {
  		case 0:
  			break;
***************
*** 455,460 ****
--- 459,467 ----
  				nofilter = BOTH_FILTER;
  			}
  			break;
+ 		case 'N':
+ 			Nflag++;
+ 			break;
  		case 'o':
  			oflag++;
  			break;
***************
*** 1707,1712 ****
--- 1714,1721 ----
  	 */
  	if (nofilter & SORT_FILTER)
  		flags |= GTOP_NOSORT;
+ 	else if (nearsort)
+ 		flags |= GTOP_NEARSORT;
  	if (literal)
  		flags |= GTOP_NOREGEX;
  	else if (Gflag)
***************
*** 1760,1768 ****
--- 1769,1797 ----
  	/*
  	 * search in current source tree.
  	 */
+ heuristic_retry:
  	count = search(pattern, root, cwd, dbpath, db);
  	total += count;
  	/*
+ 	 * Heuristic nearest tag search (-N option)
+ 	 *
+ 	 * At the first time, global(1) executes a local search normally,
+ 	 * but if no tags are found, it goes up one directory and repeat
+ 	 * this process till at least 1 definition is found.
+ 	 */
+ 	if (count == 0 && Sflag && Nflag && strlen(localprefix) > strlen("./")) {
+ 		/*
+ 		 * localprefix must start with './' and end with '/'.
+ 		 */
+ 		char *p = localprefix + strlen(localprefix) - 1;
+ 		while (*--p != '/' && p > localprefix)
+ 			;
+ 		if (*p != '/')
+ 			die("tagsearch: Impossible");
+ 		*(p + 1)= '\0';
+ 		goto heuristic_retry;
+ 	}
+ 	/*
  	 * search in library path.
  	 */
  	if (abslib)
Index: libutil/getdbpath.c
===================================================================
RCS file: /sources/global/global/libutil/getdbpath.c,v
retrieving revision 1.34
diff -c -r1.34 getdbpath.c
*** libutil/getdbpath.c	16 Mar 2015 02:24:53 -0000	1.34
--- libutil/getdbpath.c	28 May 2015 14:12:38 -0000
***************
*** 191,196 ****
--- 191,197 ----
  static char root[MAXPATHLEN];
  static char root_with_slash[MAXPATHLEN];
  static char cwd[MAXPATHLEN];
+ static char relative_cwd_with_slash[MAXPATHLEN+2];
  /**
   * setupdbpath: setup dbpath directory
   *
***************
*** 332,337 ****
--- 333,343 ----
  		strlimcpy(root_with_slash, root, sizeof(root_with_slash));
  	else
  		snprintf(root_with_slash, sizeof(root_with_slash), "%s/", root);
+ 	/*
+ 	 * relative from the project root directory.
+ 	 */
+ 	snprintf(relative_cwd_with_slash,
+ 		sizeof(relative_cwd_with_slash), "./%s/", cwd + strlen(root) + 1);
  	return 0;
  }
  /**
***************
*** 374,379 ****
--- 380,390 ----
  {
  	return (const char *)cwd;
  }
+ const char *
+ get_relative_cwd_with_slash(void)
+ {
+ 	return (const char *)relative_cwd_with_slash;
+ }
  void
  dump_dbpath(void)
  {
Index: libutil/getdbpath.h
===================================================================
RCS file: /sources/global/global/libutil/getdbpath.h,v
retrieving revision 1.14
diff -c -r1.14 getdbpath.h
*** libutil/getdbpath.h	27 Jun 2014 22:34:12 -0000	1.14
--- libutil/getdbpath.h	28 May 2015 14:12:38 -0000
***************
*** 31,36 ****
--- 31,37 ----
  const char *get_root(void);
  const char *get_root_with_slash(void);
  const char *get_cwd(void);
+ const char *get_relative_cwd_with_slash(void);
  void dump_dbpath(void);
  
  #endif /* ! _GETDBPATH_H_ */
Index: libutil/gtagsop.c
===================================================================
RCS file: /sources/global/global/libutil/gtagsop.c,v
retrieving revision 1.134
diff -c -r1.134 gtagsop.c
*** libutil/gtagsop.c	6 Apr 2015 00:30:12 -0000	1.134
--- libutil/gtagsop.c	28 May 2015 14:12:55 -0000
***************
*** 44,49 ****
--- 44,50 ----
  #include "dbop.h"
  #include "die.h"
  #include "format.h"
+ #include "getdbpath.h"
  #include "gparam.h"
  #include "gtagsop.h"
  #include "locatestring.h"
***************
*** 62,67 ****
--- 63,70 ----
  static int compare_path(const void *, const void *);
  static int compare_lineno(const void *, const void *);
  static int compare_tags(const void *, const void *);
+ static int get_nearness(const char *, const char *);
+ static int compare_nearness(const void *, const void *);
  static const char *seekto(const char *, int);
  static int is_defined_in_GTAGS(GTOP *, const char *);
  static char *get_prefix(const char *, int);
***************
*** 99,104 ****
--- 102,148 ----
  	return e1->lineno - e2->lineno;
  }
  /**
+  * compare_nearness: compare function for 'nearness sort'.
+  *
+  * Nearness sort is based on the following priority.
+  * (<n> means priority. <n> has higher priority than <n+1>)
+  *
+  * <1> files under the current directory
+  * <2> files under the parent directory except for the files which have higher priority.
+  * <3> files under the grandparent directory except for the files which have higher priority.
+  * ... (repeat until the project root directory)
+  * In every priority, they are sorted by alphabetical order.
+  */
+ static char *curdir;
+ static int
+ get_nearness(const char *p1, const char *p2)
+ {
+ 	int parts = 0;
+ 	for (; *p1 && *p2; p1++, p2++) {
+ 		if (*p1 != *p2)
+ 			break;
+ 		if (*p1 == '/')
+ 			parts++;
+ 	}
+ 	return parts;
+ }
+ static int
+ compare_nearness(const void *v1, const void *v2)
+ {
+ 	const GTP *e1 = v1, *e2 = v2;
+ 	int p1_nearness = get_nearness(e1->path, curdir);
+ 	int p2_nearness = get_nearness(e2->path, curdir);
+ 	int ret;
+ 
+ 	if (p1_nearness > p2_nearness)
+ 		return -1;
+ 	else if (p1_nearness < p2_nearness)
+ 		return 1;
+ 	if ((ret = strcmp(e1->path, e2->path)) != 0)
+ 		return ret;
+ 	return e1->lineno - e2->lineno;
+ }
+ /**
   * @fn static const char *seekto(const char *string, int n)
   * seekto: seek to the specified item of tag record.
   *
***************
*** 674,680 ****
   *			#GTOP_NOREGEX:	don't use regular expression. <br>
   *			#GTOP_IGNORECASE:	ignore case distinction. <br>
   *			#GTOP_BASICREGEX:	use basic regular expression. <br>
!  *			#GTOP_NOSORT:	don't sort
   *	@return		record
   */
  GTP *
--- 718,727 ----
   *			#GTOP_NOREGEX:	don't use regular expression. <br>
   *			#GTOP_IGNORECASE:	ignore case distinction. <br>
   *			#GTOP_BASICREGEX:	use basic regular expression. <br>
!  *			#GTOP_NEARSORT:		use 'Nearness sort'. <br>
!  *			#GTOP_NOSORT:		don't sort
!  *
!  *			By default, sort is done by alphabetical order.
   *	@return		record
   */
  GTP *
***************
*** 707,713 ****
  		gtop->dbflags |= DBOP_KEY;
  	if (!(flags & GTOP_BASICREGEX))
  		regflags |= REG_EXTENDED;
! 
  	/*
  	 * decide a read method
  	 */
--- 754,761 ----
  		gtop->dbflags |= DBOP_KEY;
  	if (!(flags & GTOP_BASICREGEX))
  		regflags |= REG_EXTENDED;
! 	if (flags & GTOP_NEARSORT)
! 		curdir = get_relative_cwd_with_slash();
  	/*
  	 * decide a read method
  	 */
***************
*** 1169,1173 ****
  	gtop->gtp_count = gtop->vb->length;
  	gtop->gtp_index = 0;
  	if (!(gtop->flags & GTOP_NOSORT))
! 		qsort(gtop->gtp_array, gtop->gtp_count, sizeof(GTP), compare_tags);
  }
--- 1217,1222 ----
  	gtop->gtp_count = gtop->vb->length;
  	gtop->gtp_index = 0;
  	if (!(gtop->flags & GTOP_NOSORT))
! 		qsort(gtop->gtp_array, gtop->gtp_count, sizeof(GTP),
! 			gtop->flags & GTOP_NEARSORT ? compare_nearness : compare_tags);
  }
Index: libutil/gtagsop.h
===================================================================
RCS file: /sources/global/global/libutil/gtagsop.h,v
retrieving revision 1.54
diff -c -r1.54 gtagsop.h
*** libutil/gtagsop.h	7 Nov 2014 04:48:38 -0000	1.54
--- libutil/gtagsop.h	28 May 2015 14:12:55 -0000
***************
*** 87,94 ****
  #define GTOP_IGNORECASE		16
  			/** use basic regular expression */
  #define GTOP_BASICREGEX		32
  			/** don't sort */
! #define GTOP_NOSORT		64
  /** @} */
  
  /**
--- 87,96 ----
  #define GTOP_IGNORECASE		16
  			/** use basic regular expression */
  #define GTOP_BASICREGEX		32
+ 			/** use 'nearness sort' instead of alphabetical sort */
+ #define GTOP_NEARSORT		64
  			/** don't sort */
! #define GTOP_NOSORT		128
  /** @} */
  
  /**
