1 /*!
2  * \file src/select.c
3  *
4  * \brief Select routines.
5  *
6  * <hr>
7  *
8  * <h1><b>Copyright.</b></h1>\n
9  *
10  * PCB, interactive printed circuit board design
11  *
12  * Copyright (C) 1994,1995,1996 Thomas Nau
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, write to the Free Software Foundation, Inc.,
26  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  *
28  * Contact addresses for paper mail and Email:
29  *
30  * Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
31  *
32  * Thomas.Nau@rz.uni-ulm.de
33  */
34 
35 
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39 
40 #include "global.h"
41 
42 #include "data.h"
43 #include "draw.h"
44 #include "error.h"
45 #include "flags.h"
46 #include "search.h"
47 #include "select.h"
48 #include "undo.h"
49 #include "rats.h"
50 #include "misc.h"
51 #include "find.h"
52 
53 #include <sys/types.h>
54 #ifdef HAVE_REGEX_H
55 #include <regex.h>
56 #else
57 #ifdef HAVE_UNISTD_H
58 #include <unistd.h>
59 #endif
60 #endif
61 
62 #ifdef HAVE_LIBDMALLOC
63 #include <dmalloc.h>
64 #endif
65 
66 /*!
67  * \brief Toggles the selection of any kind of object.
68  *
69  * The various types are defined in search.h.
70  */
71 bool
SelectObject(void)72 SelectObject (void)
73 {
74   void *ptr1, *ptr2, *ptr3;
75   LayerType *layer;
76   int type;
77 
78   bool changed = true;
79 
80   type = SearchScreen (Crosshair.X, Crosshair.Y, SELECT_TYPES,
81 		       &ptr1, &ptr2, &ptr3);
82   if (type == NO_TYPE || TEST_FLAG (LOCKFLAG, (PinType *) ptr2))
83     return (false);
84   switch (type)
85     {
86     case VIA_TYPE:
87       AddObjectToFlagUndoList (VIA_TYPE, ptr1, ptr1, ptr1);
88       TOGGLE_FLAG (SELECTEDFLAG, (PinType *) ptr1);
89       DrawVia ((PinType *) ptr1);
90       break;
91 
92     case LINE_TYPE:
93       {
94 	LineType *line = (LineType *) ptr2;
95 
96 	layer = (LayerType *) ptr1;
97 	AddObjectToFlagUndoList (LINE_TYPE, ptr1, ptr2, ptr2);
98 	TOGGLE_FLAG (SELECTEDFLAG, line);
99 	DrawLine (layer, line);
100 	break;
101       }
102 
103     case RATLINE_TYPE:
104       {
105 	RatType *rat = (RatType *) ptr2;
106 
107 	AddObjectToFlagUndoList (RATLINE_TYPE, ptr1, ptr1, ptr1);
108 	TOGGLE_FLAG (SELECTEDFLAG, rat);
109 	DrawRat (rat);
110 	break;
111       }
112 
113     case ARC_TYPE:
114       {
115 	ArcType *arc = (ArcType *) ptr2;
116 
117 	layer = (LayerType *) ptr1;
118 	AddObjectToFlagUndoList (ARC_TYPE, ptr1, ptr2, ptr2);
119 	TOGGLE_FLAG (SELECTEDFLAG, arc);
120 	DrawArc (layer, arc);
121 	break;
122       }
123 
124     case TEXT_TYPE:
125       {
126 	TextType *text = (TextType *) ptr2;
127 
128 	layer = (LayerType *) ptr1;
129 	AddObjectToFlagUndoList (TEXT_TYPE, ptr1, ptr2, ptr2);
130 	TOGGLE_FLAG (SELECTEDFLAG, text);
131 	DrawText (layer, text);
132 	break;
133       }
134 
135     case POLYGON_TYPE:
136       {
137 	PolygonType *poly = (PolygonType *) ptr2;
138 
139 	layer = (LayerType *) ptr1;
140 	AddObjectToFlagUndoList (POLYGON_TYPE, ptr1, ptr2, ptr2);
141 	TOGGLE_FLAG (SELECTEDFLAG, poly);
142 	DrawPolygon (layer, poly);
143 	/* changing memory order no longer effects draw order */
144 	break;
145       }
146 
147     case PIN_TYPE:
148       AddObjectToFlagUndoList (PIN_TYPE, ptr1, ptr2, ptr2);
149       TOGGLE_FLAG (SELECTEDFLAG, (PinType *) ptr2);
150       DrawPin ((PinType *) ptr2);
151       break;
152 
153     case PAD_TYPE:
154       AddObjectToFlagUndoList (PAD_TYPE, ptr1, ptr2, ptr2);
155       TOGGLE_FLAG (SELECTEDFLAG, (PadType *) ptr2);
156       DrawPad ((PadType *) ptr2);
157       break;
158 
159     case ELEMENTNAME_TYPE:
160       {
161 	ElementType *element = (ElementType *) ptr1;
162 
163 	/* select all names of the element */
164 	ELEMENTTEXT_LOOP (element);
165 	{
166 	  AddObjectToFlagUndoList (ELEMENTNAME_TYPE, element, text, text);
167 	  TOGGLE_FLAG (SELECTEDFLAG, text);
168 	}
169 	END_LOOP;
170 	DrawElementName (element);
171 	break;
172       }
173 
174     case ELEMENT_TYPE:
175       {
176 	ElementType *element = (ElementType *) ptr1;
177 
178 	/* select all pins and names of the element */
179 	PIN_LOOP (element);
180 	{
181 	  AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
182 	  TOGGLE_FLAG (SELECTEDFLAG, pin);
183 	}
184 	END_LOOP;
185 	PAD_LOOP (element);
186 	{
187 	  AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
188 	  TOGGLE_FLAG (SELECTEDFLAG, pad);
189 	}
190 	END_LOOP;
191 	ELEMENTTEXT_LOOP (element);
192 	{
193 	  AddObjectToFlagUndoList (ELEMENTNAME_TYPE, element, text, text);
194 	  TOGGLE_FLAG (SELECTEDFLAG, text);
195 	}
196 	END_LOOP;
197 	AddObjectToFlagUndoList (ELEMENT_TYPE, element, element, element);
198 	TOGGLE_FLAG (SELECTEDFLAG, element);
199 	if (PCB->ElementOn &&
200 	    ((TEST_FLAG (ONSOLDERFLAG, element) != 0) == SWAP_IDENT ||
201 	     PCB->InvisibleObjectsOn))
202 	  if (PCB->ElementOn)
203 	    {
204 	      DrawElementName (element);
205 	      DrawElementPackage (element);
206 	    }
207 	if (PCB->PinOn)
208 	  DrawElementPinsAndPads (element);
209 	break;
210       }
211     }
212   Draw ();
213   IncrementUndoSerialNumber ();
214   return (changed);
215 }
216 
217 /*!
218  * \brief Selects/unselects all visible objects within the passed box.
219  *
220  * "select" determines if the block is to be selected or unselected.
221  *
222  * \return true if the state of any object has changed.
223  */
224 bool
SelectBlock(BoxType * Box,bool select)225 SelectBlock (BoxType *Box, bool select)
226 {
227   bool changed = false;
228 
229   if (PCB->RatOn || !select)
230     RAT_LOOP (PCB->Data);
231   {
232     if (LINE_IN_BOX ((LineType *) line, Box) &&
233 	!TEST_FLAG (LOCKFLAG, line) && TEST_FLAG (SELECTEDFLAG, line) != select)
234       {
235 	AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
236 	ASSIGN_FLAG (SELECTEDFLAG, select, line);
237 	if (PCB->RatOn)
238 	  DrawRat (line);
239 	changed = true;
240       }
241   }
242   END_LOOP;
243 
244   /* check layers */
245   LAYER_LOOP(PCB->Data, max_copper_layer + SILK_LAYER);
246   {
247     if (layer == & PCB->Data->SILKLAYER)
248       {
249 	if (! (PCB->ElementOn || !select))
250 	  continue;
251       }
252     else if (layer == & PCB->Data->BACKSILKLAYER)
253       {
254 	if (! (PCB->InvisibleObjectsOn || !select))
255 	  continue;
256       }
257     else
258       if (! (layer->On || !select))
259 	continue;
260 
261     LINE_LOOP (layer);
262     {
263       if (LINE_IN_BOX (line, Box)
264 	  && !TEST_FLAG (LOCKFLAG, line)
265 	  && TEST_FLAG (SELECTEDFLAG, line) != select)
266 	{
267 	  AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
268 	  ASSIGN_FLAG (SELECTEDFLAG, select, line);
269 	  if (layer->On)
270 	    DrawLine (layer, line);
271 	  changed = true;
272 	}
273     }
274     END_LOOP;
275     ARC_LOOP (layer);
276     {
277       if (ARC_IN_BOX (arc, Box)
278 	  && !TEST_FLAG (LOCKFLAG, arc)
279 	  && TEST_FLAG (SELECTEDFLAG, arc) != select)
280 	{
281 	  AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
282 	  ASSIGN_FLAG (SELECTEDFLAG, select, arc);
283 	  if (layer->On)
284 	    DrawArc (layer, arc);
285 	  changed = true;
286 	}
287     }
288     END_LOOP;
289     TEXT_LOOP (layer);
290     {
291       if (!select || TEXT_IS_VISIBLE(PCB, layer, text))
292 	{
293 	  if (TEXT_IN_BOX (text, Box)
294 	      && !TEST_FLAG (LOCKFLAG, text)
295 	      && TEST_FLAG (SELECTEDFLAG, text) != select)
296 	    {
297 	      AddObjectToFlagUndoList (TEXT_TYPE, layer, text, text);
298 	      ASSIGN_FLAG (SELECTEDFLAG, select, text);
299 	      if (TEXT_IS_VISIBLE(PCB, layer, text))
300 		DrawText (layer, text);
301 	      changed = true;
302 	    }
303 	}
304     }
305     END_LOOP;
306     POLYGON_LOOP (layer);
307     {
308       if (POLYGON_IN_BOX (polygon, Box)
309 	  && !TEST_FLAG (LOCKFLAG, polygon)
310 	  && TEST_FLAG (SELECTEDFLAG, polygon) != select)
311 	{
312 	  AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
313 	  ASSIGN_FLAG (SELECTEDFLAG, select, polygon);
314 	  if (layer->On)
315 	    DrawPolygon (layer, polygon);
316 	  changed = true;
317 	}
318     }
319     END_LOOP;
320   }
321   END_LOOP;
322 
323   /* elements */
324   ELEMENT_LOOP (PCB->Data);
325   {
326     {
327       bool gotElement = false;
328       if ((PCB->ElementOn || !select)
329 	  && !TEST_FLAG (LOCKFLAG, element)
330 	  && ((TEST_FLAG (ONSOLDERFLAG, element) != 0) == SWAP_IDENT
331 	      || PCB->InvisibleObjectsOn))
332 	{
333 	  if (BOX_IN_BOX
334 	      (&ELEMENT_TEXT (PCB, element).BoundingBox, Box)
335 	      && !TEST_FLAG (LOCKFLAG, &ELEMENT_TEXT (PCB, element))
336 	      && TEST_FLAG (SELECTEDFLAG,
337 			    &ELEMENT_TEXT (PCB, element)) != select)
338 	    {
339 	      /* select all names of element */
340 	      ELEMENTTEXT_LOOP (element);
341 	      {
342 		AddObjectToFlagUndoList (ELEMENTNAME_TYPE,
343 					 element, text, text);
344 		ASSIGN_FLAG (SELECTEDFLAG, select, text);
345 	      }
346 	      END_LOOP;
347 	      if (PCB->ElementOn)
348 		DrawElementName (element);
349 	      changed = true;
350 	    }
351 	  if ((PCB->PinOn || !select) && ELEMENT_IN_BOX (element, Box))
352 	    if (TEST_FLAG (SELECTEDFLAG, element) != select)
353 	      {
354 		AddObjectToFlagUndoList (ELEMENT_TYPE,
355 					 element, element, element);
356 		ASSIGN_FLAG (SELECTEDFLAG, select, element);
357 		PIN_LOOP (element);
358 		{
359 		  if (TEST_FLAG (SELECTEDFLAG, pin) != select)
360 		    {
361 		      AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
362 		      ASSIGN_FLAG (SELECTEDFLAG, select, pin);
363 		      if (PCB->PinOn)
364 			DrawPin (pin);
365 		      changed = true;
366 		    }
367 		}
368 		END_LOOP;
369 		PAD_LOOP (element);
370 		{
371 		  if (TEST_FLAG (SELECTEDFLAG, pad) != select)
372 		    {
373 		      AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
374 		      ASSIGN_FLAG (SELECTEDFLAG, select, pad);
375 		      if (PCB->PinOn)
376 			DrawPad (pad);
377 		      changed = true;
378 		    }
379 		}
380 		END_LOOP;
381 		if (PCB->PinOn)
382 		  DrawElement (element);
383 		changed = true;
384 		gotElement = true;
385 	      }
386 	}
387       if ((PCB->PinOn || !select) && !TEST_FLAG (LOCKFLAG, element) && !gotElement)
388 	{
389 	  PIN_LOOP (element);
390 	  {
391 	    if ((VIA_OR_PIN_IN_BOX (pin, Box)
392 		 && TEST_FLAG (SELECTEDFLAG, pin) != select))
393 	      {
394 		AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
395 		ASSIGN_FLAG (SELECTEDFLAG, select, pin);
396 		if (PCB->PinOn)
397 		  DrawPin (pin);
398 		changed = true;
399 	      }
400 	  }
401 	  END_LOOP;
402 	  PAD_LOOP (element);
403 	  {
404 	    if (PAD_IN_BOX (pad, Box)
405 		&& TEST_FLAG (SELECTEDFLAG, pad) != select
406 		&& (TEST_FLAG (ONSOLDERFLAG, pad) == SWAP_IDENT
407 		    || PCB->InvisibleObjectsOn
408 		    || !select))
409 	      {
410 		AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
411 		ASSIGN_FLAG (SELECTEDFLAG, select, pad);
412 		if (PCB->PinOn)
413 		  DrawPad (pad);
414 		changed = true;
415 	      }
416 	  }
417 	  END_LOOP;
418 	}
419     }
420   }
421   END_LOOP;
422   /* end with vias */
423   if (PCB->ViaOn || !select)
424     VIA_LOOP (PCB->Data);
425   {
426     if (VIA_OR_PIN_IN_BOX (via, Box)
427 	&& !TEST_FLAG (LOCKFLAG, via)
428 	&& TEST_FLAG (SELECTEDFLAG, via) != select)
429       {
430 	AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
431 	ASSIGN_FLAG (SELECTEDFLAG, select, via);
432 	if (PCB->ViaOn)
433 	  DrawVia (via);
434 	changed = true;
435       }
436   }
437   END_LOOP;
438   if (changed)
439     {
440       Draw ();
441       IncrementUndoSerialNumber ();
442     }
443   return (changed);
444 }
445 
446 /*!
447  * \brief Performs several operations on the passed object.
448  */
449 void *
ObjectOperation(ObjectFunctionType * F,int Type,void * Ptr1,void * Ptr2,void * Ptr3)450 ObjectOperation (ObjectFunctionType *F,
451 		 int Type, void *Ptr1, void *Ptr2, void *Ptr3)
452 {
453   switch (Type)
454     {
455     case LINE_TYPE:
456       if (F->Line)
457 	return (F->Line ((LayerType *) Ptr1, (LineType *) Ptr2));
458       break;
459 
460     case ARC_TYPE:
461       if (F->Arc)
462 	return (F->Arc ((LayerType *) Ptr1, (ArcType *) Ptr2));
463       break;
464 
465     case LINEPOINT_TYPE:
466       if (F->LinePoint)
467 	return (F->LinePoint ((LayerType *) Ptr1, (LineType *) Ptr2,
468 			      (PointType *) Ptr3));
469       break;
470 
471     case TEXT_TYPE:
472       if (F->Text)
473 	return (F->Text ((LayerType *) Ptr1, (TextType *) Ptr2));
474       break;
475 
476     case POLYGON_TYPE:
477       if (F->Polygon)
478 	return (F->Polygon ((LayerType *) Ptr1, (PolygonType *) Ptr2));
479       break;
480 
481     case POLYGONPOINT_TYPE:
482       if (F->Point)
483 	return (F->Point ((LayerType *) Ptr1, (PolygonType *) Ptr2,
484 			  (PointType *) Ptr3));
485       break;
486 
487     case VIA_TYPE:
488       if (F->Via)
489 	return (F->Via ((PinType *) Ptr1));
490       break;
491 
492     case ELEMENT_TYPE:
493       if (F->Element)
494 	return (F->Element ((ElementType *) Ptr1));
495       break;
496 
497     case PIN_TYPE:
498       if (F->Pin)
499 	return (F->Pin ((ElementType *) Ptr1, (PinType *) Ptr2));
500       break;
501 
502     case PAD_TYPE:
503       if (F->Pad)
504 	return (F->Pad ((ElementType *) Ptr1, (PadType *) Ptr2));
505       break;
506 
507     case ELEMENTNAME_TYPE:
508       if (F->ElementName)
509 	return (F->ElementName ((ElementType *) Ptr1));
510       break;
511 
512     case RATLINE_TYPE:
513       if (F->Rat)
514 	return (F->Rat ((RatType *) Ptr1));
515       break;
516     }
517   return (NULL);
518 }
519 
520 /*!
521  * \brief Performs several operations on selected objects which are also
522  * visible.
523  *
524  * The lowlevel procedures are passed together with additional
525  * information.
526  *
527  * Resets the selected flag if requested.
528  *
529  * \return true if anything has changed.
530  */
531 bool
SelectedOperation(ObjectFunctionType * F,bool Reset,int type)532 SelectedOperation (ObjectFunctionType *F, bool Reset, int type)
533 {
534   bool changed = false;
535 
536   /* check lines */
537   if (type & LINE_TYPE && F->Line)
538     VISIBLELINE_LOOP (PCB->Data);
539   {
540     if (TEST_FLAG (SELECTEDFLAG, line))
541       {
542 	if (Reset)
543 	  {
544 	    AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
545 	    CLEAR_FLAG (SELECTEDFLAG, line);
546 	  }
547 	F->Line (layer, line);
548 	changed = true;
549       }
550   }
551   ENDALL_LOOP;
552 
553   /* check arcs */
554   if (type & ARC_TYPE && F->Arc)
555     VISIBLEARC_LOOP (PCB->Data);
556   {
557     if (TEST_FLAG (SELECTEDFLAG, arc))
558       {
559 	if (Reset)
560 	  {
561 	    AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
562 	    CLEAR_FLAG (SELECTEDFLAG, arc);
563 	  }
564 	F->Arc (layer, arc);
565 	changed = true;
566       }
567   }
568   ENDALL_LOOP;
569 
570   /* check text */
571   if (type & TEXT_TYPE && F->Text)
572     ALLTEXT_LOOP (PCB->Data);
573   {
574     if (TEST_FLAG (SELECTEDFLAG, text) && TEXT_IS_VISIBLE (PCB, layer, text))
575       {
576 	if (Reset)
577 	  {
578 	    AddObjectToFlagUndoList (TEXT_TYPE, layer, text, text);
579 	    CLEAR_FLAG (SELECTEDFLAG, text);
580 	  }
581 	F->Text (layer, text);
582 	changed = true;
583       }
584   }
585   ENDALL_LOOP;
586 
587   /* check polygons */
588   if (type & POLYGON_TYPE && F->Polygon)
589     VISIBLEPOLYGON_LOOP (PCB->Data);
590   {
591     if (TEST_FLAG (SELECTEDFLAG, polygon))
592       {
593 	if (Reset)
594 	  {
595 	    AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
596 	    CLEAR_FLAG (SELECTEDFLAG, polygon);
597 	  }
598 	F->Polygon (layer, polygon);
599 	changed = true;
600       }
601   }
602   ENDALL_LOOP;
603 
604   /* elements silkscreen */
605   if (type & ELEMENT_TYPE && PCB->ElementOn && F->Element)
606     ELEMENT_LOOP (PCB->Data);
607   {
608     if (TEST_FLAG (SELECTEDFLAG, element))
609       {
610 	if (Reset)
611 	  {
612 	    AddObjectToFlagUndoList (ELEMENT_TYPE, element, element, element);
613 	    CLEAR_FLAG (SELECTEDFLAG, element);
614 	  }
615 	F->Element (element);
616 	changed = true;
617       }
618   }
619   END_LOOP;
620   if (type & ELEMENTNAME_TYPE && PCB->ElementOn && F->ElementName)
621     ELEMENT_LOOP (PCB->Data);
622   {
623     if (TEST_FLAG (SELECTEDFLAG, &ELEMENT_TEXT (PCB, element)))
624       {
625 	if (Reset)
626 	  {
627 	    AddObjectToFlagUndoList (ELEMENTNAME_TYPE,
628 				     element,
629 				     &ELEMENT_TEXT (PCB, element),
630 				     &ELEMENT_TEXT (PCB, element));
631 	    CLEAR_FLAG (SELECTEDFLAG, &ELEMENT_TEXT (PCB, element));
632 	  }
633 	F->ElementName (element);
634 	changed = true;
635       }
636   }
637   END_LOOP;
638 
639   if (type & PIN_TYPE && PCB->PinOn && F->Pin)
640     ELEMENT_LOOP (PCB->Data);
641   {
642     PIN_LOOP (element);
643     {
644       if (TEST_FLAG (SELECTEDFLAG, pin))
645 	{
646 	  if (Reset)
647 	    {
648 	      AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
649 	      CLEAR_FLAG (SELECTEDFLAG, pin);
650 	    }
651 	  F->Pin (element, pin);
652 	  changed = true;
653 	}
654     }
655     END_LOOP;
656   }
657   END_LOOP;
658 
659   if (type & PAD_TYPE && PCB->PinOn && F->Pad)
660     ELEMENT_LOOP (PCB->Data);
661   {
662     PAD_LOOP (element);
663     {
664       if (TEST_FLAG (SELECTEDFLAG, pad))
665 	{
666 	  if (Reset)
667 	    {
668 	      AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
669 	      CLEAR_FLAG (SELECTEDFLAG, pad);
670 	    }
671 	  F->Pad (element, pad);
672 	  changed = true;
673 	}
674     }
675     END_LOOP;
676   }
677   END_LOOP;
678 
679   /* process vias */
680   if (type & VIA_TYPE && PCB->ViaOn && F->Via)
681     VIA_LOOP (PCB->Data);
682   {
683     if (TEST_FLAG (SELECTEDFLAG, via))
684       {
685 	if (Reset)
686 	  {
687 	    AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
688 	    CLEAR_FLAG (SELECTEDFLAG, via);
689 	  }
690 	F->Via (via);
691 	changed = true;
692       }
693   }
694   END_LOOP;
695   /* and rat-lines */
696   if (type & RATLINE_TYPE && PCB->RatOn && F->Rat)
697     RAT_LOOP (PCB->Data);
698   {
699     if (TEST_FLAG (SELECTEDFLAG, line))
700       {
701 	if (Reset)
702 	  {
703 	    AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
704 	    CLEAR_FLAG (SELECTEDFLAG, line);
705 	  }
706 	F->Rat (line);
707 	changed = true;
708       }
709   }
710   END_LOOP;
711   if (Reset && changed)
712     IncrementUndoSerialNumber ();
713   return (changed);
714 }
715 
716 /*!
717  * \brief Selects/unselects all objects which have (any of) the
718  * specified flag(s) set.
719  *
720  * This is typically the FOUNDFLAG, assigned during a connection scan.
721  *
722  * "select" determines if they are to be selected or unselected.
723  *
724  * \return true if the state of any object has changed.
725  *
726  * \note Text objects and elements cannot be selected by this routine.
727  */
728 bool
SelectByFlag(int flag,bool select)729 SelectByFlag (int flag, bool select)
730 {
731   bool changed = false;
732 
733   if (PCB->RatOn)
734     RAT_LOOP (PCB->Data);
735   {
736     if (TEST_FLAG (flag, line))
737       {
738 	AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
739 	ASSIGN_FLAG (SELECTEDFLAG, select, line);
740 	DrawRat (line);
741 	changed = true;
742       }
743   }
744   END_LOOP;
745 
746   VISIBLELINE_LOOP (PCB->Data);
747   {
748     if (TEST_FLAG (flag, line) && !TEST_FLAG (LOCKFLAG, line))
749       {
750 	AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
751 	ASSIGN_FLAG (SELECTEDFLAG, select, line);
752 	DrawLine (layer, line);
753 	changed = true;
754       }
755   }
756   ENDALL_LOOP;
757   VISIBLEARC_LOOP (PCB->Data);
758   {
759     if (TEST_FLAG (flag, arc) && !TEST_FLAG (LOCKFLAG, arc))
760       {
761 	AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
762 	ASSIGN_FLAG (SELECTEDFLAG, select, arc);
763 	DrawArc (layer, arc);
764 	changed = true;
765       }
766   }
767   ENDALL_LOOP;
768   VISIBLEPOLYGON_LOOP (PCB->Data);
769   {
770     if (TEST_FLAG (flag, polygon) && !TEST_FLAG (LOCKFLAG, polygon))
771       {
772 	AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
773 	ASSIGN_FLAG (SELECTEDFLAG, select, polygon);
774 	DrawPolygon (layer, polygon);
775 	changed = true;
776       }
777   }
778   ENDALL_LOOP;
779 
780   if (PCB->PinOn && PCB->ElementOn)
781     {
782       ALLPIN_LOOP (PCB->Data);
783       {
784 	if (!TEST_FLAG (LOCKFLAG, element) && TEST_FLAG (flag, pin))
785 	  {
786 	    AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
787 	    ASSIGN_FLAG (SELECTEDFLAG, select, pin);
788 	    DrawPin (pin);
789 	    changed = true;
790 	  }
791       }
792       ENDALL_LOOP;
793       ALLPAD_LOOP (PCB->Data);
794       {
795 	if (!TEST_FLAG (LOCKFLAG, element) && TEST_FLAG (flag, pad))
796 	  {
797 	    AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
798 	    ASSIGN_FLAG (SELECTEDFLAG, select, pad);
799 	    DrawPad (pad);
800 	    changed = true;
801 	  }
802       }
803       ENDALL_LOOP;
804     }
805 
806   if (PCB->ViaOn)
807     VIA_LOOP (PCB->Data);
808   {
809     if (TEST_FLAG (flag, via) && !TEST_FLAG (LOCKFLAG, via))
810       {
811 	AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
812 	ASSIGN_FLAG (SELECTEDFLAG, select, via);
813 	DrawVia (via);
814 	changed = true;
815       }
816   }
817   END_LOOP;
818   return (changed);
819 }
820 
821 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
822 /*!
823  * \brief Selects objects as defined by Type by name; it's a case
824  * insensitive match.
825  *
826  * \return true if any object has been selected.
827  */
828 #if defined (HAVE_REGCOMP)
829 static int
regexec_match_all(const regex_t * preg,const char * string)830 regexec_match_all (const  regex_t  *preg,  const  char  *string)
831 {
832   regmatch_t match;
833 
834   if (regexec (preg, string, 1, &match, 0) != 0)
835     return 0;
836   if (match.rm_so != 0)
837     return 0;
838   if (match.rm_eo != strlen(string))
839     return 0;
840   return 1;
841 }
842 #endif
843 
844 bool
SelectObjectByName(int Type,char * Pattern,bool select)845 SelectObjectByName (int Type, char *Pattern, bool select)
846 {
847   bool changed = false;
848 
849 #if defined(HAVE_REGCOMP)
850 #define	REGEXEC(arg)	(regexec_match_all(&compiled, (arg)))
851 
852   int result;
853   regex_t compiled;
854 
855   /* compile the regular expression */
856   result = regcomp (&compiled, Pattern, REG_EXTENDED | REG_ICASE);
857   if (result)
858     {
859       char errorstring[128];
860 
861       regerror (result, &compiled, errorstring, 128);
862       Message (_("regexp error: %s\n"), errorstring);
863       regfree (&compiled);
864       return (false);
865     }
866 #else
867 #define	REGEXEC(arg)	(re_exec((arg)) == 1)
868 
869   char *compiled;
870 
871   /* compile the regular expression */
872   if ((compiled = re_comp (Pattern)) != NULL)
873     {
874       Message (_("re_comp error: %s\n"), compiled);
875       return (false);
876     }
877 #endif
878 
879   /* loop over all visible objects with names */
880   if (Type & TEXT_TYPE)
881     ALLTEXT_LOOP (PCB->Data);
882   {
883     if (!TEST_FLAG (LOCKFLAG, text)
884 	&& TEXT_IS_VISIBLE (PCB, layer, text)
885 	&& text->TextString
886 	&& REGEXEC (text->TextString)
887 	&& TEST_FLAG (SELECTEDFLAG, text) != select)
888       {
889 	AddObjectToFlagUndoList (TEXT_TYPE, layer, text, text);
890 	ASSIGN_FLAG (SELECTEDFLAG, select, text);
891 	DrawText (layer, text);
892 	changed = true;
893       }
894   }
895   ENDALL_LOOP;
896 
897   if (PCB->ElementOn && (Type & ELEMENT_TYPE))
898     ELEMENT_LOOP (PCB->Data);
899   {
900     if (!TEST_FLAG (LOCKFLAG, element)
901 	&& ((TEST_FLAG (ONSOLDERFLAG, element) != 0) == SWAP_IDENT
902 	    || PCB->InvisibleObjectsOn)
903 	&& TEST_FLAG (SELECTEDFLAG, element) != select)
904       {
905 	String name = ELEMENT_NAME (PCB, element);
906 	if (name && REGEXEC (name))
907 	  {
908 	    AddObjectToFlagUndoList (ELEMENT_TYPE, element, element, element);
909 	    ASSIGN_FLAG (SELECTEDFLAG, select, element);
910 	    PIN_LOOP (element);
911 	    {
912 	      AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
913 	      ASSIGN_FLAG (SELECTEDFLAG, select, pin);
914 	    }
915 	    END_LOOP;
916 	    PAD_LOOP (element);
917 	    {
918 	      AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
919 	      ASSIGN_FLAG (SELECTEDFLAG, select, pad);
920 	    }
921 	    END_LOOP;
922 	    ELEMENTTEXT_LOOP (element);
923 	    {
924 	      AddObjectToFlagUndoList (ELEMENTNAME_TYPE, element, text, text);
925 	      ASSIGN_FLAG (SELECTEDFLAG, select, text);
926 	    }
927 	    END_LOOP;
928 	    DrawElementName (element);
929 	    DrawElement (element);
930 	    changed = true;
931 	  }
932       }
933   }
934   END_LOOP;
935   if (PCB->PinOn && (Type & PIN_TYPE))
936     ALLPIN_LOOP (PCB->Data);
937   {
938     if (!TEST_FLAG (LOCKFLAG, element)
939 	&& pin->Name && REGEXEC (pin->Name)
940 	&& TEST_FLAG (SELECTEDFLAG, pin) != select)
941       {
942 	AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
943 	ASSIGN_FLAG (SELECTEDFLAG, select, pin);
944 	DrawPin (pin);
945 	changed = true;
946       }
947   }
948   ENDALL_LOOP;
949   if (PCB->PinOn && (Type & PAD_TYPE))
950     ALLPAD_LOOP (PCB->Data);
951   {
952     if (!TEST_FLAG (LOCKFLAG, element)
953 	&& ((TEST_FLAG (ONSOLDERFLAG, pad) != 0) == SWAP_IDENT
954 	    || PCB->InvisibleObjectsOn)
955 	&& TEST_FLAG (SELECTEDFLAG, pad) != select)
956       if (pad->Name && REGEXEC (pad->Name))
957 	{
958 	  AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
959 	  ASSIGN_FLAG (SELECTEDFLAG, select, pad);
960 	  DrawPad (pad);
961 	  changed = true;
962 	}
963   }
964   ENDALL_LOOP;
965   if (PCB->ViaOn && (Type & VIA_TYPE))
966     VIA_LOOP (PCB->Data);
967   {
968     if (!TEST_FLAG (LOCKFLAG, via)
969 	&& via->Name
970 	&& REGEXEC (via->Name) && TEST_FLAG (SELECTEDFLAG, via) != select)
971       {
972 	AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
973 	ASSIGN_FLAG (SELECTEDFLAG, select, via);
974 	DrawVia (via);
975 	changed = true;
976       }
977   }
978   END_LOOP;
979   if (Type & NET_TYPE)
980     {
981       InitConnectionLookup ();
982       changed = ClearFlagOnAllObjects (FOUNDFLAG, true) || changed;
983 
984       MENU_LOOP (&PCB->NetlistLib);
985       {
986         Cardinal i;
987         LibraryEntryType *entry;
988         ConnectionType conn;
989 
990         /* Name[0] and Name[1] are special purpose, not the actual name*/
991         if (menu->Name && menu->Name[0] != '\0' && menu->Name[1] != '\0' &&
992             REGEXEC (menu->Name + 2))
993           {
994             for (i = menu->EntryN, entry = menu->Entry; i; i--, entry++)
995               if (SeekPad (entry, &conn, false))
996                 RatFindHook (conn.type, conn.ptr1, conn.ptr2, conn.ptr2,
997                              true, FOUNDFLAG, true);
998           }
999       }
1000       END_LOOP;
1001 
1002       changed = SelectByFlag (FOUNDFLAG, select) || changed;
1003       changed = ClearFlagOnAllObjects (FOUNDFLAG, false) || changed;
1004       FreeConnectionLookupMemory ();
1005     }
1006 
1007 #if defined(HAVE_REGCOMP)
1008 #if !defined(sgi)
1009   regfree (&compiled);
1010 #endif
1011 #endif
1012 
1013   if (changed)
1014     {
1015       IncrementUndoSerialNumber ();
1016       Draw ();
1017     }
1018   return (changed);
1019 }
1020 #endif /* defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP) */
1021 
1022 /*!
1023  * \brief Selects all blind/buried vias
1024  *
1025  * \return true if any object has been selected.
1026  */
1027 bool
SelectBuriedVias(bool select)1028 SelectBuriedVias (bool select)
1029 {
1030   bool changed = false;
1031 
1032   VIA_LOOP (PCB->Data)
1033    if (TEST_FLAG (LOCKFLAG, via))
1034      continue;
1035    if (VIA_IS_BURIED (via))
1036       {
1037 	AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
1038 	ASSIGN_FLAG (SELECTEDFLAG, select, via);
1039 	changed = true;
1040       }
1041   END_LOOP;
1042 
1043   return changed;
1044 }
1045