etags.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /* editor C-code navigation via tags.
  2. make TAGS file via command:
  3. $ find . -type f -name "*.[ch]" | etags -l c --declarations -
  4. or, if etags utility not installed:
  5. $ find . -type f -name "*.[ch]" | ctags --c-kinds=+p --fields=+iaS --extra=+q -e -L-
  6. Copyright (C) 2009 Free Software Foundation, Inc.
  7. Authors:
  8. Ilia Maslakov <il.smind@gmail.com>, 2009
  9. Slava Zanko <slavazanko@gmail.com>, 2009
  10. This file is part of the Midnight Commander.
  11. The Midnight Commander is free software; you can redistribute it
  12. and/or modify it under the terms of the GNU General Public License as
  13. published by the Free Software Foundation; either version 2 of the
  14. License, or (at your option) any later version.
  15. The Midnight Commander is distributed in the hope that it will be
  16. useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  17. of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. General Public License for more details.
  19. You should have received a copy of the GNU General Public License
  20. along with this program; if not, write to the Free Software
  21. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  22. MA 02110-1301, USA.
  23. */
  24. #include <config.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <inttypes.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include "../src/global.h"
  31. #include "../src/util.h" /* canonicalize_pathname() */
  32. #include "../edit/etags.h"
  33. /*** file scope functions **********************************************/
  34. static gboolean parse_define(char *buf, char **long_name, char **short_name, long *line)
  35. {
  36. enum {in_longname, in_shortname, in_shortname_first_char, in_line, finish} def_state = in_longname;
  37. static char longdef[LONG_DEF_LEN];
  38. static char shortdef[SHORT_DEF_LEN];
  39. static char linedef[LINE_DEF_LEN];
  40. int nlong = 0;
  41. int nshort = 0;
  42. int nline = 0;
  43. char c = *buf;
  44. while ( !(c =='\0' || c =='\n') ) {
  45. switch ( def_state ) {
  46. case in_longname:
  47. if ( c == 0x01 ) {
  48. def_state = in_line;
  49. } else if ( c == 0x7F ) {
  50. def_state = in_shortname;
  51. } else {
  52. if ( nlong < LONG_DEF_LEN - 1 ) {
  53. longdef[nlong++] = c;
  54. }
  55. }
  56. break;
  57. case in_shortname_first_char:
  58. if ( isdigit(c) ) {
  59. nshort = 0;
  60. buf--;
  61. def_state = in_line;
  62. } else if ( c == 0x01 ) {
  63. def_state = in_line;
  64. } else {
  65. if ( nshort < SHORT_DEF_LEN - 1 ) {
  66. shortdef[nshort++] = c;
  67. def_state = in_shortname;
  68. }
  69. }
  70. break;
  71. case in_shortname:
  72. if ( c == 0x01 ) {
  73. def_state = in_line;
  74. } else if ( c == '\n' ) {
  75. def_state = finish;
  76. } else {
  77. if ( nshort < SHORT_DEF_LEN - 1 ) {
  78. shortdef[nshort++] = c;
  79. }
  80. }
  81. break;
  82. case in_line:
  83. if ( c == ',' || c == '\n') {
  84. def_state = finish;
  85. } else if ( isdigit(c) ) {
  86. if ( nline < LINE_DEF_LEN - 1 ) {
  87. linedef[nline++] = c;
  88. }
  89. }
  90. break;
  91. case finish:
  92. longdef[nlong] = '\0';
  93. shortdef[nshort] = '\0';
  94. linedef[nline] = '\0';
  95. *long_name = g_strdup (longdef);
  96. *short_name = g_strdup (shortdef);
  97. *line = atol (linedef);
  98. return TRUE;
  99. break;
  100. }
  101. buf++;
  102. c = *buf;
  103. }
  104. *long_name = NULL;
  105. *short_name = NULL;
  106. *line = 0;
  107. return FALSE;
  108. }
  109. /*** public functions **************************************************/
  110. int etags_set_definition_hash(const char *tagfile, const char *start_path,
  111. const char *match_func,
  112. etags_hash_t *def_hash)
  113. {
  114. enum {start, in_filename, in_define} state = start;
  115. FILE *f;
  116. static char buf[BUF_LARGE];
  117. char *longname = NULL;
  118. char *shortname = NULL;
  119. long line;
  120. char *chekedstr = NULL;
  121. int num = 0; /* returned value */
  122. int pos;
  123. char *filename = NULL;
  124. if ( !match_func || !tagfile )
  125. return 0;
  126. /* open file with positions */
  127. f = fopen (tagfile, "r");
  128. if (!f)
  129. return 0;
  130. while (fgets (buf, sizeof (buf), f)) {
  131. switch ( state ) {
  132. case start:
  133. if ( buf[0] == 0x0C ) {
  134. state = in_filename;
  135. }
  136. break;
  137. case in_filename:
  138. pos = strcspn(buf, ",");
  139. g_free(filename);
  140. filename = g_malloc (pos + 2);
  141. g_strlcpy(filename, (char *)buf, pos + 1);
  142. state = in_define;
  143. break;
  144. case in_define:
  145. if ( buf[0] == 0x0C ) {
  146. state = in_filename;
  147. break;
  148. }
  149. /* check if the filename matches the define pos */
  150. chekedstr = strstr (buf, match_func);
  151. if ( chekedstr ) {
  152. parse_define (chekedstr, &longname, &shortname, &line);
  153. if ( num < MAX_DEFINITIONS - 1 ) {
  154. def_hash[num].filename_len = strlen (filename);
  155. def_hash[num].fullpath = g_build_filename ( start_path, filename, (char *) NULL);
  156. canonicalize_pathname (def_hash[num].fullpath);
  157. def_hash[num].filename = g_strdup (filename);
  158. if ( shortname ) {
  159. def_hash[num].short_define = g_strdup (shortname);
  160. } else {
  161. def_hash[num].short_define = g_strdup (longname);
  162. }
  163. def_hash[num].line = line;
  164. g_free(shortname);
  165. g_free(longname);
  166. num++;
  167. }
  168. }
  169. break;
  170. }
  171. }
  172. g_free(filename);
  173. return num;
  174. }