root/src/editor/etags.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. etags_hash_free
  2. parse_define
  3. etags_set_definition_hash

   1 /*
   2    Editor C-code navigation via tags.
   3    make TAGS file via command:
   4    $ find . -type f -name "*.[ch]" | etags -l c --declarations -
   5 
   6    or, if etags utility not installed:
   7    $ find . -type f -name "*.[ch]" | ctags --c-kinds=+p --fields=+iaS --extra=+q -e -L-
   8 
   9    Copyright (C) 2009-2021
  10    Free Software Foundation, Inc.
  11 
  12    Written by:
  13    Ilia Maslakov <il.smind@gmail.com>, 2009
  14    Slava Zanko <slavazanko@gmail.com>, 2009
  15 
  16    This file is part of the Midnight Commander.
  17 
  18    The Midnight Commander is free software: you can redistribute it
  19    and/or modify it under the terms of the GNU General Public License as
  20    published by the Free Software Foundation, either version 3 of the License,
  21    or (at your option) any later version.
  22 
  23    The Midnight Commander is distributed in the hope that it will be useful,
  24    but WITHOUT ANY WARRANTY; without even the implied warranty of
  25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26    GNU General Public License for more details.
  27 
  28    You should have received a copy of the GNU General Public License
  29    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  30  */
  31 
  32 #include <config.h>
  33 
  34 #include <ctype.h>
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <string.h>
  38 
  39 #include "lib/global.h"
  40 #include "lib/util.h"           /* canonicalize_pathname() */
  41 
  42 #include "etags.h"
  43 
  44 /*** global variables ****************************************************************************/
  45 
  46 /*** file scope macro definitions ****************************************************************/
  47 
  48 /*** file scope type declarations ****************************************************************/
  49 
  50 /*** file scope variables ************************************************************************/
  51 
  52 /* --------------------------------------------------------------------------------------------- */
  53 /*** file scope functions ************************************************************************/
  54 /* --------------------------------------------------------------------------------------------- */
  55 
  56 static void
  57 etags_hash_free (gpointer data)
     /* [previous][next][first][last][top][bottom][index][help]  */
  58 {
  59     etags_hash_t *hash = (etags_hash_t *) data;
  60 
  61     g_free (hash->filename);
  62     g_free (hash->fullpath);
  63     g_free (hash->short_define);
  64     g_free (hash);
  65 }
  66 
  67 /* --------------------------------------------------------------------------------------------- */
  68 
  69 static gboolean
  70 parse_define (const char *buf, char **long_name, char **short_name, long *line)
     /* [previous][next][first][last][top][bottom][index][help]  */
  71 {
  72     /* *INDENT-OFF* */
  73     enum
  74     {
  75         in_longname,
  76         in_shortname,
  77         in_shortname_first_char,
  78         in_line,
  79         finish
  80     } def_state = in_longname;
  81     /* *INDENT-ON* */
  82 
  83     GString *longdef = NULL;
  84     GString *shortdef = NULL;
  85     GString *linedef = NULL;
  86 
  87     char c = *buf;
  88 
  89     while (!(c == '\0' || c == '\n'))
  90     {
  91         switch (def_state)
  92         {
  93         case in_longname:
  94             if (c == 0x01)
  95                 def_state = in_line;
  96             else if (c == 0x7F)
  97                 def_state = in_shortname;
  98             else
  99             {
 100                 if (longdef == NULL)
 101                     longdef = g_string_sized_new (32);
 102 
 103                 g_string_append_c (longdef, c);
 104             }
 105             break;
 106 
 107         case in_shortname_first_char:
 108             if (isdigit (c))
 109             {
 110                 if (shortdef == NULL)
 111                     shortdef = g_string_sized_new (32);
 112                 else
 113                     g_string_set_size (shortdef, 0);
 114 
 115                 buf--;
 116                 def_state = in_line;
 117             }
 118             else if (c == 0x01)
 119                 def_state = in_line;
 120             else
 121             {
 122                 if (shortdef == NULL)
 123                     shortdef = g_string_sized_new (32);
 124 
 125                 g_string_append_c (shortdef, c);
 126                 def_state = in_shortname;
 127             }
 128             break;
 129 
 130         case in_shortname:
 131             if (c == 0x01)
 132                 def_state = in_line;
 133             else if (c == '\n')
 134                 def_state = finish;
 135             else
 136             {
 137                 if (shortdef == NULL)
 138                     shortdef = g_string_sized_new (32);
 139 
 140                 g_string_append_c (shortdef, c);
 141             }
 142             break;
 143 
 144         case in_line:
 145             if (c == ',' || c == '\n')
 146                 def_state = finish;
 147             else if (isdigit (c))
 148             {
 149                 if (linedef == NULL)
 150                     linedef = g_string_sized_new (32);
 151 
 152                 g_string_append_c (linedef, c);
 153             }
 154             break;
 155 
 156         case finish:
 157             *long_name = longdef == NULL ? NULL : g_string_free (longdef, FALSE);
 158             *short_name = shortdef == NULL ? NULL : g_string_free (shortdef, FALSE);
 159 
 160             if (linedef == NULL)
 161                 *line = 0;
 162             else
 163             {
 164                 *line = atol (linedef->str);
 165                 g_string_free (linedef, TRUE);
 166             }
 167             return TRUE;
 168 
 169         default:
 170             break;
 171         }
 172 
 173         buf++;
 174         c = *buf;
 175     }
 176 
 177     *long_name = NULL;
 178     *short_name = NULL;
 179     *line = 0;
 180 
 181     return FALSE;
 182 }
 183 
 184 /* --------------------------------------------------------------------------------------------- */
 185 /*** public functions ****************************************************************************/
 186 /* --------------------------------------------------------------------------------------------- */
 187 
 188 GPtrArray *
 189 etags_set_definition_hash (const char *tagfile, const char *start_path, const char *match_func)
     /* [previous][next][first][last][top][bottom][index][help]  */
 190 {
 191     /* *INDENT-OFF* */
 192     enum
 193     {
 194         start,
 195         in_filename,
 196         in_define
 197     } state = start;
 198     /* *INDENT-ON* */
 199 
 200     FILE *f;
 201     char buf[BUF_LARGE];
 202     char *filename = NULL;
 203     GPtrArray *ret = NULL;
 204 
 205     if (match_func == NULL || tagfile == NULL)
 206         return NULL;
 207 
 208     /* open file with positions */
 209     f = fopen (tagfile, "r");
 210     if (f == NULL)
 211         return NULL;
 212 
 213     while (fgets (buf, sizeof (buf), f) != NULL)
 214         switch (state)
 215         {
 216         case start:
 217             if (buf[0] == 0x0C)
 218                 state = in_filename;
 219             break;
 220 
 221         case in_filename:
 222             {
 223                 size_t pos;
 224 
 225                 pos = strcspn (buf, ",");
 226                 g_free (filename);
 227                 filename = g_strndup (buf, pos);
 228                 state = in_define;
 229                 break;
 230             }
 231 
 232         case in_define:
 233             if (buf[0] == 0x0C)
 234                 state = in_filename;
 235             else
 236             {
 237                 char *chekedstr;
 238 
 239                 /* check if the filename matches the define pos */
 240                 chekedstr = strstr (buf, match_func);
 241                 if (chekedstr != NULL)
 242                 {
 243                     char *longname = NULL;
 244                     char *shortname = NULL;
 245                     etags_hash_t *def_hash;
 246 
 247                     def_hash = g_new (etags_hash_t, 1);
 248 
 249                     def_hash->fullpath = mc_build_filename (start_path, filename, (char *) NULL);
 250                     canonicalize_pathname (def_hash->fullpath);
 251                     def_hash->filename = g_strdup (filename);
 252 
 253                     def_hash->line = 0;
 254 
 255                     parse_define (chekedstr, &longname, &shortname, &def_hash->line);
 256 
 257                     if (shortname != NULL && *shortname != '\0')
 258                     {
 259                         def_hash->short_define = shortname;
 260                         g_free (longname);
 261                     }
 262                     else
 263                     {
 264                         def_hash->short_define = longname;
 265                         g_free (shortname);
 266                     }
 267 
 268                     if (ret == NULL)
 269                         ret = g_ptr_array_new_with_free_func (etags_hash_free);
 270 
 271                     g_ptr_array_add (ret, def_hash);
 272                 }
 273             }
 274             break;
 275 
 276         default:
 277             break;
 278         }
 279 
 280     g_free (filename);
 281     fclose (f);
 282 
 283     return ret;
 284 }
 285 
 286 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */