xref: /minix/external/bsd/nvi/dist/motif_l/m_search.c (revision 0a6a1f1d)
1 /*-
2  * Copyright (c) 1996
3  *	Rob Zimmermann.  All rights reserved.
4  * Copyright (c) 1996
5  *	Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9 
10 #include "config.h"
11 
12 #include <sys/cdefs.h>
13 #if 0
14 #ifndef lint
15 static const char sccsid[] = "Id: m_search.c,v 8.14 2003/11/05 17:10:00 skimo Exp  (Berkeley) Date: 2003/11/05 17:10:00 ";
16 #endif /* not lint */
17 #else
18 __RCSID("$NetBSD: m_search.c,v 1.2 2014/01/26 21:43:45 christos Exp $");
19 #endif
20 
21 #include <sys/queue.h>
22 
23 /* context */
24 #include <X11/X.h>
25 #include <X11/Intrinsic.h>
26 #include <Xm/DialogS.h>
27 #include <Xm/Form.h>
28 #include <Xm/Label.h>
29 #include <Xm/PushBG.h>
30 #include <Xm/TextF.h>
31 #include <Xm/ToggleB.h>
32 #include <Xm/RowColumn.h>
33 
34 #include <bitstring.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 
38 #undef LOCK_SUCCESS
39 #include "../common/common.h"
40 #include "../ipc/ip.h"
41 #include "m_motif.h"
42 
43 extern int vi_ofd;
44 
45 
46 /* types */
47 
48 typedef struct sds {
49     struct sds	*next;
50     Widget	shell;
51 } save_dialog;
52 
53 static	save_dialog	*dialogs = NULL;
54 
55 typedef struct	{
56     String	name;
57     void	(*cb)();
58 } ButtonData;
59 
60 
61 /* globals and constants */
62 
63 static	String	PatternWidget = "text";
64 static	String	pattern = NULL;
65 
66 static optData  search_toggles[] = {
67 	{ optToggle,	"extended",	NULL,	VI_SEARCH_EXT	},
68 	{ optToggle,	"iclower",	NULL,	VI_SEARCH_ICL	},
69 	{ optToggle,	"ignorecase",	NULL,	VI_SEARCH_IC	},
70 	{ optToggle,	"literal",	NULL,	VI_SEARCH_LIT	},
71 	{ optToggle,	"searchincr",	NULL,	VI_SEARCH_INCR	},
72 	{ optToggle,	"wrapscan",	NULL,	VI_SEARCH_WR	},
73 	{ optTerminator,		},
74 };
75 
76 static void done_func __P((Widget));
77 static void next_func __P((Widget));
78 static void prev_func __P((Widget));
79 static void search __P((Widget, int));
80 
81 static	ButtonData button_data[] = {
82     { "Next",		next_func	},
83     { "Previous", 	prev_func	},
84     { "Cancel", 	done_func	}	/* always last */
85 };
86 
87 
88 /* Xt utilities */
89 
90 #if defined(__STDC__)
get_child_widget(Widget parent,String name)91 static	Widget	get_child_widget( Widget parent, String name )
92 #else
93 static	Widget	get_child_widget( parent, name )
94 	Widget	parent;
95 	String	name;
96 #endif
97 {
98     char buffer[1024];
99 
100     strcpy( buffer, "*" );
101     strcat( buffer, name );
102     return XtNameToWidget( parent, buffer );
103 }
104 
105 
106 /* sync the global state */
107 
108 #if defined(__STDC__)
get_state(Widget w)109 static	void	get_state( Widget w )
110 #else
111 static	void	get_state( w )
112 	Widget	w;
113 #endif
114 {
115 #if defined(SelfTest)
116     int		i;
117 #endif
118     Widget	shell = w;
119 
120     /* get all the data from the root of the widget tree */
121     while ( ! XtIsShell(shell) ) shell = XtParent(shell);
122 
123 #if defined(SelfTest)
124     /* which flags? */
125     for (i=0; i<XtNumber(toggle_data); i++) {
126 	if (( w = get_child_widget( shell, toggle_data[i].name )) != NULL ) {
127 	    XtVaGetValues( w, XmNset, &toggle_data[i].value, 0 );
128 	}
129     }
130 #endif
131 
132     /* what's the pattern? */
133     if (( w = get_child_widget( shell, PatternWidget )) != NULL ) {
134 	if ( pattern != NULL ) XtFree( pattern );
135 	pattern = XmTextFieldGetString( w );
136     }
137 }
138 
139 
140 /* Translate the user's actions into nvi commands */
141 /*
142  * next_func --
143  *	Action for next button.
144  */
145 static void
next_func(Widget w)146 next_func(Widget w)
147 {
148 	search(w, 0);
149 }
150 
151 /*
152  * prev_func --
153  *	Action for previous button.
154  */
155 static void
prev_func(Widget w)156 prev_func(Widget w)
157 {
158 	search(w, VI_SEARCH_REV);
159 }
160 
161 /*
162  * search --
163  *	Perform the search.
164  */
165 static void
search(Widget w,int flags)166 search(Widget w, int flags)
167 {
168 	IP_BUF ipb;
169 	optData *opt;
170 	Widget shell;
171 
172 	shell = w;
173 	while ( ! XtIsShell(shell) ) shell = XtParent(shell);
174 
175 	/* Get current data from the root of the widget tree?
176 	 * Do it if we are a child of a dialog shell (assume we
177 	 * are a 'Find' dialog).  Otherwise don't (we are the child
178 	 * of a menu and being invoked via accelerator)
179 	 */
180 	if (XmIsDialogShell(shell))
181 		get_state(w);
182 
183 	/* no pattern? probably, we haven't posted a search dialog yet.
184 	 * there ought to be a better thing to do here.
185 	 */
186 	if ( pattern == NULL ) {
187 	    vi_info_message( w, "No previous string specified" );
188 	    return;
189 	}
190 
191 	ipb.str1 = pattern;
192 	ipb.len1 = strlen(pattern);
193 
194 	/* Initialize the search flags based on the buttons. */
195 	ipb.val1 = flags;
196 	for (opt = search_toggles; opt->kind != optTerminator; ++opt)
197 		if (opt->value != NULL)
198 			ipb.val1 |= opt->flags;
199 
200 	ipb.code = VI_C_SEARCH;
201 	vi_send(vi_ofd, "a1", &ipb);
202 }
203 
204 #if defined(__STDC__)
done_func(Widget w)205 static	void	done_func( Widget w )
206 #else
207 static	void	done_func( w )
208 	Widget	w;
209 #endif
210 {
211     save_dialog	*ptr;
212 
213 #if defined(SelfTest)
214     puts( XtName(w) );
215 #endif
216 
217     while ( ! XtIsShell(w) ) w = XtParent(w);
218     XtPopdown( w );
219 
220     /* save it for later */
221     ptr		= (save_dialog *) malloc( sizeof(save_dialog) );
222     ptr->next	= dialogs;
223     ptr->shell	= w;
224     dialogs	= ptr;
225 }
226 
227 
228 /* create a set of push buttons */
229 
230 #define	SpacingRatio	4	/* 3:1 button to spaces */
231 
232 #if defined(__STDC__)
create_push_buttons(Widget parent,ButtonData * data,int count)233 static	Widget	create_push_buttons( Widget parent,
234 				     ButtonData *data,
235 				     int count
236 				    )
237 #else
238 static	Widget	create_push_buttons( parent, data, count )
239     Widget	parent;
240     ButtonData	*data;
241     int		count;
242 #endif
243 {
244     Widget	w, form;
245     int		pos = 1, base;
246 
247     base = SpacingRatio*count + 1;
248     form = XtVaCreateManagedWidget( "buttons",
249 				    xmFormWidgetClass,
250 				    parent,
251 				    XmNleftAttachment,	XmATTACH_FORM,
252 				    XmNrightAttachment,	XmATTACH_FORM,
253 				    XmNfractionBase,	base,
254 				    XmNshadowType,	XmSHADOW_ETCHED_IN,
255 				    XmNshadowThickness,	2,
256 				    XmNverticalSpacing,	4,
257 				    0
258 				    );
259 
260     while ( count-- > 0 ) {
261 	w = XtVaCreateManagedWidget(data->name,
262 				    xmPushButtonGadgetClass,
263 				    form,
264 				    XmNtopAttachment,	XmATTACH_FORM,
265 				    XmNbottomAttachment,XmATTACH_FORM,
266 				    XmNleftAttachment,	XmATTACH_POSITION,
267 				    XmNleftPosition,	pos,
268 				    XmNshowAsDefault,	False,
269 				    XmNrightAttachment,	XmATTACH_POSITION,
270 				    XmNrightPosition,	pos+SpacingRatio-1,
271 				    0
272 				    );
273 	XtAddCallback( w, XmNactivateCallback, data->cb, 0 );
274 	pos += SpacingRatio;
275 	data++;
276     }
277 
278     /* last button is 'cancel' */
279     XtVaSetValues( XtParent(form), XmNcancelButton, w, 0 );
280 
281     return form;
282 }
283 
284 
285 /* create a set of check boxes */
286 
287 #if defined(SelfTest)
288 
289 #if defined(__STDC__)
create_check_boxes(Widget parent,ToggleData * toggles,int count)290 static	Widget	create_check_boxes( Widget parent,
291 				    ToggleData *toggles,
292 				    int count
293 				    )
294 #else
295 static	Widget	create_check_boxes( parent, toggles, count )
296 	Widget	parent;
297 	ToggleData *toggles;
298 	int	count;
299 #endif
300 {
301     Widget	form;
302     int		pos = 1, base;
303 
304     base = SpacingRatio*count +1;
305     form = XtVaCreateManagedWidget( "toggles",
306 				    xmFormWidgetClass,
307 				    parent,
308 				    XmNleftAttachment,	XmATTACH_FORM,
309 				    XmNrightAttachment,	XmATTACH_FORM,
310 				    XmNfractionBase,	base,
311 				    XmNverticalSpacing,	4,
312 				    0
313 				    );
314 
315     while ( count-- > 0 ) {
316 	XtVaCreateManagedWidget(toggles->name,
317 				xmToggleButtonWidgetClass,
318 				form,
319 				XmNtopAttachment,	XmATTACH_FORM,
320 				XmNbottomAttachment,	XmATTACH_FORM,
321 				XmNleftAttachment,	XmATTACH_POSITION,
322 				XmNleftPosition,	pos,
323 				XmNrightAttachment,	XmATTACH_POSITION,
324 				XmNrightPosition,	pos+SpacingRatio-1,
325 				0
326 				);
327 	pos += SpacingRatio;
328 	++toggles;
329     }
330 
331     return form;
332 }
333 
334 #endif
335 
336 
337 /* Routines to handle the text field widget */
338 
339 /* when the user hits 'CR' in a text widget, fire the default pushbutton */
340 #if defined(__STDC__)
text_cr(Widget w,void * ptr,void * ptr2)341 static	void	text_cr( Widget w, void *ptr, void *ptr2 )
342 #else
343 static	void	text_cr( w, ptr, ptr2 )
344 	Widget	w;
345 	void	*ptr;
346 	void	*ptr2;
347 #endif
348 {
349     next_func( w );
350 }
351 
352 
353 #ifdef notdef
354 /*
355  * when the user hits any other character, if we are doing incremental
356  * search, send the updated string to nvi
357  *
358  * XXX
359  * I don't currently see any way to make this work -- incremental search
360  * is going to be really nasty.  What makes it worse is that the dialog
361  * box almost certainly obscured a chunk of the text file, so there's no
362  * way to use it even if it works.
363  */
364 #if defined(__STDC__)
value_changed(Widget w,void * ptr,void * ptr2)365 static	void	value_changed( Widget w, void *ptr, void *ptr2 )
366 #else
367 static	void	value_changed( w, ptr, ptr2 )
368 	Widget	w;
369 	void	*ptr;
370 	void	*ptr2;
371 #endif
372 {
373     /* get all the data from the root of the widget tree */
374     get_state( w );
375 
376     /* send it along? */
377 #if defined(SelfTest)
378     if ( incremental_search ) send_command( w );
379 #else
380     if ( __vi_incremental_search() ) send_command( w );
381 #endif
382 }
383 #endif /* notdef */
384 
385 
386 /* Draw and display a dialog the describes nvi search capability */
387 
388 #if defined(__STDC__)
create_search_dialog(Widget parent,String title)389 static	Widget	create_search_dialog( Widget parent, String title )
390 #else
391 static	Widget	create_search_dialog( parent, title )
392 	Widget	parent;
393 	String	title;
394 #endif
395 {
396     Widget	box, form, label, text, checks, buttons, form2;
397     save_dialog	*ptr;
398 
399     /* use an existing one? */
400     if ( dialogs != NULL ) {
401 	box = dialogs->shell;
402 	ptr = dialogs->next;
403 	free( dialogs );
404 	dialogs = ptr;
405 	return box;
406     }
407 
408     box = XtVaCreatePopupShell( title,
409 				xmDialogShellWidgetClass,
410 				parent,
411 				XmNtitle,		title,
412 				XmNallowShellResize,	False,
413 				0
414 				);
415 
416     form = XtVaCreateWidget( "form",
417 				xmFormWidgetClass,
418 				box,
419 				XmNverticalSpacing,	4,
420 				XmNhorizontalSpacing,	4,
421 				0
422 				);
423 
424     form2 = XtVaCreateManagedWidget( "form",
425 				xmFormWidgetClass,
426 				form,
427 				XmNtopAttachment,	XmATTACH_FORM,
428 				XmNleftAttachment,	XmATTACH_FORM,
429 				XmNrightAttachment,	XmATTACH_FORM,
430 				0
431 				);
432 
433     label = XtVaCreateManagedWidget( "Pattern:",
434 				    xmLabelWidgetClass,
435 				    form2,
436 				    XmNtopAttachment,	XmATTACH_FORM,
437 				    XmNbottomAttachment,XmATTACH_FORM,
438 				    XmNleftAttachment,	XmATTACH_FORM,
439 				    0
440 				    );
441 
442     text = XtVaCreateManagedWidget( PatternWidget,
443 				    xmTextFieldWidgetClass,
444 				    form2,
445 				    XmNtopAttachment,	XmATTACH_FORM,
446 				    XmNbottomAttachment,XmATTACH_FORM,
447 				    XmNleftAttachment,	XmATTACH_WIDGET,
448 				    XmNleftWidget,	label,
449 				    XmNrightAttachment,	XmATTACH_FORM,
450 				    0
451 				    );
452 #ifdef notdef
453     XtAddCallback( text, XmNvalueChangedCallback, value_changed, 0 );
454 #endif
455     XtAddCallback( text, XmNactivateCallback, text_cr, 0 );
456 
457     buttons = create_push_buttons( form, button_data, XtNumber(button_data) );
458     XtVaSetValues( buttons,
459 		   XmNbottomAttachment,	XmATTACH_FORM,
460 		   0
461 		   );
462 
463 #if defined(SelfTest)
464     checks = create_check_boxes( form, toggle_data, XtNumber(toggle_data) );
465 #else
466     checks = (Widget) __vi_create_search_toggles( form, search_toggles );
467 #endif
468     XtVaSetValues( checks,
469 		   XmNtopAttachment,	XmATTACH_WIDGET,
470 		   XmNtopWidget,	form2,
471 		   XmNbottomAttachment,	XmATTACH_WIDGET,
472 		   XmNbottomWidget,	buttons,
473 		   0
474 		   );
475 
476     XtManageChild( form );
477     return box;
478 }
479 
480 
481 /* Module interface to the outside world
482  *
483  *	xip_show_search_dialog( parent, title )
484  *	pops up a search dialog
485  *
486  *	xip_next_search()
487  *	simulates a 'next' assuming that a search has been done
488  */
489 
490 #if defined(__STDC__)
__vi_show_search_dialog(Widget parent,String title)491 void 	__vi_show_search_dialog( Widget parent, String title )
492 #else
493 void	__vi_show_search_dialog( parent, data, cbs )
494 Widget	parent;
495 String	title;
496 #endif
497 {
498     Widget 	db = create_search_dialog( parent, title );
499     Dimension	height;
500 
501     /* we can handle getting taller and wider or narrower, but not shorter */
502     XtVaGetValues( db, XmNheight, &height, 0 );
503     XtVaSetValues( db, XmNmaxHeight, height, XmNminHeight, height, 0 );
504 
505     /* post the dialog */
506     XtPopup( db, XtGrabNone );
507 
508     /* request initial focus to the text widget */
509     XmProcessTraversal( get_child_widget( db, PatternWidget ),
510 			XmTRAVERSE_CURRENT
511 			);
512 }
513 
514 
515 /*
516  * __vi_search --
517  *
518  * PUBLIC: void __vi_search __P((Widget));
519  */
520 void
__vi_search(Widget w)521 __vi_search(Widget w)
522 {
523     next_func( w );
524 }
525 
526 
527 #if defined(SelfTest)
528 
529 #if defined(__STDC__)
show_search(Widget w,XtPointer data,XtPointer cbs)530 static void show_search( Widget w, XtPointer data, XtPointer cbs )
531 #else
532 static void show_search( w, data, cbs )
533 Widget w;
534 XtPointer	data;
535 XtPointer	cbs;
536 #endif
537 {
538     __vi_show_search_dialog( data, "Search" );
539 }
540 
main(int argc,char * argv[])541 main( int argc, char *argv[] )
542 {
543     XtAppContext	ctx;
544     Widget		top_level, rc, button;
545     extern		exit();
546 
547     /* create a top-level shell for the window manager */
548     top_level = XtVaAppInitialize( &ctx,
549 				   argv[0],
550 				   NULL, 0,	/* options */
551 				   (ArgcType) &argc,
552 				   argv,	/* might get modified */
553 				   NULL,
554 				   NULL
555 				   );
556 
557     rc = XtVaCreateManagedWidget( "rc",
558 				  xmRowColumnWidgetClass,
559 				  top_level,
560 				  0
561 				  );
562 
563     button = XtVaCreateManagedWidget( "Pop up search dialog",
564 				      xmPushButtonGadgetClass,
565 				      rc,
566 				      0
567 				      );
568     XtAddCallback( button, XmNactivateCallback, show_search, rc );
569 
570     button = XtVaCreateManagedWidget( "Quit",
571 				      xmPushButtonGadgetClass,
572 				      rc,
573 				      0
574 				      );
575     XtAddCallback( button, XmNactivateCallback, exit, 0 );
576 
577     XtRealizeWidget(top_level);
578     XtAppMainLoop(ctx);
579 }
580 #endif
581