1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include "filter.h"
23 #include "window.h"
24 #include "nedit.h"
25 #include "preferences.h"
26
27 #include "../util/nedit_malloc.h"
28 #include "../util/misc.h"
29 #include "../util/managedList.h"
30 #include "../util/DialogF.h"
31 #include "../util/ec_glob.h"
32
33 #include "help.h"
34
35 #include <string.h>
36 #include <ctype.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <pthread.h>
40 #include <sys/wait.h>
41 #include <Xm/XmAll.h>
42
43 static IOFilter **filters;
44 static size_t numFilters;
45
46
47 typedef struct {
48 Widget shell;
49 Widget managedListW;
50 Widget nameW;
51 Widget patternW;
52 Widget extW;
53 Widget cmdInW;
54 Widget cmdOutW;
55
56 IOFilter **filters;
57 int nfilters;
58 int filteralloc;
59 } filterDialog;
60
61 static filterDialog fd = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL};
62
63 static char* create_ec_pattern(
char *pattern);
64
65 static void fdDestroyCB(Widget w, XtPointer clientData, XtPointer callData);
66 static void fdOkCB(Widget w, XtPointer clientData, XtPointer callData);
67 static void fdApplyCB(Widget w, XtPointer clientData, XtPointer callData);
68 static void fdCloseCB(Widget w, XtPointer clientData, XtPointer callData);
69 static void fdHelpCB(Widget w, XtPointer clientData, XtPointer callData);
70
71 static int fdUpdateList(
void);
72
73
74 static int fdIsEmpty(
void)
75 {
76 Widget w[] = { fd.nameW, fd.patternW, fd.extW, fd.cmdInW, fd.cmdOutW };
77 size_t n =
sizeof(w) /
sizeof(Widget);
78 for(
int i=
0;i<n;i++) {
79 char *s = XmTextGetString(w[i]);
80 size_t len = s ? strlen(s) :
0;
81 XtFree(s);
82 if(len >
0) {
83 return 0;
84 }
85 }
86 return 1;
87 }
88
89 static void fdFreeItemCB(
void *item)
90 {
91 IOFilter *f = item;
92 XtFree(f->name);
93 XtFree(f->pattern);
94 XtFree(f->ext);
95 XtFree(f->cmdin);
96 XtFree(f->cmdout);
97 NEditFree(f->ec_pattern);
98 NEditFree(f);
99 }
100
101 static void *fdGetDisplayedCB(
void *oldItem,
int explicitRequest,
int *abort,
102 void *cbArg)
103 {
104 if(fdIsEmpty()) {
105 return NULL;
106 }
107
108 IOFilter *filter = NEditMalloc(
sizeof(IOFilter));
109 filter->name = XmTextGetString(fd.nameW);
110 filter->pattern = XmTextGetString(fd.patternW);
111 filter->ext = XmTextGetString(fd.extW);
112 filter->cmdin = XmTextGetString(fd.cmdInW);
113 filter->cmdout = XmTextGetString(fd.cmdOutW);
114 filter->ec_pattern = create_ec_pattern(filter->pattern);
115
116 if (strlen(filter->name) ==
0 ||
117 strlen(filter->pattern) ==
0 ||
118 strlen(filter->ext) ==
0 ||
119 strlen(filter->cmdin) ==
0 ||
120 strlen(filter->cmdout) ==
0 ||
121 fd.nfilters == fd.filteralloc)
122 {
123 fdFreeItemCB(filter);
124 *abort =
1;
125 }
126
127 return filter;
128 }
129
130 static void fdSetDisplayedCB(
void *item,
void *cbArg)
131 {
132 if(!item) {
133 XmTextSetString(fd.nameW,
"");
134 XmTextSetString(fd.patternW,
"");
135 XmTextSetString(fd.extW,
"");
136 XmTextSetString(fd.cmdInW,
"");
137 XmTextSetString(fd.cmdOutW,
"");
138 }
else {
139 IOFilter *f = item;
140 XmTextSetString(fd.nameW, f->name);
141 XmTextSetString(fd.patternW, f->pattern);
142 XmTextSetString(fd.extW, f->ext);
143 XmTextSetString(fd.cmdInW, f->cmdin);
144 XmTextSetString(fd.cmdOutW, f->cmdout);
145 }
146 }
147
148 static IOFilter* fdCopyFilter(IOFilter *f) {
149 IOFilter *cp = NEditMalloc(
sizeof(IOFilter));
150 cp->name = NEditStrdup(f->name ? f->name :
"");
151 cp->pattern = NEditStrdup(f->pattern ? f->pattern :
"");
152 cp->ext = NEditStrdup(f->ext ? f->ext :
"");
153 cp->cmdin = NEditStrdup(f->cmdin ? f->cmdin :
"");
154 cp->cmdout = NEditStrdup(f->cmdout ? f->cmdout :
"");
155 cp->ec_pattern = f->ec_pattern ? NEditStrdup(f->ec_pattern) :
NULL;
156 return cp;
157 }
158
159 #define FD_LIST_RIGHT 30
160 #define FD_LEFT_MARGIN_POS 1
161 #define FD_RIGHT_MARGIN_POS 99
162 #define FD_H_MARGIN 10
163
164 void FilterSettings(WindowInfo *window)
165 {
166 XmString s1;
167
168 if(fd.shell) {
169 RaiseDialogWindow(fd.shell);
170 return;
171 }
172
173 fd.filteralloc =
256;
174 fd.filters = NEditCalloc(
sizeof(IOFilter), fd.filteralloc);
175 fd.nfilters = numFilters;
176 for(
int i=
0;i<numFilters;i++) {
177 fd.filters[i] = fdCopyFilter(filters[i]);
178 }
179
180 int ac =
0;
181 Arg args[
20];
182
183 XtSetArg(args[ac], XmNtitle,
"Filters"); ac++;
184 fd.shell = CreateWidget(TheAppShell,
"filters",
185 topLevelShellWidgetClass, args, ac);
186 AddSmallIcon(fd.shell);
187 Widget form = XtVaCreateManagedWidget(
"filtersForm", xmFormWidgetClass,
188 fd.shell, XmNautoUnmanage, False,
189 XmNresizePolicy, XmRESIZE_NONE,
NULL);
190
191 Widget topLbl = XtVaCreateManagedWidget(
"topLabel", xmLabelGadgetClass, form,
192 XmNlabelString, s1=
MKSTRING(
193 "To modify the properties of an existing filter, select the name\n\
194 from the list on the left. Select \"New\" to add a new filter to the list."),
195 XmNmnemonic,
'N',
196 XmNtopAttachment, XmATTACH_POSITION,
197 XmNtopPosition,
2,
198 XmNleftAttachment, XmATTACH_FORM,
199 XmNleftOffset,
6,
200 XmNrightAttachment, XmATTACH_FORM,
201 XmNrightOffset,
6,
202 NULL);
203 XmStringFree(s1);
204
205 Widget okBtn = XtVaCreateManagedWidget(
"ok",xmPushButtonWidgetClass,form,
206 XmNlabelString, s1=XmStringCreateSimple(
"OK"),
207 XmNmarginWidth,
BUTTON_WIDTH_MARGIN,
208 XmNleftAttachment, XmATTACH_POSITION,
209 XmNleftPosition,
4,
210 XmNrightAttachment, XmATTACH_POSITION,
211 XmNrightPosition,
21,
212 XmNbottomAttachment, XmATTACH_FORM,
213 XmNbottomOffset,
6,
214 NULL);
215 XtAddCallback(okBtn, XmNactivateCallback, fdOkCB,
NULL);
216 XmStringFree(s1);
217
218 Widget applyBtn = XtVaCreateManagedWidget(
"apply",xmPushButtonWidgetClass,form,
219 XmNlabelString, s1=XmStringCreateSimple(
"Apply"),
220 XmNmnemonic,
'A',
221 XmNleftAttachment, XmATTACH_POSITION,
222 XmNleftPosition,
29,
223 XmNrightAttachment, XmATTACH_POSITION,
224 XmNrightPosition,
46,
225 XmNbottomAttachment, XmATTACH_FORM,
226 XmNbottomOffset,
6,
227 NULL);
228 XtAddCallback(applyBtn, XmNactivateCallback, fdApplyCB,
NULL);
229 XmStringFree(s1);
230
231 Widget closeBtn = XtVaCreateManagedWidget(
"close",
232 xmPushButtonWidgetClass, form,
233 XmNlabelString, s1=XmStringCreateSimple(
"Close"),
234 XmNleftAttachment, XmATTACH_POSITION,
235 XmNleftPosition,
54,
236 XmNrightAttachment, XmATTACH_POSITION,
237 XmNrightPosition,
71,
238 XmNbottomAttachment, XmATTACH_FORM,
239 XmNbottomOffset,
6,
240 NULL);
241 XtAddCallback(closeBtn, XmNactivateCallback, fdCloseCB,
NULL);
242 XmStringFree(s1);
243
244 Widget helpBtn = XtVaCreateManagedWidget(
"help",
245 xmPushButtonWidgetClass, form,
246 XmNlabelString, s1=XmStringCreateSimple(
"Help"),
247 XmNleftAttachment, XmATTACH_POSITION,
248 XmNleftPosition,
79,
249 XmNrightAttachment, XmATTACH_POSITION,
250 XmNrightPosition,
96,
251 XmNbottomAttachment, XmATTACH_FORM,
252 XmNbottomOffset,
6,
253 NULL);
254 XtAddCallback(helpBtn, XmNactivateCallback, fdHelpCB,
NULL);
255 XmStringFree(s1);
256
257 Widget sep1 = XtVaCreateManagedWidget(
"sep1", xmSeparatorGadgetClass, form,
258 XmNleftAttachment, XmATTACH_FORM,
259 XmNrightAttachment, XmATTACH_FORM,
260 XmNleftOffset,
6,
261 XmNrightOffset,
6,
262 XmNbottomAttachment, XmATTACH_WIDGET,
263 XmNbottomWidget, okBtn,
264 XmNbottomOffset,
4,
265 NULL);
266
267 ac =
0;
268 XtSetArg(args[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
269 XtSetArg(args[ac], XmNtopOffset,
FD_H_MARGIN); ac++;
270 XtSetArg(args[ac], XmNtopWidget, topLbl); ac++;
271 XtSetArg(args[ac], XmNleftAttachment, XmATTACH_POSITION); ac++;
272 XtSetArg(args[ac], XmNleftPosition,
FD_LEFT_MARGIN_POS); ac++;
273 XtSetArg(args[ac], XmNrightAttachment, XmATTACH_POSITION); ac++;
274 XtSetArg(args[ac], XmNrightPosition,
FD_LIST_RIGHT-
1); ac++;
275 XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
276 XtSetArg(args[ac], XmNbottomWidget, sep1); ac++;
277 XtSetArg(args[ac], XmNbottomOffset,
FD_H_MARGIN); ac++;
278 fd.managedListW = CreateManagedList(form,
"list", args, ac,
279 (
void **)fd.filters, &fd.nfilters,
280 256,
20, fdGetDisplayedCB,
NULL, fdSetDisplayedCB,
281 form, fdFreeItemCB);
282
283 s1 = XmStringCreateLocalized(
"Name");
284 Widget lblName = XtVaCreateManagedWidget(
"nameLbl", xmLabelGadgetClass, form,
285 XmNtopAttachment, XmATTACH_WIDGET,
286 XmNtopWidget, topLbl,
287 XmNtopOffset,
FD_H_MARGIN,
288 XmNleftAttachment, XmATTACH_WIDGET,
289 XmNleftWidget, fd.managedListW,
290 XmNrightAttachment, XmATTACH_FORM,
291 XmNleftOffset,
6,
292 XmNrightOffset,
6,
293 XmNlabelString, s1,
294 XmNalignment, XmALIGNMENT_BEGINNING,
295 NULL);
296 XmStringFree(s1);
297
298 fd.nameW = XtVaCreateManagedWidget(
"patternLbl", xmTextWidgetClass, form,
299 XmNtopAttachment, XmATTACH_WIDGET,
300 XmNtopWidget, lblName,
301 XmNtopOffset,
6,
302 XmNleftAttachment, XmATTACH_WIDGET,
303 XmNleftWidget, fd.managedListW,
304 XmNrightAttachment, XmATTACH_FORM,
305 XmNleftOffset,
6,
306 XmNrightOffset,
6,
307 NULL);
308
309 s1 = XmStringCreateLocalized(
"File Pattern");
310 Widget lblPattern = XtVaCreateManagedWidget(
"nameLbl", xmLabelGadgetClass, form,
311 XmNtopAttachment, XmATTACH_WIDGET,
312 XmNtopWidget, fd.nameW,
313 XmNtopOffset,
6,
314 XmNleftAttachment, XmATTACH_WIDGET,
315 XmNleftWidget, fd.managedListW,
316
317
318 XmNleftOffset,
6,
319 XmNlabelString, s1,
320 XmNalignment, XmALIGNMENT_BEGINNING,
321 NULL);
322 XmStringFree(s1);
323
324 fd.patternW = XtVaCreateManagedWidget(
"patternLbl", xmTextWidgetClass, form,
325 XmNtopAttachment, XmATTACH_WIDGET,
326 XmNtopWidget, lblPattern,
327 XmNtopOffset,
6,
328 XmNleftAttachment, XmATTACH_WIDGET,
329 XmNleftWidget, fd.managedListW,
330 XmNrightAttachment, XmATTACH_POSITION,
331 XmNrightPosition,
75,
332 XmNleftOffset,
6,
333 NULL);
334
335 s1 = XmStringCreateLocalized(
"Default Extension");
336 Widget lblExt = XtVaCreateManagedWidget(
"extLbl", xmLabelGadgetClass, form,
337 XmNtopAttachment, XmATTACH_WIDGET,
338 XmNtopWidget, fd.nameW,
339 XmNtopOffset,
6,
340 XmNrightAttachment, XmATTACH_FORM,
341 XmNleftAttachment, XmATTACH_WIDGET,
342 XmNleftWidget, fd.patternW,
343 XmNleftOffset,
6,
344 XmNleftPosition,
76,
345 XmNrightOffset,
6,
346 XmNlabelString, s1,
347 XmNalignment, XmALIGNMENT_BEGINNING,
348 NULL);
349 XmStringFree(s1);
350
351 fd.extW = XtVaCreateManagedWidget(
"patternLbl", xmTextWidgetClass, form,
352 XmNtopAttachment, XmATTACH_WIDGET,
353 XmNtopWidget, lblExt,
354 XmNtopOffset,
6,
355 XmNleftAttachment, XmATTACH_WIDGET,
356 XmNleftWidget, fd.patternW,
357 XmNleftOffset,
6,
358 XmNrightAttachment, XmATTACH_FORM,
359 XmNrightOffset,
6,
360 NULL);
361
362 s1 = XmStringCreateLocalized(
"Input Filter Command");
363 Widget lblCmdIn = XtVaCreateManagedWidget(
"cmdInLbl", xmLabelGadgetClass, form,
364 XmNtopAttachment, XmATTACH_WIDGET,
365 XmNtopWidget, fd.patternW,
366 XmNtopOffset,
6,
367 XmNleftAttachment, XmATTACH_WIDGET,
368 XmNleftWidget, fd.managedListW,
369 XmNrightAttachment, XmATTACH_FORM,
370 XmNleftOffset,
6,
371 XmNrightOffset,
6,
372 XmNlabelString, s1,
373 XmNalignment, XmALIGNMENT_BEGINNING,
374 NULL);
375 XmStringFree(s1);
376
377 ac =
0;
378 XtSetArg(args[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
379 XtSetArg(args[ac], XmNtopWidget, lblCmdIn); ac++;
380 XtSetArg(args[ac], XmNtopOffset,
6); ac++;
381 XtSetArg(args[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
382 XtSetArg(args[ac], XmNleftWidget, fd.managedListW); ac++;
383 XtSetArg(args[ac], XmNleftOffset,
6); ac++;
384 XtSetArg(args[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
385 XtSetArg(args[ac], XmNrightOffset,
6); ac++;
386 XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_POSITION); ac++;
387 XtSetArg(args[ac], XmNbottomPosition,
61); ac++;
388 XtSetArg(args[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
389 XtSetArg(args[ac], XmNrows,
4); ac++;
390 fd.cmdInW = XmCreateScrolledText(form,
"cmdInText", args, ac);
391 XtManageChild(fd.cmdInW);
392
393 s1 = XmStringCreateLocalized(
"Output Filter Command");
394 Widget lblCmdOut = XtVaCreateManagedWidget(
"cmdOutLbl", xmLabelGadgetClass, form,
395 XmNtopAttachment, XmATTACH_WIDGET,
396 XmNtopWidget, fd.cmdInW,
397 XmNtopOffset,
FD_H_MARGIN,
398 XmNleftAttachment, XmATTACH_WIDGET,
399 XmNleftWidget, fd.managedListW,
400 XmNrightAttachment, XmATTACH_FORM,
401 XmNleftOffset,
6,
402 XmNrightOffset,
6,
403 XmNlabelString, s1,
404 XmNalignment, XmALIGNMENT_BEGINNING,
405 NULL);
406 XmStringFree(s1);
407
408 ac =
0;
409 XtSetArg(args[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
410 XtSetArg(args[ac], XmNtopWidget, lblCmdOut); ac++;
411 XtSetArg(args[ac], XmNtopOffset,
6); ac++;
412 XtSetArg(args[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
413 XtSetArg(args[ac], XmNleftWidget, fd.managedListW); ac++;
414 XtSetArg(args[ac], XmNleftOffset,
6); ac++;
415 XtSetArg(args[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
416 XtSetArg(args[ac], XmNrightOffset,
6); ac++;
417 XtSetArg(args[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
418 XtSetArg(args[ac], XmNbottomWidget, sep1); ac++;
419 XtSetArg(args[ac], XmNbottomOffset,
FD_H_MARGIN); ac++;
420 XtSetArg(args[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
421 XtSetArg(args[ac], XmNrows,
4); ac++;
422 fd.cmdOutW = XmCreateScrolledText(form,
"cmdInText", args, ac);
423 XtManageChild(fd.cmdOutW);
424
425
426 XtVaSetValues(form, XmNdefaultButton, okBtn,
NULL);
427 XtVaSetValues(form, XmNcancelButton, closeBtn,
NULL);
428
429 XtAddCallback(form, XmNdestroyCallback, fdDestroyCB,
NULL);
430 AddMotifCloseCallback(fd.shell, fdCloseCB,
NULL);
431
432 RealizeWithoutForcingPosition(fd.shell);
433 }
434
435 static void fdDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
436 {
437 for(
int i=
0;i<fd.nfilters;i++) {
438 fdFreeItemCB(fd.filters[i]);
439 }
440 NEditFree(fd.filters);
441 }
442
443 static void fdApplyCB(Widget w, XtPointer clientData, XtPointer callData)
444 {
445 fdUpdateList();
446 }
447
448 static void fdOkCB(Widget w, XtPointer clientData, XtPointer callData)
449 {
450 if(!fdUpdateList()) {
451 return;
452 }
453
454 XtDestroyWidget(fd.shell);
455 fd.shell =
NULL;
456 }
457
458 static void fdCloseCB(Widget w, XtPointer clientData, XtPointer callData)
459 {
460 XtDestroyWidget(fd.shell);
461 fd.shell =
NULL;
462 }
463
464 static void fdHelpCB(Widget w, XtPointer clientData, XtPointer callData)
465 {
466 Help(
HELP_FILTERS);
467 }
468
469 static int fdUpdateList(
void)
470 {
471 if (!UpdateManagedList(fd.managedListW, True))
472 return False;
473
474 for(
int i=
0;i<numFilters;i++) {
475 fdFreeItemCB(filters[i]);
476 }
477 NEditFree(filters);
478
479 filters = NEditCalloc(fd.nfilters,
sizeof(IOFilter*));
480 numFilters = fd.nfilters;
481 for(
int i=
0;i<numFilters;i++) {
482 filters[i] = fdCopyFilter(fd.filters[i]);
483 }
484
485
486 MarkPrefsChanged();
487
488 return True;
489 }
490
491
492 static int valueListNext(
char *str,
int len)
493 {
494 for(
int i=
0;i<len;i++) {
495 if(str[i] ==
';') {
496 str[i] =
'\0';
497 len = i;
498 break;
499 }
500 }
501 return len;
502 }
503
504 static char* create_ec_pattern(
char *pattern)
505 {
506 if(!pattern) {
507 return NULL;
508 }
509
510 char *ecPattern =
NULL;
511 if(pattern[
0] ==
'/') {
512 ecPattern = NEditStrdup(pattern);
513 }
else {
514
515 size_t len = strlen(pattern);
516 int newlen = len+
3;
517 ecPattern = NEditMalloc(newlen+
1);
518 memcpy(ecPattern,
"**/",
3);
519 memcpy(ecPattern+
3, pattern, len);
520 ecPattern[newlen] =
0;
521 }
522
523 return ecPattern;
524 }
525
526 static IOFilter* ParseFilterStr(
char *str,
int len)
527 {
528 char *name = str;
529 int namelen = valueListNext(str, len);
530 int skip_space =
0;
531 while(isspace(*name) && namelen >
0) {
532 name++;
533 namelen--;
534 skip_space++;
535 }
536 if(namelen <=
0) {
537 return NULL;
538 }
539 str += skip_space + namelen +
1;
540 len -= skip_space + namelen +
1;
541 char *pattern = str;
542 int patternlen = valueListNext(str, len);
543 if(patternlen <=
0) {
544 return NULL;
545 }
546 str += patternlen +
1;
547 len -= patternlen +
1;
548 char *ext = str;
549 int extlen = valueListNext(str, len);
550 if(extlen <=
0) {
551 return NULL;
552 }
553 str += extlen +
1;
554 len -= extlen +
1;
555 char *cmdin = str;
556 int cmdinlen = valueListNext(str, len);
557 if(cmdinlen <=
0) {
558 return NULL;
559 }
560 str += cmdinlen +
1;
561 len -= cmdinlen +
1;
562 char *cmdout = str;
563
564 int cmdoutlen = valueListNext(str, len);
565 if(cmdoutlen <=
0) {
566 return NULL;
567 }
568
569
570
571 IOFilter *filter = NEditMalloc(
sizeof(IOFilter));
572 filter->name = NEditStrndup(name, namelen);
573 filter->pattern = NEditStrndup(pattern, patternlen);
574 filter->ext = NEditStrndup(ext, extlen);
575 filter->cmdin = NEditStrndup(cmdin, cmdinlen);
576 filter->cmdout = NEditStrndup(cmdout, cmdoutlen);
577 filter->ec_pattern = create_ec_pattern(filter->pattern);
578 return filter;
579 }
580
581 void ParseFilterSettings(
char *str)
582 {
583 size_t filterAlloc =
8;
584 filters = NEditCalloc(filterAlloc,
sizeof(IOFilter*));
585 numFilters =
0;
586
587 size_t len = strlen(str);
588 int lineStart =
0;
589 for(
int i=
0;i<=len;i++) {
590 if(i == len || str[i] ==
'\n') {
591 IOFilter *filter = ParseFilterStr(str+lineStart, i-lineStart);
592 lineStart = i+
1;
593
594 if(filter) {
595 if(numFilters == filterAlloc) {
596 filterAlloc +=
8;
597 NEditRealloc(filters, filterAlloc *
sizeof(IOFilter*));
598 }
599 filters[numFilters] = filter;
600 numFilters++;
601 }
602 }
603 }
604 }
605
606 char* WriteFilterString(
void)
607 {
608 size_t str_alloc =
2048;
609 size_t len =
0;
610 char *str = NEditMalloc(str_alloc);
611 str[
0] =
0;
612
613 for(
int i=
0;i<numFilters;i++) {
614 IOFilter *filter = filters[i];
615 char *prefix = i >
0 ?
"\t" :
"";
616 char *suffix = i+
1 != numFilters ?
"\\n\\\n" :
"";
617 for(;;) {
618 size_t remaining = str_alloc - len;
619 size_t w = snprintf(
620 str + len,
621 remaining,
622 "%s%s;%s;%s;%s;%s%s",
623 prefix,
624 filter->name,
625 filter->pattern,
626 filter->ext,
627 filter->cmdin,
628 filter->cmdout,
629 suffix);
630 if(w < remaining) {
631 len += w;
632 break;
633 }
else {
634 str_alloc +=
1024;
635 str = NEditRealloc(str, str_alloc);
636 }
637 }
638 }
639
640 return str;
641 }
642
643 IOFilter** GetFilterList(
size_t *num)
644 {
645 *num = numFilters;
646 return filters;
647 }
648
649 IOFilter* GetFilterFromName(
const char *name)
650 {
651 if(!name) {
652 return NULL;
653 }
654 for(
int i=
0;i<numFilters;i++) {
655 if(!strcmp(filters[i]->name, name)) {
656 return filters[i];
657 }
658 }
659 return NULL;
660 }
661
662 IOFilter* GetFilterForPath(
const char *path) {
663 IOFilter *filter =
NULL;
664 for(
int i=
0;i<numFilters;i++) {
665 if(!ec_glob(filters[i]->ec_pattern, path)) {
666 filter = filters[i];
667 break;
668 }
669 }
670 return filter;
671 }
672
673
674
675 typedef struct FilterIOThreadData {
676 XtAppContext appcontext;
677 Widget widget;
678 FILE *file;
679 int fd_in;
680 int fd_out;
681 pid_t pid;
682 } FilterIOThreadData;
683
684 typedef struct FilterCmdError {
685 Widget w;
686 int status;
687 int io_errno;
688 } FilterCmdError;
689
690 static void filter_command_error(XtPointer clientData, XtIntervalId *id) {
691 FilterCmdError *error = clientData;
692
693
694 Widget w =
NULL;
695 for (WindowInfo *win=WindowList; win!=
NULL; win=win->next) {
696 if(win->shell == error->w) {
697 w = error->w;
698 break;
699 }
700 }
701 if(w) {
702 if(error->io_errno !=
0) {
703 (
void)DialogF(
DF_WARN, error->w,
1,
"Command Failure",
704 "Filter IO Error: %s\n",
705 "OK",
706 strerror(error->io_errno));
707 }
else {
708 (
void)DialogF(
DF_WARN, error->w,
1,
"Command Failure",
709 "Filter command reported failed exit status: %d\n",
710 "OK",
711 error->status);
712 }
713 }
714
715 NEditFree(error);
716 }
717
718 static void* file_input_thread(
void *data) {
719 FilterIOThreadData *stream = data;
720
721 int ioerror =
0;
722 int io_errno =
0;
723
724 char buf[
16384];
725 size_t r;
726 while((r = fread(buf,
1,
16384, stream->file)) >
0) {
727 char *wbuf = buf;
728 while(r >
0) {
729 ssize_t w = write(stream->fd_in, wbuf, r);
730 if(w <=
0) {
731 ioerror =
1;
732 io_errno = errno;
733 break;
734 }
735 r -= w;
736 wbuf += w;
737 }
738
739 if(ioerror) {
740 break;
741 }
742 }
743
744 close(stream->fd_in);
745
746 int status = -
1;
747 waitpid(stream->pid, &status,
0);
748 if(status !=
0 || ioerror) {
749 FilterCmdError *error = NEditMalloc(
sizeof(FilterCmdError));
750 error->w = stream->widget;
751 error->status = status;
752 error->io_errno = io_errno;
753 XtAppAddTimeOut(
754 stream->appcontext,
755 0,
756 filter_command_error,
757 error);
758 }
759
760 NEditFree(stream);
761
762 return NULL;
763 }
764
765 #define FILTER_IO_BUFSIZE 16384
766
767 static void* file_output_thread(
void *data) {
768 FilterIOThreadData *stream = data;
769
770 char buf[
FILTER_IO_BUFSIZE];
771 ssize_t r;
772 while((r = read(stream->fd_out, buf,
FILTER_IO_BUFSIZE)) >
0) {
773 fwrite(buf,
1, r, stream->file);
774 }
775
776 close(stream->fd_out);
777 fclose(stream->file);
778
779 int status = -
1;
780 waitpid(stream->pid, &status,
0);
781 if(status !=
0) {
782 FilterCmdError *error = NEditMalloc(
sizeof(FilterCmdError));
783 error->w = stream->widget;
784 error->status = status;
785 XtAppAddTimeOut(
786 stream->appcontext,
787 0,
788 filter_command_error,
789 error);
790 }
791
792 NEditFree(stream);
793
794 return NULL;
795 }
796
797 static int filestream_create_pipes(FileStream *stream) {
798 if(pipe(stream->pin)) {
799 return 1;
800 }
801 if(pipe(stream->pout)) {
802 close(stream->pin[
0]);
803 close(stream->pin[
1]);
804 return 1;
805 }
806 return 0;
807 }
808
809 static FileStream* filestream_open(Widget w,
FILE *f,
const char *filter_cmd,
int mode) {
810 FileStream *stream = NEditMalloc(
sizeof(FileStream));
811 stream->file = f;
812 stream->filter_cmd = filter_cmd ? NEditStrdup(filter_cmd) :
NULL;
813 stream->pid =
0;
814 stream->hdrbufpos =
0;
815 stream->hdrbuflen =
0;
816 stream->mode = mode;
817
818 if(filter_cmd) {
819 if(filestream_create_pipes(stream)) {
820 NEditFree(stream->filter_cmd);
821 NEditFree(stream);
822 fclose(f);
823 fprintf(stderr,
"Failed to create pipe: %s\n", strerror(errno));
824 return NULL;
825 }
826
827 pid_t child = fork();
828 if(child ==
0) {
829 close(
STDIN_FILENO);
830 close(
STDOUT_FILENO);
831
832
833
834 if(dup2(stream->pin[
0],
STDIN_FILENO) == -
1) {
835 perror(
"dup2");
836 exit(
1);
837 }
838 if(dup2(stream->pout[
1],
STDOUT_FILENO) == -
1) {
839 perror(
"dup2");
840 exit(
1);
841 }
842
843 close(stream->pin[
1]);
844
845
846
847 execlp(GetPrefShell(), GetPrefShell(),
"-c", filter_cmd,
NULL);
848
849
850 fprintf(stderr,
"Error starting shell: %s\n", GetPrefShell());
851 exit(
1);
852 }
else {
853 stream->pid = child;
854
855 FilterIOThreadData *data = NEditMalloc(
sizeof(FilterIOThreadData));
856 data->appcontext = XtWidgetToApplicationContext(w);
857 data->widget = w;
858 data->file = stream->file;
859 data->fd_in = stream->pin[
1];
860 data->fd_out = stream->pout[
0];
861 data->pid = child;
862
863 pthread_t tid;
864 if(pthread_create(&tid,
NULL, mode ==
0 ? file_input_thread : file_output_thread, data)) {
865 fprintf(stderr,
"Errro: cannot create file input thread: %s\n", strerror(errno));
866 NEditFree(data);
867 close(stream->pin[
0]);
868 close(stream->pin[
1]);
869 close(stream->pout[
0]);
870 close(stream->pout[
1]);
871 fclose(f);
872 NEditFree(stream->filter_cmd);
873 NEditFree(stream);
874 return NULL;
875 }
876
877 if(mode ==
1) {
878 stream->file =
NULL;
879 }
880
881 close(stream->pout[
1]);
882 }
883 }
884
885 return stream;
886 }
887
888 FileStream* filestream_open_r(Widget w,
FILE *f,
const char *filter_cmd) {
889 return filestream_open(w, f, filter_cmd,
0);
890 }
891
892 FileStream* filestream_open_w(Widget w,
FILE *f,
const char *filter_cmd) {
893 return filestream_open(w, f, filter_cmd,
1);
894 }
895
896 int filestream_reset(FileStream *stream,
int pos) {
897 if(stream->pid ==
0) {
898 fseek(stream->file, pos,
SEEK_SET);
899 }
else {
900 if(pos > stream->hdrbuflen || stream->hdrbufpos > stream->hdrbuflen) {
901 return 1;
902 }
903 stream->hdrbufpos = pos;
904 }
905 return 0;
906 }
907
908 size_t filestream_read(
void *buffer,
size_t nbytes, FileStream *stream) {
909 if(stream->pid ==
0) {
910 return fread(buffer,
1, nbytes, stream->file);
911 }
else {
912 if(stream->hdrbufpos < stream->hdrbuflen) {
913
914 size_t r = stream->hdrbuflen - stream->hdrbufpos;
915 if(r > nbytes) {
916 r = nbytes;
917 }
918 memcpy(buffer, stream->hdrbuf, r);
919 nbytes -= r;
920 buffer = ((
char*)buffer) + r;
921 stream->hdrbufpos += r;
922 if(nbytes >
0) {
923 r += filestream_read(buffer, nbytes, stream);
924 }
925 return r;
926 }
927
928 ssize_t sr = read(stream->pout[
0], buffer, nbytes);
929
930
931 if(sr <
0) {
932 return 0;
933 }
934
935
936
937 if(stream->hdrbuflen <
FILESTREAM_HDR_BUFLEN) {
938 size_t buflen =
FILESTREAM_HDR_BUFLEN - stream->hdrbuflen;
939 if(buflen > sr) {
940 buflen = sr;
941 }
942 memcpy(stream->hdrbuf + stream->hdrbuflen, buffer, buflen);
943 stream->hdrbuflen += buflen;
944 }
945
946 stream->hdrbufpos += sr;
947 return (
size_t)sr;
948 }
949 }
950
951 size_t filestream_write(
const void *buffer,
size_t nbytes, FileStream *stream) {
952 if(stream->pid ==
0) {
953 return fwrite(buffer,
1, nbytes, stream->file);
954 }
else {
955 ssize_t w = write(stream->pin[
1], buffer, nbytes);
956 if(w <
0) {
957 w =
0;
958 }
959 return w;
960 }
961 }
962
963 int filestream_close(FileStream *stream) {
964 if(stream->pid !=
0) {
965 if(stream->mode ==
0) {
966 if(close(stream->pin[
0])) {
967 perror(
"pipe pin[0] close");
968 }
969 if(close(stream->pout[
0])) {
970 perror(
"pipe pout[0] close");
971 }
972 }
else {
973 if(close(stream->pin[
1])) {
974 perror(
"pipe pin[1] close");
975 }
976 }
977 }
978 int err =
0;
979 if(stream->file) {
980 err = fclose(stream->file);
981 }
982 NEditFree(stream->filter_cmd);
983 NEditFree(stream);
984 return err;
985 }
986