"Fossies" - the Fresh Open Source Software Archive

Member "global-6.6.5/libutil/convert.c" (3 Sep 2020, 15059 Bytes) of package /linux/misc/global-6.6.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "convert.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.6.4_vs_6.6.5.

    1 /*
    2  * Copyright (c) 2005, 2006, 2010, 2014
    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 #ifdef HAVE_CONFIG_H
   21 #include <config.h>
   22 #endif
   23 #include <stdio.h>
   24 #include <ctype.h>
   25 #ifdef STDC_HEADERS
   26 #include <stdlib.h>
   27 #endif
   28 #ifdef HAVE_STRING_H
   29 #include <string.h>
   30 #else
   31 #include <strings.h>
   32 #endif
   33 
   34 #include "abs2rel.h"
   35 #include "char.h"
   36 #include "checkalloc.h"
   37 #include "die.h"
   38 #include "encodepath.h"
   39 #include "format.h"
   40 #include "gparam.h"
   41 #include "gpathop.h"
   42 #include "gtagsop.h"
   43 #include "rewrite.h"
   44 #include "strbuf.h"
   45 #include "strlimcpy.h"
   46 
   47 #include "convert.h"
   48 static int debug = 0;
   49 static int flags;
   50 
   51 /**
   52  * This module converts records before output.
   53  * The converting includes the followings:
   54  *
   55  * 1. constructing format (-x, -t, --result)
   56  * 2. converting path style (-a, --path-style)
   57  * 3. inserting escape sequences for coloring (--color)
   58  */
   59 /**
   60  * coloring support using ANSI escape sequence (SGR)
   61  */
   62 #define ESC '\033'
   63 #define EOE 'm'
   64 #define DEFAULT_COLOR "01;31"
   65 static REWRITE *rewrite;
   66 static char last_pattern[IDENTLEN];
   67 static int locked;
   68 static int (*code_fputs)(const char *s, FILE *op) = fputs;
   69 
   70 /**
   71  * set output flags.
   72  */
   73 void
   74 set_convert_flags(int a_flags)
   75 {
   76     flags = a_flags;
   77 }
   78 /**
   79  * fputs with coloring.
   80  */
   81 static int
   82 color_code_fputs(const char *string, FILE *op)
   83 {
   84     return fputs(rewrite_string(rewrite, string, 0), op);
   85 }
   86 /**
   87  * set_color_method: setup ANSI escape sequence (SGR).
   88  */
   89 static void
   90 set_color_method(void)
   91 {
   92     STATIC_STRBUF(sb);
   93     const char *sgr = DEFAULT_COLOR;
   94     const char *col = getenv("GREP_COLOR");
   95     int len;
   96 
   97     if (col != NULL)
   98         sgr = col;
   99     len = strlen(sgr);
  100     col = getenv("GREP_COLORS");
  101     if (col != NULL) {
  102         const char *part = strstr(col, "mt=");
  103         if (part == NULL)
  104             part = strstr(col, "ms=");
  105         if (part != NULL) {
  106             const char *sep = strchr(part, ':');
  107             if (sep == NULL)
  108                 sep = strchr(part, '\0');
  109             if (sep[-1] != '=') {
  110                 sgr = part + 3;
  111                 len = sep - sgr;
  112             }
  113         }
  114     }
  115     strbuf_clear(sb);
  116     /* begin coloring */
  117     strbuf_putc(sb, ESC); 
  118     strbuf_putc(sb, '[');
  119     strbuf_nputs(sb, sgr, len);
  120     strbuf_putc(sb, EOE);
  121     /* tag name */
  122     strbuf_putc(sb, '&');
  123     /* end coloring */
  124     strbuf_putc(sb, ESC); 
  125     strbuf_putc(sb, '[');
  126     strbuf_putc(sb, EOE);
  127     if (rewrite)
  128         rewrite_close(rewrite);
  129     rewrite = rewrite_open(NULL, strbuf_value(sb), 0);
  130     locked = 0;
  131     last_pattern[0] = '\0';
  132 }
  133 /**
  134  * set_color_tag: construct regular expression for coloring tag.
  135  *
  136  * You should not call this function when locked == true.
  137  */
  138 static void
  139 set_color_tag(const char *pattern)
  140 {
  141     STATIC_STRBUF(sb);
  142     int rewrite_flags = 0;
  143 
  144     if (rewrite == NULL)
  145         die("set_color_tag: impossible.");
  146     if (pattern == NULL || !strcmp(pattern, last_pattern))
  147         return;     /* nothing to do */
  148     strlimcpy(last_pattern, pattern, sizeof(last_pattern));
  149     strbuf_clear(sb);
  150     if (flags & CONVERT_IDUTILS) {
  151         /*
  152          * refuse '.*' because it brings confused output.
  153          */
  154         if (!strcmp(pattern, ".*") ||
  155             !strcmp(pattern, "^.*") ||
  156             !strcmp(pattern, ".*$") ||
  157             !strcmp(pattern, "^.*$"))
  158         {
  159             rewrite_cancel(rewrite);
  160             locked = 1;
  161             return;
  162         }
  163         /*
  164          * Though color support for the -I command is far
  165          * from perfection, it works in almost case.
  166          */
  167         strbuf_puts(sb, "\\b");
  168         if (isregex(pattern)) {
  169             int len = strlen(pattern);
  170             int inclass, quote, dollar, i;
  171 #define TOKEN_CHARS  "[A-Za-z_0-9]"
  172             inclass = quote = dollar = i = 0;
  173             if (*pattern == '^') {
  174                 i = 1;
  175             } else {
  176                 strbuf_puts(sb, TOKEN_CHARS);
  177                 strbuf_putc(sb, '*');
  178             }
  179             for (; i < len; i++) {
  180                 int c = pattern[i];
  181 
  182                 if (quote) {
  183                     quote = 0;
  184                     strbuf_putc(sb, c);
  185                 } else if (inclass) {
  186                     if (c == ']')
  187                         inclass = 0;
  188                     strbuf_putc(sb, c);
  189                 } else if (c == '\\') {
  190                     quote = 1;
  191                     strbuf_putc(sb, c);
  192                 } else if (c == '[') {
  193                     inclass = 1;
  194                     strbuf_putc(sb, c);
  195                     if (pattern[i + 1] == ']')
  196                         strbuf_putc(sb, pattern[++i]);
  197                 } else if (c == '.') {
  198                     strbuf_puts(sb, TOKEN_CHARS);
  199                 } else if (c == '$' && i == len - 1) {
  200                     dollar = 1;
  201                 } else {
  202                     strbuf_putc(sb, c);
  203                 }
  204             }
  205             if (!dollar) {
  206                 strbuf_puts(sb, TOKEN_CHARS);
  207                 strbuf_putc(sb, '*');
  208             }
  209         } else {
  210             strbuf_puts(sb, pattern);
  211         }
  212         strbuf_puts(sb, "\\b");
  213         locked = 1;
  214     } else if (flags & CONVERT_PATH) {
  215         if (*pattern == '^') {
  216             strbuf_putc(sb, *pattern++);
  217             if (*pattern != '/')
  218                 strbuf_putc(sb, '/');
  219         }
  220         strbuf_puts(sb, pattern);
  221         locked = 1;
  222     } else if (flags & CONVERT_GREP || isregex(pattern)) {
  223         strbuf_puts(sb, pattern);
  224         locked = 1;
  225     } else {
  226         strbuf_puts(sb, "\\b");
  227         strbuf_puts(sb, pattern);
  228         strbuf_puts(sb, "\\b");
  229     }
  230     if (debug)
  231         fprintf(stdout, "regex: |%s|\n", strbuf_value(sb));
  232     if (!(flags & CONVERT_BASIC))
  233         rewrite_flags |= REG_EXTENDED;
  234     if (flags & CONVERT_ICASE)
  235         rewrite_flags |= REG_ICASE;
  236     /* compile the regular expression */
  237     if (rewrite_pattern(rewrite, strbuf_value(sb), rewrite_flags) < 0)
  238         die("invalid regular expression. '%s'", strbuf_value(sb));
  239 }
  240 /**
  241  * void set_print0(void)
  242  *
  243  * set_print0: change newline to '\0'.
  244  */
  245 static int newline = '\n';
  246 void
  247 set_print0(void)
  248 {
  249     newline = '\0';
  250 }
  251 /**
  252  * Path filter for the output of global(1).
  253  * The path name starts with "./" which is the project root directory.
  254  */
  255 static const char *
  256 convert_pathname(CONVERT *cv, const char *path)
  257 {
  258     static char buf[MAXPATHLEN];
  259     const char *a, *b;
  260 
  261     if (flags & CONVERT_COLOR && flags & CONVERT_PATH) {
  262         STATIC_STRBUF(sb);
  263         const char *p;
  264 
  265         /* color the path */
  266         path = rewrite_string(rewrite, path + 1, 0);
  267         /* normalize the path */
  268         strbuf_clear(sb);
  269         strbuf_puts(sb, "./");
  270         for (p = path; *p && (*p == '/' || *p == ESC); p++) {
  271             if (*p == ESC) {
  272                 for (; *p && *p != EOE; p++)
  273                     strbuf_putc(sb, *p);
  274                 strbuf_putc(sb, *p);
  275             }
  276         }
  277         strbuf_puts(sb, p);
  278         path = strbuf_value(sb);
  279     }
  280     if (cv->type != PATH_THROUGH) {
  281         /*
  282          * make absolute path name.
  283          * 'path + 1' means skipping "." at the head.
  284          */
  285         strbuf_setlen(cv->abspath, cv->start_point);
  286         strbuf_puts(cv->abspath, path + 1);
  287         /*
  288          * print path name with converting.
  289          */
  290         switch (cv->type) {
  291         case PATH_ABSOLUTE:
  292             path = strbuf_value(cv->abspath);
  293             break;
  294         case PATH_RELATIVE:
  295         case PATH_SHORTER:
  296             a = strbuf_value(cv->abspath);
  297             b = cv->basedir;
  298 #if defined(_WIN32) || defined(__DJGPP__)
  299             /*
  300              * use absolute if on different drives.
  301              */
  302             if (tolower(*a) != tolower(*b)) {
  303                 path = a;
  304                 break;
  305             }
  306             while (*a != '/')
  307                 a++;
  308             while (*b != '/')
  309                 b++;
  310 #endif
  311             if (!abs2rel(a, b, buf, sizeof(buf)))
  312                 die("abs2rel failed. (path=%s, base=%s).", a, b);
  313             path = buf;
  314             if (cv->type == PATH_SHORTER && strlen(path) > strbuf_getlen(cv->abspath))
  315                 path = strbuf_value(cv->abspath);
  316             break;
  317         default:
  318             die("unknown path type.");
  319             break;
  320         }
  321     }
  322     /*
  323      * encoding of the path name.
  324      */
  325     if (use_encoding()) {
  326         const char *p;
  327         int required = 0;
  328 
  329         for (p = path; *p; p++) {
  330             if (required_encode(*p)) {
  331                 required = 1;
  332                 break;
  333             }
  334         }
  335         if (required) {
  336             static char buf[MAXPATHLEN];
  337             char c[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  338             char *q = buf;
  339 
  340             for (p = path; *p; p++) {
  341                 if (required_encode(*p)) {
  342                     *q++ = '%';
  343                     *q++ = c[*p / 16];
  344                     *q++ = c[*p % 16];
  345                 } else
  346                     *q++ = *p;
  347             }
  348             *q = '\0';
  349             path = buf;
  350         }
  351     }
  352     return (const char *)path;
  353 }
  354 /**
  355  * convert_open: open convert filter
  356  *
  357  *  @param[in]  type    PATH_ABSOLUTE, PATH_RELATIVE, PATH_THROUGH
  358  *  @param[in]  format  tag record format
  359  *  @param[in]  root    root directory of source tree
  360  *  @param[in]  cwd current directory
  361  *  @param[in]  dbpath  dbpath directory
  362  *  @param[in]  op  output file
  363  *  @param[in]  db  tag type (GTAGS, GRTAGS, GSYMS, GPATH, NOTAGS)
  364  */
  365 CONVERT *
  366 convert_open(int type, int format, const char *root, const char *cwd, const char *dbpath, FILE *op, int db)
  367 {
  368     CONVERT *cv = (CONVERT *)check_calloc(sizeof(CONVERT), 1);
  369     /*
  370      * set base directory.
  371      */
  372     cv->abspath = strbuf_open(MAXPATHLEN);
  373     strbuf_puts(cv->abspath, root);
  374     strbuf_unputc(cv->abspath, '/');
  375     cv->start_point = strbuf_getlen(cv->abspath);
  376     /*
  377      * copy elements.
  378      */
  379     if (strlen(cwd) > MAXPATHLEN)
  380         die("current directory name too long.");
  381     strlimcpy(cv->basedir, cwd, sizeof(cv->basedir));
  382     cv->type = type;
  383     cv->format = format;
  384     cv->op = op;
  385     cv->db = db;
  386     /*
  387      * open GPATH.
  388      */
  389     if (gpath_open(dbpath, 0) < 0)
  390         die("GPATH not found.");
  391     /*
  392      * setup coloring.
  393      */
  394     code_fputs = fputs;
  395     if (flags & CONVERT_COLOR) {
  396         set_color_method();
  397         if (!(flags & CONVERT_PATH))
  398             code_fputs = color_code_fputs;
  399     }
  400     return cv;
  401 }
  402 /**
  403  * convert_put: convert path into relative or absolute and print.
  404  *
  405  *  @param[in]  cv  CONVERT structure
  406  *  @param[in]  ctags_x tag record (ctags-x format)
  407  *
  408  * [Note] This function is only called by global with the --path option.
  409  */
  410 void
  411 convert_put(CONVERT *cv, const char *ctags_x)
  412 {
  413     char *tagnextp = NULL;
  414     int tagnextc = 0;
  415     char *tag = NULL, *lineno = NULL, *path, *rest = NULL;
  416     const char *fid = NULL;
  417 
  418     if (cv->format == FORMAT_PATH)
  419         die("convert_put: internal error.");    /* Use convert_put_path() */
  420     /*
  421      * parse tag line.
  422      * Don't use split() function not to destroy line image.
  423      */
  424     {
  425         char *p = (char *)ctags_x;
  426         /*
  427          * tag name
  428          */
  429         tag = p;
  430         for (; *p && !isspace(*p); p++)
  431             ;
  432         if (*p == '\0')
  433             die("invalid ctags-x format (line number not found).");
  434         tagnextp = p;
  435         tagnextc = *p;
  436         *p++ = '\0';
  437         /* skip blanks */
  438         for (; *p && isspace(*p); p++)
  439             ;
  440         if (*p == '\0')
  441             die("invalid ctags-x format (line number not found).");
  442         /*
  443          * line number
  444          */
  445         lineno = p;
  446         for (; *p && !isspace(*p); p++)
  447             ;
  448         if (*p == '\0')
  449             die("invalid ctags-x format (path name not found).");
  450         *p++ = '\0';
  451         /* skip blanks */
  452         for (; *p && isspace(*p); p++)
  453             ;
  454         if (*p == '\0')
  455             die("invalid ctags-x format (path name not found).");
  456         /*
  457          * path name
  458          */
  459         path = p;
  460         for (; *p && !isspace(*p); p++)
  461             ;
  462         if (*p == '\0')
  463             die("invalid ctags-x format (line image not found).");
  464         *p++ = '\0';
  465         rest = p;
  466     }
  467     /*
  468      * The path name has already been encoded.
  469      */
  470     path = decode_path(path);
  471     switch (cv->format) {
  472     case FORMAT_CTAGS:
  473     case FORMAT_CTAGS_PLUS:
  474         fputs(tag, cv->op);
  475         fputc('\t', cv->op);
  476         fputs(convert_pathname(cv, path), cv->op);
  477         fputc('\t', cv->op);
  478         fputs(lineno, cv->op);
  479         if (cv->format == FORMAT_CTAGS_PLUS) {
  480             fputc('\t', cv->op);
  481             fputs(rest, cv->op);
  482         }
  483         break;
  484     case FORMAT_CTAGS_XID:
  485         fid = gpath_path2fid(path, NULL);
  486         if (fid == NULL)
  487             die("convert_put: unknown file. '%s'", path);
  488         fputs(fid, cv->op);
  489         fputc(' ', cv->op);
  490         /* PASS THROUGH */
  491     case FORMAT_CTAGS_X:
  492         /*
  493          * print until path name.
  494          */
  495         *tagnextp = tagnextc;
  496         fputs(ctags_x, cv->op);
  497         fputc(' ', cv->op);
  498         /*
  499          * print path name and the rest.
  500          */
  501         fputs(convert_pathname(cv, path), cv->op);
  502         fputc(' ', cv->op);
  503         fputs(rest, cv->op);
  504         break;
  505     case FORMAT_CTAGS_MOD:
  506         fputs(convert_pathname(cv, path), cv->op);
  507         fputc('\t', cv->op);
  508         fputs(lineno, cv->op);
  509         fputc('\t', cv->op);
  510         fputs(rest, cv->op);
  511         break;
  512     case FORMAT_GREP:
  513         fputs(convert_pathname(cv, path), cv->op);
  514         fputc(':', cv->op);
  515         fputs(lineno, cv->op);
  516         fputc(':', cv->op);
  517         fputs(rest, cv->op);
  518         break;
  519     case FORMAT_CSCOPE:
  520         fputs(convert_pathname(cv, path), cv->op);
  521         fputc(' ', cv->op);
  522         fputs(tag, cv->op);
  523         fputc(' ', cv->op);
  524         fputs(lineno, cv->op);
  525         fputc(' ', cv->op);
  526         for (; *rest && isspace(*rest); rest++)
  527             ;
  528         if (*rest)
  529             fputs(rest, cv->op);
  530         else
  531             fputs("<unknown>", cv->op);
  532         break;
  533     default:
  534         die("unknown format type.");
  535     }
  536     (void)fputc(newline, cv->op);
  537 }
  538 /**
  539  * convert_put_path: convert path into relative or absolute and print.
  540  *
  541  *  @param[in]  cv  CONVERT structure
  542  *      @param[in]      pattern pattern
  543  *  @param[in]  path    path name
  544  */
  545 void
  546 convert_put_path(CONVERT *cv, const char *pattern, const char *path)
  547 {
  548     if (flags & CONVERT_COLOR && !locked && pattern)
  549         set_color_tag(pattern);
  550     if (cv->format != FORMAT_PATH)
  551         die("convert_put_path: internal error.");
  552     fputs(convert_pathname(cv, path), cv->op);
  553     (void)fputc(newline, cv->op);
  554 }
  555 /**
  556  * convert_put_using: convert path into relative or absolute and print.
  557  *
  558  *  @param[in]  cv  CONVERT structure
  559  *      @param[in]      tag     tag name
  560  *      @param[in]      path    path name
  561  *      @param[in]      lineno  line number
  562  *      @param[in]      rest    line image
  563  *  @param[in]  fid file id (only when fid != NULL)
  564  */
  565 void
  566 convert_put_using(CONVERT *cv, const char *tag, const char *path, int lineno, const char *rest, const char *fid)
  567 {
  568     if (rest == NULL)
  569         rest = "";  /* for safety */
  570     if (flags & CONVERT_COLOR && !locked)
  571         set_color_tag(tag);
  572     if (cv->tag_for_display)
  573         tag = cv->tag_for_display;
  574     switch (cv->format) {
  575     case FORMAT_PATH:
  576         fputs(convert_pathname(cv, path), cv->op);
  577         break;
  578     case FORMAT_CTAGS:
  579     case FORMAT_CTAGS_PLUS:
  580         fputs(tag, cv->op);
  581         fputc('\t', cv->op);
  582         fputs(convert_pathname(cv, path), cv->op);
  583         fputc('\t', cv->op);
  584         fprintf(cv->op, "%d", lineno);
  585         if (cv->format == FORMAT_CTAGS_PLUS) {
  586             fputc('\t', cv->op);
  587             code_fputs(rest, cv->op);
  588         }
  589         break;
  590     case FORMAT_CTAGS_XID:
  591         if (fid == NULL) {
  592             fid = gpath_path2fid(path, NULL);
  593             if (fid == NULL)
  594                 die("convert_put_using: unknown file. '%s'", path);
  595         }
  596         fputs(fid, cv->op);
  597         fputc(' ', cv->op);
  598         /* PASS THROUGH */
  599     case FORMAT_CTAGS_X:
  600         fprintf(cv->op, "%-16s %4d %-16s ",
  601             tag, lineno, convert_pathname(cv, path));
  602         code_fputs(rest, cv->op);
  603         break;
  604     case FORMAT_CTAGS_MOD:
  605         fputs(convert_pathname(cv, path), cv->op);
  606         fputc('\t', cv->op);
  607         fprintf(cv->op, "%d", lineno);
  608         fputc('\t', cv->op);
  609         code_fputs(rest, cv->op);
  610         break;
  611     case FORMAT_GREP:
  612         fputs(convert_pathname(cv, path), cv->op);
  613         fputc(':', cv->op);
  614         fprintf(cv->op, "%d", lineno);
  615         fputc(':', cv->op);
  616         code_fputs(rest, cv->op);
  617         break;
  618     case FORMAT_CSCOPE:
  619         fputs(convert_pathname(cv, path), cv->op);
  620         fputc(' ', cv->op);
  621         fputs(tag, cv->op);
  622         fputc(' ', cv->op);
  623         fprintf(cv->op, "%d", lineno);
  624         fputc(' ', cv->op);
  625         for (; *rest && isspace(*rest); rest++)
  626             ;
  627         if (*rest)
  628             code_fputs(rest, cv->op);
  629         else
  630             fputs("<unknown>", cv->op);
  631         break;
  632     default:
  633         die("unknown format type.");
  634     }
  635     (void)fputc(newline, cv->op);
  636 }
  637 void
  638 convert_close(CONVERT *cv)
  639 {
  640     strbuf_close(cv->abspath);
  641     gpath_close();
  642     free(cv);
  643 }