2727#include "include/util.h"
2828#include "include/main.h"
2929
30+ /*
31+ * Maximum column for wrapping text in posts.
32+ */
33+ #define MAX_COLUMN 80
34+
3035/*
3136 * Number of spaces used for indenting post replies.
3237 */
@@ -143,7 +148,8 @@ static inline void print_pad(FILE* fp, int amount) {
143148}
144149
145150/*
146- * Print the specified string as if they were the contents of a 4chan post.
151+ * Print the specified string as if they were the contents of a 4chan post,
152+ * wrapping lines at word boundaries if they exceed MAX_COLUMN.
147153 */
148154static void print_post_contents (FILE * fp , const char * str , bool use_pad ) {
149155 bool in_quote = false; /* >foo */
@@ -153,42 +159,87 @@ static void print_post_contents(FILE* fp, const char* str, bool use_pad) {
153159 XPOST_TEXT , /* >>>/foo/ */
154160 } xpost_state = XPOST_NONE ;
155161
156- for (size_t i = 0 ; str [i ] != '\0' ; i ++ ) {
157- const bool first_of_line = (i == 0 || str [i - 1 ] == '\n' );
162+ /* Position in the string of the last printed newline or space */
163+ size_t last_newline_idx = 0 , last_space_idx = 0 ;
164+
165+ size_t i ;
166+ for (i = 0 ; str [i ] != '\0' ; i ++ ) {
167+ /*
168+ * Store that we found a space (and optionally a newline) in the current
169+ * iteration.
170+ */
171+ if (isspace (str [i ])) {
172+ last_space_idx = i ;
173+ if (str [i ] == '\n' )
174+ last_newline_idx = i ;
175+ continue ;
176+ }
177+
178+ if (!isspace (str [i + 1 ]) && str [i + 1 ] != '\0' )
179+ continue ;
180+
181+ const bool is_first_word_of_input_line =
182+ (last_space_idx == 0 || str [last_space_idx ] == '\n' );
158183
159- /* Whenever we change line, reset color and quote state */
160- if (first_of_line ) {
184+ /* TODO: Check one-off errors */
185+ if (i - last_newline_idx >= MAX_COLUMN ) {
186+ fputc ('\n' , fp );
187+ last_newline_idx = last_space_idx ;
188+ if (use_pad )
189+ print_pad (fp , POST_PAD );
190+ /*
191+ * It shouldn't be necessary to specify the color again, but some
192+ * terminals reset on newline (e.g. when piping to 'less -R').
193+ */
161194 if (in_quote )
195+ fprintf (fp , COL_QUOTE ">" );
196+ } else if (last_space_idx != 0 ) {
197+ fputc (str [last_space_idx ], fp );
198+ }
199+
200+ /* Whenever we change an input line, reset color and quote state */
201+ if (is_first_word_of_input_line ) {
202+ if (in_quote || xpost_state != XPOST_NONE )
162203 fprintf (fp , COL_POST );
163204 if (use_pad )
164205 print_pad (fp , POST_PAD );
165- in_quote = false;
206+ in_quote = false;
207+ xpost_state = XPOST_NONE ;
166208 }
167209
168- /* Check if this character starts a quote, and what kind */
169- if (str [i ] == '>' ) {
170- if (str [i + 1 ] == '>' ) {
171- if (isdigit (str [i + 2 ])) {
172- xpost_state = XPOST_DIGITS ; /* >>123456789 */
173- fprintf (fp , COL_XPOST );
174- } else if (str [i + 2 ] == '>' ) {
175- xpost_state = XPOST_TEXT ; /* >>>/foo/ */
176- fprintf (fp , COL_XPOST );
210+ /* Print the last word of the input */
211+ const size_t word_start =
212+ (last_space_idx == 0 ) ? 0 : last_space_idx + 1 ;
213+ for (size_t j = word_start ; j <= i ; j ++ ) {
214+ /* Check if this character starts a quote, and what kind */
215+ if (xpost_state == XPOST_NONE && str [j ] == '>' ) {
216+ if (str [j + 1 ] == '>' ) {
217+ if (isdigit (str [j + 2 ])) {
218+ xpost_state = XPOST_DIGITS ; /* >>123456789 */
219+ fprintf (fp , COL_XPOST );
220+ } else if (str [j + 2 ] == '>' ) {
221+ xpost_state = XPOST_TEXT ; /* >>>/foo/ */
222+ fprintf (fp , COL_XPOST );
223+ }
224+
225+ while (str [j + 1 ] == '>' )
226+ fputc (str [j ++ ], fp );
227+ } else if (is_first_word_of_input_line && !in_quote ) {
228+ in_quote = true; /* >foo */
229+ fprintf (fp , COL_QUOTE );
177230 }
178- } else if (first_of_line && !in_quote ) {
179- in_quote = true; /* >foo */
180- fprintf (fp , COL_QUOTE );
231+ } else if ((xpost_state == XPOST_DIGITS && !isdigit (str [j ])) ||
232+ (xpost_state == XPOST_TEXT && isspace (str [j ]))) {
233+ const char * old_color = (in_quote ) ? COL_QUOTE : COL_POST ;
234+ fprintf (fp , "%s" , old_color );
235+ xpost_state = XPOST_NONE ;
181236 }
182- } else if ((xpost_state == XPOST_DIGITS && !isdigit (str [i ])) ||
183- (xpost_state == XPOST_TEXT && isspace (str [i ]))) {
184- const char * old_color = (in_quote ) ? COL_QUOTE : COL_POST ;
185- fprintf (fp , "%s" , old_color );
186- xpost_state = XPOST_NONE ;
187- }
188237
189- fputc (str [i ], fp );
238+ fputc (str [j ], fp );
239+ }
190240 }
191241
242+ /* Reset terminal color */
192243 fprintf (fp , "%s" , COL_NORM );
193244}
194245
0 commit comments