root/libutil/tab.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. settabs
  2. read_file_detabing
  3. detab_replacing

/*
 * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2006
 *      Tama Communications Corporation
 *
 * This file is part of GNU GLOBAL.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>

#include "die.h"
#include "tab.h"

/*
 * Puct and getc are very slow on some platforms including GNU/Linux.
 * Because GLOBAL does not have multi-threaded program,
 * they can be replaced with non thread safe version.
 */
#ifdef HAVE_PUTC_UNLOCKED
#undef putc
#define putc    putc_unlocked
#endif
#ifdef HAVE_GETC_UNLOCKED
#undef getc
#define getc    getc_unlocked
#endif

static int tabs = 8;

/*
 * settabs: set default tab stop
 *
 *      i)      n       tab stop
 */
void
settabs(int n)
{
        if (n < 1 || n > 32)
                return;
        tabs = n;
}
/*
 * Read file converting tabs into spaces.
 *
 *      o)      buf     
 *      i)      size    size of 'buf'
 *      i)      ip      input file
 *      o)      dest_saved      current column in 'buf'
 *      o)      spaces_saved    left spaces
 *      r)              size of data
 *
 * Dest_saved and spaces_saved are control variables.
 * You must initialize them with 0 when the input file is opened.
 */
#define PUTSPACES \
        do {                                                                    \
                int n = (spaces < size) ? spaces : size;                        \
                dest += n;                                                      \
                size -= n;                                                      \
                spaces -= n;                                                    \
                do {                                                            \
                        *p++ = ' ';                                             \
                } while (--n);                                                  \
        } while (0)
size_t
read_file_detabing(char *buf, size_t size, FILE *ip, int *dest_saved, int *spaces_saved)
{
        char *p;
        int c, dest, spaces;

        if (size == 0)
                return 0;
        p = buf;
        dest = *dest_saved;
        spaces = *spaces_saved;
        if (spaces > 0)
                PUTSPACES;
        while (size > 0) {
                c = getc(ip);
                if (c == EOF) {
                        if (ferror(ip))
                                die("read error.");
                        break;
                }
                if (c == '\t') {
                        spaces = tabs - dest % tabs;
                        PUTSPACES;
                } else {
                        *p++ = c;
                        dest++;
                        if (c == '\n')
                                dest = 0;
                        size--;
                }
        }
        *dest_saved = dest;
        *spaces_saved = spaces;
        return p - buf;
}
/*
 * detab_replacing: convert tabs into spaces and print with replacing.
 *
 *      i)      op      FILE *
 *      i)      buf     string including tabs
 *      i)      replace replacing function
 */
void
detab_replacing(FILE *op, const char *buf, const char *(*replace)(int c))
{
        int dst, spaces;
        int c;

        dst = 0;
        while ((c = *buf++) != '\0') {
                if (c == '\t') {
                        spaces = tabs - dst % tabs;
                        dst += spaces;
                        do {
                                putc(' ', op);
                        } while (--spaces);
                } else {
                        const char *s = replace(c);
                        if (s)
                                fputs(s, op);
                        else
                                putc(c, op);
                        dst++;
                }
        }
        putc('\n', op);
}

/* [<][>][^][v][top][bottom][index][help] */