3 Copyright (C) 1997, 1998, 2002, 2004, 2009 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* FIXME: this is small for testing */
22 #define BUFFER_SIZE (8)
24 #define LEN(X, I) ((X)->p[(I)].one_past_end - (X)->p[(I)].start)
25 #define EMPTY(X) ((X)->n_bufs == 1 && LEN (X, 0) == 0)
27 #define ONE_PAST_END(X, I) ((X)->p[(I)].one_past_end)
34 typedef struct Line_ptr Line_ptr
;
48 typedef struct Buf Buf
;
51 buf_init_from_stdin (Buf
*x
, char eol_byte
)
53 bool last_byte_is_eol_byte
= true;
56 #define OBS (&(x->obs))
61 char *buf
= (char *) malloc (BUFFER_SIZE
);
66 /* Fall back on the code that relies on a temporary file.
67 Write all buffers to that file and free them. */
72 bytes_read
= full_read (STDIN_FILENO
, buf
, BUFFER_SIZE
);
73 if (bytes_read
!= buffer_size
&& errno
!= 0)
74 error (EXIT_FAILURE
, errno
, _("read error"));
79 bp
.one_past_end
= buf
+ bytes_read
;
80 obstack_grow (OBS
, &bp
, sizeof (bp
));
84 last_byte_is_eol_byte
= (buf
[bytes_read
- 1] == eol_byte
);
86 if (bytes_read
< BUFFER_SIZE
)
92 /* If the file was non-empty and lacked an EOL_BYTE at its end,
93 then add a buffer containing just that one byte. */
94 if (!last_byte_is_eol_byte
)
96 char *buf
= malloc (1);
99 /* FIXME: just like above */
107 bp
.one_past_end
= buf
+ 1;
108 obstack_grow (OBS
, &bp
, sizeof (bp
));
113 x
->n_bufs
= obstack_object_size (OBS
) / sizeof (x
->p
[0]);
114 x
->p
= (struct B_pair
*) obstack_finish (OBS
);
116 /* If there are two or more buffers and the last buffer is empty,
117 then free the last one and decrement the buffer count. */
119 && x
->p
[x
->n_bufs
- 1].start
== x
->p
[x
->n_bufs
- 1].one_past_end
)
120 free (x
->p
[--(x
->n_bufs
)].start
);
129 for (i
= 0; i
< x
->n_bufs
; i
++)
130 free (x
->p
[i
].start
);
131 obstack_free (OBS
, NULL
);
135 line_ptr_decrement (const Buf
*x
, const Line_ptr
*lp
)
139 if (lp
->ptr
> x
->p
[lp
->i
].start
)
142 lp_new
.ptr
= lp
->ptr
- 1;
147 lp_new
.i
= lp
->i
- 1;
148 lp_new
.ptr
= ONE_PAST_END (x
, lp
->i
- 1) - 1;
154 line_ptr_increment (const Buf
*x
, const Line_ptr
*lp
)
158 assert (lp
->ptr
<= ONE_PAST_END (x
, lp
->i
) - 1);
159 if (lp
->ptr
< ONE_PAST_END (x
, lp
->i
) - 1)
162 lp_new
.ptr
= lp
->ptr
+ 1;
166 assert (lp
->i
< x
->n_bufs
- 1);
167 lp_new
.i
= lp
->i
+ 1;
168 lp_new
.ptr
= x
->p
[lp
->i
+ 1].start
;
174 find_bol (const Buf
*x
,
175 const Line_ptr
*last_bol
, Line_ptr
*new_bol
, char eol_byte
)
181 if (last_bol
->ptr
== x
->p
[0].start
)
184 tmp
= line_ptr_decrement (x
, last_bol
);
185 last_bol_ptr
= tmp
.ptr
;
189 char *nl
= memrchr (x
->p
[i
].start
, last_bol_ptr
, eol_byte
);
195 *new_bol
= line_ptr_increment (x
, &nl_pos
);
203 last_bol_ptr
= ONE_PAST_END (x
, i
);
206 /* If last_bol->ptr didn't point at the first byte of X, then reaching
207 this point means that we're about to return the line that is at the
209 if (last_bol
->ptr
!= x
->p
[0].start
)
212 new_bol
->ptr
= x
->p
[0].start
;
220 print_line (FILE *out_stream
, const Buf
*x
,
221 const Line_ptr
*bol
, const Line_ptr
*bol_next
)
224 for (i
= bol
->i
; i
<= bol_next
->i
; i
++)
226 char *a
= (i
== bol
->i
? bol
->ptr
: x
->p
[i
].start
);
227 char *b
= (i
== bol_next
->i
? bol_next
->ptr
: ONE_PAST_END (x
, i
));
228 fwrite (a
, 1, b
- a
, out_stream
);
237 char eol_byte
= '\n';
239 if (! buf_init_from_stdin (&x
, eol_byte
))
245 /* Special case the empty file. */
249 /* Initially, point at one past the last byte of the file. */
250 bol
.i
= x
.n_bufs
- 1;
251 bol
.ptr
= ONE_PAST_END (&x
, bol
.i
);
256 if (! find_bol (&x
, &bol
, &new_bol
, eol_byte
))
258 print_line (stdout
, &x
, &new_bol
, &bol
);