root/plugin-factory/exuberant-ctags.c

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

DEFINITIONS

This source file includes following definitions.
  1. copy_langmap_converting_cpp
  2. start_ctags
  3. terminate_ctags
  4. get_line
  5. put_line
  6. parser

   1 /*
   2  * Copyright (c) 2010
   3  *      Tama Communications Corporation
   4  *
   5  * This file is part of GNU GLOBAL.
   6  *
   7  * This program is free software: you can redistribute it and/or modify
   8  * it under the terms of the GNU General Public License as published by
   9  * the Free Software Foundation, either version 3 of the License, or
  10  * (at your option) any later version.
  11  * 
  12  * This program is distributed in the hope that it will be useful,
  13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  * 
  17  * You should have received a copy of the GNU General Public License
  18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19  */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include <config.h>
  23 #endif
  24 #include <sys/types.h>
  25 #if !defined(_WIN32) || defined(__CYGWIN__)
  26 #include <sys/wait.h>
  27 #endif
  28 #include <assert.h>
  29 #include <ctype.h>
  30 #include <errno.h>
  31 #include <stdio.h>
  32 #ifdef STDC_HEADERS
  33 #include <stdlib.h>
  34 #endif
  35 #ifdef HAVE_STRING_H
  36 #include <string.h>
  37 #else
  38 #include <strings.h>
  39 #endif
  40 #ifdef HAVE_UNISTD_H
  41 #include <unistd.h>
  42 #endif
  43 
  44 #include "parser.h"
  45 
  46 /*
  47  * Function layer plugin parser sample
  48  */
  49 
  50 #define TERMINATOR              "###terminator###"
  51 #define LANGMAP_OPTION          "--langmap="
  52 #define INITIAL_BUFSIZE         1024
  53 
  54 static char *argv[] = {
  55         EXUBERANT_CTAGS,
  56         NULL,
  57 #ifdef USE_TYPE_STRING
  58         "--gtags",
  59 #endif
  60         "-xu",
  61         "--filter",
  62         "--filter-terminator=" TERMINATOR "\n",
  63         "--format=1",
  64         NULL
  65 };
  66 static pid_t pid;
  67 static FILE *ip, *op;
  68 static char *linebuf;
  69 static size_t bufsize;
  70 static char *ctagsnotfound = "Exuberant Ctags not found. Please see ./configure --help.";
  71 
  72 static void
  73 copy_langmap_converting_cpp(char *dst, const char *src)
  74 {
  75         const char *p;
  76 
  77         if (strncmp(src, "cpp:", 4) == 0) {
  78                 memcpy(dst, "c++:", 4);
  79                 dst += 4;
  80                 src += 4;
  81         }
  82         while ((p = strstr(src, ",cpp:")) != NULL) {
  83                 memcpy(dst, src, p - src);
  84                 dst += p - src;
  85                 memcpy(dst, ",c++:", 5);
  86                 dst += 5;
  87                 src = p + 5;
  88         }
  89         strcpy(dst, src);
  90 }
  91 
  92 static void
  93 start_ctags(const struct parser_param *param)
  94 {
  95         int opipe[2], ipipe[2];
  96 
  97         if (strlen(EXUBERANT_CTAGS) == 0 || !strcmp(EXUBERANT_CTAGS, "no"))
  98                 param->die(ctagsnotfound);
  99         argv[1] = malloc(sizeof(LANGMAP_OPTION) + strlen(param->langmap));
 100         if (argv[1] == NULL)
 101                 param->die("short of memory.");
 102         memcpy(argv[1], LANGMAP_OPTION, sizeof(LANGMAP_OPTION) - 1);
 103         copy_langmap_converting_cpp(argv[1] + sizeof(LANGMAP_OPTION) - 1, param->langmap);
 104 
 105         if (pipe(opipe) < 0 || pipe(ipipe) < 0)
 106                 param->die("cannot create pipe.");
 107         pid = fork();
 108         if (pid == 0) {
 109                 /* child process */
 110                 close(opipe[1]);
 111                 close(ipipe[0]);
 112                 if (dup2(opipe[0], STDIN_FILENO) < 0
 113                  || dup2(ipipe[1], STDOUT_FILENO) < 0)
 114                         param->die("dup2 failed.");
 115                 close(opipe[0]);
 116                 close(ipipe[1]);
 117                 execvp(EXUBERANT_CTAGS, argv);
 118                 param->die("execvp failed.");
 119         }
 120         /* parent process */
 121         if (pid < 0)
 122                 param->die("fork failed.");
 123         free(argv[1]);
 124         close(opipe[0]);
 125         close(ipipe[1]);
 126         ip = fdopen(ipipe[0], "r");
 127         op = fdopen(opipe[1], "w");
 128         if (ip == NULL || op == NULL)
 129                 param->die("fdopen failed.");
 130 
 131         bufsize = INITIAL_BUFSIZE;
 132         linebuf = malloc(bufsize);
 133         if (linebuf == NULL)
 134                 param->die("short of memory.");
 135 }
 136 
 137 #ifdef __GNUC__
 138 static void terminate_ctags(void) __attribute__((destructor));
 139 #endif
 140 
 141 static void
 142 terminate_ctags(void)
 143 {
 144         if (op == NULL)
 145                 return;
 146         free(linebuf);
 147         fclose(op);
 148         fclose(ip);
 149         while (waitpid(pid, NULL, 0) < 0 && errno == EINTR)
 150                 ;
 151 }
 152 
 153 static char *
 154 get_line(const struct parser_param *param)
 155 {
 156         size_t linelen = 0;
 157 
 158         for (;;) {
 159                 if (fgets(linebuf + linelen, bufsize - linelen, ip) == NULL) {
 160                         if (linelen == 0)
 161                                 return NULL;
 162                         break;
 163                 }
 164                 linelen += strlen(linebuf + linelen);
 165                 if (linelen < bufsize - 1 || linebuf[linelen - 1] == '\n'
 166                  || feof(ip))
 167                         break;
 168                 bufsize *= 2;
 169                 linebuf = realloc(linebuf, bufsize);
 170                 if (linebuf == NULL)
 171                         param->die("short of memory.");
 172         }
 173         while (linelen-- > 0
 174                 && (linebuf[linelen] == '\n' || linebuf[linelen] == '\r'))
 175                 linebuf[linelen] = '\0';
 176         return linebuf;
 177 }
 178 
 179 static void
 180 put_line(char *ctags_x, const struct parser_param *param)
 181 {
 182         int lineno;
 183         int type = PARSER_DEF;
 184         char *p, *tagname, *filename;
 185 
 186 #ifdef USE_TYPE_STRING
 187         /*
 188          * Output of ctags:
 189          * ctags -x ...
 190          * main              326 global/global.c  main(int argc, char **argv)
 191          *
 192          * ctags -x --gtags ...
 193          * D main              326 global/global.c  main(int argc, char **argv)
 194          */
 195         switch (*ctags_x) {
 196         case 'D':
 197                 type = PARSER_DEF;
 198                 break;
 199         case 'R':
 200                 type = PARSER_REF_SYM;
 201                 break;
 202         default:
 203                 param->die("unexpected type string.");
 204         }
 205         /* skip type string */
 206         while (*ctags_x && !isspace((unsigned char)*ctags_x))
 207                 ctags_x++;
 208         while (*ctags_x  && isspace((unsigned char)*ctags_x))
 209                 ctags_x++;
 210 #endif
 211         filename = strstr(ctags_x, param->file);
 212         if (filename == NULL || filename == ctags_x)
 213                 return;
 214         p = filename - 1;
 215         if (!isspace((unsigned char)*p))
 216                 return;
 217         while (p >= ctags_x && isspace((unsigned char)*p))
 218                 *p-- = '\0';
 219         if (p < ctags_x)
 220                 return;
 221         if (!isdigit((unsigned char)*p))
 222                 return;
 223         while (p >= ctags_x && isdigit((unsigned char)*p))
 224                 p--;
 225         if (p < ctags_x)
 226                 return;
 227         lineno = atoi(p + 1);
 228         if (!isspace((unsigned char)*p))
 229                 return;
 230         while (p >= ctags_x && isspace((unsigned char)*p))
 231                 *p-- = '\0';
 232         if (p < ctags_x)
 233                 return;
 234         while (p >= ctags_x && !isspace((unsigned char)*p))
 235                 p--;
 236         tagname = p + 1;
 237         p = filename + strlen(param->file);
 238         if (*p != '\0') {
 239                 if (!isspace((unsigned char)*p))
 240                         return;
 241                 *p++ = '\0';
 242                 while (isspace((unsigned char)*p))
 243                         p++;
 244         }
 245         param->put(type, tagname, lineno, filename, p, param->arg);
 246 }
 247 
 248 void
 249 parser(const struct parser_param *param)
 250 {
 251         char *ctags_x;
 252 
 253         assert(param->size >= sizeof(*param));
 254 
 255         if (op == NULL)
 256                 start_ctags(param);
 257 
 258         /* Write path of input file to pipe. */
 259         fputs(param->file, op);
 260         putc('\n', op);
 261         fflush(op);
 262 
 263         /* Read output of ctags command. */
 264         for (;;) {
 265                 ctags_x = get_line(param);
 266                 if (ctags_x == NULL)
 267                         param->die("unexpected EOF.");
 268                 if (strcmp(ctags_x, TERMINATOR) == 0)
 269                         break;
 270                 put_line(ctags_x, param);
 271         }
 272 }

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