root/libutil/pathconvert.c

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

DEFINITIONS

This source file includes following definitions.
  1. set_encode_chars
  2. set_print0
  3. decode_path
  4. convert_pathname
  5. convert_open
  6. convert_put
  7. convert_put_path
  8. convert_put_using
  9. convert_close

   1 /*
   2  * Copyright (c) 2005, 2006, 2010 Tama Communications Corporation
   3  *
   4  * This file is part of GNU GLOBAL.
   5  *
   6  * This program is free software: you can redistribute it and/or modify
   7  * it under the terms of the GNU General Public License as published by
   8  * the Free Software Foundation, either version 3 of the License, or
   9  * (at your option) any later version.
  10  * 
  11  * This program is distributed in the hope that it will be useful,
  12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  * GNU General Public License for more details.
  15  * 
  16  * You should have received a copy of the GNU General Public License
  17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18  */
  19 #ifdef HAVE_CONFIG_H
  20 #include <config.h>
  21 #endif
  22 #include <stdio.h>
  23 #include <ctype.h>
  24 #ifdef STDC_HEADERS
  25 #include <stdlib.h>
  26 #endif
  27 #ifdef HAVE_STRING_H
  28 #include <string.h>
  29 #else
  30 #include <strings.h>
  31 #endif
  32 
  33 #include "abs2rel.h"
  34 #include "checkalloc.h"
  35 #include "die.h"
  36 #include "format.h"
  37 #include "gparam.h"
  38 #include "gpathop.h"
  39 #include "gtagsop.h"
  40 #include "pathconvert.h"
  41 #include "strbuf.h"
  42 #include "strlimcpy.h"
  43 
  44 static unsigned char encode[256];
  45 static int encoding;
  46 static int newline = '\n';
  47 
  48 #define required_encode(c) encode[(unsigned char)c]
  49 /**
  50  * set_encode_chars: stores chars to be encoded.
  51  */
  52 void
  53 set_encode_chars(const unsigned char *chars)
  54 {
  55         unsigned int i;
  56 
  57         /* clean the table */
  58         memset(encode, 0, sizeof(encode));
  59         /* set bits */
  60         for (i = 0; chars[i]; i++) {
  61                 encode[(unsigned char)chars[i]] = 1;
  62         }
  63         /* You cannot encode '.' and '/'. */
  64         encode['.'] = 0;
  65         encode['/'] = 0;
  66         /* '%' is always encoded when encode is enable. */
  67         encode['%'] = 1;
  68         encoding = 1;
  69 }
  70 /**
  71  * set_print0: change newline to @CODE{'\0'}.
  72  */
  73 void
  74 set_print0(void)
  75 {
  76         newline = '\0';
  77 }
  78 #define outofrange(c)   (c < '0' || c > 'f')
  79 #define h2int(c) (c >= 'a' ? c - 'a' + 10 : c - '0')
  80 /**
  81  * decode_path: decode encoded path name.
  82  *
  83  *      @param[in]      path    encoded path name
  84  *      @return         decoded path name
  85  */
  86 char *
  87 decode_path(const char *path)
  88 {
  89         STATIC_STRBUF(sb);
  90         const char *p;
  91 
  92         if (strchr(path, '%') == NULL)
  93                 return (char *)path;
  94         strbuf_clear(sb);
  95         for (p = path; *p; p++) {
  96                 if (*p == '%') {
  97                         unsigned char c1, c2;
  98                         c1 = *++p;
  99                         c2 = *++p;
 100                         if (outofrange(c1) || outofrange(c2))
 101                                 die("decode_path: unexpected character. (%%%c%c)", c1, c2);
 102                         strbuf_putc(sb, h2int(c1) * 16 + h2int(c2));
 103                 } else
 104                         strbuf_putc(sb, *p);
 105         }
 106         return strbuf_value(sb);
 107 }
 108 /**
 109  * Path filter for the output of @XREF{global,1}.
 110  */
 111 static const char *
 112 convert_pathname(CONVERT *cv, const char *path)
 113 {
 114         static char buf[MAXPATHLEN];
 115         const char *a, *b;
 116 
 117         if (cv->type != PATH_THROUGH) {
 118                 /*
 119                  * make absolute path name.
 120                  * 'path + 1' means skipping "." at the head.
 121                  */
 122                 strbuf_setlen(cv->abspath, cv->start_point);
 123                 strbuf_puts(cv->abspath, path + 1);
 124                 /*
 125                  * print path name with converting.
 126                  */
 127                 switch (cv->type) {
 128                 case PATH_ABSOLUTE:
 129                         path = strbuf_value(cv->abspath);
 130                         break;
 131                 case PATH_RELATIVE:
 132                 case PATH_SHORTER:
 133                         a = strbuf_value(cv->abspath);
 134                         b = cv->basedir;
 135 #if defined(_WIN32) || defined(__DJGPP__)
 136                         while (*a != '/')
 137                                 a++;
 138                         while (*b != '/')
 139                                 b++;
 140 #endif
 141                         if (!abs2rel(a, b, buf, sizeof(buf)))
 142                                 die("abs2rel failed. (path=%s, base=%s).", a, b);
 143                         path = buf;
 144                         if (cv->type == PATH_SHORTER && strlen(path) > strbuf_getlen(cv->abspath))
 145                                 path = strbuf_value(cv->abspath);
 146                         break;
 147                 default:
 148                         die("unknown path type.");
 149                         break;
 150                 }
 151         }
 152         /*
 153          * encoding of the path name.
 154          */
 155         if (encoding) {
 156                 const char *p;
 157                 int required = 0;
 158 
 159                 for (p = path; *p; p++) {
 160                         if (required_encode(*p)) {
 161                                 required = 1;
 162                                 break;
 163                         }
 164                 }
 165                 if (required) {
 166                         static char buf[MAXPATHLEN];
 167                         char c[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
 168                         char *q = buf;
 169 
 170                         for (p = path; *p; p++) {
 171                                 if (required_encode(*p)) {
 172                                         *q++ = '%';
 173                                         *q++ = c[*p / 16];
 174                                         *q++ = c[*p % 16];
 175                                 } else
 176                                         *q++ = *p;
 177                         }
 178                         *q = '\0';
 179                         path = buf;
 180                 }
 181         }
 182         return (const char *)path;
 183 }
 184 /**
 185  * convert_open: open convert filter
 186  *
 187  *      @param[in]      type    #PATH_ABSOLUTE, #PATH_RELATIVE, #PATH_THROUGH
 188  *      @param[in]      format  tag record format
 189  *      @param[in]      root    root directory of source tree
 190  *      @param[in]      cwd     current directory
 191  *      @param[in]      dbpath  dbpath directory
 192  *      @param[in]      op      output file
 193  *      @param[in]      db      tag type (#GTAGS, #GRTAGS, #GSYMS, #GPATH, #NOTAGS) <br>
 194  *                      only for @NAME{cscope} format
 195  */
 196 CONVERT *
 197 convert_open(int type, int format, const char *root, const char *cwd, const char *dbpath, FILE *op, int db)
 198 {
 199         CONVERT *cv = (CONVERT *)check_calloc(sizeof(CONVERT), 1);
 200         /*
 201          * set base directory.
 202          */
 203         cv->abspath = strbuf_open(MAXPATHLEN);
 204         strbuf_puts(cv->abspath, root);
 205         strbuf_unputc(cv->abspath, '/');
 206         cv->start_point = strbuf_getlen(cv->abspath);
 207         /*
 208          * copy elements.
 209          */
 210         if (strlen(cwd) > MAXPATHLEN)
 211                 die("current directory name too long.");
 212         strlimcpy(cv->basedir, cwd, sizeof(cv->basedir));
 213         cv->type = type;
 214         cv->format = format;
 215         cv->op = op;
 216         cv->db = db;
 217         /*
 218          * open GPATH.
 219          */
 220         if (gpath_open(dbpath, 0) < 0)
 221                 die("GPATH not found.");
 222         return cv;
 223 }
 224 /**
 225  * convert_put: convert path into relative or absolute and print.
 226  *
 227  *      @param[in]      cv      #CONVERT structure
 228  *      @param[in]      ctags_x tag record (@NAME{ctags-x} format)
 229  *
 230  * @note This function is only called by @NAME{gtags} with the @OPTION{--path} option.
 231  */
 232 void
 233 convert_put(CONVERT *cv, const char *ctags_x)
 234 {
 235         char *tagnextp = NULL;
 236         int tagnextc = 0;
 237         char *tag = NULL, *lineno = NULL, *path, *rest = NULL;
 238         const char *fid = NULL;
 239 
 240         if (cv->format == FORMAT_PATH)
 241                 die("convert_put: internal error.");    /* Use convert_put_path() */
 242         /*
 243          * parse tag line.
 244          * Don't use split() function not to destroy line image.
 245          */
 246         {
 247                 char *p = (char *)ctags_x;
 248                 /*
 249                  * tag name
 250                  */
 251                 tag = p;
 252                 for (; *p && !isspace(*p); p++)
 253                         ;
 254                 if (*p == '\0')
 255                         die("illegal ctags-x format (line number not found).");
 256                 tagnextp = p;
 257                 tagnextc = *p;
 258                 *p++ = '\0';
 259                 /* skip blanks */
 260                 for (; *p && isspace(*p); p++)
 261                         ;
 262                 if (*p == '\0')
 263                         die("illegal ctags-x format (line number not found).");
 264                 /*
 265                  * line number
 266                  */
 267                 lineno = p;
 268                 for (; *p && !isspace(*p); p++)
 269                         ;
 270                 if (*p == '\0')
 271                         die("illegal ctags-x format (path name not found).");
 272                 *p++ = '\0';
 273                 /* skip blanks */
 274                 for (; *p && isspace(*p); p++)
 275                         ;
 276                 if (*p == '\0')
 277                         die("illegal ctags-x format (path name not found).");
 278                 /*
 279                  * path name
 280                  */
 281                 path = p;
 282                 for (; *p && !isspace(*p); p++)
 283                         ;
 284                 if (*p == '\0')
 285                         die("illegal ctags-x format (line image not found).");
 286                 *p++ = '\0';
 287                 rest = p;
 288         }
 289         /*
 290          * The path name has already been encoded.
 291          */
 292         path = decode_path(path);
 293         switch (cv->format) {
 294         case FORMAT_CTAGS:
 295                 fputs(tag, cv->op);
 296                 fputc('\t', cv->op);
 297                 fputs(convert_pathname(cv, path), cv->op);
 298                 fputc('\t', cv->op);
 299                 fputs(lineno, cv->op);
 300                 break;
 301         case FORMAT_CTAGS_XID:
 302                 fid = gpath_path2fid(path, NULL);
 303                 if (fid == NULL)
 304                         die("convert_put: unknown file. '%s'", path);
 305                 fputs(fid, cv->op);
 306                 fputc(' ', cv->op);
 307                 /* PASS THROUGH */
 308         case FORMAT_CTAGS_X:
 309                 /*
 310                  * print until path name.
 311                  */
 312                 *tagnextp = tagnextc;
 313                 fputs(ctags_x, cv->op);
 314                 fputc(' ', cv->op);
 315                 /*
 316                  * print path name and the rest.
 317                  */
 318                 fputs(convert_pathname(cv, path), cv->op);
 319                 fputc(' ', cv->op);
 320                 fputs(rest, cv->op);
 321                 break;
 322         case FORMAT_CTAGS_MOD:
 323                 fputs(convert_pathname(cv, path), cv->op);
 324                 fputc('\t', cv->op);
 325                 fputs(lineno, cv->op);
 326                 fputc('\t', cv->op);
 327                 fputs(rest, cv->op);
 328                 break;
 329         case FORMAT_GREP:
 330                 fputs(convert_pathname(cv, path), cv->op);
 331                 fputc(':', cv->op);
 332                 fputs(lineno, cv->op);
 333                 fputc(':', cv->op);
 334                 fputs(rest, cv->op);
 335                 break;
 336         case FORMAT_CSCOPE:
 337                 fputs(convert_pathname(cv, path), cv->op);
 338                 fputc(' ', cv->op);
 339                 fputs(tag, cv->op);
 340                 fputc(' ', cv->op);
 341                 fputs(lineno, cv->op);
 342                 fputc(' ', cv->op);
 343                 for (; *rest && isspace(*rest); rest++)
 344                         ;
 345                 if (*rest)
 346                         fputs(rest, cv->op);
 347                 else
 348                         fputs("<unknown>", cv->op);
 349                 break;
 350         default:
 351                 die("unknown format type.");
 352         }
 353         (void)fputc(newline, cv->op);
 354 }
 355 /**
 356  * convert_put_path: convert @a path into relative or absolute and print.
 357  *
 358  *      @param[in]      cv      #CONVERT structure
 359  *      @param[in]      path    path name
 360  */
 361 void
 362 convert_put_path(CONVERT *cv, const char *path)
 363 {
 364         if (cv->format != FORMAT_PATH)
 365                 die("convert_put_path: internal error.");
 366         fputs(convert_pathname(cv, path), cv->op);
 367         (void)fputc(newline, cv->op);
 368 }
 369 /**
 370  * convert_put_using: convert @a path into relative or absolute and print.
 371  *
 372  *      @param[in]      cv      #CONVERT structure
 373  *      @param[in]      tag     tag name
 374  *      @param[in]      path    path name
 375  *      @param[in]      lineno  line number
 376  *      @param[in]      rest    line image
 377  *      @param[in]      fid     file id (only when @CODE{fid != NULL})
 378  */
 379 void
 380 convert_put_using(CONVERT *cv, const char *tag, const char *path, int lineno, const char *rest, const char *fid)
 381 {
 382         switch (cv->format) {
 383         case FORMAT_PATH:
 384                 fputs(convert_pathname(cv, path), cv->op);
 385                 break;
 386         case FORMAT_CTAGS:
 387                 fputs(tag, cv->op);
 388                 fputc('\t', cv->op);
 389                 fputs(convert_pathname(cv, path), cv->op);
 390                 fputc('\t', cv->op);
 391                 fprintf(cv->op, "%d", lineno);
 392                 break;
 393         case FORMAT_CTAGS_XID:
 394                 if (fid == NULL) {
 395                         fid = gpath_path2fid(path, NULL);
 396                         if (fid == NULL)
 397                                 die("convert_put_using: unknown file. '%s'", path);
 398                 }
 399                 fputs(fid, cv->op);
 400                 fputc(' ', cv->op);
 401                 /* PASS THROUGH */
 402         case FORMAT_CTAGS_X:
 403                 fprintf(cv->op, "%-16s %4d %-16s %s",
 404                         tag, lineno, convert_pathname(cv, path), rest);
 405                 break;
 406         case FORMAT_CTAGS_MOD:
 407                 fputs(convert_pathname(cv, path), cv->op);
 408                 fputc('\t', cv->op);
 409                 fprintf(cv->op, "%d", lineno);
 410                 fputc('\t', cv->op);
 411                 fputs(rest, cv->op);
 412                 break;
 413         case FORMAT_GREP:
 414                 fputs(convert_pathname(cv, path), cv->op);
 415                 fputc(':', cv->op);
 416                 fprintf(cv->op, "%d", lineno);
 417                 fputc(':', cv->op);
 418                 fputs(rest, cv->op);
 419                 break;
 420         case FORMAT_CSCOPE:
 421                 fputs(convert_pathname(cv, path), cv->op);
 422                 fputc(' ', cv->op);
 423                 fputs(tag, cv->op);
 424                 fputc(' ', cv->op);
 425                 fprintf(cv->op, "%d", lineno);
 426                 fputc(' ', cv->op);
 427                 for (; *rest && isspace(*rest); rest++)
 428                         ;
 429                 if (*rest)
 430                         fputs(rest, cv->op);
 431                 else
 432                         fputs("<unknown>", cv->op);
 433                 break;
 434         default:
 435                 die("unknown format type.");
 436         }
 437         (void)fputc(newline, cv->op);
 438 }
 439 void
 440 convert_close(CONVERT *cv)
 441 {
 442         strbuf_close(cv->abspath);
 443         gpath_close();
 444         free(cv);
 445 }

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