2 * gEDA - GNU Electronic Design Automation
4 * Copyright (C) 2000-2006 Andreas Andersson
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 \brief Excellon drill parsing functions
29 * 21 Feb 2007 patch for metric drill files:
30 * 1) METRIC/INCH commands (partly) parsed to define units of the header
31 * 2) units of the header and the program body are independent
32 * 3) ICI command parsed in the header
47 #include <math.h> /* pow() */
50 #include <sys/types.h>
57 #include "attribute.h"
61 #include "drill_stats.h"
65 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
66 #define dprintf if(DEBUG) printf
68 #define NOT_IMPL(fd, s) do { \
69 GERB_MESSAGE("Not Implemented:%s\n", s); \
73 #define DRILL_READ_DOUBLE_SIZE 32
76 #define max(a,b) ((a) > (b) ? (a) : (b))
78 #define min(a,b) ((a) < (b) ? (a) : (b))
80 enum drill_file_section_t
{DRILL_NONE
, DRILL_HEADER
, DRILL_DATA
};
81 enum drill_coordinate_mode_t
{DRILL_MODE_ABSOLUTE
, DRILL_MODE_INCREMENTAL
};
83 enum drill_m_code_t
{DRILL_M_UNKNOWN
, DRILL_M_NOT_IMPLEMENTED
,
84 DRILL_M_END
, DRILL_M_ENDREWIND
,
85 DRILL_M_MESSAGE
, DRILL_M_LONGMESSAGE
,
86 DRILL_M_HEADER
, DRILL_M_ENDHEADER
,
87 DRILL_M_METRIC
, DRILL_M_IMPERIAL
,
88 DRILL_M_BEGINPATTERN
, DRILL_M_ENDPATTERN
,
89 DRILL_M_CANNEDTEXT
, DRILL_M_TIPCHECK
,
90 DRILL_M_METRICHEADER
, DRILL_M_IMPERIALHEADER
};
93 enum drill_g_code_t
{DRILL_G_ABSOLUTE
, DRILL_G_INCREMENTAL
,
94 DRILL_G_ZEROSET
, DRILL_G_UNKNOWN
,
95 DRILL_G_ROUT
, DRILL_G_DRILL
,
96 DRILL_G_LINEARMOVE
, DRILL_G_CWMOVE
, DRILL_G_CCWMOVE
};
98 enum number_fmt_t
{FMT_00_0000
/* INCH */,
99 FMT_000_000
/* METRIC 6-digit, 1 um */,
100 FMT_000_00
/* METRIC 5-digit, 10 um */,
101 FMT_0000_00
/* METRIC 6-digit, 10 um */,
102 FMT_USER
/* User defined format */};
104 typedef struct drill_state
{
113 /* number_format is used throughout the file itself.
115 header_number_format is used to parse the tool definition C
116 codes within the header. It is fixed to FMT_00_0000 for INCH
117 measures, and FMT_000_000 (1 um resolution) for metric
119 enum number_fmt_t number_format
, header_number_format
;
120 /* Used as a backup when temporarily switching to INCH. */
121 enum number_fmt_t backup_number_format
;
123 /* 0 means we don't try to autodetect any of the other values */
126 /* in FMT_USER this specifies the number of digits before the
127 * decimal point when doing trailing zero supression. Otherwise
128 * it is the number of digits *after* the decimal
135 /* Local function prototypes */
136 static int drill_parse_G_code(gerb_file_t
*fd
, gerbv_image_t
*image
);
137 static int drill_parse_M_code(gerb_file_t
*fd
, drill_state_t
*state
,
138 gerbv_image_t
*image
);
139 static int drill_parse_T_code(gerb_file_t
*fd
, drill_state_t
*state
,
140 gerbv_image_t
*image
);
141 static void drill_parse_coordinate(gerb_file_t
*fd
, char firstchar
,
142 gerbv_image_t
*image
, drill_state_t
*state
);
143 static drill_state_t
*new_state(drill_state_t
*state
);
144 static double read_double(gerb_file_t
*fd
, enum number_fmt_t fmt
,
145 gerbv_omit_zeros_t omit_zeros
, int decimals
);
146 static void eat_line(gerb_file_t
*fd
);
147 static char *get_line(gerb_file_t
*fd
);
149 /* -------------------------------------------------------------- */
150 /* This is the list of specific attributes a drill file may have from
151 * the point of view of parsing it.
154 static const char *supression_list
[] = {
164 static const char *units_list
[] = {
167 /* we don't do anything with mil yet so don't offer it as an
177 static gerbv_HID_Attribute drill_attribute_list
[] = {
178 /* This should be first */
179 {"autodetect", "Try to autodetect the file format",
180 HID_Boolean
, 0, 0, {1, 0, 0}, 0, 0},
183 {"zero_supression", "Zero supression",
184 HID_Enum
, 0, 0, {0, 0, 0}, supression_list
, 0},
185 #define HA_supression 1
188 HID_Enum
, 0, 0, {0, 0, 0}, units_list
, 0},
189 #define HA_xy_units 2
192 {"tool_units", "Tool size units",
193 HID_Enum
, 0, 0, {0, 0, 0}, units_list
, 0},
194 #define HA_tool_units 3
197 {"digits", "Number of digits. For trailing zero supression,"
198 " this is the number of digits before the decimal point. "
199 "Otherwise this is the number of digits after the decimal point.",
200 HID_Integer
, 0, 20, {5, 0, 0}, 0, 0},
206 drill_attribute_merge (gerbv_HID_Attribute
*dest
, int ndest
, gerbv_HID_Attribute
*src
, int nsrc
)
210 /* Here is a brain dead merge algorithm which shold make anyone cringe.
211 * Still, it is simple and we won't merge many attributes and not
215 for (i
= 0 ; i
< nsrc
; i
++) {
216 /* see if our destination wants this attribute */
218 while (j
< ndest
&& strcmp (src
[i
].name
, dest
[j
].name
) != 0)
221 /* if we wanted it and it is the same type, copy it over */
222 if (j
< ndest
&& src
[i
].type
== dest
[j
].type
) {
223 dest
[j
].default_val
= src
[i
].default_val
;
230 * Adds the actual drill hole to the drawing
233 drill_add_drill_hole (gerbv_image_t
*image
, drill_state_t
*state
, gerbv_drill_stats_t
*stats
, gerbv_net_t
*curr_net
)
235 /* Add one to drill stats for the current tool */
236 drill_stats_increment_drill_counter(image
->drill_stats
->drill_list
,
237 state
->current_tool
);
239 curr_net
->next
= (gerbv_net_t
*)g_malloc(sizeof(gerbv_net_t
));
240 if (curr_net
->next
== NULL
)
241 GERB_FATAL_ERROR("malloc curr_net->next failed\n");
242 curr_net
= curr_net
->next
;
243 memset((void *)curr_net
, 0, sizeof(gerbv_net_t
));
244 curr_net
->layer
= image
->layers
;
245 curr_net
->state
= image
->states
;
246 curr_net
->start_x
= (double)state
->curr_x
;
247 curr_net
->start_y
= (double)state
->curr_y
;
248 /* KLUDGE. This function isn't allowed to return anything
250 if(state
->unit
== GERBV_UNIT_MM
) {
251 curr_net
->start_x
/= 25.4;
252 curr_net
->start_y
/= 25.4;
253 /* KLUDGE. All images, regardless of input format,
254 are returned in INCH format */
255 curr_net
->state
->unit
= GERBV_UNIT_INCH
;
258 curr_net
->stop_x
= curr_net
->start_x
- state
->origin_x
;
259 curr_net
->stop_y
= curr_net
->start_y
- state
->origin_y
;
260 curr_net
->aperture
= state
->current_tool
;
261 curr_net
->aperture_state
= GERBV_APERTURE_STATE_FLASH
;
263 /* Find min and max of image.
264 Mustn't forget (again) to add the hole radius */
266 /* Check if aperture is set. Ignore the below instead of
268 if(image
->aperture
[state
->current_tool
] == NULL
)
271 curr_net
->boundingBox
.left
=curr_net
->start_x
-
272 image
->aperture
[state
->current_tool
]->parameter
[0] / 2;
273 curr_net
->boundingBox
.right
=curr_net
->start_x
+
274 image
->aperture
[state
->current_tool
]->parameter
[0] / 2;
275 curr_net
->boundingBox
.bottom
=curr_net
->start_y
-
276 image
->aperture
[state
->current_tool
]->parameter
[0] / 2;
277 curr_net
->boundingBox
.top
=curr_net
->start_y
+
278 image
->aperture
[state
->current_tool
]->parameter
[0] / 2;
281 min(image
->info
->min_x
,
283 image
->aperture
[state
->current_tool
]->parameter
[0] / 2));
285 min(image
->info
->min_y
,
287 image
->aperture
[state
->current_tool
]->parameter
[0] / 2));
289 max(image
->info
->max_x
,
291 image
->aperture
[state
->current_tool
]->parameter
[0] / 2));
293 max(image
->info
->max_y
,
295 image
->aperture
[state
->current_tool
]->parameter
[0] / 2));
300 /* -------------------------------------------------------------- */
302 parse_drillfile(gerb_file_t
*fd
, gerbv_HID_Attribute
*attr_list
, int n_attr
, int reload
)
304 drill_state_t
*state
= NULL
;
305 gerbv_image_t
*image
= NULL
;
306 gerbv_net_t
*curr_net
= NULL
;
308 gerbv_drill_stats_t
*stats
;
313 * many locales redefine "." as "," and so on, so sscanf and strtod
314 * has problems when reading files using %f format.
315 * Fixes bug #1963618 reported by Lorenzo Marcantonio.
317 setlocale(LC_NUMERIC
, "C" );
319 /* Create new image for this layer */
320 dprintf("In parse_drillfile, about to create image for this layer\n");
322 image
= gerbv_create_image(image
, "Excellon Drill File");
324 GERB_FATAL_ERROR("malloc image failed\n");
326 if (reload
&& attr_list
!= NULL
) {
327 /* FIXME there should probably just be a function to copy an
328 attribute list including using strdup as needed */
330 image
->info
->n_attr
= n_attr
;
331 image
->info
->attr_list
= gerbv_attribute_dup(attr_list
, n_attr
);
334 /* Copy in the default attribute list for drill files. We make a
335 * copy here because we will allow per-layer editing of the
338 image
->info
->n_attr
= sizeof (drill_attribute_list
) / sizeof (drill_attribute_list
[0]);
339 image
->info
->attr_list
= gerbv_attribute_dup (drill_attribute_list
, image
->info
->n_attr
);
341 /* now merge any project attributes */
342 drill_attribute_merge (image
->info
->attr_list
, image
->info
->n_attr
,
346 curr_net
= image
->netlist
;
347 curr_net
->layer
= image
->layers
;
348 curr_net
->state
= image
->states
;
349 image
->layertype
= GERBV_LAYERTYPE_DRILL
;
350 stats
= gerbv_drill_stats_new();
352 GERB_FATAL_ERROR("malloc stats failed\n");
353 image
->drill_stats
= stats
;
355 /* Create local state variable to track photoplotter state */
356 state
= new_state(state
);
358 GERB_FATAL_ERROR("malloc state failed\n");
360 image
->format
= (gerbv_format_t
*)g_malloc(sizeof(gerbv_format_t
));
361 if (image
->format
== NULL
)
362 GERB_FATAL_ERROR("malloc format failed\n");
363 memset((void *)image
->format
, 0, sizeof(gerbv_format_t
));
364 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_UNSPECIFIED
;
367 if (!image
->info
->attr_list
[HA_auto
].default_val
.int_value
) {
369 state
->number_format
= FMT_USER
;
370 state
->decimals
= image
->info
->attr_list
[HA_digits
].default_val
.int_value
;
371 if (image
->info
->attr_list
[HA_xy_units
].default_val
.int_value
== UNITS_MM
)
372 state
->unit
= GERBV_UNIT_MM
;
373 switch (image
->info
->attr_list
[HA_supression
].default_val
.int_value
) {
375 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
379 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_TRAILING
;
383 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_EXPLICIT
;
388 dprintf("%s(): Starting parsing of drill file\n", __FUNCTION__
);
389 while ((read
= gerb_fgetc(fd
)) != EOF
) {
391 switch ((char) read
) {
393 /* Comment found. Eat rest of line */
398 tmps
= get_line (fd
);
399 if (strcmp (tmps
, "DETECT,ON") == 0 ||
400 strcmp (tmps
, "DETECT,OFF") == 0) {
403 if (strcmp (tmps
, "DETECT,ON") == 0)
408 /* broken tool detect on/off. Silently ignored. */
410 tmps2
= g_strdup_printf ("%s\n%s", stats
->detect
, tmps3
);
411 g_free (stats
->detect
);
413 tmps2
= g_strdup_printf ("%s", tmps3
);
415 stats
->detect
= tmps2
;
417 string
= g_strdup_printf("Undefined header line = '%s'\n",tmps
);
418 drill_stats_add_error(stats
->error_list
,
428 tmps
= get_line (fd
);
429 /* Silently ignore FMAT,2. Not sure what others are allowed */
430 if (strcmp (tmps
, "FMAT,2") != 0) {
431 string
= g_strdup_printf("Undefined header line = '%s'\n",tmps
);
432 drill_stats_add_error(stats
->error_list
,
442 /* Most G codes aren't used, for now */
443 switch(drill_parse_G_code(fd
, image
)) {
445 drill_stats_add_error(stats
->error_list
,
447 "Rout mode data is not supported\n",
448 GERBV_MESSAGE_ERROR
);
452 case DRILL_G_ABSOLUTE
:
453 state
->coordinate_mode
= DRILL_MODE_ABSOLUTE
;
455 case DRILL_G_INCREMENTAL
:
456 state
->coordinate_mode
= DRILL_MODE_INCREMENTAL
;
458 case DRILL_G_ZEROSET
:
459 if((read
= gerb_fgetc(fd
)) == EOF
)
460 drill_stats_add_error(stats
->error_list
,
462 "Unexpected EOF found.\n",
463 GERBV_MESSAGE_ERROR
);
464 drill_parse_coordinate(fd
, (char)read
, image
, state
);
465 state
->origin_x
= state
->curr_x
;
466 state
->origin_y
= state
->curr_y
;
474 if (state
->curr_section
!= DRILL_HEADER
)
477 int c
= gerb_fgetc(fd
);
480 if ('C' == gerb_fgetc(fd
)) {
481 if ('H' == gerb_fgetc(fd
)) {
482 state
->unit
= GERBV_UNIT_INCH
;
485 if (',' == gerb_fgetc(fd
)) {
487 if (c
!= EOF
&& 'Z' == gerb_fgetc(fd
)) {
491 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_TRAILING
;
492 state
->header_number_format
=
493 state
->number_format
= FMT_00_0000
;
500 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
501 state
->header_number_format
=
502 state
->number_format
= FMT_00_0000
;
508 drill_stats_add_error(stats
->error_list
,
510 "Found junk after INCH command\n",
511 GERBV_MESSAGE_WARNING
);
515 drill_stats_add_error(stats
->error_list
,
517 "Found junk after INCH command\n",
518 GERBV_MESSAGE_WARNING
);
522 /* unget the char in case we just advanced past a new line char */
528 if ('I' == gerb_fgetc(fd
))
529 if (',' == gerb_fgetc(fd
))
530 if ('O' == gerb_fgetc(fd
)) {
531 if ('N' == (c
= gerb_fgetc(fd
)))
532 state
->coordinate_mode
= DRILL_MODE_INCREMENTAL
;
533 else if ('F' == c
) if ('F' == gerb_fgetc(fd
))
534 state
->coordinate_mode
= DRILL_MODE_ABSOLUTE
;
543 switch(drill_parse_M_code(fd
, state
, image
)) {
544 case DRILL_M_HEADER
:
545 state
->curr_section
= DRILL_HEADER
;
547 case DRILL_M_ENDHEADER
:
548 state
->curr_section
= DRILL_DATA
;
550 if (image
->format
->omit_zeros
== GERBV_OMIT_ZEROS_UNSPECIFIED
) {
551 /* Excellon says they default to specify leading
552 zeros, i.e. omit trailing zeros. The Excellon
553 files floating around that don't specify the
554 leading/trailing zeros in the header seem to
555 contradict to this though.
557 XXX We should probably ask the user. */
559 drill_stats_add_error(stats
->error_list
,
561 "End of Excellon header reached but no leading/trailing zero handling specified.\n",
562 GERBV_MESSAGE_ERROR
);
563 drill_stats_add_error(stats
->error_list
,
565 "Assuming leading zeros.\n",
566 GERBV_MESSAGE_WARNING
);
567 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
570 case DRILL_M_METRIC
:
571 if (state
->unit
== GERBV_UNIT_UNSPECIFIED
&&
572 state
->curr_section
!= DRILL_HEADER
) {
573 drill_stats_add_error(stats
->error_list
,
575 "M71 code found but no METRIC specification in header.\n",
576 GERBV_MESSAGE_ERROR
);
577 drill_stats_add_error(stats
->error_list
,
579 "Assuming all tool sizes are MM.\n",
580 GERBV_MESSAGE_WARNING
);
583 stats
= image
->drill_stats
;
584 for (tool_num
= TOOL_MIN
; tool_num
< TOOL_MAX
; tool_num
++) {
585 if (image
->aperture
&& image
->aperture
[tool_num
]) {
586 /* First update stats. Do this before changing drill dias.
587 * Maybe also put error into stats? */
588 size
= image
->aperture
[tool_num
]->parameter
[0];
589 drill_stats_modify_drill_list(stats
->drill_list
,
593 /* Now go back and update all tool dias, since
594 * tools are displayed in inch units
596 image
->aperture
[tool_num
]->parameter
[0] /= 25.4;
601 state
->number_format
= state
->backup_number_format
;
602 state
->unit
= GERBV_UNIT_MM
;
605 case DRILL_M_IMPERIAL
:
607 if (state
->number_format
!= FMT_00_0000
)
608 /* save metric format definition for later */
609 state
->backup_number_format
= state
->number_format
;
610 state
->number_format
= FMT_00_0000
;
612 state
->unit
= GERBV_UNIT_INCH
;
616 case DRILL_M_LONGMESSAGE
:
617 case DRILL_M_MESSAGE
:
618 case DRILL_M_CANNEDTEXT
:
620 string
= g_strdup_printf("Message embedded in drill file: '%s'\n",
622 drill_stats_add_error(stats
->error_list
,
629 case DRILL_M_NOT_IMPLEMENTED
:
630 case DRILL_M_ENDPATTERN
:
631 case DRILL_M_TIPCHECK
:
634 /* M00 has optional arguments */
636 case DRILL_M_ENDREWIND
:
637 goto drill_parse_end
;
639 case DRILL_M_METRICHEADER
:
640 state
->unit
= GERBV_UNIT_MM
;
643 drill_stats_add_error(stats
->error_list
,
645 "Undefined M code found.\n",
646 GERBV_MESSAGE_ERROR
);
651 if(state
->curr_section
== DRILL_HEADER
) {
652 drill_stats_add_error(stats
->error_list
,
654 "R codes are not allowed in the header.\n",
655 GERBV_MESSAGE_ERROR
);
657 double start_x
, start_y
;
658 double step_x
, step_y
;
662 * This is the "Repeat hole" command. Format is:
664 * This repeats the previous hole stepping in the X and
665 * Y increments give. Example:
666 * R04X0.1 -- repeats the drill hole 4 times, stepping
667 * 0.1" in the X direction. Note that the X and Y step
668 * sizes default to zero if not given and that they use
669 * the same format and units as the normal X,Y
674 start_x
= state
->curr_x
;
675 start_y
= state
->curr_y
;
679 /* figure out how many repeats there are */
682 while ( '0' <= c
&& c
<= '9') {
683 rcnt
= 10*rcnt
+ (c
- '0');
686 dprintf ("working on R code (repeat) with a number of reps equal to %d\n", rcnt
);
690 step_x
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
696 step_y
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
701 dprintf ("Getting ready to repeat the drill %d times with delta_x = %g, delta_y = %g\n", rcnt
, step_x
, step_y
);
703 /* spit out the drills */
704 for (c
= 1 ; c
<= rcnt
; c
++) {
705 state
->curr_x
= start_x
+ c
*step_x
;
706 state
->curr_y
= start_y
+ c
*step_y
;
707 dprintf (" Repeat #%d -- new location is (%g, %g)\n", c
, state
->curr_x
, state
->curr_y
);
708 curr_net
= drill_add_drill_hole (image
, state
, stats
, curr_net
);
714 drill_stats_add_error(stats
->error_list
,
716 "Drill file sets spindle speed -- ignoring.\n",
721 drill_parse_T_code(fd
, state
, image
);
725 tmps
= get_line (fd
);
726 /* Silently ignore VER,1. Not sure what others are allowed */
727 if (strcmp (tmps
, "VER,1") != 0) {
728 string
= g_strdup_printf("Undefined header line = '%s'\n",tmps
);
729 drill_stats_add_error(stats
->error_list
,
731 g_strdup_printf("Undefined header line = '%s'\n",tmps
),
740 /* Hole coordinate found. Do some parsing */
741 drill_parse_coordinate(fd
, read
, image
, state
);
743 /* add the new drill hole */
744 curr_net
= drill_add_drill_hole (image
, state
, stats
, curr_net
);
748 state
->curr_section
= DRILL_DATA
;
750 case 10 : /* White space */
756 if(state
->curr_section
== DRILL_HEADER
) {
757 /* Unrecognised crap in the header is thrown away */
758 drill_stats_add_error(stats
->error_list
,
760 "Undefined codes found in header.\n",
761 GERBV_MESSAGE_ERROR
);
764 string
= g_strdup_printf("Undefined header line = '%s'\n",
766 drill_stats_add_error(stats
->error_list
,
773 string
= g_strdup_printf("Undefined character '%c' [0x%02x] found inside data, ignoring\n",
775 drill_stats_add_error(stats
->error_list
,
778 GERBV_MESSAGE_ERROR
);
783 drill_stats_add_error(stats
->error_list
,
785 "No EOF found in drill file.\n",
786 GERBV_MESSAGE_ERROR
);
789 dprintf ("%s(): Populating file attributes\n", __FUNCTION__
);
791 switch (state
->unit
) {
793 image
->info
->attr_list
[HA_xy_units
].default_val
.int_value
= UNITS_MM
;
797 image
->info
->attr_list
[HA_xy_units
].default_val
.int_value
= UNITS_INCH
;
801 switch (state
->number_format
) {
804 image
->info
->attr_list
[HA_digits
].default_val
.int_value
= 2;
808 image
->info
->attr_list
[HA_digits
].default_val
.int_value
= 3;
812 image
->info
->attr_list
[HA_digits
].default_val
.int_value
= 4;
816 dprintf ("%s(): Keeping user specified number of decimal places (%d)\n",
818 image
->info
->attr_list
[HA_digits
].default_val
.int_value
);
825 switch (image
->format
->omit_zeros
) {
826 case GERBV_OMIT_ZEROS_LEADING
:
827 image
->info
->attr_list
[HA_supression
].default_val
.int_value
= SUP_LEAD
;
830 case GERBV_OMIT_ZEROS_TRAILING
:
831 image
->info
->attr_list
[HA_supression
].default_val
.int_value
= SUP_TRAIL
;
835 image
->info
->attr_list
[HA_supression
].default_val
.int_value
= SUP_NONE
;
842 } /* parse_drillfile */
845 /* -------------------------------------------------------------- */
847 * Checks for signs that this is a drill file
848 * Returns TRUE if it is, FALSE if not.
851 drill_file_p(gerb_file_t
*fd
, gboolean
*returnFoundBinary
)
857 int zero
= 48; /* ascii 0 */
858 int nine
= 57; /* ascii 9 */
860 gboolean found_binary
= FALSE
;
861 gboolean found_M48
= FALSE
;
862 gboolean found_M30
= FALSE
;
863 gboolean found_percent
= FALSE
;
864 gboolean found_T
= FALSE
;
865 gboolean found_X
= FALSE
;
866 gboolean found_Y
= FALSE
;
868 buf
= g_malloc(MAXL
);
870 GERB_FATAL_ERROR("malloc buf failed while checking for drill file.\n");
872 while (fgets(buf
, MAXL
, fd
->fd
) != NULL
) {
875 /* First look through the file for indications of its type */
877 /* check that file is not binary (non-printing chars) */
878 for (i
= 0; i
< len
; i
++) {
879 ascii
= (int) buf
[i
];
880 if ((ascii
> 128) || (ascii
< 0)) {
885 /* Check for M48 = start of drill header */
886 if (g_strstr_len(buf
, len
, "M48")) {
890 /* Check for M30 = end of drill program */
891 if (g_strstr_len(buf
, len
, "M30")) {
893 found_M30
= TRUE
; /* Found M30 after % = good */
897 /* Check for % on its own line at end of header */
898 if ((letter
= g_strstr_len(buf
, len
, "%")) != NULL
) {
899 if ((letter
[1] == '\r') || (letter
[1] == '\n'))
900 found_percent
= TRUE
;
903 /* Check for T<number> */
904 if ((letter
= g_strstr_len(buf
, len
, "T")) != NULL
) {
905 if (!found_T
&& (found_X
|| found_Y
)) {
906 found_T
= FALSE
; /* Found first T after X or Y */
908 if (isdigit( (int) letter
[1])) { /* verify next char is digit */
914 /* look for X<number> or Y<number> */
915 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
916 ascii
= (int) letter
[1]; /* grab char after X */
917 if ((ascii
>= zero
) && (ascii
<= nine
)) {
921 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
922 ascii
= (int) letter
[1]; /* grab char after Y */
923 if ((ascii
>= zero
) && (ascii
<= nine
)) {
927 } /* while (fgets(buf, MAXL, fd->fd) */
931 *returnFoundBinary
= found_binary
;
933 /* Now form logical expression determining if this is a drill file */
934 if ( ((found_X
|| found_Y
) && found_T
) &&
935 (found_M48
|| (found_percent
&& found_M30
)) )
937 else if (found_M48
&& found_T
&& found_percent
&& found_M30
)
938 /* Pathological case of drill file with valid header
939 and EOF but no drill XY locations. */
946 /* -------------------------------------------------------------- */
947 /* Parse tool definition. This can get a bit tricky since it can
948 appear in the header and/or data section.
949 Returns tool number on success, -1 on error */
951 drill_parse_T_code(gerb_file_t
*fd
, drill_state_t
*state
, gerbv_image_t
*image
)
954 gboolean done
= FALSE
;
957 gerbv_drill_stats_t
*stats
= image
->drill_stats
;
961 /* Sneak a peek at what's hiding after the 'T'. Ugly fix for
962 broken headers from Orcad, which is crap */
963 temp
= gerb_fgetc(fd
);
964 dprintf("Found a char %d after the T\n", temp
);
966 /* might be a tool tool change stop switch on/off*/
967 if((temp
== 'C') && ((fd
->ptr
+ 2) < fd
->datalen
)){
968 if(gerb_fgetc(fd
) == 'S'){
969 if (gerb_fgetc(fd
) == 'T' ){
971 tmps
= get_line(fd
++);
972 string
= g_strdup_printf("Tool change stop switch found: %s\n", tmps
);
973 drill_stats_add_error(stats
->error_list
,
986 if( !(isdigit(temp
) != 0 || temp
== '+' || temp
=='-') ) {
988 drill_stats_add_error(stats
->error_list
,
990 "Orcad bug: Junk text found in place of tool definition.\n",
991 GERBV_MESSAGE_ERROR
);
993 string
= g_strdup_printf("Junk text = %s\n",
995 drill_stats_add_error(stats
->error_list
,
1001 drill_stats_add_error(stats
->error_list
,
1003 "Ignorning junk text.\n",
1004 GERBV_MESSAGE_WARNING
);
1010 tool_num
= (int) gerb_fgetint(fd
, NULL
);
1011 dprintf ("In %s: handling tool_num = %d\n", __FUNCTION__
, tool_num
);
1014 return tool_num
; /* T00 is a command to unload the drill */
1016 if ( (tool_num
< TOOL_MIN
) || (tool_num
>= TOOL_MAX
) ) {
1017 string
= g_strdup_printf("Drill number out of bounds: %d.\n", tool_num
);
1018 drill_stats_add_error(stats
->error_list
,
1021 GERBV_MESSAGE_ERROR
);
1025 /* Set the current tool to the correct one */
1026 state
->current_tool
= tool_num
;
1028 /* Check for a size definition */
1029 temp
= gerb_fgetc(fd
);
1031 /* This bit of code looks for a tool definition by scanning for strings
1032 * of form TxxC, TxxF, TxxS. */
1035 switch((char)temp
) {
1037 size
= read_double(fd
, state
->header_number_format
, GERBV_OMIT_ZEROS_TRAILING
, state
->decimals
);
1038 dprintf ("%s: Read a size of %g %s\n", __FUNCTION__
, size
,
1039 state
->unit
== GERBV_UNIT_MM
? "mm" : "inch");
1040 if(state
->unit
== GERBV_UNIT_MM
) {
1042 } else if(size
>= 4.0) {
1043 /* If the drill size is >= 4 inches, assume that this
1044 must be wrong and that the units are mils.
1045 The limit being 4 inches is because the smallest drill
1046 I've ever seen used is 0,3mm(about 12mil). Half of that
1047 seemed a bit too small a margin, so a third it is */
1048 string
= g_strdup_printf("Read a drill of diameter %g inches.\n", size
);
1049 drill_stats_add_error(stats
->error_list
,
1052 GERBV_MESSAGE_ERROR
);
1054 string
= g_strdup_printf("Assuming units are mils.\n");
1055 drill_stats_add_error(stats
->error_list
,
1058 GERBV_MESSAGE_WARNING
);
1063 if(size
<= 0. || size
>= 10000.) {
1064 string
= g_strdup_printf("Unreasonable drill size found for drill %d: %g\n", tool_num
, size
);
1065 drill_stats_add_error(stats
->error_list
,
1068 GERBV_MESSAGE_ERROR
);
1071 if(image
->aperture
[tool_num
] != NULL
) {
1072 /* allow a redefine of a tool only if the new definition is exactly the same.
1073 * This avoid lots of spurious complaints with the output of some cad
1074 * tools while keeping complaints if there is a true problem
1076 if (image
->aperture
[tool_num
]->parameter
[0] != size
||
1077 image
->aperture
[tool_num
]->type
!= GERBV_APTYPE_CIRCLE
||
1078 image
->aperture
[tool_num
]->nuf_parameters
!= 1 ||
1079 image
->aperture
[tool_num
]->unit
!= GERBV_UNIT_INCH
) {
1080 string
= g_strdup_printf("Found redefinition of drill %d.\n", tool_num
);
1081 drill_stats_add_error(stats
->error_list
,
1084 GERBV_MESSAGE_ERROR
);
1088 image
->aperture
[tool_num
] =
1089 (gerbv_aperture_t
*)g_malloc(sizeof(gerbv_aperture_t
));
1090 if (image
->aperture
[tool_num
] == NULL
) {
1091 GERB_FATAL_ERROR("malloc tool failed\n");
1093 /* make sure we zero out all aperature parameters */
1094 memset((void *)image
->aperture
[tool_num
], 0, sizeof(gerbv_aperture_t
));
1095 /* There's really no way of knowing what unit the tools
1096 are defined in without sneaking a peek in the rest of
1097 the file first. That's done in drill_guess_format() */
1098 image
->aperture
[tool_num
]->parameter
[0] = size
;
1099 image
->aperture
[tool_num
]->type
= GERBV_APTYPE_CIRCLE
;
1100 image
->aperture
[tool_num
]->nuf_parameters
= 1;
1101 image
->aperture
[tool_num
]->unit
= GERBV_UNIT_INCH
;
1105 /* Add the tool whose definition we just found into the list
1106 * of tools for this layer used to generate statistics. */
1107 stats
= image
->drill_stats
;
1108 string
= g_strdup_printf("%s", (state
->unit
== GERBV_UNIT_MM
? "mm" : "inch"));
1109 drill_stats_add_to_drill_list(stats
->drill_list
,
1111 state
->unit
== GERBV_UNIT_MM
? size
*25.4 : size
,
1118 /* Silently ignored. They're not important. */
1119 gerb_fgetint(fd
, NULL
);
1123 /* Stop when finding anything but what's expected
1124 (and put it back) */
1128 } /* switch((char)temp) */
1130 if( (temp
= gerb_fgetc(fd
)) == EOF
) {
1131 drill_stats_add_error(stats
->error_list
,
1133 "Unexpected EOF encountered header of drill file.\n",
1134 GERBV_MESSAGE_ERROR
);
1136 } /* while(!done) */ /* Done looking at tool definitions */
1138 /* Catch the tools that aren't defined.
1139 This isn't strictly a good thing, but at least something is shown */
1140 if(image
->aperture
[tool_num
] == NULL
) {
1143 image
->aperture
[tool_num
] =
1144 (gerbv_aperture_t
*)g_malloc(sizeof(gerbv_aperture_t
));
1145 if (image
->aperture
[tool_num
] == NULL
) {
1146 GERB_FATAL_ERROR("malloc tool failed\n");
1148 /* make sure we zero out all aperature parameters */
1149 memset((void *)image
->aperture
[tool_num
], 0, sizeof(gerbv_aperture_t
));
1151 /* See if we have the tool table */
1152 dia
= gerbv_get_tool_diameter(tool_num
);
1155 * There is no tool. So go out and make some.
1156 * This size calculation is, of course, totally bogus.
1158 dia
= (double)(16 + 8 * tool_num
) / 1000;
1160 * Oooh, this is sooo ugly. But some CAD systems seem to always
1161 * use T00 at the end of the file while others that don't have
1162 * tool definitions inside the file never seem to use T00 at all.
1165 string
= g_strdup_printf("Tool %02d used without being defined\n", tool_num
);
1166 drill_stats_add_error(stats
->error_list
,
1169 GERBV_MESSAGE_ERROR
);
1171 string
= g_strdup_printf("Setting a default size of %g\"\n", dia
);
1172 drill_stats_add_error(stats
->error_list
,
1175 GERBV_MESSAGE_WARNING
);
1180 image
->aperture
[tool_num
]->type
= GERBV_APTYPE_CIRCLE
;
1181 image
->aperture
[tool_num
]->nuf_parameters
= 1;
1182 image
->aperture
[tool_num
]->parameter
[0] = dia
;
1184 /* Add the tool whose definition we just found into the list
1185 * of tools for this layer used to generate statistics. */
1186 if (tool_num
!= 0) { /* Only add non-zero tool nums.
1187 * Zero = unload command. */
1188 stats
= image
->drill_stats
;
1189 string
= g_strdup_printf("%s",
1190 (state
->unit
== GERBV_UNIT_MM
? "mm" : "inch"));
1191 drill_stats_add_to_drill_list(stats
->drill_list
,
1193 state
->unit
== GERBV_UNIT_MM
? dia
*25.4 : dia
,
1197 } /* if(image->aperture[tool_num] == NULL) */
1200 } /* drill_parse_T_code */
1203 /* -------------------------------------------------------------- */
1205 drill_parse_M_code(gerb_file_t
*fd
, drill_state_t
*state
, gerbv_image_t
*image
)
1209 gerbv_drill_stats_t
*stats
= image
->drill_stats
;
1212 dprintf("---> entering drill_parse_M_code ...\n");
1214 read
[0] = gerb_fgetc(fd
);
1215 read
[1] = gerb_fgetc(fd
);
1217 if ((read
[0] == EOF
) || (read
[1] == EOF
))
1218 drill_stats_add_error(stats
->error_list
,
1220 "Unexpected EOF found while parsing M code.\n",
1221 GERBV_MESSAGE_ERROR
);
1222 op
[0] = read
[0], op
[1] = read
[1], op
[2] = 0;
1224 if (strncmp(op
, "00", 2) == 0) {
1226 result
= DRILL_M_END
;
1227 } else if (strncmp(op
, "01", 2) == 0) {
1229 result
= DRILL_M_ENDPATTERN
;
1230 } else if (strncmp(op
, "18", 2) == 0) {
1232 result
= DRILL_M_TIPCHECK
;
1233 } else if (strncmp(op
, "25", 2) == 0) {
1235 result
= DRILL_M_BEGINPATTERN
;
1236 } else if (strncmp(op
, "31", 2) == 0) {
1238 result
= DRILL_M_BEGINPATTERN
;
1239 } else if (strncmp(op
, "30", 2) == 0) {
1241 result
= DRILL_M_ENDREWIND
;
1242 } else if (strncmp(op
, "45", 2) == 0) {
1244 result
= DRILL_M_LONGMESSAGE
;
1245 } else if (strncmp(op
, "47", 2) == 0) {
1247 result
= DRILL_M_MESSAGE
;
1248 } else if (strncmp(op
, "48", 2) == 0) {
1250 result
= DRILL_M_HEADER
;
1251 } else if (strncmp(op
, "71", 2) == 0) {
1254 result
= DRILL_M_METRIC
;
1255 } else if (strncmp(op
, "72", 2) == 0) {
1258 result
= DRILL_M_IMPERIAL
;
1259 } else if (strncmp(op
, "95", 2) == 0) {
1261 result
= DRILL_M_ENDHEADER
;
1262 } else if (strncmp(op
, "97", 2) == 0) {
1264 result
= DRILL_M_CANNEDTEXT
;
1265 } else if (strncmp(op
, "98", 2) == 0) {
1267 return DRILL_M_CANNEDTEXT
;
1268 } else if (state
->curr_section
== DRILL_HEADER
&&
1269 strncmp(op
, "ET", 2) == 0) {
1270 /* METRIC is not an actual M code but a command that is only
1271 acceptable within the header.
1274 METRIC[,{TZ|LZ}][,{000.000|000.00|0000.00}]
1276 if ('R' == gerb_fgetc(fd
) &&
1277 'I' == gerb_fgetc(fd
) &&
1278 'C' == gerb_fgetc(fd
)) {
1280 if (',' == gerb_fgetc(fd
)) {
1283 /* Is it tzlz, or zerofmt? */
1284 switch ((c
= gerb_fgetc(fd
))) {
1287 if ('Z' != gerb_fgetc(fd
))
1291 dprintf ("%s(): Detected a file that probably has trailing zero supression\n", __FUNCTION__
);
1294 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_TRAILING
;
1299 dprintf ("%s(): Detected a file that probably has leading zero supression\n", __FUNCTION__
);
1302 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
1307 /* Default metric number format is 6-digit, 1 um
1308 resolution. The header number format (for T#C#
1309 definitions) is fixed to that, while the number
1310 format within the file can differ. */
1311 state
->header_number_format
=
1312 state
->number_format
= FMT_000_000
;
1313 state
->decimals
= 3;
1318 /* anticipate number format will follow */
1323 if ('0' != gerb_fgetc(fd
) ||
1324 '0' != gerb_fgetc(fd
))
1326 /* We just parsed three 0s, the remainder options
1327 so far are: .000 | .00 | 0.00 */
1328 read
[0] = gerb_fgetc(fd
);
1329 read
[1] = gerb_fgetc(fd
);
1330 if (read
[0] == EOF
|| read
[1] == EOF
)
1334 if (strcmp(op
, "0.") == 0) {
1335 /* expecting FMT_0000_00,
1336 two trailing 0s must follow */
1337 if ('0' != gerb_fgetc(fd
) ||
1338 '0' != gerb_fgetc(fd
))
1343 state
->number_format
= FMT_0000_00
;
1344 state
->decimals
= 2;
1348 if (strcmp(op
, ".0") != 0)
1350 /* must be either FMT_000_000 or FMT_000_00, depending
1351 on whether one or two 0s are following */
1352 if ('0' != gerb_fgetc(fd
))
1354 if ('0' == gerb_fgetc(fd
) && state
->autod
)
1356 state
->number_format
= FMT_000_000
;
1357 state
->decimals
= 3;
1363 state
->number_format
= FMT_000_00
;
1364 state
->decimals
= 2;
1372 drill_stats_add_error(stats
->error_list
,
1374 "Found junk after METRIC command\n",
1375 GERBV_MESSAGE_WARNING
);
1385 return DRILL_M_METRICHEADER
;
1389 result
= DRILL_M_UNKNOWN
;
1392 dprintf("<---- ...leaving drill_parse_M_code.\n");
1394 } /* drill_parse_M_code */
1397 /* -------------------------------------------------------------- */
1399 drill_parse_G_code(gerb_file_t
*fd
, gerbv_image_t
*image
)
1403 gerbv_drill_stats_t
*stats
= image
->drill_stats
;
1406 dprintf("---> entering drill_parse_G_code ...\n");
1408 read
[0] = gerb_fgetc(fd
);
1409 read
[1] = gerb_fgetc(fd
);
1411 if ((read
[0] == EOF
) || (read
[1] == EOF
)) {
1412 drill_stats_add_error(stats
->error_list
,
1414 "Unexpected EOF found while parsing G code.\n",
1415 GERBV_MESSAGE_ERROR
);
1418 op
[0] = read
[0], op
[1] = read
[1], op
[2] = 0;
1420 if (strncmp(op
, "00", 2) == 0) {
1422 result
= DRILL_G_ROUT
;
1423 } else if (strncmp(op
, "01", 2) == 0) {
1425 result
= DRILL_G_LINEARMOVE
;
1426 } else if (strncmp(op
, "02", 2) == 0) {
1428 result
= DRILL_G_CWMOVE
;
1429 } else if (strncmp(op
, "03", 2) == 0) {
1431 result
= DRILL_G_CCWMOVE
;
1432 } else if (strncmp(op
, "05", 2) == 0) {
1434 result
= DRILL_G_DRILL
;
1435 } else if (strncmp(op
, "90", 2) == 0) {
1437 result
= DRILL_G_ABSOLUTE
;
1438 } else if (strncmp(op
, "91", 2) == 0) {
1440 result
= DRILL_G_INCREMENTAL
;
1441 } else if (strncmp(op
, "93", 2) == 0) {
1443 result
= DRILL_G_ZEROSET
;
1446 result
= DRILL_G_UNKNOWN
;
1449 dprintf("<---- ...leaving drill_parse_G_code.\n");
1452 } /* drill_parse_G_code */
1455 /* -------------------------------------------------------------- */
1456 /* Parse on drill file coordinate.
1457 Returns nothing, but modifies state */
1459 drill_parse_coordinate(gerb_file_t
*fd
, char firstchar
,
1460 gerbv_image_t
*image
, drill_state_t
*state
)
1465 if(state
->coordinate_mode
== DRILL_MODE_ABSOLUTE
) {
1466 if(firstchar
== 'X') {
1467 state
->curr_x
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1468 if((read
= (char)gerb_fgetc(fd
)) == 'Y') {
1469 state
->curr_y
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1472 state
->curr_y
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1474 } else if(state
->coordinate_mode
== DRILL_MODE_INCREMENTAL
) {
1475 if(firstchar
== 'X') {
1476 state
->curr_x
+= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1477 if((read
= (char)gerb_fgetc(fd
)) == 'Y') {
1478 state
->curr_y
+= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1481 state
->curr_y
+= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1485 } /* drill_parse_coordinate */
1488 /* Allocates and returns a new drill_state structure
1489 Returns state pointer on success, NULL on ERROR */
1490 static drill_state_t
*
1491 new_state(drill_state_t
*state
)
1493 state
= (drill_state_t
*)g_malloc(sizeof(drill_state_t
));
1494 if (state
!= NULL
) {
1495 /* Init structure */
1496 memset((void *)state
, 0, sizeof(drill_state_t
));
1497 state
->curr_section
= DRILL_NONE
;
1498 state
->coordinate_mode
= DRILL_MODE_ABSOLUTE
;
1499 state
->origin_x
= 0.0;
1500 state
->origin_y
= 0.0;
1501 state
->unit
= GERBV_UNIT_UNSPECIFIED
;
1502 state
->backup_number_format
= FMT_000_000
; /* only used for METRIC */
1503 state
->header_number_format
= state
->number_format
= FMT_00_0000
; /* i. e. INCH */
1505 state
->decimals
= 4;
1512 /* -------------------------------------------------------------- */
1513 /* Reads one double from fd and returns it.
1514 If a decimal point is found, fmt is not used. */
1516 read_double(gerb_file_t
*fd
, enum number_fmt_t fmt
, gerbv_omit_zeros_t omit_zeros
, int decimals
)
1519 char temp
[DRILL_READ_DOUBLE_SIZE
];
1520 int i
= 0, ndigits
= 0;
1522 gboolean decimal_point
= FALSE
;
1523 gboolean sign_prepend
= FALSE
;
1525 dprintf("%s(%p, %d, %d, %d)\n", __FUNCTION__
, fd
, fmt
, omit_zeros
, decimals
);
1527 memset(temp
, 0, sizeof(temp
));
1529 read
= gerb_fgetc(fd
);
1530 while(read
!= EOF
&& i
< (DRILL_READ_DOUBLE_SIZE
-1) &&
1531 (isdigit(read
) || read
== '.' || read
== ',' || read
== '+' || read
== '-')) {
1532 if(read
== ',' || read
== '.') decimal_point
= TRUE
;
1535 * FIXME -- if we are going to do this, don't we need a
1536 * locale-independent strtod()? I think pcb has one.
1539 read
= '.'; /* adjust for strtod() */
1541 if(isdigit(read
)) ndigits
++;
1543 if(read
== '-' || read
== '+')
1544 sign_prepend
= TRUE
;
1546 temp
[i
++] = (char)read
;
1547 read
= gerb_fgetc(fd
);
1552 if (decimal_point
) {
1553 result
= strtod(temp
, NULL
);
1557 char tmp2
[DRILL_READ_DOUBLE_SIZE
];
1559 memset(tmp2
, 0, sizeof(tmp2
));
1561 dprintf("%s(): omit_zeros = %d, fmt = %d\n", __FUNCTION__
, omit_zeros
, fmt
);
1562 /* Nothing to take care for when leading zeros are
1564 if (omit_zeros
== GERBV_OMIT_ZEROS_TRAILING
) {
1583 wantdigits
= decimals
;
1587 /* cannot happen, just plugs a compiler warning */
1588 fprintf(stderr
, "%s(): omit_zeros == GERBV_OMIT_ZEROS_TRAILING but fmt = %d.\n"
1589 "This should never have happened\n", __FUNCTION__
, fmt
);
1593 /* need to add an extra char for '+' or '-' */
1599 * we need at least wantdigits + one for the decimal place
1600 * + one for the terminating null character
1602 if (wantdigits
> sizeof(tmp2
) - 2) {
1603 fprintf(stderr
, "%s(): wantdigits = %d which exceeds the maximum allowed size\n",
1604 __FUNCTION__
, wantdigits
);
1609 * After we have read the correct number of digits
1610 * preceeding the decimal point, insert a decimal point
1611 * and append the rest of the digits.
1613 dprintf("%s(): wantdigits = %d, strlen(\"%s\") = %ld\n",
1614 __FUNCTION__
, wantdigits
, temp
, (long) strlen(temp
));
1615 for (i
= 0 ; i
< wantdigits
; i
++) {
1618 tmp2
[wantdigits
] = '.';
1619 for (i
= wantdigits
; i
<= strlen(temp
) ; i
++) {
1620 tmp2
[i
+1] = temp
[i
];
1622 dprintf("%s(): After dealing with trailing zero supression, convert \"%s\"\n", __FUNCTION__
, tmp2
);
1625 for (i
= 0 ; i
<= strlen(tmp2
) && i
< sizeof (temp
) ; i
++) {
1632 * figure out the scale factor when we are not suppressing
1650 scale
= pow (10.0, -1.0*decimals
);
1654 /* cannot happen, just plugs a compiler warning */
1655 fprintf (stderr
, "%s(): Unhandled fmt ` %d\n", __FUNCTION__
, fmt
);
1660 result
= strtod(temp
, NULL
) * scale
;
1667 /* -------------------------------------------------------------- */
1668 /* Eats all characters up to and including
1669 the first one of CR or LF */
1671 eat_line(gerb_file_t
*fd
)
1673 int read
= gerb_fgetc(fd
);
1675 while(read
!= 10 && read
!= 13) {
1676 if (read
== EOF
) return;
1677 read
= gerb_fgetc(fd
);
1682 /* -------------------------------------------------------------- */
1684 get_line(gerb_file_t
*fd
)
1686 int read
= gerb_fgetc(fd
);
1687 gchar
*retstring
= "";
1690 while(read
!= 10 && read
!= 13) {
1691 if (read
== EOF
) return retstring
;
1692 retstring
= g_strdup_printf("%s%c", retstring
, read
);
1694 /* since g_strdup_printf allocates memory, we need to free it */
1700 read
= gerb_fgetc(fd
);