1 /*!
2  * \file src/flags.c
3  *
4  * \brief .
5  *
6  * <hr>
7  *
8  * <h1><b>Copyright.</b></h1>\n
9  *
10  * PCB, interactive printed circuit board design
11  *
12  * Copyright (C) 2005 DJ Delorie
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 
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include <math.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 
41 #include "global.h"
42 #include "data.h"
43 #include "draw.h"
44 #include "pcb-printf.h"
45 #include "search.h"
46 #include "set.h" /* SetChangedFlag */
47 #include "strflags.h"
48 #include "undo.h"
49 
50 #include <glib.h>
51 
52 #ifdef HAVE_LIBDMALLOC
53 #include <dmalloc.h>
54 #endif
55 
56 int pcb_flag_eq (FlagType *f1, FlagType *f2);
57 
58 /*!
59  * \brief .
60  *
61  * \warning ignore unknowns for now: the only place where we use this
62  * function, undo.c, won't care.
63  */
64 int
pcb_flag_eq(FlagType * f1,FlagType * f2)65 pcb_flag_eq (FlagType *f1, FlagType *f2)
66 {
67   if (f1->f != f2->f)
68     return 0;
69 
70   return (memcmp(f1->t, &f2->t, sizeof(f1->t)) == 0);
71 }
72 
73 static int
FlagCurrentStyle(void * data)74 FlagCurrentStyle (void *data)
75 {
76   STYLE_LOOP (PCB);
77   {
78     if (style->Thick == Settings.LineThickness &&
79 	style->Diameter == Settings.ViaThickness &&
80 	style->Hole == Settings.ViaDrillingHole &&
81 	style->Keepaway == Settings.Keepaway)
82       return n + 1;
83   }
84   END_LOOP;
85   return 0;
86 }
87 
88 static int
FlagGrid(void * data)89 FlagGrid (void *data)
90 {
91   return PCB->Grid > 1;
92 }
93 
94 static int
FlagGridSize(void * data)95 FlagGridSize (void *data)
96 {
97   return PCB->Grid;
98 }
99 
100 static int
FlagUnitsMm(void * data)101 FlagUnitsMm (void *data)
102 {
103   static const Unit *u = NULL;
104   if (u == NULL)
105     u = get_unit_struct ("mm");
106   return (Settings.grid_unit == u);
107 }
108 
109 static int
FlagUnitsMil(void * data)110 FlagUnitsMil (void *data)
111 {
112   static const Unit *u = NULL;
113   if (u == NULL)
114     u = get_unit_struct ("mil");
115   return (Settings.grid_unit == u);
116 }
117 
118 static int
FlagBuffer(void * data)119 FlagBuffer (void *data)
120 {
121   return (int) (Settings.BufferNumber + 1);
122 }
123 
124 static int
FlagElementName(void * data)125 FlagElementName (void  *data)
126 {
127   if (TEST_FLAG (NAMEONPCBFLAG, PCB))
128     return 2;
129   if (TEST_FLAG (DESCRIPTIONFLAG, PCB))
130     return 1;
131   return 3;
132 }
133 
134 static int
FlagTESTFLAG(void * data)135 FlagTESTFLAG (void *data)
136 {
137   int bit = GPOINTER_TO_INT (data);
138   return TEST_FLAG (bit, PCB) ? 1 : 0;
139 }
140 
141 static int
FlagSETTINGS(void * data)142 FlagSETTINGS (void *data)
143 {
144   size_t ofs = (size_t)data;
145   return *(bool *) ((char *)(&Settings) + ofs);
146 }
147 
148 static int
FlagMode(void * data)149 FlagMode (void *data)
150 {
151   int x = GPOINTER_TO_INT (data);
152   if (x == -1)
153     return Settings.Mode;
154   return Settings.Mode == x;
155 }
156 
157 static int
FlagHaveRegex(void * data)158 FlagHaveRegex (void *data)
159 {
160 #if defined(HAVE_REGCOMP) || defined(HAVE_RE_COMP)
161   return 1;
162 #else
163   return 0;
164 #endif
165 }
166 
167 enum {
168   FL_SILK = -6,
169   FL_PINS,
170   FL_RATS,
171   FL_VIAS,
172   FL_BACK,
173   FL_MASK
174 };
175 
176 static int
FlagLayerShown(void * data)177 FlagLayerShown (void *data)
178 {
179   int n = GPOINTER_TO_INT (data);
180   switch (n)
181     {
182     case FL_SILK:
183       return PCB->ElementOn;
184     case FL_PINS:
185       return PCB->PinOn;
186     case FL_RATS:
187       return PCB->RatOn;
188     case FL_VIAS:
189       return PCB->ViaOn;
190     case FL_BACK:
191       return PCB->InvisibleObjectsOn;
192     case FL_MASK:
193       return TEST_FLAG (SHOWMASKFLAG, PCB);
194     default:
195       if (n >= 0 && n < max_copper_layer)
196 	return PCB->Data->Layer[n].On;
197     }
198   return 0;
199 }
200 
201 static int
FlagLayerActive(void * data)202 FlagLayerActive (void *data)
203 {
204   int test_layer = GPOINTER_TO_INT (data);
205   int current_layer;
206   if (PCB->RatDraw)
207     current_layer = FL_RATS;
208   else if (PCB->SilkActive)
209     current_layer = FL_SILK;
210   else
211     return 0;
212 
213   return current_layer == test_layer;
214 }
215 
216 int
mem_any_set(unsigned char * ptr,int bytes)217 mem_any_set (unsigned char *ptr, int bytes)
218 {
219   while (bytes--)
220     if (*ptr++)
221       return 1;
222   return 0;
223 }
224 
225 /*!
226  * \brief This just fills in a FlagType with current flags.
227  */
228 FlagType
MakeFlags(unsigned int flags)229 MakeFlags (unsigned int flags)
230 {
231   FlagType rv;
232   memset (&rv, 0, sizeof (rv));
233   rv.f = flags;
234   return rv;
235 }
236 
237 /*!
238  * \brief This converts old flag bits (from saved PCB files) to new
239  * format.
240  */
241 FlagType
OldFlags(unsigned int flags)242 OldFlags (unsigned int flags)
243 {
244   FlagType rv;
245   int i, f;
246   memset (&rv, 0, sizeof (rv));
247   /* If we move flag bits around, this is where we map old bits to them.  */
248   rv.f = flags & 0xffff;
249   f = 0x10000;
250   for (i = 0; i < 8; i++)
251   {
252     /* use the closest thing to the old thermal style */
253     if (flags & f)
254       rv.t[i / 2] |= (1 << (4 * (i % 2)));
255     f <<= 1;
256   }
257   return rv;
258 }
259 
260 FlagType
AddFlags(FlagType flag,unsigned int flags)261 AddFlags (FlagType flag, unsigned int flags)
262 {
263   flag.f |= flags;
264   return flag;
265 }
266 
267 FlagType
MaskFlags(FlagType flag,unsigned int flags)268 MaskFlags (FlagType flag, unsigned int flags)
269 {
270   flag.f &= ~flags;
271   return flag;
272 }
273 
274 /*!
275  * \brief Resets all used flags of pins and vias.
276  */
277 bool
ClearFlagOnPinsViasAndPads(int flag,bool undoable)278 ClearFlagOnPinsViasAndPads (int flag, bool undoable)
279 {
280   bool change = false;
281 
282   VIA_LOOP (PCB->Data);
283   {
284     if (TEST_FLAG (flag, via))
285     {
286       if (undoable)
287         AddObjectToFlagUndoList (VIA_TYPE, via, via, via);
288       CLEAR_FLAG (flag, via);
289       change = true;
290     }
291   }
292   END_LOOP;
293   ELEMENT_LOOP (PCB->Data);
294   {
295     PIN_LOOP (element);
296     {
297       if (TEST_FLAG (flag, pin))
298       {
299         if (undoable)
300           AddObjectToFlagUndoList (PIN_TYPE, element, pin, pin);
301         CLEAR_FLAG (flag, pin);
302         change = true;
303       }
304     }
305     END_LOOP;
306     PAD_LOOP (element);
307     {
308       if (TEST_FLAG (flag, pad))
309       {
310         if (undoable)
311           AddObjectToFlagUndoList (PAD_TYPE, element, pad, pad);
312         CLEAR_FLAG (flag, pad);
313         change = true;
314       }
315     }
316     END_LOOP;
317   }
318   END_LOOP;
319   if (change)
320     SetChangedFlag (true);
321   return change;
322 }
323 
324 /*!
325  * \brief Resets all used flags of LOs.
326  */
327 bool
ClearFlagOnLinesAndPolygons(int flag,bool undoable)328 ClearFlagOnLinesAndPolygons (int flag, bool undoable)
329 {
330   bool change = false;
331 
332   RAT_LOOP (PCB->Data);
333   {
334     if (TEST_FLAG (flag, line))
335     {
336       if (undoable)
337         AddObjectToFlagUndoList (RATLINE_TYPE, line, line, line);
338       CLEAR_FLAG (flag, line);
339       change = true;
340     }
341   }
342   END_LOOP;
343   COPPERLINE_LOOP (PCB->Data);
344   {
345     if (TEST_FLAG (flag, line))
346     {
347       if (undoable)
348         AddObjectToFlagUndoList (LINE_TYPE, layer, line, line);
349       CLEAR_FLAG (flag, line);
350       change = true;
351     }
352   }
353   ENDALL_LOOP;
354   COPPERARC_LOOP (PCB->Data);
355   {
356     if (TEST_FLAG (flag, arc))
357     {
358       if (undoable)
359         AddObjectToFlagUndoList (ARC_TYPE, layer, arc, arc);
360       CLEAR_FLAG (flag, arc);
361       change = true;
362     }
363   }
364   ENDALL_LOOP;
365   COPPERPOLYGON_LOOP (PCB->Data);
366   {
367     if (TEST_FLAG (flag, polygon))
368     {
369       if (undoable)
370         AddObjectToFlagUndoList (POLYGON_TYPE, layer, polygon, polygon);
371       CLEAR_FLAG (flag, polygon);
372       change = true;
373     }
374   }
375   ENDALL_LOOP;
376   if (change)
377     SetChangedFlag (true);
378   return change;
379 }
380 
381 /*!
382  * \brief Resets all found connections.
383  */
384 bool
ClearFlagOnAllObjects(int flag,bool undoable)385 ClearFlagOnAllObjects (int flag, bool undoable)
386 {
387   bool change = false;
388 
389   change = ClearFlagOnPinsViasAndPads  (flag, undoable) || change;
390   change = ClearFlagOnLinesAndPolygons (flag, undoable) || change;
391 
392   return change;
393 }
394 
395 static const char dump_flags_syntax[] = ("DumpFlags([Output file])");
396 static const char dump_flags_help[] = ("Write out a list of objects and their flags.");
397 
398 static int
ActionDumpFlags(int argc,char ** argv,Coord x,Coord y)399 ActionDumpFlags(int argc, char **argv, Coord x, Coord y)
400 {
401   int i = -1;
402   bool found_something = false;
403   int type = 0;
404   FILE * fp;
405   void *p1, *p2, *p3, *p;
406 
407   if (argc == 1) fp = fopen(argv[0], "w");
408   else fp = stdout;
409 
410   while (1){
411     i++;
412     type = SearchObjectByID(PCB->Data, &p1, &p2, &p3, i, ALL_TYPES);
413     if (type == NO_TYPE){
414       /* There's a gap in the ID numbers at the beginning */
415       if (found_something) break;
416       else continue;
417     }
418     found_something = true;
419     /* Points don't use flags (I don't think) */
420     if (type & (LINEPOINT_TYPE | POLYGONPOINT_TYPE)) continue; /*p = p3;*/
421     else if (type && (LINE_TYPE | ARC_TYPE | TEXT_TYPE | POLYGON_TYPE | ELEMENTLINE_TYPE | ELEMENTARC_TYPE | ELEMENTNAME_TYPE | PIN_TYPE | PAD_TYPE)) p = p2;
422     else p = p1;
423 
424     fprintf(fp, "%4d %3d %s\n", i, type,
425             flags_to_string(((AnyObjectType*)p)->Flags, type));
426   }
427 
428   fclose(fp);
429   return 0;
430 }
431 
432 HID_Action flag_action_list[] = {
433   {"DumpFlags", 0, ActionDumpFlags, dump_flags_help, dump_flags_syntax}
434 };
435 
436 REGISTER_ACTIONS (flag_action_list)
437 
438 
439 #define OFFSET_POINTER(a, b) (&(((a *)0)->b))
440 
441 HID_Flag flags_flag_list[] = {
442   {"style",                FlagCurrentStyle, NULL},
443   {"grid",                 FlagGrid,         NULL},
444   {"gridsize",             FlagGridSize,     NULL},
445   {"elementname",          FlagElementName,  NULL},
446   {"have_regex",           FlagHaveRegex,    NULL},
447 
448   {"silk_shown",           FlagLayerShown,   GINT_TO_POINTER (FL_SILK)},
449   {"pins_shown",           FlagLayerShown,   GINT_TO_POINTER (FL_PINS)},
450   {"rats_shown",           FlagLayerShown,   GINT_TO_POINTER (FL_RATS)},
451   {"vias_shown",           FlagLayerShown,   GINT_TO_POINTER (FL_VIAS)},
452   {"back_shown",           FlagLayerShown,   GINT_TO_POINTER (FL_BACK)},
453   {"mask_shown",           FlagLayerShown,   GINT_TO_POINTER (FL_MASK)},
454 
455   {"silk_active",          FlagLayerActive,  GINT_TO_POINTER (FL_SILK)},
456   {"rats_active",          FlagLayerActive,  GINT_TO_POINTER (FL_RATS)},
457 
458   {"mode",                 FlagMode,         GINT_TO_POINTER (-1)},
459   {"nomode",               FlagMode,         GINT_TO_POINTER (NO_MODE)},
460   {"arcmode",              FlagMode,         GINT_TO_POINTER (ARC_MODE)},
461   {"arrowmode",            FlagMode,         GINT_TO_POINTER (ARROW_MODE)},
462   {"copymode",             FlagMode,         GINT_TO_POINTER (COPY_MODE)},
463   {"insertpointmode",      FlagMode,         GINT_TO_POINTER (INSERTPOINT_MODE)},
464   {"linemode",             FlagMode,         GINT_TO_POINTER (LINE_MODE)},
465   {"lockmode",             FlagMode,         GINT_TO_POINTER (LOCK_MODE)},
466   {"movemode",             FlagMode,         GINT_TO_POINTER (MOVE_MODE)},
467   {"pastebuffermode",      FlagMode,         GINT_TO_POINTER (PASTEBUFFER_MODE)},
468   {"polygonmode",          FlagMode,         GINT_TO_POINTER (POLYGON_MODE)},
469   {"polygonholemode",      FlagMode,         GINT_TO_POINTER (POLYGONHOLE_MODE)},
470   {"rectanglemode",        FlagMode,         GINT_TO_POINTER (RECTANGLE_MODE)},
471   {"removemode",           FlagMode,         GINT_TO_POINTER (REMOVE_MODE)},
472   {"rotatemode",           FlagMode,         GINT_TO_POINTER (ROTATE_MODE)},
473   {"rubberbandmovemode",   FlagMode,         GINT_TO_POINTER (RUBBERBANDMOVE_MODE)},
474   {"textmode",             FlagMode,         GINT_TO_POINTER (TEXT_MODE)},
475   {"thermalmode",          FlagMode,         GINT_TO_POINTER (THERMAL_MODE)},
476   {"viamode",              FlagMode,         GINT_TO_POINTER (VIA_MODE)},
477 
478   {"shownumber",           FlagTESTFLAG,     GINT_TO_POINTER (SHOWNUMBERFLAG)},
479   {"localref",             FlagTESTFLAG,     GINT_TO_POINTER (LOCALREFFLAG)},
480   {"checkplanes",          FlagTESTFLAG,     GINT_TO_POINTER (CHECKPLANESFLAG)},
481   {"showdrc",              FlagTESTFLAG,     GINT_TO_POINTER (SHOWDRCFLAG)},
482   {"rubberband",           FlagTESTFLAG,     GINT_TO_POINTER (RUBBERBANDFLAG)},
483   {"description",          FlagTESTFLAG,     GINT_TO_POINTER (DESCRIPTIONFLAG)},
484   {"nameonpcb",            FlagTESTFLAG,     GINT_TO_POINTER (NAMEONPCBFLAG)},
485   {"autodrc",              FlagTESTFLAG,     GINT_TO_POINTER (AUTODRCFLAG)},
486   {"alldirection",         FlagTESTFLAG,     GINT_TO_POINTER (ALLDIRECTIONFLAG)},
487   {"swapstartdir",         FlagTESTFLAG,     GINT_TO_POINTER (SWAPSTARTDIRFLAG)},
488   {"uniquename",           FlagTESTFLAG,     GINT_TO_POINTER (UNIQUENAMEFLAG)},
489   {"clearnew",             FlagTESTFLAG,     GINT_TO_POINTER (CLEARNEWFLAG)},
490   {"snappin",              FlagTESTFLAG,     GINT_TO_POINTER (SNAPPINFLAG)},
491   {"showmask",             FlagTESTFLAG,     GINT_TO_POINTER (SHOWMASKFLAG)},
492   {"thindraw",             FlagTESTFLAG,     GINT_TO_POINTER (THINDRAWFLAG)},
493   {"orthomove",            FlagTESTFLAG,     GINT_TO_POINTER (ORTHOMOVEFLAG)},
494   {"liveroute",            FlagTESTFLAG,     GINT_TO_POINTER (LIVEROUTEFLAG)},
495   {"thindrawpoly",         FlagTESTFLAG,     GINT_TO_POINTER (THINDRAWPOLYFLAG)},
496   {"locknames",            FlagTESTFLAG,     GINT_TO_POINTER (LOCKNAMESFLAG)},
497   {"onlynames",            FlagTESTFLAG,     GINT_TO_POINTER (ONLYNAMESFLAG)},
498   {"newfullpoly",          FlagTESTFLAG,     GINT_TO_POINTER (NEWFULLPOLYFLAG)},
499   {"hidenames",            FlagTESTFLAG,     GINT_TO_POINTER (HIDENAMESFLAG)},
500   {"autoburiedvias",       FlagTESTFLAG,     GINT_TO_POINTER (AUTOBURIEDVIASFLAG)},
501 
502   {"grid_units_mm",        FlagUnitsMm,      NULL},
503   {"grid_units_mil",       FlagUnitsMil,     NULL},
504 
505   {"fullpoly",             FlagSETTINGS,     OFFSET_POINTER (SettingType, FullPoly)},
506   {"clearline",            FlagSETTINGS,     OFFSET_POINTER (SettingType, ClearLine)},
507   {"uniquenames",          FlagSETTINGS,     OFFSET_POINTER (SettingType, UniqueNames)},
508   {"showsolderside",       FlagSETTINGS,     OFFSET_POINTER (SettingType, ShowBottomSide)},
509   {"savelastcommand",      FlagSETTINGS,     OFFSET_POINTER (SettingType, SaveLastCommand)},
510   {"saveintmp",            FlagSETTINGS,     OFFSET_POINTER (SettingType, SaveInTMP)},
511   {"drawgrid",             FlagSETTINGS,     OFFSET_POINTER (SettingType, DrawGrid)},
512   {"ratwarn",              FlagSETTINGS,     OFFSET_POINTER (SettingType, RatWarn)},
513   {"stipplepolygons",      FlagSETTINGS,     OFFSET_POINTER (SettingType, StipplePolygons)},
514   {"alldirectionlines",    FlagSETTINGS,     OFFSET_POINTER (SettingType, AllDirectionLines)},
515   {"rubberbandmode",       FlagSETTINGS,     OFFSET_POINTER (SettingType, RubberBandMode)},
516   {"swapstartdirection",   FlagSETTINGS,     OFFSET_POINTER (SettingType, SwapStartDirection)},
517   {"showdrcmode",          FlagSETTINGS,     OFFSET_POINTER (SettingType, ShowDRC)},
518   {"resetafterelement",    FlagSETTINGS,     OFFSET_POINTER (SettingType, ResetAfterElement)},
519   {"ringbellwhenfinished", FlagSETTINGS,     OFFSET_POINTER (SettingType, RingBellWhenFinished)},
520 
521   {"buffer",               FlagBuffer,       NULL},
522 
523 };
524 
525 REGISTER_FLAGS (flags_flag_list)
526 
527