/*
* unexpand - convert spaces to tabs
*
* Gunnar Ritter, Freiburg i. Br., Germany, May 2003.
*/
/*
* Copyright (c) 2003 Gunnar Ritter
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute
* it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
#if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4
#define USED __attribute__ ((used))
#elif defined __GNUC__
#define USED __attribute__ ((unused))
#else
#define USED
#endif
static const char sccsid[] USED = "@(#)unexpand.sl 1.7 (gritter) 5/29/05";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <locale.h>
#include <wchar.h>
#include <unistd.h>
#include <ctype.h>
#if defined (__GLIBC__)
#if defined (_IO_putc_unlocked)
#undef putchar
#define putchar(c) _IO_putc_unlocked(c, stdout)
#endif
#endif
#include <iblok.h>
#include "tablist.h"
static int aflag;
static int status;
static int mb_cur_max;
static const char *progname;
static void usage(void);
static void unexpand(const char *);
static void spaces(long long *, long long *, struct tab **);
int
main(int argc, char **argv)
{
int i;
progname = basename(argv[0]);
setlocale(LC_CTYPE, "");
mb_cur_max = MB_CUR_MAX;
for (i = 1; i < argc && argv[i][0] == '-' && argv[i][1]; i++) {
if (argv[i][1] == '-' && argv[i][2] == '\0') {
i++;
break;
}
optc: if (argv[i][1] == 't') {
aflag = 1;
if (argv[i][2])
settab(&argv[i][2]);
else
settab(argv[++i]);
} else if (argv[i][1] == 'a') {
aflag = 1;
if (argv[i][2]) {
argv[i]++;
goto optc;
}
} else if (isdigit(argv[i][2]))
settab(&argv[i][1]);
else
usage();
}
if (tablist)
aflag = 0;
if (i < argc)
while (i < argc)
unexpand(argv[i++]);
else
unexpand(NULL);
return status;
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [ -a ] file ...\n",
progname);
exit(2);
}
static void
unexpand(const char *fn)
{
struct iblok *ip;
struct tab *tp;
char *cp;
char b;
wint_t c;
int n, w;
long long col, spc = 0;
if ((ip = fn ? ib_open(fn, 0) : ib_alloc(0, 0)) == NULL) {
perror(fn ? fn : "stdin");
status |= 1;
return;
}
col = 0;
tp = tablist;
while ((mb_cur_max > 1 ? cp = ib_getw(ip, &c, &n) :
(b = c = ib_get(ip), n = 1,
cp = c == (wint_t)EOF ? 0 : &b)),
cp != NULL) {
if (c == ' ' && (col == 0 || aflag || tablist && tp)) {
spc++;
continue;
}
if (spc && (col == 0 || aflag || tablist && tp))
spaces(&spc, &col, &tp);
switch (c) {
case '\n':
col = 0;
tp = tablist;
break;
case '\b':
if (col > 0)
col--;
break;
default:
if (mb_cur_max > 1) {
if ((w = wcwidth(c)) >= 0)
col += w;
else
col++;
} else
col++;
break;
case '\t':
if (tp)
while (tp && col > tp->t_pos)
tp = tp->t_nxt;
if (tp && col == tp->t_pos) {
col++;
tp = tp->t_nxt;
}
if (tp) {
while (col < tp->t_pos)
col++;
tp = tp->t_nxt;
} else if (tablist == 0) {
if (col % tabstop == 0)
col++;
while (col % tabstop)
col++;
} else
col++;
break;
}
while (n--) {
putchar(*cp & 0377);
cp++;
}
}
if (spc && (col == 0 || aflag || tablist && tp))
spaces(&spc, &col, &tp);
if (ip->ib_fd != 0)
ib_close(ip);
else
ib_free(ip);
}
static void
spaces(long long *sp, long long *cp, struct tab **tp)
{
int bol;
long long nsp;
bol = *cp == 0;
if (tablist) {
while (*tp && (*tp)->t_pos <= *cp)
*tp = (*tp)->t_nxt;
while (*sp && *tp && (*cp + *sp) >= (*tp)->t_pos) {
if (*sp == 1 && !bol)
putchar(' ');
else
putchar('\t');
*sp -= (*tp)->t_pos - *cp;
*cp = (*tp)->t_pos;
*tp = (*tp)->t_nxt;
}
} else {
while (*sp >= (nsp = tabstop - *cp % tabstop)) {
if (*sp == 1 && !bol)
putchar(' ');
else
putchar('\t');
*sp -= nsp;
*cp += nsp;
}
}
while (*sp) {
putchar(' ');
(*cp)++;
(*sp)--;
}
}
syntax highlighted by Code2HTML, v. 0.9.1