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