1 /*
2  * Copyright (c) 1996, 1997, 1998, 1999, 2000, 2006
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 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 
26 #include "die.h"
27 #include "tab.h"
28 
29 /*
30  * Puct and getc are very slow on some platforms including GNU/Linux.
31  * Because GLOBAL does not have multi-threaded program,
32  * they can be replaced with non thread safe version.
33  */
34 #ifdef HAVE_PUTC_UNLOCKED
35 #undef putc
36 #define putc	putc_unlocked
37 #endif
38 #ifdef HAVE_GETC_UNLOCKED
39 #undef getc
40 #define getc	getc_unlocked
41 #endif
42 
43 static int tabs = 8;
44 
45 /**
46  * settabs: set default tab stop
47  *
48  *	@param[in]	n	tab stop (1...32 only)
49  */
50 void
settabs(int n)51 settabs(int n)
52 {
53 	if (n < 1 || n > 32)
54 		return;
55 	tabs = n;
56 }
57 /**
58  * size_t read_file_detabing(char *buf, size_t size, FILE *ip, int *dest_saved, int *spaces_saved)
59  *
60  * Read file converting tabs into spaces.
61  *
62  *	@param[out]	buf
63  *	@param[in]	size	size of buf
64  *	@param[in]	ip	input file
65  *	@param[out]	dest_saved	current column in buf
66  *	@param[out]	spaces_saved	left spaces
67  *	@return		size of data
68  *
69  * dest_saved and spaces_saved are control variables.
70  * You must initialize them with 0 (zero) when the input file is opened.
71  */
72 #define PUTSPACES \
73 	do {									\
74 		int n = (spaces < size) ? spaces : size;			\
75 		dest += n;							\
76 		size -= n;							\
77 		spaces -= n;							\
78 		do {								\
79 			*p++ = ' ';						\
80 		} while (--n);							\
81 	} while (0)
82 size_t
read_file_detabing(char * buf,size_t size,FILE * ip,int * dest_saved,int * spaces_saved)83 read_file_detabing(char *buf, size_t size, FILE *ip, int *dest_saved, int *spaces_saved)
84 {
85 	char *p;
86 	int c, dest, spaces;
87 
88 	if (size == 0)
89 		return 0;
90 	p = buf;
91 	dest = *dest_saved;
92 	spaces = *spaces_saved;
93 	if (spaces > 0)
94 		PUTSPACES;
95 	while (size > 0) {
96 		c = getc(ip);
97 		if (c == EOF) {
98 			if (ferror(ip))
99 				die("read error.");
100 			break;
101 		}
102 		if (c == '\t') {
103 			spaces = tabs - dest % tabs;
104 			PUTSPACES;
105 		} else {
106 			*p++ = c;
107 			dest++;
108 			if (c == '\n')
109 				dest = 0;
110 			size--;
111 		}
112 	}
113 	*dest_saved = dest;
114 	*spaces_saved = spaces;
115 	return p - buf;
116 }
117 /**
118  * detab_replacing: convert tabs into spaces and print with replacing.
119  *
120  *	@param[in]	op	FILE *
121  *	@param[in]	buf	string including tabs
122  *	@param[in]	replace	replacing function
123  */
124 void
detab_replacing(FILE * op,const char * buf,const char * (* replace)(int c))125 detab_replacing(FILE *op, const char *buf, const char *(*replace)(int c))
126 {
127 	int dst, spaces;
128 	int c;
129 
130 	dst = 0;
131 	while ((c = *buf++) != '\0') {
132 		if (c == '\t') {
133 			spaces = tabs - dst % tabs;
134 			dst += spaces;
135 			do {
136 				putc(' ', op);
137 			} while (--spaces);
138 		} else {
139 			const char *s = replace(c);
140 			if (s)
141 				fputs(s, op);
142 			else
143 				putc(c, op);
144 			dst++;
145 		}
146 	}
147 	putc('\n', op);
148 }
149