(broken) removing a lot of code - iomenu - interactive terminal-based selection menu
(HTM) git clone git://bitreich.org/iomenu git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/iomenu
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Tags
(DIR) README
(DIR) LICENSE
---
(DIR) commit 0a259537342b214215afbeb7625ba86142ba7e8f
(DIR) parent b327379ab041e7fbd37f3246b1affe7014109135
(HTM) Author: Josuah Demangeonā ā µ <mail@josuah.net>
Date: Mon, 13 Mar 2017 22:10:01 +0100
(broken) removing a lot of code
Diffstat:
M Makefile | 8 +-------
M buffer.c | 52 +++++--------------------------
M draw.c | 38 ++++++++-----------------------
M input.c | 12 +-----------
M iomenu.1 | 5 +++--
A iomenu.c | 128 +++++++++++++++++++++++++++++++
A iomenu.h | 67 +++++++++++++++++++++++++++++++
D main.c | 91 -------------------------------
D main.h | 95 ------------------------------
D nohup.out | 92 -------------------------------
D util.c | 73 -------------------------------
11 files changed, 218 insertions(+), 443 deletions(-)
---
(DIR) diff --git a/Makefile b/Makefile
@@ -1,17 +1,11 @@
CFLAGS = -std=c89 -pedantic -Wall -Wextra -g -static
-SRC = main.c buffer.c util.c draw.c input.c
OBJ = ${SRC:.c=.o}
MANPREFIX = $(PREFIX)
all: clean iomenu
-.c.o:
- ${CC} -c ${CFLAGS} $<
-
-iomenu: ${OBJ}
- ${CC} -o $@ ${OBJ} ${LDFLAGS}
- rm -f *.o
+iomenu: buffer.c draw.c input.c
clean:
rm -f iomenu ${OBJ}
(DIR) diff --git a/buffer.c b/buffer.c
@@ -3,18 +3,18 @@
#include <stdlib.h>
#include <string.h>
-#include "main.h"
+#include "iomenu.h"
/*
- * Fill the buffer apropriately with the lines and headers.
+ * Fill the buffer apropriately with the lines
*/
Buffer *
fill_buffer(char *separator)
{
/* fill buffer with string */
char s[LINE_SIZE];
- Buffer *buffer = malloc(sizeof(Buffer));
+ Line **buffer = malloc(sizeof(Line));
FILE *fp = stdin;
int l;
@@ -26,22 +26,13 @@ fill_buffer(char *separator)
/* empty line in case no line come from stdin */
buffer->first = buffer->current = malloc(sizeof(Line));
- buffer->first->content = buffer->first->comment = "";
buffer->first->next = buffer->first->prev = NULL;
buffer->last = NULL;
/* read the file into a doubly linked list of lines */
- for (l = 1; fgets(s, LINE_SIZE, fp); buffer->total++, l++) {
+ for (l = 1; fgets(s, LINE_SIZE, fp); buffer->total++, l++)
buffer->last = add_line(buffer, l, s, separator, buffer->last);
- l = buffer->last->header ? 0 : l;
- }
-
- /* prevent initial current line to be a header */
- buffer->current = buffer->first;
- while (buffer->current->next && buffer->current->header)
- buffer->current = buffer->current->next;
-
return buffer;
}
@@ -70,40 +61,16 @@ add_line(Buffer *buffer, int number, char *s, char *separator, Line *prev)
}
-/*
- * Parse the line content to determine if it is a header and identify the
- * separator if any.
- */
Line *
new_line(char *s, char *separator)
{
Line *line = malloc(sizeof(Line));
- char *sep = separator ? strstr(s, separator) : NULL;
- int pos = sep ? (int) (sep - s) : (int) strlen(s) - 1;
-
- /* header is when separator is the first character of the line */
- line->header = (sep == s);
/* strip trailing newline */
s[strlen(s) - 1] = '\0';
/* fill line->content */
- line->content = malloc((pos + 1) * sizeof(char));
- strncpy(line->content, s, pos);
-
- /* fill line->comment */
- line->comment = malloc((strlen(s) - pos) * sizeof(char));
- if (sep) {
- strcpy(line->comment, s + pos + strlen(separator));
- }
-
- /* strip trailing whitespaces from line->content */
- for (pos--; pos > 0 && isspace(line->content[pos]); pos--)
- line->content[pos] = '\0';
-
- /* strip leading whitespaces from line->comment */
- for (pos = 0; isspace(line->comment[pos]); pos++);
- line->comment += pos;
+ line->content = s;
return line;
}
@@ -161,7 +128,7 @@ filter_lines(Buffer *buffer, int inc)
buffer->current = line;
} else if ((inc && line->matches) || (!inc && !line->matches)) {
line->matches = match_line(line, tokv, tokc);
- buffer->matching += line->header ? 0 : line->matches;
+ buffer->matching += line->matches;
}
line = line->next;
@@ -177,9 +144,6 @@ match_line(Line *line, char **tokv, size_t tokc)
{
size_t i, match = 1, offset = 0;
- if (line->header)
- return 1;
-
for (i = 0; i < tokc && match; i++)
match = !!strstr(line->content + offset, tokv[i]);
@@ -193,7 +157,7 @@ match_line(Line *line, char **tokv, size_t tokc)
Line *
matching_prev(Line *line)
{
- while ((line = line->prev) && (!line->matches || line->header));
+ while ((line = line->prev) && !line->matches);
return line;
}
@@ -204,6 +168,6 @@ matching_prev(Line *line)
Line *
matching_next(Line *line)
{
- while ((line = line->next) && (!line->matches || line->header));
+ while ((line = line->next) && !line->matches);
return line;
}
(DIR) diff --git a/draw.c b/draw.c
@@ -3,7 +3,7 @@
#include <stdio.h>
#include <sys/ioctl.h>
-#include "main.h"
+#include "iomenu.h"
/*
@@ -12,12 +12,10 @@
void
draw_line(Line *line, int current, const int cols, Opt *opt)
{
- char *content = expand_tabs(line->content);
- char *comment = expand_tabs(line->comment);
char output[LINE_SIZE * sizeof(char)] = "\033[K";
int n = 0;
- if (opt->line_numbers && !line->header) {
+ if (opt->line_numbers) {
strcat(output, current ? "\033[1;37m" : "\033[1;30m");
sprintf(output + strlen(output), "%7d\033[m ", line->number);
} else {
@@ -25,34 +23,22 @@ draw_line(Line *line, int current, const int cols, Opt *opt)
}
n += 8;
-
/* highlight current line */
if (current)
strcat(output, "\033[1;33m");
/* content */
- strncat(output, content, cols - n);
- n += strlen(content);
-
- /* align comment */
- if (!line->header && line->comment[0] != '\0') {
- /* MAX with '1' as \033[0C still move 1 to the right */
- sprintf(output + strlen(output), "\033[%dC",
- MAX(1, 40 - n));
- n += MAX(1, 40 - n);
- } else if (line->header)
-
- /* comment */
- strcat(output, "\033[1;30m");
- strncat(output, comment, cols - n);
- n += strlen(comment);
+ strncat(output, line->content, cols - n);
+ n += strlen(line->content);
+ /* MAX with '1' as \033[0C still move 1 to the right */
+ sprintf(output + strlen(output), "\033[%dC",
+ MAX(1, 40 - n));
+ n += MAX(1, 40 - n);
strcat(output, "\033[m\n");
fputs(output, stderr);
- free(content);
- free(comment);
}
@@ -137,8 +123,6 @@ draw_prompt(Buffer *buffer, int cols, Opt *opt)
size_t i;
int matching = buffer->matching;
int total = buffer->total;
- char *input = expand_tabs(buffer->input);
- char *suggest = expand_tabs(buffer->current->content);
/* for the '/' separator between the numbers */
cols--;
@@ -153,8 +137,8 @@ draw_prompt(Buffer *buffer, int cols, Opt *opt)
cols -= 2 + MAX(strlen(opt->prompt), 6);
/* input without overflowing terminal width */
- for (i = 0; i < strlen(input) && cols > 0; cols--, i++)
- fputc(input[i], stderr);
+ for (i = 0; i < strlen(buffer->input) && cols > 0; cols--, i++)
+ fputc(buffer->input[i], stderr);
/* save the cursor position at the end of the input */
fputs("\033[s", stderr);
@@ -171,6 +155,4 @@ draw_prompt(Buffer *buffer, int cols, Opt *opt)
/* restore cursor position at the end of the input */
fputs("\033[m\033[u", stderr);
- free(input);
- free(suggest);
}
(DIR) diff --git a/input.c b/input.c
@@ -4,7 +4,7 @@
#include <string.h>
#include <termios.h>
-#include "main.h"
+#include "iomenu.h"
/*
@@ -214,16 +214,6 @@ action_print_selection(Buffer *buffer, int return_input, Opt *opt)
fputs("\r\033[K", stderr);
- if (opt->print_header) {
- for (line = buffer->current; line; line = line->prev) {
- if (line->header) {
- fputs(line->comment, stdout);
- break;
- }
- }
- fputc((int) '\t', stdout);
- }
-
if (opt->print_number) {
if (buffer->matching > 0)
printf("%d\n", buffer->current->number);
(DIR) diff --git a/iomenu.1 b/iomenu.1
@@ -1,11 +1,12 @@
-.Dd $Mdocdate: October 16 2016 $
+.Dd Mars 16 2016
.Dt IOMENU 1
.Os
+.
.Sh NAME
+.
.Nm iomenu
.Op Fl nNHksl
.
-.
.Sh DESCRIPTION
.
The
(DIR) diff --git a/iomenu.c b/iomenu.c
@@ -0,0 +1,128 @@
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+
+#include "iomenu.h"
+
+
+/*
+ * Reset the terminal state and exit with error.
+ */
+void
+die(const char *s)
+{
+ /* tcsetattr(STDIN_FILENO, TCSANOW, &termio_old); */
+ fprintf(stderr, "%s\n", s);
+ exit(EXIT_FAILURE);
+}
+
+
+/*
+ * Set terminal to send one char at a time for interactive mode, and return the
+ * last terminal state.
+ */
+struct termios
+set_terminal(int tty_fd)
+{
+ struct termios termio_old;
+ struct termios termio_new;
+
+ /* set the terminal to send one key at a time. */
+
+ /* get the terminal's state */
+ if (tcgetattr(tty_fd, &termio_old) < 0)
+ die("Can not get terminal attributes with tcgetattr().");
+
+ /* create a new modified state by switching the binary flags */
+ termio_new = termio_old;
+ termio_new.c_lflag &= ~(ICANON | ECHO | IGNBRK);
+
+ /* apply this state to current terminal now (TCSANOW) */
+ tcsetattr(tty_fd, TCSANOW, &termio_new);
+
+ return termio_old;
+}
+
+
+void
+usage(void)
+{
+ fputs("usage: iomenu [-n] [-N] [-k key] [-s separator] ", stderr);
+ fputs("[-p prompt] [-l lines]\n", stderr);
+
+ exit(EXIT_FAILURE);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ int i, exit_code, tty_fd = open("/dev/tty", O_RDWR);
+ Buffer *buffer = NULL;
+ Opt *opt = malloc(sizeof(Opt));
+
+ opt->line_numbers = 0;
+ opt->print_number = 0;
+ opt->validate_key = CONTROL('M');
+ opt->separator = NULL;
+ opt->lines = 30;
+ opt->prompt = "";
+
+ /* command line arguments */
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-' || strlen(argv[i]) != 2)
+ usage();
+
+ switch (argv[i][1]) {
+ case 'n':
+ opt->line_numbers = 1;
+ break;
+ case 'N':
+ opt->print_number = 1;
+ opt->line_numbers = 1;
+ break;
+ case 'k':
+ opt->validate_key = (argv[++i][0] == '^') ?
+ CONTROL(toupper(argv[i][1])): argv[i][0];
+ break;
+ case 's':
+ opt->separator = argv[++i];
+ break;
+ case 'l':
+ if (sscanf(argv[++i], "%d", &opt->lines) <= 0)
+ die("wrong number format after -l");
+ break;
+ case 'p':
+ if (++i >= argc)
+ die("wrong string format after -p");
+ opt->prompt = argv[i];
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* command line arguments */
+ buffer = fill_buffer(opt->separator);
+
+ /* set the interface */
+ draw_screen(buffer, tty_fd, opt);
+
+ /* listen and interact to input */
+ exit_code = input_get(buffer, tty_fd, opt);
+
+ draw_clear(opt->lines);
+
+ /* close files descriptors and pointers, and free memory */
+ close(tty_fd);
+ free(opt);
+ free_buffer(buffer);
+
+ return exit_code;
+}
(DIR) diff --git a/iomenu.h b/iomenu.h
@@ -0,0 +1,67 @@
+#define LINE_SIZE 1024
+#define OFFSET 5
+#define CONTINUE 2 /* as opposed to EXIT_SUCCESS and EXIT_FAILURE */
+
+#define CONTROL(char) (char ^ 0x40)
+#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+
+
+/*
+ * Options from the command line, to pass to each function that need some
+ */
+typedef struct Opt {
+ int line_numbers;
+ int print_number;
+ char validate_key;
+ char *separator;
+ int lines;
+ char *prompt;
+} Opt;
+
+
+/*
+ * Line coming from stdin
+ */
+typedef struct Line {
+ char *content; /* sent as output and matched by input */
+ int matches; /* whether it matches buffer's input */
+} Line;
+
+
+/* iomenu */
+
+void die(const char *);
+struct termios set_terminal(int);
+void usage(void);
+
+
+/* buffer */
+
+Buffer * fill_buffer(char *);
+void free_buffer(Buffer *);
+Line * add_line(Buffer *, int, char *, char *, Line *);
+Line * new_line(char *, char *);
+Line * matching_next(Line *);
+Line * matching_prev(Line *);
+int match_line(Line *, char **, size_t);
+void filter_lines(Buffer *, int);
+
+
+/* draw */
+
+void draw_screen(Buffer *, int, Opt *);
+void draw_clear(int);
+void draw_line(Line *, int, int, Opt *);
+void draw_lines(Buffer *, int, int, Opt *);
+void draw_prompt(Buffer *, int, Opt *);
+
+
+/* input */
+
+int input_get(Buffer *, int, Opt *);
+int input_key(FILE *, Buffer *, Opt *);
+void action_jump(Buffer *, int);
+void action_print_selection(Buffer *,int, Opt *);
+void action_remove_word_input(Buffer *);
+void action_add_character(Buffer *, char);
(DIR) diff --git a/main.c b/main.c
@@ -1,91 +0,0 @@
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include "main.h"
-
-
-void
-usage(void)
-{
- fputs("usage: iomenu [-n] [-N] [-k key] [-s separator] ", stderr);
- fputs("[-p prompt] [-l lines]\n", stderr);
-
- exit(EXIT_FAILURE);
-}
-
-
-int
-main(int argc, char *argv[])
-{
- int i, exit_code, tty_fd = open("/dev/tty", O_RDWR);
- Buffer *buffer = NULL;
- Opt *opt = malloc(sizeof(Opt));
-
- opt->line_numbers = 0;
- opt->print_number = 0;
- opt->validate_key = CONTROL('M');
- opt->separator = NULL;
- opt->lines = 30;
- opt->prompt = "";
-
- /* command line arguments */
- for (i = 1; i < argc; i++) {
- if (argv[i][0] != '-' || strlen(argv[i]) != 2)
- usage();
-
- switch (argv[i][1]) {
- case 'n':
- opt->line_numbers = 1;
- break;
- case 'N':
- opt->print_number = 1;
- opt->line_numbers = 1;
- break;
- case 'H':
- opt->print_header = 1;
- break;
- case 'k':
- opt->validate_key = (argv[++i][0] == '^') ?
- CONTROL(toupper(argv[i][1])): argv[i][0];
- break;
- case 's':
- opt->separator = argv[++i];
- break;
- case 'l':
- if (sscanf(argv[++i], "%d", &opt->lines) <= 0)
- die("wrong number format after -l");
- break;
- case 'p':
- if (++i >= argc)
- die("wrong string format after -p");
- opt->prompt = argv[i];
- break;
- default:
- usage();
- }
- }
-
- /* command line arguments */
- buffer = fill_buffer(opt->separator);
-
- /* set the interface */
- draw_screen(buffer, tty_fd, opt);
-
- /* listen and interact to input */
- exit_code = input_get(buffer, tty_fd, opt);
-
- draw_clear(opt->lines);
-
- /* close files descriptors and pointers, and free memory */
- close(tty_fd);
- free(opt);
- free_buffer(buffer);
-
- return exit_code;
-}
(DIR) diff --git a/main.h b/main.h
@@ -1,95 +0,0 @@
-#define LINE_SIZE 1024
-#define OFFSET 5
-#define CONTINUE 2 /* as opposed to EXIT_SUCCESS and EXIT_FAILURE */
-
-#define CONTROL(char) (char ^ 0x40)
-#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
-#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
-
-
-/*
- * Options from the command line, to pass to each function that need some
- */
-typedef struct Opt {
- int line_numbers;
- int print_number;
- int print_header;
- char validate_key;
- char *separator;
- int lines;
- char *prompt;
-} Opt;
-
-
-/*
- * Line coming from stdin, wrapped in a header.
- */
-typedef struct Line {
- char *content; /* sent as output and matched by input */
- char *comment; /* displayed at the right of the content */
-
- int number; /* set here as order will not change */
- int matches; /* whether it matches buffer's input */
- int header; /* whether the line is a header */
-
- struct Line *prev; /* doubly linked list structure */
- struct Line *next;
-} Line;
-
-
-/*
- * Buffer containing a doubly linked list of headers
- */
-typedef struct Buffer {
- int total; /* total number of line in buffer */
- int matching; /* number lines matching the input */
-
- char input[LINE_SIZE]; /* string from user's keyboard */
-
- Line *current; /* selected line, highlighted */
- Line *first; /* boundaries of the linked list */
- Line *last;
-} Buffer;
-
-
-/* main */
-
-void usage(void);
-
-
-/* buffer */
-
-Buffer * fill_buffer(char *);
-void free_buffer(Buffer *);
-Line * add_line(Buffer *, int, char *, char *, Line *);
-Line * new_line(char *, char *);
-Line * matching_next(Line *);
-Line * matching_prev(Line *);
-int match_line(Line *, char **, size_t);
-void filter_lines(Buffer *, int);
-
-
-/* draw */
-
-void draw_screen(Buffer *, int, Opt *);
-void draw_clear(int);
-void draw_line(Line *, int, int, Opt *);
-void draw_lines(Buffer *, int, int, Opt *);
-void draw_prompt(Buffer *, int, Opt *);
-
-
-/* input */
-
-int input_get(Buffer *, int, Opt *);
-int input_key(FILE *, Buffer *, Opt *);
-void action_jump(Buffer *, int);
-void action_print_selection(Buffer *,int, Opt *);
-void action_remove_word_input(Buffer *);
-void action_add_character(Buffer *, char);
-
-
-/* util */
-
-void die(const char *);
-struct termios set_terminal(int);
-char * expand_tabs(char *);
(DIR) diff --git a/nohup.out b/nohup.out
@@ -1,92 +0,0 @@
-build: [1mInstalling tmux[0m
-checking for a BSD-compatible install... /usr/bin/install -c
-checking whether build environment is sane... yes
-checking for a thread-safe mkdir -p... /bin/mkdir -p
-checking for gawk... no
-checking for mawk... mawk
-checking whether make sets $(MAKE)... yes
-checking whether make supports nested variables... yes
-checking build system type... x86_64-unknown-linux-gnu
-checking host system type... x86_64-unknown-linux-gnu
-checking for gcc... gcc
-checking whether the C compiler works... yes
-checking for C compiler default output file name... a.out
-checking for suffix of executables...
-checking whether we are cross compiling... no
-checking for suffix of object files... o
-checking whether we are using the GNU C compiler... yes
-checking whether gcc accepts -g... yes
-checking for gcc option to accept ISO C89... none needed
-checking whether gcc understands -c and -o together... yes
-checking for style of include used by make... GNU
-checking dependency style of gcc... gcc3
-checking how to run the C preprocessor... gcc -E
-checking for grep that handles long lines and -e... /bin/grep
-checking for egrep... /bin/grep -E
-checking for pkg-config... /usr/bin/pkg-config
-checking pkg-config is at least version 0.9.0... yes
-checking for glibc... yes
-checking for ANSI C header files... yes
-checking for sys/types.h... yes
-checking for sys/stat.h... yes
-checking for stdlib.h... yes
-checking for string.h... yes
-checking for memory.h... yes
-checking for strings.h... yes
-checking for inttypes.h... yes
-checking for stdint.h... yes
-checking for unistd.h... yes
-checking bitstring.h usability... no
-checking bitstring.h presence... no
-checking for bitstring.h... no
-checking dirent.h usability... yes
-checking dirent.h presence... yes
-checking for dirent.h... yes
-checking fcntl.h usability... yes
-checking fcntl.h presence... yes
-checking for fcntl.h... yes
-checking for inttypes.h... (cached) yes
-checking libutil.h usability... no
-checking libutil.h presence... no
-checking for libutil.h... no
-checking ndir.h usability... no
-checking ndir.h presence... no
-checking for ndir.h... no
-checking paths.h usability... yes
-checking paths.h presence... yes
-checking for paths.h... yes
-checking pty.h usability... yes
-checking pty.h presence... yes
-checking for pty.h... yes
-checking for stdint.h... (cached) yes
-checking sys/dir.h usability... yes
-checking sys/dir.h presence... yes
-checking for sys/dir.h... yes
-checking sys/ndir.h usability... no
-checking sys/ndir.h presence... no
-checking for sys/ndir.h... no
-checking sys/tree.h usability... no
-checking sys/tree.h presence... no
-checking for sys/tree.h... no
-checking term.h usability... no
-checking term.h presence... no
-checking for term.h... no
-checking util.h usability... no
-checking util.h presence... no
-checking for util.h... no
-checking for library containing flock... none required
-checking for dirfd... yes
-checking for flock... yes
-checking for prctl... yes
-checking for sysconf... yes
-checking for cfmakeraw... yes
-checking for library containing clock_gettime... none required
-checking for LIBEVENT... no
-checking for library containing event_init... no
-checking event.h usability... no
-checking event.h presence... no
-checking for event.h... no
-configure: error: "libevent not found"
-make: *** No rule to make target 'install'. Stop.
-build: [1mUpdating index in /home/josuah/.local/tmux[0m
-build: [1mRemoving broken links from /home/josuah/.local[0m
(DIR) diff --git a/util.c b/util.c
@@ -1,73 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include "main.h"
-
-
-/*
- * Reset the terminal state and exit with error.
- */
-void
-die(const char *s)
-{
- /* tcsetattr(STDIN_FILENO, TCSANOW, &termio_old); */
- fprintf(stderr, "%s\n", s);
- exit(EXIT_FAILURE);
-}
-
-
-/*
- * Set terminal to send one char at a time for interactive mode, and return the
- * last terminal state.
- */
-struct termios
-set_terminal(int tty_fd)
-{
- struct termios termio_old;
- struct termios termio_new;
-
- /* set the terminal to send one key at a time. */
-
- /* get the terminal's state */
- if (tcgetattr(tty_fd, &termio_old) < 0)
- die("Can not get terminal attributes with tcgetattr().");
-
- /* create a new modified state by switching the binary flags */
- termio_new = termio_old;
- termio_new.c_lflag &= ~(ICANON | ECHO | IGNBRK);
-
- /* apply this state to current terminal now (TCSANOW) */
- tcsetattr(tty_fd, TCSANOW, &termio_new);
-
- return termio_old;
-}
-
-
-/*
- * Replace tab as a multiple of 8 spaces in a line.
- *
- * Allocates memory.
- */
-char *
-expand_tabs(char *line)
-{
- size_t i, n;
- char *converted = malloc(sizeof(char) * (strlen(line) * 8 + 1));
-
- for (i = 0, n = 0; i < strlen(line); i++, n++) {
- if (line[i] == '\t') {
- for (; n == 0 || n % 8 != 0; n++)
- converted[n] = ' ';
- n--;
- } else {
- converted[n] = line[i];
- }
- }
-
- converted[n] = '\0';
-
- return converted;
-}