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
,
628 case DRILL_M_NOT_IMPLEMENTED
:
629 case DRILL_M_ENDPATTERN
:
630 case DRILL_M_TIPCHECK
:
633 /* M00 has optional arguments */
635 case DRILL_M_ENDREWIND
:
636 goto drill_parse_end
;
638 case DRILL_M_METRICHEADER
:
639 state
->unit
= GERBV_UNIT_MM
;
642 drill_stats_add_error(stats
->error_list
,
644 "Undefined M code found.\n",
645 GERBV_MESSAGE_ERROR
);
650 if(state
->curr_section
== DRILL_HEADER
) {
651 drill_stats_add_error(stats
->error_list
,
653 "R codes are not allowed in the header.\n",
654 GERBV_MESSAGE_ERROR
);
656 double start_x
, start_y
;
657 double step_x
, step_y
;
661 * This is the "Repeat hole" command. Format is:
663 * This repeats the previous hole stepping in the X and
664 * Y increments give. Example:
665 * R04X0.1 -- repeats the drill hole 4 times, stepping
666 * 0.1" in the X direction. Note that the X and Y step
667 * sizes default to zero if not given and that they use
668 * the same format and units as the normal X,Y
673 start_x
= state
->curr_x
;
674 start_y
= state
->curr_y
;
678 /* figure out how many repeats there are */
681 while ( '0' <= c
&& c
<= '9') {
682 rcnt
= 10*rcnt
+ (c
- '0');
685 dprintf ("working on R code (repeat) with a number of reps equal to %d\n", rcnt
);
689 step_x
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
695 step_y
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
700 dprintf ("Getting ready to repeat the drill %d times with delta_x = %g, delta_y = %g\n", rcnt
, step_x
, step_y
);
702 /* spit out the drills */
703 for (c
= 1 ; c
<= rcnt
; c
++) {
704 state
->curr_x
= start_x
+ c
*step_x
;
705 state
->curr_y
= start_y
+ c
*step_y
;
706 dprintf (" Repeat #%d -- new location is (%g, %g)\n", c
, state
->curr_x
, state
->curr_y
);
707 curr_net
= drill_add_drill_hole (image
, state
, stats
, curr_net
);
713 drill_stats_add_error(stats
->error_list
,
715 "Drill file sets spindle speed -- ignoring.\n",
720 drill_parse_T_code(fd
, state
, image
);
724 tmps
= get_line (fd
);
725 /* Silently ignore VER,1. Not sure what others are allowed */
726 if (strcmp (tmps
, "VER,1") != 0) {
727 string
= g_strdup_printf("Undefined header line = '%s'\n",tmps
);
728 drill_stats_add_error(stats
->error_list
,
730 g_strdup_printf("Undefined header line = '%s'\n",tmps
),
739 /* Hole coordinate found. Do some parsing */
740 drill_parse_coordinate(fd
, read
, image
, state
);
742 /* add the new drill hole */
743 curr_net
= drill_add_drill_hole (image
, state
, stats
, curr_net
);
747 state
->curr_section
= DRILL_DATA
;
749 case 10 : /* White space */
755 if(state
->curr_section
== DRILL_HEADER
) {
756 /* Unrecognised crap in the header is thrown away */
757 drill_stats_add_error(stats
->error_list
,
759 "Undefined codes found in header.\n",
760 GERBV_MESSAGE_ERROR
);
763 string
= g_strdup_printf("Undefined header line = '%s'\n",
765 drill_stats_add_error(stats
->error_list
,
772 string
= g_strdup_printf("Undefined character '%c' [0x%02x] found inside data, ignoring\n",
774 drill_stats_add_error(stats
->error_list
,
777 GERBV_MESSAGE_ERROR
);
782 drill_stats_add_error(stats
->error_list
,
784 "No EOF found in drill file.\n",
785 GERBV_MESSAGE_ERROR
);
788 dprintf ("%s(): Populating file attributes\n", __FUNCTION__
);
790 switch (state
->unit
) {
792 image
->info
->attr_list
[HA_xy_units
].default_val
.int_value
= UNITS_MM
;
796 image
->info
->attr_list
[HA_xy_units
].default_val
.int_value
= UNITS_INCH
;
800 switch (state
->number_format
) {
803 image
->info
->attr_list
[HA_digits
].default_val
.int_value
= 2;
807 image
->info
->attr_list
[HA_digits
].default_val
.int_value
= 3;
811 image
->info
->attr_list
[HA_digits
].default_val
.int_value
= 4;
815 dprintf ("%s(): Keeping user specified number of decimal places (%d)\n",
817 image
->info
->attr_list
[HA_digits
].default_val
.int_value
);
824 switch (image
->format
->omit_zeros
) {
825 case GERBV_OMIT_ZEROS_LEADING
:
826 image
->info
->attr_list
[HA_supression
].default_val
.int_value
= SUP_LEAD
;
829 case GERBV_OMIT_ZEROS_TRAILING
:
830 image
->info
->attr_list
[HA_supression
].default_val
.int_value
= SUP_TRAIL
;
834 image
->info
->attr_list
[HA_supression
].default_val
.int_value
= SUP_NONE
;
841 } /* parse_drillfile */
844 /* -------------------------------------------------------------- */
846 * Checks for signs that this is a drill file
847 * Returns TRUE if it is, FALSE if not.
850 drill_file_p(gerb_file_t
*fd
, gboolean
*returnFoundBinary
)
852 char *buf
=NULL
, *tbuf
;
856 int zero
= 48; /* ascii 0 */
857 int nine
= 57; /* ascii 9 */
859 gboolean found_binary
= FALSE
;
860 gboolean found_M48
= FALSE
;
861 gboolean found_M30
= FALSE
;
862 gboolean found_percent
= FALSE
;
863 gboolean found_T
= FALSE
;
864 gboolean found_X
= FALSE
;
865 gboolean found_Y
= FALSE
;
866 gboolean end_comments
=FALSE
;
868 tbuf
= g_malloc(MAXL
);
870 GERB_FATAL_ERROR("malloc buf failed while checking for drill file.\n");
872 while (fgets(tbuf
, MAXL
, fd
->fd
) != NULL
) {
875 /* check for comments at top of file. */
877 if(g_strstr_len(buf
, len
, ";")!=NULL
){/* comments at top of file */
878 for (i
=0;i
<len
-1;++i
){
879 if(buf
[i
]=='\n' && buf
[i
+1] != ';' && buf
[i
+1] != '\r' && buf
[i
+1] != '\n'){
881 buf
=&tbuf
[i
+1]; /* set rest of parser to end of comments */
892 /* First look through the file for indications of its type */
894 /* check that file is not binary (non-printing chars) */
895 for (i
= 0; i
< len
; i
++) {
896 ascii
= (int) buf
[i
];
897 if ((ascii
> 128) || (ascii
< 0)) {
902 /* Check for M48 = start of drill header */
903 if (g_strstr_len(buf
, len
, "M48")) {
907 /* Check for M30 = end of drill program */
908 if (g_strstr_len(buf
, len
, "M30")) {
910 found_M30
= TRUE
; /* Found M30 after % = good */
914 /* Check for % on its own line at end of header */
915 if ((letter
= g_strstr_len(buf
, len
, "%")) != NULL
) {
916 if ((letter
[1] == '\r') || (letter
[1] == '\n'))
917 found_percent
= TRUE
;
920 /* Check for T<number> */
921 if ((letter
= g_strstr_len(buf
, len
, "T")) != NULL
) {
922 if (!found_T
&& (found_X
|| found_Y
)) {
923 found_T
= FALSE
; /* Found first T after X or Y */
925 if (isdigit( (int) letter
[1])) { /* verify next char is digit */
931 /* look for X<number> or Y<number> */
932 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
933 ascii
= (int) letter
[1]; /* grab char after X */
934 if ((ascii
>= zero
) && (ascii
<= nine
)) {
938 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
939 ascii
= (int) letter
[1]; /* grab char after Y */
940 if ((ascii
>= zero
) && (ascii
<= nine
)) {
944 } /* while (fgets(buf, MAXL, fd->fd) */
948 *returnFoundBinary
= found_binary
;
950 /* Now form logical expression determining if this is a drill file */
951 if ( ((found_X
|| found_Y
) && found_T
) &&
952 (found_M48
|| (found_percent
&& found_M30
)) )
954 else if (found_M48
&& found_T
&& found_percent
&& found_M30
)
955 /* Pathological case of drill file with valid header
956 and EOF but no drill XY locations. */
963 /* -------------------------------------------------------------- */
964 /* Parse tool definition. This can get a bit tricky since it can
965 appear in the header and/or data section.
966 Returns tool number on success, -1 on error */
968 drill_parse_T_code(gerb_file_t
*fd
, drill_state_t
*state
, gerbv_image_t
*image
)
971 gboolean done
= FALSE
;
974 gerbv_drill_stats_t
*stats
= image
->drill_stats
;
978 /* Sneak a peek at what's hiding after the 'T'. Ugly fix for
979 broken headers from Orcad, which is crap */
980 temp
= gerb_fgetc(fd
);
981 dprintf("Found a char %d after the T\n", temp
);
983 /* might be a tool tool change stop switch on/off*/
984 if((temp
== 'C') && ((fd
->ptr
+ 2) < fd
->datalen
)){
985 if(gerb_fgetc(fd
) == 'S'){
986 if (gerb_fgetc(fd
) == 'T' ){
988 tmps
= get_line(fd
++);
989 string
= g_strdup_printf("Tool change stop switch found: %s\n", tmps
);
990 drill_stats_add_error(stats
->error_list
,
1003 if( !(isdigit(temp
) != 0 || temp
== '+' || temp
=='-') ) {
1005 drill_stats_add_error(stats
->error_list
,
1007 "Orcad bug: Junk text found in place of tool definition.\n",
1008 GERBV_MESSAGE_ERROR
);
1009 tmps
= get_line(fd
);
1010 string
= g_strdup_printf("Junk text = %s\n",
1012 drill_stats_add_error(stats
->error_list
,
1015 GERBV_MESSAGE_NOTE
);
1018 drill_stats_add_error(stats
->error_list
,
1020 "Ignorning junk text.\n",
1021 GERBV_MESSAGE_WARNING
);
1027 tool_num
= (int) gerb_fgetint(fd
, NULL
);
1028 dprintf ("In %s: handling tool_num = %d\n", __FUNCTION__
, tool_num
);
1031 return tool_num
; /* T00 is a command to unload the drill */
1033 if ( (tool_num
< TOOL_MIN
) || (tool_num
>= TOOL_MAX
) ) {
1034 string
= g_strdup_printf("Drill number out of bounds: %d.\n", tool_num
);
1035 drill_stats_add_error(stats
->error_list
,
1038 GERBV_MESSAGE_ERROR
);
1042 /* Set the current tool to the correct one */
1043 state
->current_tool
= tool_num
;
1045 /* Check for a size definition */
1046 temp
= gerb_fgetc(fd
);
1048 /* This bit of code looks for a tool definition by scanning for strings
1049 * of form TxxC, TxxF, TxxS. */
1052 switch((char)temp
) {
1054 size
= read_double(fd
, state
->header_number_format
, GERBV_OMIT_ZEROS_TRAILING
, state
->decimals
);
1055 dprintf ("%s: Read a size of %g %s\n", __FUNCTION__
, size
,
1056 state
->unit
== GERBV_UNIT_MM
? "mm" : "inch");
1057 if(state
->unit
== GERBV_UNIT_MM
) {
1059 } else if(size
>= 4.0) {
1060 /* If the drill size is >= 4 inches, assume that this
1061 must be wrong and that the units are mils.
1062 The limit being 4 inches is because the smallest drill
1063 I've ever seen used is 0,3mm(about 12mil). Half of that
1064 seemed a bit too small a margin, so a third it is */
1065 string
= g_strdup_printf("Read a drill of diameter %g inches.\n", size
);
1066 drill_stats_add_error(stats
->error_list
,
1069 GERBV_MESSAGE_ERROR
);
1071 string
= g_strdup_printf("Assuming units are mils.\n");
1072 drill_stats_add_error(stats
->error_list
,
1075 GERBV_MESSAGE_WARNING
);
1080 if(size
<= 0. || size
>= 10000.) {
1081 string
= g_strdup_printf("Unreasonable drill size found for drill %d: %g\n", tool_num
, size
);
1082 drill_stats_add_error(stats
->error_list
,
1085 GERBV_MESSAGE_ERROR
);
1088 if(image
->aperture
[tool_num
] != NULL
) {
1089 /* allow a redefine of a tool only if the new definition is exactly the same.
1090 * This avoid lots of spurious complaints with the output of some cad
1091 * tools while keeping complaints if there is a true problem
1093 if (image
->aperture
[tool_num
]->parameter
[0] != size
||
1094 image
->aperture
[tool_num
]->type
!= GERBV_APTYPE_CIRCLE
||
1095 image
->aperture
[tool_num
]->nuf_parameters
!= 1 ||
1096 image
->aperture
[tool_num
]->unit
!= GERBV_UNIT_INCH
) {
1097 string
= g_strdup_printf("Found redefinition of drill %d.\n", tool_num
);
1098 drill_stats_add_error(stats
->error_list
,
1101 GERBV_MESSAGE_ERROR
);
1105 image
->aperture
[tool_num
] =
1106 (gerbv_aperture_t
*)g_malloc(sizeof(gerbv_aperture_t
));
1107 if (image
->aperture
[tool_num
] == NULL
) {
1108 GERB_FATAL_ERROR("malloc tool failed\n");
1110 /* make sure we zero out all aperature parameters */
1111 memset((void *)image
->aperture
[tool_num
], 0, sizeof(gerbv_aperture_t
));
1112 /* There's really no way of knowing what unit the tools
1113 are defined in without sneaking a peek in the rest of
1114 the file first. That's done in drill_guess_format() */
1115 image
->aperture
[tool_num
]->parameter
[0] = size
;
1116 image
->aperture
[tool_num
]->type
= GERBV_APTYPE_CIRCLE
;
1117 image
->aperture
[tool_num
]->nuf_parameters
= 1;
1118 image
->aperture
[tool_num
]->unit
= GERBV_UNIT_INCH
;
1122 /* Add the tool whose definition we just found into the list
1123 * of tools for this layer used to generate statistics. */
1124 stats
= image
->drill_stats
;
1125 string
= g_strdup_printf("%s", (state
->unit
== GERBV_UNIT_MM
? "mm" : "inch"));
1126 drill_stats_add_to_drill_list(stats
->drill_list
,
1128 state
->unit
== GERBV_UNIT_MM
? size
*25.4 : size
,
1135 /* Silently ignored. They're not important. */
1136 gerb_fgetint(fd
, NULL
);
1140 /* Stop when finding anything but what's expected
1141 (and put it back) */
1145 } /* switch((char)temp) */
1147 if( (temp
= gerb_fgetc(fd
)) == EOF
) {
1148 drill_stats_add_error(stats
->error_list
,
1150 "Unexpected EOF encountered header of drill file.\n",
1151 GERBV_MESSAGE_ERROR
);
1153 } /* while(!done) */ /* Done looking at tool definitions */
1155 /* Catch the tools that aren't defined.
1156 This isn't strictly a good thing, but at least something is shown */
1157 if(image
->aperture
[tool_num
] == NULL
) {
1160 image
->aperture
[tool_num
] =
1161 (gerbv_aperture_t
*)g_malloc(sizeof(gerbv_aperture_t
));
1162 if (image
->aperture
[tool_num
] == NULL
) {
1163 GERB_FATAL_ERROR("malloc tool failed\n");
1165 /* make sure we zero out all aperature parameters */
1166 memset((void *)image
->aperture
[tool_num
], 0, sizeof(gerbv_aperture_t
));
1168 /* See if we have the tool table */
1169 dia
= gerbv_get_tool_diameter(tool_num
);
1172 * There is no tool. So go out and make some.
1173 * This size calculation is, of course, totally bogus.
1175 dia
= (double)(16 + 8 * tool_num
) / 1000;
1177 * Oooh, this is sooo ugly. But some CAD systems seem to always
1178 * use T00 at the end of the file while others that don't have
1179 * tool definitions inside the file never seem to use T00 at all.
1182 string
= g_strdup_printf("Tool %02d used without being defined\n", tool_num
);
1183 drill_stats_add_error(stats
->error_list
,
1186 GERBV_MESSAGE_ERROR
);
1188 string
= g_strdup_printf("Setting a default size of %g\"\n", dia
);
1189 drill_stats_add_error(stats
->error_list
,
1192 GERBV_MESSAGE_WARNING
);
1197 image
->aperture
[tool_num
]->type
= GERBV_APTYPE_CIRCLE
;
1198 image
->aperture
[tool_num
]->nuf_parameters
= 1;
1199 image
->aperture
[tool_num
]->parameter
[0] = dia
;
1201 /* Add the tool whose definition we just found into the list
1202 * of tools for this layer used to generate statistics. */
1203 if (tool_num
!= 0) { /* Only add non-zero tool nums.
1204 * Zero = unload command. */
1205 stats
= image
->drill_stats
;
1206 string
= g_strdup_printf("%s",
1207 (state
->unit
== GERBV_UNIT_MM
? "mm" : "inch"));
1208 drill_stats_add_to_drill_list(stats
->drill_list
,
1210 state
->unit
== GERBV_UNIT_MM
? dia
*25.4 : dia
,
1214 } /* if(image->aperture[tool_num] == NULL) */
1217 } /* drill_parse_T_code */
1220 /* -------------------------------------------------------------- */
1222 drill_parse_M_code(gerb_file_t
*fd
, drill_state_t
*state
, gerbv_image_t
*image
)
1226 gerbv_drill_stats_t
*stats
= image
->drill_stats
;
1229 dprintf("---> entering drill_parse_M_code ...\n");
1231 read
[0] = gerb_fgetc(fd
);
1232 read
[1] = gerb_fgetc(fd
);
1234 if ((read
[0] == EOF
) || (read
[1] == EOF
))
1235 drill_stats_add_error(stats
->error_list
,
1237 "Unexpected EOF found while parsing M code.\n",
1238 GERBV_MESSAGE_ERROR
);
1239 op
[0] = read
[0], op
[1] = read
[1], op
[2] = 0;
1241 if (strncmp(op
, "00", 2) == 0) {
1243 result
= DRILL_M_END
;
1244 } else if (strncmp(op
, "01", 2) == 0) {
1246 result
= DRILL_M_ENDPATTERN
;
1247 } else if (strncmp(op
, "18", 2) == 0) {
1249 result
= DRILL_M_TIPCHECK
;
1250 } else if (strncmp(op
, "25", 2) == 0) {
1252 result
= DRILL_M_BEGINPATTERN
;
1253 } else if (strncmp(op
, "31", 2) == 0) {
1255 result
= DRILL_M_BEGINPATTERN
;
1256 } else if (strncmp(op
, "30", 2) == 0) {
1258 result
= DRILL_M_ENDREWIND
;
1259 } else if (strncmp(op
, "45", 2) == 0) {
1261 result
= DRILL_M_LONGMESSAGE
;
1262 } else if (strncmp(op
, "47", 2) == 0) {
1264 result
= DRILL_M_MESSAGE
;
1265 } else if (strncmp(op
, "48", 2) == 0) {
1267 result
= DRILL_M_HEADER
;
1268 } else if (strncmp(op
, "71", 2) == 0) {
1271 result
= DRILL_M_METRIC
;
1272 } else if (strncmp(op
, "72", 2) == 0) {
1275 result
= DRILL_M_IMPERIAL
;
1276 } else if (strncmp(op
, "95", 2) == 0) {
1278 result
= DRILL_M_ENDHEADER
;
1279 } else if (strncmp(op
, "97", 2) == 0) {
1281 result
= DRILL_M_CANNEDTEXT
;
1282 } else if (strncmp(op
, "98", 2) == 0) {
1284 return DRILL_M_CANNEDTEXT
;
1285 } else if (state
->curr_section
== DRILL_HEADER
&&
1286 strncmp(op
, "ET", 2) == 0) {
1287 /* METRIC is not an actual M code but a command that is only
1288 acceptable within the header.
1291 METRIC[,{TZ|LZ}][,{000.000|000.00|0000.00}]
1293 if ('R' == gerb_fgetc(fd
) &&
1294 'I' == gerb_fgetc(fd
) &&
1295 'C' == gerb_fgetc(fd
)) {
1297 if (',' == gerb_fgetc(fd
)) {
1300 /* Is it tzlz, or zerofmt? */
1301 switch ((c
= gerb_fgetc(fd
))) {
1304 if ('Z' != gerb_fgetc(fd
))
1308 dprintf ("%s(): Detected a file that probably has trailing zero supression\n", __FUNCTION__
);
1311 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_TRAILING
;
1316 dprintf ("%s(): Detected a file that probably has leading zero supression\n", __FUNCTION__
);
1319 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
1324 /* Default metric number format is 6-digit, 1 um
1325 resolution. The header number format (for T#C#
1326 definitions) is fixed to that, while the number
1327 format within the file can differ. */
1328 state
->header_number_format
=
1329 state
->number_format
= FMT_000_000
;
1330 state
->decimals
= 3;
1335 /* anticipate number format will follow */
1340 if ('0' != gerb_fgetc(fd
) ||
1341 '0' != gerb_fgetc(fd
))
1343 /* We just parsed three 0s, the remainder options
1344 so far are: .000 | .00 | 0.00 */
1345 read
[0] = gerb_fgetc(fd
);
1346 read
[1] = gerb_fgetc(fd
);
1347 if (read
[0] == EOF
|| read
[1] == EOF
)
1351 if (strcmp(op
, "0.") == 0) {
1352 /* expecting FMT_0000_00,
1353 two trailing 0s must follow */
1354 if ('0' != gerb_fgetc(fd
) ||
1355 '0' != gerb_fgetc(fd
))
1360 state
->number_format
= FMT_0000_00
;
1361 state
->decimals
= 2;
1365 if (strcmp(op
, ".0") != 0)
1367 /* must be either FMT_000_000 or FMT_000_00, depending
1368 on whether one or two 0s are following */
1369 if ('0' != gerb_fgetc(fd
))
1371 if ('0' == gerb_fgetc(fd
) && state
->autod
)
1373 state
->number_format
= FMT_000_000
;
1374 state
->decimals
= 3;
1380 state
->number_format
= FMT_000_00
;
1381 state
->decimals
= 2;
1389 drill_stats_add_error(stats
->error_list
,
1391 "Found junk after METRIC command\n",
1392 GERBV_MESSAGE_WARNING
);
1402 return DRILL_M_METRICHEADER
;
1406 result
= DRILL_M_UNKNOWN
;
1409 dprintf("<---- ...leaving drill_parse_M_code.\n");
1411 } /* drill_parse_M_code */
1414 /* -------------------------------------------------------------- */
1416 drill_parse_G_code(gerb_file_t
*fd
, gerbv_image_t
*image
)
1420 gerbv_drill_stats_t
*stats
= image
->drill_stats
;
1423 dprintf("---> entering drill_parse_G_code ...\n");
1425 read
[0] = gerb_fgetc(fd
);
1426 read
[1] = gerb_fgetc(fd
);
1428 if ((read
[0] == EOF
) || (read
[1] == EOF
)) {
1429 drill_stats_add_error(stats
->error_list
,
1431 "Unexpected EOF found while parsing G code.\n",
1432 GERBV_MESSAGE_ERROR
);
1435 op
[0] = read
[0], op
[1] = read
[1], op
[2] = 0;
1437 if (strncmp(op
, "00", 2) == 0) {
1439 result
= DRILL_G_ROUT
;
1440 } else if (strncmp(op
, "01", 2) == 0) {
1442 result
= DRILL_G_LINEARMOVE
;
1443 } else if (strncmp(op
, "02", 2) == 0) {
1445 result
= DRILL_G_CWMOVE
;
1446 } else if (strncmp(op
, "03", 2) == 0) {
1448 result
= DRILL_G_CCWMOVE
;
1449 } else if (strncmp(op
, "05", 2) == 0) {
1451 result
= DRILL_G_DRILL
;
1452 } else if (strncmp(op
, "90", 2) == 0) {
1454 result
= DRILL_G_ABSOLUTE
;
1455 } else if (strncmp(op
, "91", 2) == 0) {
1457 result
= DRILL_G_INCREMENTAL
;
1458 } else if (strncmp(op
, "93", 2) == 0) {
1460 result
= DRILL_G_ZEROSET
;
1463 result
= DRILL_G_UNKNOWN
;
1466 dprintf("<---- ...leaving drill_parse_G_code.\n");
1469 } /* drill_parse_G_code */
1472 /* -------------------------------------------------------------- */
1473 /* Parse on drill file coordinate.
1474 Returns nothing, but modifies state */
1476 drill_parse_coordinate(gerb_file_t
*fd
, char firstchar
,
1477 gerbv_image_t
*image
, drill_state_t
*state
)
1482 if(state
->coordinate_mode
== DRILL_MODE_ABSOLUTE
) {
1483 if(firstchar
== 'X') {
1484 state
->curr_x
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1485 if((read
= (char)gerb_fgetc(fd
)) == 'Y') {
1486 state
->curr_y
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1489 state
->curr_y
= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1491 } else if(state
->coordinate_mode
== DRILL_MODE_INCREMENTAL
) {
1492 if(firstchar
== 'X') {
1493 state
->curr_x
+= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1494 if((read
= (char)gerb_fgetc(fd
)) == 'Y') {
1495 state
->curr_y
+= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1498 state
->curr_y
+= read_double(fd
, state
->number_format
, image
->format
->omit_zeros
, state
->decimals
);
1502 } /* drill_parse_coordinate */
1505 /* Allocates and returns a new drill_state structure
1506 Returns state pointer on success, NULL on ERROR */
1507 static drill_state_t
*
1508 new_state(drill_state_t
*state
)
1510 state
= (drill_state_t
*)g_malloc(sizeof(drill_state_t
));
1511 if (state
!= NULL
) {
1512 /* Init structure */
1513 memset((void *)state
, 0, sizeof(drill_state_t
));
1514 state
->curr_section
= DRILL_NONE
;
1515 state
->coordinate_mode
= DRILL_MODE_ABSOLUTE
;
1516 state
->origin_x
= 0.0;
1517 state
->origin_y
= 0.0;
1518 state
->unit
= GERBV_UNIT_UNSPECIFIED
;
1519 state
->backup_number_format
= FMT_000_000
; /* only used for METRIC */
1520 state
->header_number_format
= state
->number_format
= FMT_00_0000
; /* i. e. INCH */
1522 state
->decimals
= 4;
1529 /* -------------------------------------------------------------- */
1530 /* Reads one double from fd and returns it.
1531 If a decimal point is found, fmt is not used. */
1533 read_double(gerb_file_t
*fd
, enum number_fmt_t fmt
, gerbv_omit_zeros_t omit_zeros
, int decimals
)
1536 char temp
[DRILL_READ_DOUBLE_SIZE
];
1537 int i
= 0, ndigits
= 0;
1539 gboolean decimal_point
= FALSE
;
1540 gboolean sign_prepend
= FALSE
;
1542 dprintf("%s(%p, %d, %d, %d)\n", __FUNCTION__
, fd
, fmt
, omit_zeros
, decimals
);
1544 memset(temp
, 0, sizeof(temp
));
1546 read
= gerb_fgetc(fd
);
1547 while(read
!= EOF
&& i
< (DRILL_READ_DOUBLE_SIZE
-1) &&
1548 (isdigit(read
) || read
== '.' || read
== ',' || read
== '+' || read
== '-')) {
1549 if(read
== ',' || read
== '.') decimal_point
= TRUE
;
1552 * FIXME -- if we are going to do this, don't we need a
1553 * locale-independent strtod()? I think pcb has one.
1556 read
= '.'; /* adjust for strtod() */
1558 if(isdigit(read
)) ndigits
++;
1560 if(read
== '-' || read
== '+')
1561 sign_prepend
= TRUE
;
1563 temp
[i
++] = (char)read
;
1564 read
= gerb_fgetc(fd
);
1569 if (decimal_point
) {
1570 result
= strtod(temp
, NULL
);
1574 char tmp2
[DRILL_READ_DOUBLE_SIZE
];
1576 memset(tmp2
, 0, sizeof(tmp2
));
1578 dprintf("%s(): omit_zeros = %d, fmt = %d\n", __FUNCTION__
, omit_zeros
, fmt
);
1579 /* Nothing to take care for when leading zeros are
1581 if (omit_zeros
== GERBV_OMIT_ZEROS_TRAILING
) {
1600 wantdigits
= decimals
;
1604 /* cannot happen, just plugs a compiler warning */
1605 fprintf(stderr
, "%s(): omit_zeros == GERBV_OMIT_ZEROS_TRAILING but fmt = %d.\n"
1606 "This should never have happened\n", __FUNCTION__
, fmt
);
1610 /* need to add an extra char for '+' or '-' */
1616 * we need at least wantdigits + one for the decimal place
1617 * + one for the terminating null character
1619 if (wantdigits
> sizeof(tmp2
) - 2) {
1620 fprintf(stderr
, "%s(): wantdigits = %d which exceeds the maximum allowed size\n",
1621 __FUNCTION__
, wantdigits
);
1626 * After we have read the correct number of digits
1627 * preceeding the decimal point, insert a decimal point
1628 * and append the rest of the digits.
1630 dprintf("%s(): wantdigits = %d, strlen(\"%s\") = %ld\n",
1631 __FUNCTION__
, wantdigits
, temp
, (long) strlen(temp
));
1632 for (i
= 0 ; i
< wantdigits
; i
++) {
1635 tmp2
[wantdigits
] = '.';
1636 for (i
= wantdigits
; i
<= strlen(temp
) ; i
++) {
1637 tmp2
[i
+1] = temp
[i
];
1639 dprintf("%s(): After dealing with trailing zero supression, convert \"%s\"\n", __FUNCTION__
, tmp2
);
1642 for (i
= 0 ; i
<= strlen(tmp2
) && i
< sizeof (temp
) ; i
++) {
1649 * figure out the scale factor when we are not suppressing
1667 scale
= pow (10.0, -1.0*decimals
);
1671 /* cannot happen, just plugs a compiler warning */
1672 fprintf (stderr
, "%s(): Unhandled fmt ` %d\n", __FUNCTION__
, fmt
);
1677 result
= strtod(temp
, NULL
) * scale
;
1684 /* -------------------------------------------------------------- */
1685 /* Eats all characters up to and including
1686 the first one of CR or LF */
1688 eat_line(gerb_file_t
*fd
)
1690 int read
= gerb_fgetc(fd
);
1692 while(read
!= 10 && read
!= 13) {
1693 if (read
== EOF
) return;
1694 read
= gerb_fgetc(fd
);
1698 /* -------------------------------------------------------------- */
1700 get_line(gerb_file_t
*fd
)
1702 int read
= gerb_fgetc(fd
);
1704 gchar
*tmps
=g_strdup("");
1706 while(read
!= 10 && read
!= 13) {
1709 retstring
= g_strdup_printf("%s%c", tmps
, read
);
1711 /* since g_strdup_printf allocates memory, we need to free it */
1717 read
= gerb_fgetc(fd
);