* prevent duplicate objects from being selected
[geda-gerbv.git] / src / amacro.c
blobaf8ece10661086450c36eb088b8becb5614ed9e2
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This files is a part of gerbv.
5 * Copyright (C) 2000-2002 Stefan Petersen (spe@stacken.kth.se)
7 * $Id$
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
24 /** \file amacro.c
25 \brief Aperture macro parsing functions
26 \ingroup libgerbv
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
33 #include "gerbv.h"
34 #include "gerb_file.h"
35 #include "amacro.h"
38 * Allocates a new instruction structure
40 static gerbv_instruction_t *
41 new_instruction(void)
43 gerbv_instruction_t *instruction;
45 instruction = (gerbv_instruction_t *)malloc(sizeof(gerbv_instruction_t));
46 if (instruction == NULL) {
47 free(instruction);
48 return NULL;
51 memset(instruction, 0, sizeof(gerbv_instruction_t));
53 return instruction;
54 } /* new_instruction */
58 * Allocates a new amacro structure
60 static gerbv_amacro_t *
61 new_amacro(void)
63 gerbv_amacro_t *amacro;
65 amacro = (gerbv_amacro_t *)malloc(sizeof(gerbv_amacro_t));
66 if (amacro == NULL) {
67 free(amacro);
68 return NULL;
71 memset(amacro, 0, sizeof(gerbv_amacro_t));
73 return amacro;
74 } /* new_amacro */
78 * Parses the definition of an aperture macro
80 gerbv_amacro_t *
81 parse_aperture_macro(gerb_file_t *fd)
83 gerbv_amacro_t *amacro;
84 gerbv_instruction_t *ip = NULL;
85 int primitive = 0, c, found_primitive = 0;
86 gerbv_opcodes_t math_op = GERBV_OPCODE_NOP;
87 int comma = 0; /* Just read an operator (one of '*+X/) */
88 int neg = 0; /* negative numbers succeding , */
89 unsigned char continueLoop = 1;
90 int equate = 0;
92 amacro = new_amacro();
95 * Get macroname
97 amacro->name = gerb_fgetstring(fd, '*');
98 c = gerb_fgetc(fd); /* skip '*' */
99 if (c == EOF) {
100 continueLoop = 0;
104 * Since I'm lazy I have a dummy head. Therefore the first
105 * instruction in all programs will be NOP.
107 amacro->program = new_instruction();
108 ip = amacro->program;
110 while(continueLoop) {
112 c = gerb_fgetc(fd);
113 switch (c) {
114 case '$':
115 if (found_primitive) {
116 ip->next = new_instruction(); /* XXX Check return value */
117 ip = ip->next;
118 ip->opcode = GERBV_OPCODE_PPUSH;
119 amacro->nuf_push++;
120 ip->data.ival = gerb_fgetint(fd, NULL);
121 comma = 0;
122 } else {
123 equate = gerb_fgetint(fd, NULL);
125 break;
126 case '*':
127 if (math_op != GERBV_OPCODE_NOP) {
128 ip->next = new_instruction(); /* XXX Check return value */
129 ip = ip->next;
130 ip->opcode = math_op;
131 math_op = GERBV_OPCODE_NOP;
134 * Check is due to some gerber files has spurious empty lines.
135 * (EagleCad of course).
137 if (found_primitive) {
138 ip->next = new_instruction(); /* XXX Check return value */
139 ip = ip->next;
140 if (equate) {
141 ip->opcode = GERBV_OPCODE_PPOP;
142 ip->data.ival = equate;
143 } else {
144 ip->opcode = GERBV_OPCODE_PRIM;
145 ip->data.ival = primitive;
147 equate = 0;
148 primitive = 0;
149 found_primitive = 0;
151 break;
152 case '=':
153 if (equate) {
154 found_primitive = 1;
156 break;
157 case ',':
158 if (!found_primitive) {
159 found_primitive = 1;
160 break;
162 if (math_op != GERBV_OPCODE_NOP) {
163 ip->next = new_instruction(); /* XXX Check return value */
164 ip = ip->next;
165 ip->opcode = math_op;
166 math_op = GERBV_OPCODE_NOP;
168 comma = 1;
169 break;
170 case '+':
171 if (math_op != GERBV_OPCODE_NOP) {
172 ip->next = new_instruction(); /* XXX Check return value */
173 ip = ip->next;
174 ip->opcode = math_op;
176 math_op = GERBV_OPCODE_ADD;
177 comma = 1;
178 break;
179 case '-':
180 if (comma) {
181 neg = 1;
182 comma = 0;
183 break;
185 if (math_op != GERBV_OPCODE_NOP) {
186 ip->next = new_instruction(); /* XXX Check return value */
187 ip = ip->next;
188 ip->opcode = math_op;
190 math_op = GERBV_OPCODE_SUB;
191 break;
192 case '/':
193 if (math_op != GERBV_OPCODE_NOP) {
194 ip->next = new_instruction(); /* XXX Check return value */
195 ip = ip->next;
196 ip->opcode = math_op;
198 math_op = GERBV_OPCODE_DIV;
199 comma = 1;
200 break;
201 case 'X':
202 case 'x':
203 if (math_op != GERBV_OPCODE_NOP) {
204 ip->next = new_instruction(); /* XXX Check return value */
205 ip = ip->next;
206 ip->opcode = math_op;
208 math_op = GERBV_OPCODE_MUL;
209 comma = 1;
210 break;
211 case '0':
213 * Comments in aperture macros are a definition starting with
214 * zero and ends with a '*'
216 if (!found_primitive && (primitive == 0)) {
217 /* Comment continues 'til next *, just throw it away */
218 gerb_fgetstring(fd, '*');
219 c = gerb_fgetc(fd); /* Read the '*' */
220 break;
222 case '1':
223 case '2':
224 case '3':
225 case '4':
226 case '5':
227 case '6':
228 case '7':
229 case '8':
230 case '9':
232 * First number in an aperture macro describes the primitive
233 * as a numerical value
235 if (!found_primitive) {
236 primitive = (primitive * 10) + (c - '0');
237 break;
239 (void)gerb_ungetc(fd);
240 ip->next = new_instruction(); /* XXX Check return value */
241 ip = ip->next;
242 ip->opcode = GERBV_OPCODE_PUSH;
243 amacro->nuf_push++;
244 ip->data.fval = gerb_fgetdouble(fd);
245 if (neg)
246 ip->data.fval = -ip->data.fval;
247 neg = 0;
248 comma = 0;
249 break;
250 case '%':
251 gerb_ungetc(fd); /* Must return with % first in string
252 since the main parser needs it */
253 return amacro;
254 default :
255 /* Whitespace */
256 break;
258 if (c == EOF) {
259 continueLoop = 0;
262 free (amacro);
263 return NULL;
267 void
268 free_amacro(gerbv_amacro_t *amacro)
270 gerbv_amacro_t *am1, *am2;
271 gerbv_instruction_t *instr1, *instr2;
273 am1 = amacro;
274 while (am1 != NULL) {
275 free(am1->name);
276 am1->name = NULL;
278 instr1 = am1->program;
279 while (instr1 != NULL) {
280 instr2 = instr1;
281 instr1 = instr1->next;
282 free(instr2);
283 instr2 = NULL;
286 am2 = am1;
287 am1 = am1->next;
288 free(am2);
289 am2 = NULL;
292 return;
293 } /* free_amacro */
296 void
297 print_program(gerbv_amacro_t *amacro)
299 gerbv_instruction_t *ip;
301 printf("Macroname [%s] :\n", amacro->name);
302 for (ip = amacro->program ; ip != NULL; ip = ip->next) {
303 switch(ip->opcode) {
304 case GERBV_OPCODE_NOP:
305 printf(" NOP\n");
306 break;
307 case GERBV_OPCODE_PUSH:
308 printf(" PUSH %f\n", ip->data.fval);
309 break;
310 case GERBV_OPCODE_PPOP:
311 printf(" PPOP %d\n", ip->data.ival);
312 break;
313 case GERBV_OPCODE_PPUSH:
314 printf(" PPUSH %d\n", ip->data.ival);
315 break;
316 case GERBV_OPCODE_ADD:
317 printf(" ADD\n");
318 break;
319 case GERBV_OPCODE_SUB:
320 printf(" SUB\n");
321 break;
322 case GERBV_OPCODE_MUL:
323 printf(" MUL\n");
324 break;
325 case GERBV_OPCODE_DIV:
326 printf(" DIV\n");
327 break;
328 case GERBV_OPCODE_PRIM:
329 printf(" PRIM %d\n", ip->data.ival);
330 break;
331 default :
332 printf(" ERROR!\n");
333 break;
335 fflush(stdout);
337 } /* print_program */