/* $Id: strflags.c,v 1.3 2006/03/14 04:03:47 dj Exp $ */ /* * COPYRIGHT * * PCB, interactive printed circuit board design * Copyright (C) 2005 DJ Delorie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Contact addresses for paper mail and Email: * DJ Delorie, 334 North Road, Deerfield NH 03037-1110, USA * dj@delorie.com * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef FLAG_TEST #include #include #include #endif #include "globalconst.h" #include "global.h" #include "const.h" #include "strflags.h" /* Because all the macros expect it, that's why. */ typedef struct { FlagType Flags; } FlagHolder; /* Be careful to list more specific flags first, followed by general * flags, when two flags use the same bit. For example, "onsolder" is * for elements only, while "auto" is for everything else. They use * the same bit, but onsolder is listed first so that elements will * use it and not auto. * * Thermals are handled separately, as they're layer-selective. */ static struct { /* This is the bit that we're setting. */ int mask; /* The name used in the output file. */ char *name; int nlen; #define N(x) x, sizeof(x)-1 /* If set, this entry won't be output unless the object type is one of these. */ int object_types; } flagbits[] = { { PINFLAG, N("pin"), ALL_TYPES }, { VIAFLAG, N("via"), ALL_TYPES }, { FOUNDFLAG, N("found"), ALL_TYPES }, { HOLEFLAG, N("hole"), PIN_TYPES }, { RATFLAG, N("rat"), RATLINE_TYPE }, { PININPOLYFLAG, N("pininpoly"), PIN_TYPES | PAD_TYPE }, { CLEARPOLYFLAG, N("clearpoly"), POLYGON_TYPE }, { HIDENAMEFLAG, N("hidename"), ELEMENT_TYPE }, { DISPLAYNAMEFLAG, N("showname"), ELEMENT_TYPE }, { CLEARLINEFLAG, N("clearline"), LINE_TYPE | ARC_TYPE }, { SELECTEDFLAG, N("selected"), ALL_TYPES }, { ONSOLDERFLAG, N("onsolder"), ELEMENT_TYPE | PAD_TYPE }, { AUTOFLAG, N("auto"), ALL_TYPES }, { SQUAREFLAG, N("square"), PIN_TYPES | PAD_TYPE }, { RUBBERENDFLAG, N("rubberend"), LINE_TYPE | ARC_TYPE }, { WARNFLAG, N("warn"), PIN_TYPES | PAD_TYPE }, { USETHERMALFLAG, N("usetherm"), PIN_TYPES | PAD_TYPE }, { OCTAGONFLAG, N("octagon"), PIN_TYPES | PAD_TYPE }, { DRCFLAG, N("drc"), ALL_TYPES }, { LOCKFLAG, N("lock"), ALL_TYPES }, { EDGE2FLAG, N("edge2"), ALL_TYPES } }; #undef N #define NUM_FLAGBITS (sizeof(flagbits)/sizeof(flagbits[0])) /* * This helper function maintains a small list of buffers which are * used by flags_to_string(). Each buffer is allocated from the heap, * but the caller must not free them (they get realloced when they're * reused, but never completely freed). */ static struct { char *ptr; int len; } buffers[10]; static int bufptr = 0; static char *alloc_buf (int len) { #define B buffers[bufptr] len ++; bufptr = (bufptr + 1) % 10; if (B.len < len) { if (B.ptr) B.ptr = (char *) realloc (B.ptr, len); else B.ptr = (char *) malloc (len); B.len = len; } return B.ptr; #undef B } /* * This set of routines manages a list of layer-specific flags. * Callers should call grow_layer_list(0) to reset the list, and * set_layer_list(layer,1) to set bits in the layer list. The results * are stored in layers[], which has num_layers valid entries. */ static char *layers = 0; static int max_layers = 0, num_layers = 0; static void grow_layer_list (int num) { if (layers == 0) { layers = (char *) calloc (num, 1); max_layers = num; } else if (num > max_layers) { max_layers = num; layers = (char *) realloc (layers, max_layers); } if (num > num_layers) memset (layers + num_layers, 0, num - num_layers - 1); num_layers = num; return; } static inline void set_layer_list (int layer, int v) { if (layer >= num_layers) grow_layer_list (layer+1); layers[layer] = v; } /* * These next two convert between layer lists and strings. * parse_layer_list() is passed a pointer to a string, and parses a * list of integer which reflect layers to be flagged. It returns a * pointer to the first character following the list. The syntax of * the list is a paren-surrounded, comma-separated list of integers * and/or pairs of integers separated by a dash (like "(1,2,3-7)"). * Spaces and other punctuation are not allowed. The results are * stored in layers[] defined above. * * print_layer_list() does the opposite - it uses the flags set in * layers[] to build a string that represents them, using the syntax * above. * */ /* Returns a pointer to the first character past the list. */ static const char * parse_layer_list (const char *bp, void (*error)(const char *)) { const char *orig_bp = bp; int l = 0, range = -1; grow_layer_list (0); while (*bp) { if (*bp == ')' || *bp == ',' || *bp == '-') { if (range == -1) range = l; while (range <= l) set_layer_list (range++, 1); if (*bp == '-') range = l; else range = -1; l = 0; } else if (isdigit (*bp)) l = l * 10 + (*bp - '0'); else if (error) { char *fmt = "Syntax error parsing layer list \"%.*s\" at %c"; char *msg = alloc_buf (strlen(fmt) + strlen(orig_bp)); sprintf (msg, fmt, bp - orig_bp + 5, orig_bp, *bp); error(msg); error = NULL; } if (*bp == ')') return bp + 1; bp ++; } return bp; } /* Number of character the value "i" requires when printed. */ static int printed_int_length (int i) { int rv; if (i < 10) return 1; if (i < 100) return 2; for (rv=1; i >= 10; rv++) i /= 10; return rv; } /* Returns a pointer to an internal buffer which is overwritten with each new call. */ static char * print_layer_list () { static char *buf = 0; static int buflen = 0; int len, i, j; char *bp; len = 2; for (i=0; i i + 2) { sprintf(bp, "%d-%d,", i, j-1); i = j - 1; } else sprintf(bp, "%d,", i); bp += strlen(bp); } bp[-1] = ')'; *bp = 0; return buf; } /* * Ok, now the two entry points to this file. The first, string_to_flags, * is passed a string (usually from parse_y.y) and returns a "set of flags". * In theory, this can be anything, but for now it's just an integer. Later * it might be a structure, for example. * * Currently, there is no error handling :-P */ static void error_ignore (const char *msg) { /* do nothing */ } static FlagType empty_flags; FlagType string_to_flags (const char *flagstring, void (*error)(const char *msg)) { const char *fp, *ep; int flen; FlagHolder rv; int i; rv.Flags = empty_flags; if (error == 0) error = error_ignore; if (flagstring == NULL) return empty_flags; fp = ep = flagstring; if (*fp == '"') ep = ++fp; while (*ep && *ep != '"') { int found = 0; for (ep = fp; *ep && *ep != ',' && *ep != '"' && *ep != '('; ep++) ; flen = ep - fp; if (*ep == '(') ep = parse_layer_list (ep+1, error); if (flen == 7 && memcmp (fp, "thermal", 7) == 0) { for (i=0; if); for (l=0; l<(MAX_LAYER+7)/8; l++) printf(" %02x", f->t[l]); printf("] P:["); for (l=0; l<(MAX_LAYER+7)/8; l++) printf(" %02x", f->p[l]); printf("]"); } /* * This exists for standalone testing of this file. * * Compile as: gcc -DHAVE_CONFIG_H -DFLAG_TEST strflags.c -o strflags.x -I.. * and then run it. */ int main() { time_t now; int i; int errors = 0, count = 0; time(&now); srandom((unsigned int)now + getpid()); grow_layer_list (0); for (i=0; i<16; i++) { int j; char *p; if (i != 1 && i != 4 && i != 5 && i != 9) set_layer_list (i, 1); else set_layer_list (i, 0); p = print_layer_list (); printf("%2d : %20s =", i, p); parse_layer_list (p + 1, 0); for (j=0; j