(no commit message)
[geda-pcb/pcjc2.git] / src / strflags.c
blobf29da5bfbbb9cee5e62125fed832713a8fc14a86
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
5 * Copyright (C) 2005 DJ Delorie
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.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * Contact addresses for paper mail and Email:
22 * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA
23 * dj@delorie.com
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
31 #include <stdio.h>
32 #include <ctype.h>
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
40 #ifdef FLAG_TEST
41 #include <time.h>
42 #include <sys/types.h>
43 #include <unistd.h>
44 #endif
46 #include "globalconst.h"
47 #include "global.h"
48 #include "compat.h"
49 #include "const.h"
50 #include "strflags.h"
52 #ifdef HAVE_LIBDMALLOC
53 #include <dmalloc.h>
54 #endif
56 /* Because all the macros expect it, that's why. */
57 typedef struct
59 FlagType Flags;
60 } FlagHolder;
62 /* Be careful to list more specific flags first, followed by general
63 * flags, when two flags use the same bit. For example, "onsolder" is
64 * for elements only, while "auto" is for everything else. They use
65 * the same bit, but onsolder is listed first so that elements will
66 * use it and not auto.
68 * Thermals are handled separately, as they're layer-selective.
71 typedef struct
74 /* This is the bit that we're setting. */
75 int mask;
77 /* The name used in the output file. */
78 char *name;
79 int nlen;
80 #define N(x) x, sizeof(x)-1
82 /* If set, this entry won't be output unless the object type is one
83 of these. */
84 int object_types;
86 } FlagBitsType;
88 static FlagBitsType object_flagbits[] = {
89 { PINFLAG, N ("pin"), ALL_TYPES },
90 { VIAFLAG, N ("via"), ALL_TYPES },
91 { FOUNDFLAG, N ("found"), ALL_TYPES },
92 { HOLEFLAG, N ("hole"), PIN_TYPES },
93 { RATFLAG, N ("rat"), RATLINE_TYPE },
94 { PININPOLYFLAG, N ("pininpoly"), PIN_TYPES | PAD_TYPE },
95 { CLEARPOLYFLAG, N ("clearpoly"), POLYGON_TYPE },
96 { HIDENAMEFLAG, N ("hidename"), ELEMENT_TYPE },
97 { DISPLAYNAMEFLAG, N ("showname"), ELEMENT_TYPE },
98 { CLEARLINEFLAG, N ("clearline"), LINE_TYPE | ARC_TYPE | TEXT_TYPE },
99 { SELECTEDFLAG, N ("selected"), ALL_TYPES },
100 { ONSOLDERFLAG, N ("onsolder"), ELEMENT_TYPE | PAD_TYPE | TEXT_TYPE },
101 { AUTOFLAG, N ("auto"), ALL_TYPES },
102 { SQUAREFLAG, N ("square"), PIN_TYPES | PAD_TYPE },
103 { RUBBERENDFLAG, N ("rubberend"), LINE_TYPE | ARC_TYPE },
104 { WARNFLAG, N ("warn"), PIN_TYPES | PAD_TYPE },
105 { USETHERMALFLAG, N ("usetherm"), PIN_TYPES | LINE_TYPE | ARC_TYPE },
106 { OCTAGONFLAG, N ("octagon"), PIN_TYPES | PAD_TYPE },
107 { DRCFLAG, N ("drc"), ALL_TYPES },
108 { LOCKFLAG, N ("lock"), ALL_TYPES },
109 { EDGE2FLAG, N ("edge2"), ALL_TYPES },
110 { FULLPOLYFLAG, N ("fullpoly"), POLYGON_TYPE},
111 { NOPASTEFLAG, N ("nopaste"), PAD_TYPE },
112 { CONNECTEDFLAG, N ("connected"), ALL_TYPES }
115 static FlagBitsType pcb_flagbits[] = {
116 { SHOWNUMBERFLAG, N ("shownumber"), 1 },
117 { LOCALREFFLAG, N ("localref"), 1 },
118 { CHECKPLANESFLAG, N ("checkplanes"), 1 },
119 { SHOWDRCFLAG, N ("showdrc"), 1 },
120 { RUBBERBANDFLAG, N ("rubberband"), 1 },
121 { DESCRIPTIONFLAG, N ("description"), 1 },
122 { NAMEONPCBFLAG, N ("nameonpcb"), 1 },
123 { AUTODRCFLAG, N ("autodrc"), 1 },
124 { ALLDIRECTIONFLAG, N ("alldirection"), 1 },
125 { SWAPSTARTDIRFLAG, N ("swapstartdir"), 1 },
126 { UNIQUENAMEFLAG, N ("uniquename"), 1 },
127 { CLEARNEWFLAG, N ("clearnew"), 1 },
128 { NEWFULLPOLYFLAG, N ("newfullpoly"), 1 },
129 { SNAPPINFLAG, N ("snappin"), 1 },
130 { SHOWMASKFLAG, N ("showmask"), 1 },
131 { THINDRAWFLAG, N ("thindraw"), 1 },
132 { ORTHOMOVEFLAG, N ("orthomove"), 1 },
133 { LIVEROUTEFLAG, N ("liveroute"), 1 },
134 { THINDRAWPOLYFLAG, N ("thindrawpoly"), 1 },
135 { LOCKNAMESFLAG, N ("locknames"), 1 },
136 { ONLYNAMESFLAG, N ("onlynames"), 1 },
137 { HIDENAMESFLAG, N ("hidenames"), 1 },
140 #undef N
143 * This helper function maintains a small list of buffers which are
144 * used by flags_to_string(). Each buffer is allocated from the heap,
145 * but the caller must not free them (they get realloced when they're
146 * reused, but never completely freed).
149 static struct
151 char *ptr;
152 int len;
153 } buffers[10];
154 static int bufptr = 0;
155 static char *
156 alloc_buf (int len)
158 #define B buffers[bufptr]
159 len++;
160 bufptr = (bufptr + 1) % 10;
161 if (B.len < len)
163 if (B.ptr)
164 B.ptr = (char *) realloc (B.ptr, len);
165 else
166 B.ptr = (char *) malloc (len);
167 B.len = len;
169 return B.ptr;
170 #undef B
174 * This set of routines manages a list of layer-specific flags.
175 * Callers should call grow_layer_list(0) to reset the list, and
176 * set_layer_list(layer,1) to set bits in the layer list. The results
177 * are stored in layers[], which has num_layers valid entries.
180 static char *layers = 0;
181 static int max_layers = 0, num_layers = 0;
183 static void
184 grow_layer_list (int num)
186 if (layers == 0)
188 layers = (char *) calloc (num > 0 ? num : 1, 1);
189 max_layers = num;
191 else if (num > max_layers)
193 max_layers = num;
194 layers = (char *) realloc (layers, max_layers);
196 if (num > num_layers)
197 memset (layers + num_layers, 0, num - num_layers - 1);
198 num_layers = num;
199 return;
202 static inline void
203 set_layer_list (int layer, int v)
205 if (layer >= num_layers)
206 grow_layer_list (layer + 1);
207 layers[layer] = v;
211 * These next two convert between layer lists and strings.
212 * parse_layer_list() is passed a pointer to a string, and parses a
213 * list of integer which reflect layers to be flagged. It returns a
214 * pointer to the first character following the list. The syntax of
215 * the list is a paren-surrounded, comma-separated list of integers
216 * and/or pairs of integers separated by a dash (like "(1,2,3-7)").
217 * Spaces and other punctuation are not allowed. The results are
218 * stored in layers[] defined above.
220 * print_layer_list() does the opposite - it uses the flags set in
221 * layers[] to build a string that represents them, using the syntax
222 * above.
226 /* Returns a pointer to the first character past the list. */
227 static const char *
228 parse_layer_list (const char *bp, int (*error) (const char *))
230 const char *orig_bp = bp;
231 int l = 0, range = -1;
232 int value = 1;
234 grow_layer_list (0);
235 while (*bp)
237 if (*bp == '+')
238 value = 2;
239 else if (*bp == 'S')
240 value = 3;
241 else if (*bp == 'X')
242 value = 4;
243 else if (*bp == 't')
244 value = 5;
245 else if (*bp == ')' || *bp == ',' || *bp == '-')
247 if (range == -1)
248 range = l;
249 while (range <= l)
250 set_layer_list (range++, value);
251 if (*bp == '-')
252 range = l;
253 else
254 range = -1;
255 value = 1;
256 l = 0;
259 else if (isdigit ((int) *bp))
260 l = l * 10 + (*bp - '0');
262 else if (error)
264 char *fmt = "Syntax error parsing layer list \"%.*s\" at %c";
265 char *msg = alloc_buf (strlen (fmt) + strlen (orig_bp));
266 sprintf (msg, fmt, bp - orig_bp + 5, orig_bp, *bp);
267 error (msg);
268 error = NULL;
271 if (*bp == ')')
272 return bp + 1;
274 bp++;
276 return bp;
279 /* Number of character the value "i" requires when printed. */
280 static int
281 printed_int_length (int i, int j)
283 int rv;
285 if (i < 10)
286 return 1 + (j ? 1 : 0);
287 if (i < 100)
288 return 2 + (j ? 1 : 0);
290 for (rv = 1; i >= 10; rv++)
291 i /= 10;
292 return rv + (j ? 1 : 0);
295 /* Returns a pointer to an internal buffer which is overwritten with
296 each new call. */
297 static char *
298 print_layer_list ()
300 static char *buf = 0;
301 static int buflen = 0;
302 int len, i, j;
303 char *bp;
305 len = 2;
306 for (i = 0; i < num_layers; i++)
307 if (layers[i])
308 len += 1 + printed_int_length (i, layers[i]);
309 if (buflen < len)
311 if (buf)
312 buf = (char *) realloc (buf, len);
313 else
314 buf = (char *) malloc (len);
315 buflen = len;
318 bp = buf;
319 *bp++ = '(';
321 for (i = 0; i < num_layers; i++)
322 if (layers[i])
324 /* 0 0 1 1 1 0 0 */
325 /* i j */
326 for (j = i + 1; j < num_layers && layers[j] == 1; j++)
328 if (j > i + 2)
330 sprintf (bp, "%d-%d,", i, j - 1);
331 i = j - 1;
333 else
334 switch (layers[i])
336 case 1:
337 sprintf (bp, "%d,", i);
338 break;
339 case 2:
340 sprintf (bp, "%d+,", i);
341 break;
342 case 3:
343 sprintf (bp, "%dS,", i);
344 break;
345 case 4:
346 sprintf (bp, "%dX,", i);
347 break;
348 case 5:
349 default:
350 sprintf (bp, "%dt,", i);
351 break;
353 bp += strlen (bp);
355 bp[-1] = ')';
356 *bp = 0;
357 return buf;
361 * Ok, now the two entry points to this file. The first, string_to_flags,
362 * is passed a string (usually from parse_y.y) and returns a "set of flags".
363 * In theory, this can be anything, but for now it's just an integer. Later
364 * it might be a structure, for example.
366 * Currently, there is no error handling :-P
369 static int
370 error_ignore (const char *msg)
371 { /* do nothing */
372 return 0;
374 static FlagType empty_flags;
376 static FlagType
377 common_string_to_flags (const char *flagstring,
378 int (*error) (const char *msg),
379 FlagBitsType *flagbits,
380 int n_flagbits)
382 const char *fp, *ep;
383 int flen;
384 FlagHolder rv;
385 int i;
387 rv.Flags = empty_flags;
389 if (error == 0)
390 error = error_ignore;
392 if (flagstring == NULL)
393 return empty_flags;
395 fp = ep = flagstring;
397 if (*fp == '"')
398 ep = ++fp;
400 while (*ep && *ep != '"')
402 int found = 0;
404 for (ep = fp; *ep && *ep != ',' && *ep != '"' && *ep != '('; ep++)
406 flen = ep - fp;
407 if (*ep == '(')
408 ep = parse_layer_list (ep + 1, error);
410 if (flen == 7 && memcmp (fp, "thermal", 7) == 0)
412 for (i = 0; i < MAX_LAYER && i < num_layers; i++)
413 if (layers[i])
414 ASSIGN_THERM (i, layers[i], &rv);
416 else
418 for (i = 0; i < n_flagbits; i++)
419 if (flagbits[i].nlen == flen
420 && memcmp (flagbits[i].name, fp, flen) == 0)
422 found = 1;
423 SET_FLAG (flagbits[i].mask, &rv);
424 break;
426 if (!found)
428 const char *fmt = "Unknown flag: \"%.*s\" ignored";
429 char *msg = alloc_buf (strlen (fmt) + flen);
430 sprintf (msg, fmt, flen, fp);
431 error (msg);
434 fp = ep + 1;
436 return rv.Flags;
439 FlagType
440 string_to_flags (const char *flagstring,
441 int (*error) (const char *msg))
443 return common_string_to_flags (flagstring,
444 error,
445 object_flagbits,
446 ENTRIES (object_flagbits));
449 FlagType
450 string_to_pcbflags (const char *flagstring,
451 int (*error) (const char *msg))
453 return common_string_to_flags (flagstring,
454 error,
455 pcb_flagbits,
456 ENTRIES (pcb_flagbits));
461 * Given a set of flags for a given type of object, return a string
462 * which reflects those flags. The only requirement is that this
463 * string be parseable by string_to_flags.
465 * Note that this function knows a little about what kinds of flags
466 * will be automatically set by parsing, so it won't (for example)
467 * include the "via" flag for VIA_TYPEs because it knows those get
468 * forcibly set when vias are parsed.
471 static char *
472 common_flags_to_string (FlagType flags,
473 int object_type,
474 FlagBitsType *flagbits,
475 int n_flagbits)
477 int len;
478 int i;
479 FlagHolder fh, savef;
480 char *buf, *bp;
482 fh.Flags = flags;
484 #ifndef FLAG_TEST
485 switch (object_type)
487 case VIA_TYPE:
488 CLEAR_FLAG (VIAFLAG, &fh);
489 break;
490 case RATLINE_TYPE:
491 CLEAR_FLAG (RATFLAG, &fh);
492 break;
493 case PIN_TYPE:
494 CLEAR_FLAG (PINFLAG, &fh);
495 break;
497 #endif
499 savef = fh;
501 len = 3; /* for "()\0" */
502 for (i = 0; i < n_flagbits; i++)
503 if ((flagbits[i].object_types & object_type)
504 && (TEST_FLAG (flagbits[i].mask, &fh)))
506 len += flagbits[i].nlen + 1;
507 CLEAR_FLAG (flagbits[i].mask, &fh);
510 if (TEST_ANY_THERMS (&fh))
512 len += sizeof ("thermal()");
513 for (i = 0; i < MAX_LAYER; i++)
514 if (TEST_THERM (i, &fh))
515 len += printed_int_length (i, GET_THERM (i, &fh)) + 1;
518 bp = buf = alloc_buf (len + 2);
520 *bp++ = '"';
522 fh = savef;
523 for (i = 0; i < n_flagbits; i++)
524 if (flagbits[i].object_types & object_type
525 && (TEST_FLAG (flagbits[i].mask, &fh)))
527 if (bp != buf + 1)
528 *bp++ = ',';
529 strcpy (bp, flagbits[i].name);
530 bp += flagbits[i].nlen;
531 CLEAR_FLAG (flagbits[i].mask, &fh);
534 if (TEST_ANY_THERMS (&fh))
536 if (bp != buf + 1)
537 *bp++ = ',';
538 strcpy (bp, "thermal");
539 bp += strlen ("thermal");
540 grow_layer_list (0);
541 for (i = 0; i < MAX_LAYER; i++)
542 if (TEST_THERM (i, &fh))
543 set_layer_list (i, GET_THERM (i, &fh));
544 strcpy (bp, print_layer_list ());
545 bp += strlen (bp);
548 *bp++ = '"';
549 *bp = 0;
550 return buf;
553 char *
554 flags_to_string (FlagType flags, int object_type)
556 return common_flags_to_string (flags,
557 object_type,
558 object_flagbits,
559 ENTRIES (object_flagbits));
562 char *
563 pcbflags_to_string (FlagType flags)
565 return common_flags_to_string (flags,
566 ALL_TYPES,
567 pcb_flagbits,
568 ENTRIES (pcb_flagbits));
571 #if FLAG_TEST
573 static void
574 dump_flag (FlagType * f)
576 int l;
577 printf ("F:%08x T:[", f->f);
578 for (l = 0; l < (MAX_LAYER + 7) / 8; l++)
579 printf (" %02x", f->t[l]);
580 printf ("]");
585 mem_any_set (unsigned char *ptr, int bytes)
587 while (bytes--)
588 if (*ptr++)
589 return 1;
590 return 0;
595 * This exists for standalone testing of this file.
597 * Compile as: gcc -DHAVE_CONFIG_H -DFLAG_TEST strflags.c -o strflags.x -I..
598 * and then run it.
602 main ()
604 time_t now;
605 int i;
606 int errors = 0, count = 0;
608 time (&now);
609 srandom ((unsigned int) now + getpid ());
611 grow_layer_list (0);
612 for (i = 0; i < 16; i++)
614 int j;
615 char *p;
616 if (i != 1 && i != 4 && i != 5 && i != 9)
617 set_layer_list (i, 1);
618 else
619 set_layer_list (i, 0);
620 p = print_layer_list ();
621 printf ("%2d : %20s =", i, p);
622 parse_layer_list (p + 1, 0);
623 for (j = 0; j < num_layers; j++)
624 printf (" %d", layers[j]);
625 printf ("\n");
628 while (count < 1000000)
630 FlagHolder fh;
631 char *str;
632 FlagType new_flags;
633 int i;
634 int otype;
636 otype = ALL_TYPES;
637 fh.Flags = empty_flags;
638 for (i = 0; i < ENTRIES (object_flagbits); i++)
640 if (TEST_FLAG (object_flagbits[i].mask, &fh))
641 continue;
642 if ((otype & object_flagbits[i].object_types) == 0)
643 continue;
644 if ((random () & 4) == 0)
645 continue;
647 otype &= object_flagbits[i].object_types;
648 SET_FLAG (object_flagbits[i].mask, &fh);
651 if (otype & PIN_TYPES)
652 for (i = 0; i < MAX_LAYER; i++)
653 if (random () & 4)
654 ASSIGN_THERM (i, 3, &fh);
656 str = flags_to_string (fh.Flags, otype);
657 new_flags = string_to_flags (str, 0);
659 count++;
660 if (FLAGS_EQUAL (fh.Flags, new_flags))
661 continue;
663 dump_flag (&fh.Flags);
664 printf (" ");
665 dump_flag (&new_flags);
666 printf ("\n");
667 if (++errors == 5)
668 exit (1);
671 while (count < 1000000)
673 FlagHolder fh;
674 char *str;
675 FlagType new_flags;
676 int i;
677 int otype;
679 otype = ALL_TYPES;
680 fh.Flags = empty_flags;
681 for (i = 0; i < ENTRIES (pcb_flagbits); i++)
683 if (TEST_FLAG (pcb_flagbits[i].mask, &fh))
684 continue;
685 if ((random () & 4) == 0)
686 continue;
688 otype &= pcb_flagbits[i].object_types;
689 SET_FLAG (pcb_flagbits[i].mask, &fh);
692 str = pcbflags_to_string (fh.Flags);
693 new_flags = string_to_pcbflags (str, 0);
695 count++;
696 if (FLAGS_EQUAL (fh.Flags, new_flags))
697 continue;
699 dump_flag (&fh.Flags);
700 printf (" ");
701 dump_flag (&new_flags);
702 printf ("\n");
703 if (++errors == 5)
704 exit (1);
706 printf ("%d out of %d failed\n", errors, count);
707 return errors;
710 #endif