1 /*
2 * lo_fns.c - Line operations, remove duplicate lines, empty lines,
3 * lines with only whitespace, sort lines.
4 *
5 * Copyright 2015 Sylvan Mostert <smostert.dev@gmail.com>
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 2 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 along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22
23 #include "lo_fns.h"
24 #include "lo_prefs.h"
25
26
27 /* Get sort function based on user preferences */
28 lo_strcmpfns
getcmpfns(void)29 getcmpfns(void)
30 {
31 if(lo_info->use_collation_compare)
32 {
33 return g_utf8_collate;
34 }
35 else
36 {
37 return g_strcmp0;
38 }
39 }
40
41
42 /* comparison function to be used in qsort */
43 static gint
compare_asc(const void * a,const void * b)44 compare_asc(const void *a, const void *b)
45 {
46 lo_strcmpfns lo_strcmp = getcmpfns();
47 return lo_strcmp(*(const gchar **)a, *(const gchar **)b);
48 }
49
50
51 /* comparison function to be used in qsort */
52 static gint
compare_desc(const void * a,const void * b)53 compare_desc(const void *a, const void *b)
54 {
55 lo_strcmpfns lo_strcmp = getcmpfns();
56 return lo_strcmp(*(const gchar **)b, *(const gchar **)a);
57 }
58
59
60 /* Remove Duplicate Lines, sorted */
61 gint
rmdupst(gchar ** lines,gint num_lines,gchar * new_file)62 rmdupst(gchar **lines, gint num_lines, gchar *new_file)
63 {
64 gchar *nf_end = new_file; /* points to last char of new_file */
65 gchar *lineptr = (gchar *)" "; /* temporary line pointer */
66 gint i = 0; /* iterator */
67 gint changed = 0; /* number of lines removed */
68 lo_strcmpfns lo_strcmp = getcmpfns();
69
70 /* sort **lines ascending */
71 qsort(lines, num_lines, sizeof(gchar *), compare_asc);
72
73 /* loop through **lines, join first occurances into one str (new_file) */
74 for (i = 0; i < num_lines; i++)
75 {
76 if (lo_strcmp(lines[i], lineptr) != 0)
77 {
78 changed++; /* number of lines kept */
79 lineptr = lines[i];
80 nf_end = g_stpcpy(nf_end, lines[i]);
81 }
82 }
83
84 /* return the number of lines deleted */
85 return -(num_lines - changed);
86 }
87
88
89 /* Remove Duplicate Lines, ordered */
90 gint
rmdupln(gchar ** lines,gint num_lines,gchar * new_file)91 rmdupln(gchar **lines, gint num_lines, gchar *new_file)
92 {
93 gchar *nf_end = new_file; /* points to last char of new_file */
94 gint i = 0; /* iterator */
95 gint j = 0; /* iterator */
96 gboolean *to_remove = NULL; /* flag to 'mark' which lines to remove */
97 gint changed = 0; /* number of lines removed */
98 lo_strcmpfns lo_strcmp = getcmpfns();
99
100
101 /* allocate and set *to_remove to all FALSE
102 * to_remove[i] represents whether lines[i] should be removed */
103 to_remove = g_malloc(sizeof(gboolean) * num_lines);
104 for (i = 0; i < (num_lines); i++)
105 to_remove[i] = FALSE;
106
107 /* find which **lines are duplicate, and mark them as duplicate */
108 for (i = 0; i < num_lines; i++) /* loop through **lines */
109 {
110 /* make sure that the line is not already duplicate */
111 if (!to_remove[i])
112 {
113 /* find the rest of same lines */
114 for (j = (i + 1); j < num_lines; j++)
115 {
116 if (!to_remove[j] && lo_strcmp(lines[i], lines[j]) == 0)
117 to_remove[j] = TRUE; /* line is duplicate, mark to remove */
118 }
119 }
120 }
121
122 /* copy **lines into 'new_file' if it is not FALSE (not duplicate) */
123 for (i = 0; i < num_lines; i++)
124 if (!to_remove[i])
125 {
126 changed++; /* number of lines kept */
127 nf_end = g_stpcpy(nf_end, lines[i]);
128 }
129
130 /* free used memory */
131 g_free(to_remove);
132
133 /* return the number of lines deleted */
134 return -(num_lines - changed);
135 }
136
137
138 /* Remove Unique Lines */
139 gint
rmunqln(gchar ** lines,gint num_lines,gchar * new_file)140 rmunqln(gchar **lines, gint num_lines, gchar *new_file)
141 {
142 gchar *nf_end = new_file; /* points to last char of new_file */
143 gint i = 0; /* iterator */
144 gint j = 0; /* iterator */
145 gboolean *to_remove = NULL; /* to 'mark' which lines to remove */
146 gint changed = 0; /* number of lines removed */
147 lo_strcmpfns lo_strcmp = getcmpfns();
148
149
150 /* allocate and set *to_remove to all TRUE
151 * to_remove[i] represents whether lines[i] should be removed */
152 to_remove = g_malloc(sizeof(gboolean) * num_lines);
153 for (i = 0; i < num_lines; i++)
154 to_remove[i] = TRUE;
155
156 /* find all unique lines and set them to FALSE (not to be removed) */
157 for (i = 0; i < num_lines; i++)
158 /* make sure that the line is not already determined to be unique */
159 if (to_remove[i])
160 for (j = (i + 1); j < num_lines; j++)
161 if (to_remove[j] && lo_strcmp(lines[i], lines[j]) == 0)
162 {
163 to_remove[i] = FALSE;
164 to_remove[j] = FALSE;
165 }
166
167 /* copy **lines into 'new_file' if it is not FALSE(not duplicate) */
168 for (i = 0; i < num_lines; i++)
169 if (!to_remove[i])
170 {
171 changed++; /* number of lines kept */
172 nf_end = g_stpcpy(nf_end, lines[i]);
173 }
174
175 /* free used memory */
176 g_free(to_remove);
177
178 /* return the number of lines deleted */
179 return -(num_lines - changed);
180 }
181
182
183 /* Keep Unique Lines */
184 gint
kpunqln(gchar ** lines,gint num_lines,gchar * new_file)185 kpunqln(gchar **lines, gint num_lines, gchar *new_file)
186 {
187 gchar *nf_end = new_file; /* points to last char of new_file */
188 gint i = 0; /* iterator */
189 gint j = 0; /* iterator */
190 gboolean *to_remove = NULL; /* to 'mark' which lines to remove */
191 gint changed = 0; /* number of lines removed */
192 lo_strcmpfns lo_strcmp = getcmpfns();
193
194
195 /* allocate and set *to_remove to all FALSE
196 * to_remove[i] represents whether lines[i] should be removed */
197 to_remove = g_malloc(sizeof(gboolean) * num_lines);
198 for (i = 0; i < num_lines; i++)
199 to_remove[i] = FALSE;
200
201 /* find all non unique lines and set them to TRUE (to be removed) */
202 for (i = 0; i < num_lines; i++)
203 /* make sure that the line is not already determined to be non unique */
204 if (!to_remove[i])
205 for (j = (i + 1); j < num_lines; j++)
206 if (!to_remove[j] && lo_strcmp(lines[i], lines[j]) == 0)
207 {
208 to_remove[i] = TRUE;
209 to_remove[j] = TRUE;
210 }
211
212 /* copy **lines into 'new_file' if it is not FALSE(not duplicate) */
213 for (i = 0; i < num_lines; i++)
214 if (!to_remove[i])
215 {
216 changed++; /* number of lines kept */
217 nf_end = g_stpcpy(nf_end, lines[i]);
218 }
219
220 /* free used memory */
221 g_free(to_remove);
222
223 /* return the number of lines deleted */
224 return -(num_lines - changed);
225 }
226
227
228 /* Remove Empty Lines */
229 gint
rmemtyln(ScintillaObject * sci,gint line_num,gint end_line_num)230 rmemtyln(ScintillaObject *sci, gint line_num, gint end_line_num)
231 {
232 gint changed = 0; /* number of lines removed */
233
234 while (line_num <= end_line_num) /* loop through lines */
235 {
236 /* check if the first posn of the line is also the end of line posn */
237 if (sci_get_position_from_line(sci, line_num) ==
238 sci_get_line_end_position (sci, line_num))
239 {
240 scintilla_send_message(sci,
241 SCI_DELETERANGE,
242 sci_get_position_from_line(sci, line_num),
243 sci_get_line_length(sci, line_num));
244
245 line_num--;
246 end_line_num--;
247 changed++;
248 }
249 line_num++;
250 }
251
252 /* return the number of lines deleted */
253 return -changed;
254 }
255
256
257 /* Remove Whitespace Lines */
258 gint
rmwhspln(ScintillaObject * sci,gint line_num,gint end_line_num)259 rmwhspln(ScintillaObject *sci, gint line_num, gint end_line_num)
260 {
261 gint indent; /* indent position */
262 gint changed = 0; /* number of lines removed */
263
264 while (line_num <= end_line_num) /* loop through lines */
265 {
266 indent = scintilla_send_message(sci,
267 SCI_GETLINEINDENTPOSITION,
268 line_num, 0);
269
270 /* check if the posn of indentation is also the end of line posn */
271 if (indent -
272 sci_get_position_from_line(sci, line_num) ==
273 sci_get_line_end_position (sci, line_num) -
274 sci_get_position_from_line(sci, line_num))
275 {
276 scintilla_send_message(sci,
277 SCI_DELETERANGE,
278 sci_get_position_from_line(sci, line_num),
279 sci_get_line_length(sci, line_num));
280
281 line_num--;
282 end_line_num--;
283 changed++;
284 }
285 line_num++;
286 }
287
288 /* return the number of lines deleted */
289 return -changed;
290 }
291
292
293 /* Sort Lines Ascending */
294 gint
sortlnsasc(gchar ** lines,gint num_lines,gchar * new_file)295 sortlnsasc(gchar **lines, gint num_lines, gchar *new_file)
296 {
297 gchar *nf_end = new_file; /* points to last char of new_file */
298 gint i;
299
300 qsort(lines, num_lines, sizeof(gchar *), compare_asc);
301
302 /* join **lines into one string (new_file) */
303 for (i = 0; i < num_lines; i++)
304 nf_end = g_stpcpy(nf_end, lines[i]);
305
306 return num_lines;
307 }
308
309
310 /* Sort Lines Descending */
311 gint
sortlndesc(gchar ** lines,gint num_lines,gchar * new_file)312 sortlndesc(gchar **lines, gint num_lines, gchar *new_file)
313 {
314 gchar *nf_end = new_file; /* points to last char of new_file */
315 gint i;
316
317 qsort(lines, num_lines, sizeof(gchar *), compare_desc);
318
319 /* join **lines into one string (new_file) */
320 for (i = 0; i < num_lines; i++)
321 nf_end = g_stpcpy(nf_end, lines[i]);
322
323 return num_lines;
324 }
325
326
327 /* Remove Every Nth Line */
328 gint
rmnthln(ScintillaObject * sci,gint line_num,gint end_line_num)329 rmnthln(ScintillaObject *sci, gint line_num, gint end_line_num)
330 {
331 gboolean ok;
332 gdouble n;
333 gint count;
334 gint changed = 0; /* number of lines removed */
335
336 ok = dialogs_show_input_numeric(_("Remove every Nth line"),
337 _("Value of N"), &n, 1, 1000, 1);
338 if (ok == FALSE)
339 {
340 return 0;
341 }
342
343 count = n;
344 while (line_num <= end_line_num) /* loop through lines */
345 {
346 count--;
347
348 /* check if this is the nth line. */
349 if (count == 0)
350 {
351 scintilla_send_message(sci,
352 SCI_DELETERANGE,
353 sci_get_position_from_line(sci, line_num),
354 sci_get_line_length(sci, line_num));
355
356 line_num--;
357 end_line_num--;
358 changed++;
359 count = n;
360 }
361 line_num++;
362 }
363
364 /* return the number of lines deleted */
365 return -changed;
366 }
367