00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00028
00029
00030
00031
00032
00033
00034
00035 #ifdef HAVE_CONFIG_H
00036 #include <config.h>
00037 #endif
00038
00039 #include <stdlib.h>
00040 #include <glib.h>
00041 #include <locale.h>
00042
00043 #ifdef HAVE_STRING_H
00044 #include <string.h>
00045 #endif
00046
00047 #include <math.h>
00048 #include <ctype.h>
00049
00050 #include <sys/types.h>
00051 #include <sys/stat.h>
00052
00053 #ifdef HAVE_UNISTD_H
00054 #include <unistd.h>
00055 #endif
00056
00057 #include "gerbv.h"
00058 #include "drill.h"
00059 #include "drill_stats.h"
00060
00061 #include "common.h"
00062
00063
00064 #define dprintf if(DEBUG) printf
00065
00066 #define NOT_IMPL(fd, s) do { \
00067 GERB_MESSAGE("Not Implemented:%s\n", s); \
00068 } while(0)
00069
00070 #define MAXL 200
00071
00072
00073 #undef max
00074 #define max(a,b) ((a) > (b) ? (a) : (b))
00075 #undef min
00076 #define min(a,b) ((a) < (b) ? (a) : (b))
00077
00078 enum drill_file_section_t {DRILL_NONE, DRILL_HEADER, DRILL_DATA};
00079 enum drill_coordinate_mode_t {DRILL_MODE_ABSOLUTE, DRILL_MODE_INCREMENTAL};
00080
00081 enum drill_m_code_t {DRILL_M_UNKNOWN, DRILL_M_NOT_IMPLEMENTED,
00082 DRILL_M_END, DRILL_M_ENDREWIND,
00083 DRILL_M_MESSAGE, DRILL_M_LONGMESSAGE,
00084 DRILL_M_HEADER, DRILL_M_ENDHEADER,
00085 DRILL_M_METRIC, DRILL_M_IMPERIAL,
00086 DRILL_M_BEGINPATTERN, DRILL_M_ENDPATTERN,
00087 DRILL_M_CANNEDTEXT, DRILL_M_TIPCHECK,
00088 DRILL_M_METRICHEADER, DRILL_M_IMPERIALHEADER};
00089
00090
00091 enum drill_g_code_t {DRILL_G_ABSOLUTE, DRILL_G_INCREMENTAL,
00092 DRILL_G_ZEROSET, DRILL_G_UNKNOWN,
00093 DRILL_G_ROUT, DRILL_G_DRILL,
00094 DRILL_G_LINEARMOVE, DRILL_G_CWMOVE, DRILL_G_CCWMOVE};
00095
00096 enum number_fmt_t {FMT_00_0000 ,
00097 FMT_000_000 ,
00098 FMT_000_00 ,
00099 FMT_0000_00 ,
00100 FMT_USER };
00101
00102 typedef struct drill_state {
00103 double curr_x;
00104 double curr_y;
00105 int current_tool;
00106 int curr_section;
00107 int coordinate_mode;
00108 double origin_x;
00109 double origin_y;
00110 gerbv_unit_t unit;
00111
00112
00113
00114
00115
00116
00117 enum number_fmt_t number_format, header_number_format;
00118
00119 enum number_fmt_t backup_number_format;
00120
00121
00122 int autod;
00123
00124
00125
00126
00127 int decimals;
00128
00129 } drill_state_t;
00130
00131
00132 static int drill_parse_G_code(gerb_file_t *fd, gerbv_image_t *image);
00133 static int drill_parse_M_code(gerb_file_t *fd, drill_state_t *state,
00134 gerbv_image_t *image);
00135 static int drill_parse_T_code(gerb_file_t *fd, drill_state_t *state,
00136 gerbv_image_t *image);
00137 static void drill_parse_coordinate(gerb_file_t *fd, char firstchar,
00138 gerbv_image_t *image, drill_state_t *state);
00139 static drill_state_t *new_state(drill_state_t *state);
00140 static double read_double(gerb_file_t *fd, enum number_fmt_t fmt,
00141 gerbv_omit_zeros_t omit_zeros, int decimals);
00142 static void eat_line(gerb_file_t *fd);
00143 static char *get_line(gerb_file_t *fd);
00144
00145
00146
00147
00148
00149
00150 static const char *supression_list[] = {
00151 "None",
00152 #define SUP_NONE 0
00153 "Leading",
00154 #define SUP_LEAD 1
00155 "Trailing",
00156 #define SUP_TRAIL 2
00157 0
00158 };
00159
00160 static const char *units_list[] = {
00161 "inch",
00162 #define UNITS_INCH 0
00163 "mil (1/1000 inch)",
00164 #define UNITS_MIL 1
00165 "mm",
00166 #define UNITS_MM 2
00167 0
00168 };
00169
00170 static gerbv_HID_Attribute drill_attribute_list[] = {
00171
00172 {"Autodetect file format", "Try to autodetect the file format",
00173 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
00174 #define HA_auto 0
00175
00176 {"zero_supression", "Zero supression",
00177 HID_Enum, 0, 0, {0, 0, 0}, supression_list, 0},
00178 #define HA_supression 1
00179
00180 {"units", "Units",
00181 HID_Enum, 0, 0, {0, 0, 0}, units_list, 0},
00182 #define HA_xy_units 2
00183
00184 #if 0
00185 {"tool_units", "Tool size units",
00186 HID_Enum, 0, 0, {0, 0, 0}, units_list, 0},
00187 #define HA_tool_units 3
00188 #endif
00189
00190 {"digits", "Number of digits",
00191 HID_Integer, 0, 20, {5, 0, 0}, 0, 0},
00192 #define HA_digits 3
00193 };
00194
00195
00196 void
00197 drill_attribute_merge (gerbv_HID_Attribute *dest, int ndest, gerbv_HID_Attribute *src, int nsrc)
00198 {
00199 int i, j;
00200
00201
00202
00203
00204
00205
00206 for (i = 0 ; i < nsrc ; i++) {
00207
00208 j = 0;
00209 while (j < ndest && strcmp (src[i].name, dest[j].name) != 0)
00210 j++;
00211
00212
00213 if (j < ndest && src[i].type == dest[j].type) {
00214 dest[j].default_val = src[i].default_val;
00215 }
00216 }
00217
00218 }
00219
00220
00221
00222 gerbv_image_t *
00223 parse_drillfile(gerb_file_t *fd, gerbv_HID_Attribute *attr_list, int n_attr, int reload)
00224 {
00225 drill_state_t *state = NULL;
00226 gerbv_image_t *image = NULL;
00227 gerbv_net_t *curr_net = NULL;
00228 int read;
00229 gerbv_drill_stats_t *stats;
00230 int i;
00231 gchar *tmps;
00232 gchar *string;
00233
00234
00235
00236
00237
00238
00239 setlocale(LC_NUMERIC, "C" );
00240
00241
00242 dprintf("In parse_drillfile, about to create image for this layer\n");
00243
00244 image = gerbv_create_image(image, "Excellon Drill File");
00245 if (image == NULL)
00246 GERB_FATAL_ERROR("malloc image failed\n");
00247
00248 if (reload && attr_list != NULL) {
00249 image->info->attr_list = attr_list;
00250 image->info->n_attr = n_attr;
00251 } else {
00252
00253
00254
00255
00256 image->info->n_attr = sizeof (drill_attribute_list) / sizeof (drill_attribute_list[0]);
00257 image->info->attr_list = (gerbv_HID_Attribute *) malloc (sizeof (drill_attribute_list));
00258 if (image->info->attr_list == NULL) {
00259 fprintf (stderr, "%s(): malloc failed\n", __FUNCTION__);
00260 exit (1);
00261 }
00262 dprintf ("%s(): New attribute list is %p\n", __FUNCTION__, image->info->attr_list);
00263
00264 for (i = 0 ; i < image->info->n_attr ; i++) {
00265 image->info->attr_list[i] = drill_attribute_list[i];
00266 }
00267
00268
00269 drill_attribute_merge (image->info->attr_list, image->info->n_attr,
00270 attr_list, n_attr);
00271 }
00272
00273 curr_net = image->netlist;
00274 curr_net->layer = image->layers;
00275 curr_net->state = image->states;
00276 image->layertype = GERBV_LAYERTYPE_DRILL;
00277 stats = gerbv_drill_stats_new();
00278 if (stats == NULL)
00279 GERB_FATAL_ERROR("malloc stats failed\n");
00280 image->drill_stats = stats;
00281
00282
00283 state = new_state(state);
00284 if (state == NULL)
00285 GERB_FATAL_ERROR("malloc state failed\n");
00286
00287 image->format = (gerbv_format_t *)g_malloc(sizeof(gerbv_format_t));
00288 if (image->format == NULL)
00289 GERB_FATAL_ERROR("malloc format failed\n");
00290 memset((void *)image->format, 0, sizeof(gerbv_format_t));
00291 image->format->omit_zeros = GERBV_OMIT_ZEROS_UNSPECIFIED;
00292
00293
00294 if (!image->info->attr_list[HA_auto].default_val.int_value) {
00295 state->autod = 0;
00296 state->number_format = FMT_USER;
00297 state->decimals = image->info->attr_list[HA_digits].default_val.int_value;
00298 if (image->info->attr_list[HA_xy_units].default_val.int_value == UNITS_MM)
00299 state->unit = GERBV_UNIT_MM;
00300 switch (image->info->attr_list[HA_supression].default_val.int_value) {
00301 case SUP_LEAD:
00302 image->format->omit_zeros = GERBV_OMIT_ZEROS_LEADING;
00303 break;
00304
00305 case SUP_TRAIL:
00306 image->format->omit_zeros = GERBV_OMIT_ZEROS_TRAILING;
00307 break;
00308
00309 default:
00310 image->format->omit_zeros = GERBV_OMIT_ZEROS_EXPLICIT;
00311 break;
00312 }
00313 }
00314
00315 dprintf("%s(): Starting parsing of drill file\n", __FUNCTION__);
00316 while ((read = gerb_fgetc(fd)) != EOF) {
00317
00318 switch ((char) read) {
00319 case ';' :
00320
00321 eat_line(fd);
00322 break;
00323 case 'D' :
00324 gerb_ungetc (fd);
00325 tmps = get_line (fd);
00326 if (strcmp (tmps, "DETECT,ON") == 0 ||
00327 strcmp (tmps, "DETECT,GERBV_APERTURE_STATE_OFF") == 0) {
00328 gchar *tmps2;
00329 gchar *tmps3;
00330 if (strcmp (tmps, "DETECT,ON") == 0)
00331 tmps3 = "ON";
00332 else
00333 tmps3 = "GERBV_APERTURE_STATE_OFF";
00334
00335
00336 if (stats->detect) {
00337 tmps2 = g_strdup_printf ("%s\n%s", stats->detect, tmps3);
00338 g_free (stats->detect);
00339 } else {
00340 tmps2 = g_strdup_printf ("%s", tmps3);
00341 }
00342 stats->detect = tmps2;
00343 } else {
00344 string = g_strdup_printf("Undefined header line = '%s'\n",tmps);
00345 drill_stats_add_error(stats->error_list,
00346 -1,
00347 string,
00348 GERBV_MESSAGE_NOTE);
00349 g_free(string);
00350 }
00351 g_free (tmps);
00352 break;
00353 case 'F' :
00354 gerb_ungetc (fd);
00355 tmps = get_line (fd);
00356
00357 if (strcmp (tmps, "FMAT,2") != 0) {
00358 string = g_strdup_printf("Undefined header line = '%s'\n",tmps);
00359 drill_stats_add_error(stats->error_list,
00360 -1,
00361 string,
00362 GERBV_MESSAGE_NOTE);
00363 g_free(string);
00364 }
00365 g_free (tmps);
00366 break;
00367
00368 case 'G':
00369
00370 switch(drill_parse_G_code(fd, image)) {
00371 case DRILL_G_ROUT :
00372 drill_stats_add_error(stats->error_list,
00373 -1,
00374 "Rout mode data is not supported\n",
00375 GERBV_MESSAGE_ERROR);
00376 break;
00377 case DRILL_G_DRILL :
00378 break;
00379 case DRILL_G_ABSOLUTE :
00380 state->coordinate_mode = DRILL_MODE_ABSOLUTE;
00381 break;
00382 case DRILL_G_INCREMENTAL :
00383 state->coordinate_mode = DRILL_MODE_INCREMENTAL;
00384 break;
00385 case DRILL_G_ZEROSET :
00386 if((read = gerb_fgetc(fd)) == EOF)
00387 drill_stats_add_error(stats->error_list,
00388 -1,
00389 "Unexpected EOF found.\n",
00390 GERBV_MESSAGE_ERROR);
00391 drill_parse_coordinate(fd, (char)read, image, state);
00392 state->origin_x = state->curr_x;
00393 state->origin_y = state->curr_y;
00394 break;
00395 default :
00396 eat_line(fd);
00397 break;
00398 }
00399 break;
00400 case 'I':
00401 if (state->curr_section != DRILL_HEADER)
00402 break;
00403 {
00404 int c = gerb_fgetc(fd);
00405 switch (c) {
00406 case 'N':
00407 if ('C' == gerb_fgetc(fd)) {
00408 if ('H' == gerb_fgetc(fd)) {
00409 state->unit = GERBV_UNIT_INCH;
00410
00411
00412 if (',' == gerb_fgetc(fd)) {
00413 c = gerb_fgetc(fd);
00414 if (c != EOF && 'Z' == gerb_fgetc(fd)) {
00415 switch (c) {
00416 case 'L':
00417 if (state->autod) {
00418 image->format->omit_zeros = GERBV_OMIT_ZEROS_TRAILING;
00419 state->header_number_format =
00420 state->number_format = FMT_00_0000;
00421 state->decimals = 4;
00422 }
00423 break;
00424
00425 case 'T':
00426 if (state->autod) {
00427 image->format->omit_zeros = GERBV_OMIT_ZEROS_LEADING;
00428 state->header_number_format =
00429 state->number_format = FMT_00_0000;
00430 state->decimals = 4;
00431 }
00432 break;
00433
00434 default:
00435 drill_stats_add_error(stats->error_list,
00436 -1,
00437 "Found junk after INCH command\n",
00438 GERBV_MESSAGE_WARNING);
00439 break;
00440 }
00441 } else {
00442 drill_stats_add_error(stats->error_list,
00443 -1,
00444 "Found junk after INCH command\n",
00445 GERBV_MESSAGE_WARNING);
00446 }
00447 }
00448 }
00449 }
00450 break;
00451 case 'C':
00452 if ('I' == gerb_fgetc(fd))
00453 if (',' == gerb_fgetc(fd))
00454 if ('O' == gerb_fgetc(fd)) {
00455 if ('N' == (c = gerb_fgetc(fd)))
00456 state->coordinate_mode = DRILL_MODE_INCREMENTAL;
00457 else if ('F' == c) if ('F' == gerb_fgetc(fd))
00458 state->coordinate_mode = DRILL_MODE_ABSOLUTE;
00459 }
00460 break;
00461 }
00462 eat_line(fd);
00463 }
00464 break;
00465
00466 case 'M':
00467 switch(drill_parse_M_code(fd, state, image)) {
00468 case DRILL_M_HEADER :
00469 state->curr_section = DRILL_HEADER;
00470 break;
00471 case DRILL_M_ENDHEADER :
00472 state->curr_section = DRILL_DATA;
00473
00474 if (image->format->omit_zeros == GERBV_OMIT_ZEROS_UNSPECIFIED) {
00475
00476
00477
00478
00479
00480
00481
00482
00483 drill_stats_add_error(stats->error_list,
00484 -1,
00485 "End of Excellon header reached but no leading/trailing zero handling specified.\n",
00486 GERBV_MESSAGE_ERROR);
00487 drill_stats_add_error(stats->error_list,
00488 -1,
00489 "Assuming leading zeros.\n",
00490 GERBV_MESSAGE_WARNING);
00491 image->format->omit_zeros = GERBV_OMIT_ZEROS_LEADING;
00492 }
00493 break;
00494 case DRILL_M_METRIC :
00495 if (state->unit == GERBV_UNIT_UNSPECIFIED &&
00496 state->curr_section != DRILL_HEADER) {
00497 drill_stats_add_error(stats->error_list,
00498 -1,
00499 "M71 code found but no METRIC specification in header.\n",
00500 GERBV_MESSAGE_ERROR);
00501 drill_stats_add_error(stats->error_list,
00502 -1,
00503 "Assuming all tool sizes are MM.\n",
00504 GERBV_MESSAGE_WARNING);
00505 int tool_num;
00506 double size;
00507 stats = image->drill_stats;
00508 for (tool_num = TOOL_MIN; tool_num < TOOL_MAX; tool_num++) {
00509 if (image->aperture && image->aperture[tool_num]) {
00510
00511
00512 size = image->aperture[tool_num]->parameter[0];
00513 drill_stats_modify_drill_list(stats->drill_list,
00514 tool_num,
00515 size,
00516 "MM");
00517
00518
00519
00520 image->aperture[tool_num]->parameter[0] /= 25.4;
00521 }
00522 }
00523 }
00524 if (state->autod) {
00525 state->number_format = state->backup_number_format;
00526 state->unit = GERBV_UNIT_MM;
00527 }
00528 break;
00529 case DRILL_M_IMPERIAL :
00530 if (state->autod) {
00531 if (state->number_format != FMT_00_0000)
00532
00533 state->backup_number_format = state->number_format;
00534 state->number_format = FMT_00_0000;
00535 state->decimals = 4;
00536 state->unit = GERBV_UNIT_INCH;
00537 }
00538
00539 break;
00540 case DRILL_M_LONGMESSAGE :
00541 case DRILL_M_MESSAGE :
00542 case DRILL_M_CANNEDTEXT :
00543 tmps = get_line(fd);
00544 string = g_strdup_printf("Message embedded in drill file: '%s'\n",
00545 tmps);
00546 drill_stats_add_error(stats->error_list,
00547 -1,
00548 string,
00549 GERBV_MESSAGE_NOTE);
00550 g_free(string);
00551 g_free(tmps);
00552 break;
00553 case DRILL_M_NOT_IMPLEMENTED :
00554 case DRILL_M_ENDPATTERN :
00555 case DRILL_M_TIPCHECK :
00556 break;
00557 case DRILL_M_END :
00558
00559 eat_line(fd);
00560 case DRILL_M_ENDREWIND :
00561 goto drill_parse_end;
00562 break;
00563 case DRILL_M_METRICHEADER :
00564 state->unit = GERBV_UNIT_MM;
00565 break;
00566 default:
00567 drill_stats_add_error(stats->error_list,
00568 -1,
00569 "Undefined M code found.\n",
00570 GERBV_MESSAGE_ERROR);
00571 }
00572 break;
00573
00574 case 'S':
00575 drill_stats_add_error(stats->error_list,
00576 -1,
00577 "Drill file sets spindle speed -- ignoring.\n",
00578 GERBV_MESSAGE_NOTE);
00579 eat_line(fd);
00580 break;
00581 case 'T':
00582 drill_parse_T_code(fd, state, image);
00583 break;
00584 case 'V' :
00585 gerb_ungetc (fd);
00586 tmps = get_line (fd);
00587
00588 if (strcmp (tmps, "VER,1") != 0) {
00589 string = g_strdup_printf("Undefined header line = '%s'\n",tmps);
00590 drill_stats_add_error(stats->error_list,
00591 -1,
00592 g_strdup_printf("Undefined header line = '%s'\n",tmps),
00593 GERBV_MESSAGE_NOTE);
00594 g_free(string);
00595 }
00596 g_free (tmps);
00597 break;
00598
00599 case 'X':
00600 case 'Y':
00601
00602 drill_parse_coordinate(fd, read, image, state);
00603
00604
00605 drill_stats_increment_drill_counter(image->drill_stats->drill_list,
00606 state->current_tool);
00607
00608 curr_net->next = (gerbv_net_t *)g_malloc(sizeof(gerbv_net_t));
00609 if (curr_net->next == NULL)
00610 GERB_FATAL_ERROR("malloc curr_net->next failed\n");
00611 curr_net = curr_net->next;
00612 memset((void *)curr_net, 0, sizeof(gerbv_net_t));
00613 curr_net->layer = image->layers;
00614 curr_net->state = image->states;
00615 curr_net->start_x = (double)state->curr_x;
00616 curr_net->start_y = (double)state->curr_y;
00617
00618
00619 if(state->unit == GERBV_UNIT_MM) {
00620 curr_net->start_x /= 25.4;
00621 curr_net->start_y /= 25.4;
00622
00623
00624 curr_net->state->unit = GERBV_UNIT_INCH;
00625 }
00626
00627 curr_net->stop_x = curr_net->start_x - state->origin_x;
00628 curr_net->stop_y = curr_net->start_y - state->origin_y;
00629 curr_net->aperture = state->current_tool;
00630 curr_net->aperture_state = GERBV_APERTURE_STATE_FLASH;
00631
00632
00633
00634
00635
00636
00637 if(image->aperture[state->current_tool] == NULL)
00638 break;
00639
00640 image->info->min_x =
00641 min(image->info->min_x,
00642 (curr_net->start_x -
00643 image->aperture[state->current_tool]->parameter[0] / 2));
00644 image->info->min_y =
00645 min(image->info->min_y,
00646 (curr_net->start_y -
00647 image->aperture[state->current_tool]->parameter[0] / 2));
00648 image->info->max_x =
00649 max(image->info->max_x,
00650 (curr_net->start_x +
00651 image->aperture[state->current_tool]->parameter[0] / 2));
00652 image->info->max_y =
00653 max(image->info->max_y,
00654 (curr_net->start_y +
00655 image->aperture[state->current_tool]->parameter[0] / 2));
00656 break;
00657 case '%':
00658 state->curr_section = DRILL_DATA;
00659 break;
00660 case 10 :
00661 case 13 :
00662 case ' ' :
00663 case '\t' :
00664 break;
00665 default:
00666 if(state->curr_section == DRILL_HEADER) {
00667
00668 drill_stats_add_error(stats->error_list,
00669 -1,
00670 "Undefined codes found in header.\n",
00671 GERBV_MESSAGE_ERROR);
00672 gerb_ungetc(fd);
00673 tmps = get_line(fd);
00674 string = g_strdup_printf("Undefined header line = '%s'\n",
00675 tmps);
00676 drill_stats_add_error(stats->error_list,
00677 -1,
00678 string,
00679 GERBV_MESSAGE_NOTE);
00680 g_free(string);
00681 g_free (tmps);
00682 } else {
00683 string = g_strdup_printf("Undefined character '%c' [0x%02x] found inside data, ignoring\n",
00684 read, read);
00685 drill_stats_add_error(stats->error_list,
00686 -1,
00687 string,
00688 GERBV_MESSAGE_ERROR);
00689 g_free(string);
00690 }
00691 }
00692 }
00693 drill_stats_add_error(stats->error_list,
00694 -1,
00695 "No EOF found in drill file.\n",
00696 GERBV_MESSAGE_ERROR);
00697
00698 drill_parse_end:
00699 dprintf ("%s(): Populating file attributes\n", __FUNCTION__);
00700
00701 switch (state->unit) {
00702 case GERBV_UNIT_MM:
00703 image->info->attr_list[HA_xy_units].default_val.int_value = UNITS_MM;
00704 break;
00705
00706 default:
00707 image->info->attr_list[HA_xy_units].default_val.int_value = UNITS_INCH;
00708 break;
00709 }
00710
00711 switch (state->number_format) {
00712 case FMT_000_00:
00713 case FMT_0000_00:
00714 image->info->attr_list[HA_digits].default_val.int_value = 2;
00715 break;
00716
00717 case FMT_000_000:
00718 image->info->attr_list[HA_digits].default_val.int_value = 3;
00719 break;
00720
00721 case FMT_00_0000:
00722 image->info->attr_list[HA_digits].default_val.int_value = 4;
00723 break;
00724
00725 case FMT_USER:
00726 dprintf ("%s(): Keeping user specified number of decimal places (%d)\n",
00727 __FUNCTION__,
00728 image->info->attr_list[HA_digits].default_val.int_value);
00729 break;
00730
00731 default:
00732 break;
00733 }
00734
00735 switch (image->format->omit_zeros) {
00736 case GERBV_OMIT_ZEROS_LEADING:
00737 image->info->attr_list[HA_supression].default_val.int_value = SUP_LEAD;
00738 break;
00739
00740 case GERBV_OMIT_ZEROS_TRAILING:
00741 image->info->attr_list[HA_supression].default_val.int_value = SUP_TRAIL;
00742 break;
00743
00744 default:
00745 image->info->attr_list[HA_supression].default_val.int_value = SUP_NONE;
00746 break;
00747 }
00748
00749 g_free(state);
00750
00751 return image;
00752 }
00753
00754
00755
00756
00757
00758
00759
00760 gboolean
00761 drill_file_p(gerb_file_t *fd, gboolean *returnFoundBinary)
00762 {
00763 char *buf;
00764 int len = 0;
00765 char *letter;
00766 int ascii;
00767 int zero = 48;
00768 int nine = 57;
00769 int i;
00770 gboolean found_binary = FALSE;
00771 gboolean found_M48 = FALSE;
00772 gboolean found_M30 = FALSE;
00773 gboolean found_percent = FALSE;
00774 gboolean found_T = FALSE;
00775 gboolean found_X = FALSE;
00776 gboolean found_Y = FALSE;
00777
00778 buf = g_malloc(MAXL);
00779 if (buf == NULL)
00780 GERB_FATAL_ERROR("malloc buf failed while checking for drill file.\n");
00781
00782 while (fgets(buf, MAXL, fd->fd) != NULL) {
00783 len = strlen(buf);
00784
00785
00786
00787
00788 for (i = 0; i < len; i++) {
00789 ascii = (int) buf[i];
00790 if ((ascii > 128) || (ascii < 0)) {
00791 found_binary = TRUE;
00792 }
00793 }
00794
00795
00796 if (g_strstr_len(buf, len, "M48")) {
00797 found_M48 = TRUE;
00798 }
00799
00800
00801 if (g_strstr_len(buf, len, "M30")) {
00802 if (found_percent) {
00803 found_M30 = TRUE;
00804 }
00805 }
00806
00807
00808 if ((letter = g_strstr_len(buf, len, "%")) != NULL) {
00809 if ((letter[1] == '\r') || (letter[1] == '\n'))
00810 found_percent = TRUE;
00811 }
00812
00813
00814 if ((letter = g_strstr_len(buf, len, "T")) != NULL) {
00815 if (!found_T && (found_X || found_Y)) {
00816 found_T = FALSE;
00817 } else {
00818 if (isdigit( (int) letter[1])) {
00819 found_T = TRUE;
00820 }
00821 }
00822 }
00823
00824
00825 if ((letter = g_strstr_len(buf, len, "X")) != NULL) {
00826 ascii = (int) letter[1];
00827 if ((ascii >= zero) && (ascii <= nine)) {
00828 found_X = TRUE;
00829 }
00830 }
00831 if ((letter = g_strstr_len(buf, len, "Y")) != NULL) {
00832 ascii = (int) letter[1];
00833 if ((ascii >= zero) && (ascii <= nine)) {
00834 found_Y = TRUE;
00835 }
00836 }
00837 }
00838
00839 rewind(fd->fd);
00840 free(buf);
00841 *returnFoundBinary = found_binary;
00842
00843
00844 if ( ((found_X || found_Y) && found_T) &&
00845 (found_M48 || (found_percent && found_M30)) )
00846 return TRUE;
00847 else if (found_M48 && found_T && found_percent && found_M30)
00848
00849
00850 return TRUE;
00851 else
00852 return FALSE;
00853 }
00854
00855
00856
00857
00858
00859
00860 static int
00861 drill_parse_T_code(gerb_file_t *fd, drill_state_t *state, gerbv_image_t *image)
00862 {
00863 int tool_num;
00864 gboolean done = FALSE;
00865 int temp;
00866 double size;
00867 gerbv_drill_stats_t *stats = image->drill_stats;
00868 gchar *tmps;
00869 gchar *string;
00870
00871
00872
00873 temp = gerb_fgetc(fd);
00874 dprintf("Found a char %d after the T\n", temp);
00875
00876
00877 if((temp == 'C') && ((fd->ptr + 2) < fd->datalen)){
00878 if(gerb_fgetc(fd) == 'S'){
00879 if (gerb_fgetc(fd) == 'T' ){
00880 fd->ptr -= 4;
00881 tmps = get_line(fd++);
00882 string = g_strdup_printf("Tool change stop switch found: %s\n", tmps);
00883 drill_stats_add_error(stats->error_list,
00884 -1,
00885 string,
00886 GERBV_MESSAGE_NOTE);
00887 g_free(string);
00888 g_free (tmps);
00889 return -1;
00890 }
00891 gerb_ungetc(fd);
00892 }
00893 gerb_ungetc(fd);
00894 }
00895
00896 if( !(isdigit(temp) != 0 || temp == '+' || temp =='-') ) {
00897 if(temp != EOF) {
00898 drill_stats_add_error(stats->error_list,
00899 -1,
00900 "Orcad bug: Junk text found in place of tool definition.\n",
00901 GERBV_MESSAGE_ERROR);
00902 tmps = get_line(fd);
00903 string = g_strdup_printf("Junk text = %s\n",
00904 tmps);
00905 drill_stats_add_error(stats->error_list,
00906 -1,
00907 string,
00908 GERBV_MESSAGE_NOTE);
00909 g_free(string);
00910 g_free (tmps);
00911 drill_stats_add_error(stats->error_list,
00912 -1,
00913 "Ignorning junk text.\n",
00914 GERBV_MESSAGE_WARNING);
00915 }
00916 return -1;
00917 }
00918 gerb_ungetc(fd);
00919
00920 tool_num = (int) gerb_fgetint(fd, NULL);
00921 dprintf ("In %s: handling tool_num = %d\n", __FUNCTION__, tool_num);
00922
00923 if (tool_num == 0)
00924 return tool_num;
00925
00926 if ( (tool_num < TOOL_MIN) || (tool_num >= TOOL_MAX) ) {
00927 string = g_strdup_printf("Drill number out of bounds: %d.\n", tool_num);
00928 drill_stats_add_error(stats->error_list,
00929 -1,
00930 string,
00931 GERBV_MESSAGE_ERROR);
00932 g_free(string);
00933 }
00934
00935
00936 state->current_tool = tool_num;
00937
00938
00939 temp = gerb_fgetc(fd);
00940
00941
00942
00943 while(!done) {
00944
00945 switch((char)temp) {
00946 case 'C':
00947 size = read_double(fd, state->header_number_format, GERBV_OMIT_ZEROS_TRAILING, state->decimals);
00948 dprintf ("%s: Read a size of %g %s\n", __FUNCTION__, size,
00949 state->unit == GERBV_UNIT_MM ? "mm" : "inch");
00950 if(state->unit == GERBV_UNIT_MM) {
00951 size /= 25.4;
00952 } else if(size >= 4.0) {
00953
00954
00955
00956
00957
00958 string = g_strdup_printf("Read a drill of diameter %g inches.\n", size);
00959 drill_stats_add_error(stats->error_list,
00960 -1,
00961 string,
00962 GERBV_MESSAGE_ERROR);
00963 g_free(string);
00964 string = g_strdup_printf("Assuming units are mils.\n");
00965 drill_stats_add_error(stats->error_list,
00966 -1,
00967 string,
00968 GERBV_MESSAGE_WARNING);
00969 g_free(string);
00970 size /= 1000.0;
00971 }
00972
00973 if(size <= 0. || size >= 10000.) {
00974 string = g_strdup_printf("Unreasonable drill size found for drill %d: %g\n", tool_num, size);
00975 drill_stats_add_error(stats->error_list,
00976 -1,
00977 string,
00978 GERBV_MESSAGE_ERROR);
00979 g_free(string);
00980 } else {
00981 if(image->aperture[tool_num] != NULL) {
00982
00983
00984
00985
00986 if (image->aperture[tool_num]->parameter[0] != size ||
00987 image->aperture[tool_num]->type != GERBV_APTYPE_CIRCLE ||
00988 image->aperture[tool_num]->nuf_parameters != 1 ||
00989 image->aperture[tool_num]->unit != GERBV_UNIT_INCH) {
00990 string = g_strdup_printf("Found redefinition of drill %d.\n", tool_num);
00991 drill_stats_add_error(stats->error_list,
00992 -1,
00993 string,
00994 GERBV_MESSAGE_ERROR);
00995 g_free(string);
00996 }
00997 } else {
00998 image->aperture[tool_num] =
00999 (gerbv_aperture_t *)g_malloc(sizeof(gerbv_aperture_t));
01000 if (image->aperture[tool_num] == NULL) {
01001 GERB_FATAL_ERROR("malloc tool failed\n");
01002 }
01003
01004 memset((void *)image->aperture[tool_num], 0, sizeof(gerbv_aperture_t));
01005
01006
01007
01008 image->aperture[tool_num]->parameter[0] = size;
01009 image->aperture[tool_num]->type = GERBV_APTYPE_CIRCLE;
01010 image->aperture[tool_num]->nuf_parameters = 1;
01011 image->aperture[tool_num]->unit = GERBV_UNIT_INCH;
01012 }
01013 }
01014
01015
01016
01017 stats = image->drill_stats;
01018 string = g_strdup_printf("%s", (state->unit == GERBV_UNIT_MM ? "mm" : "inch"));
01019 drill_stats_add_to_drill_list(stats->drill_list,
01020 tool_num,
01021 state->unit == GERBV_UNIT_MM ? size*25.4 : size,
01022 string);
01023 g_free(string);
01024 break;
01025
01026 case 'F':
01027 case 'S' :
01028
01029 gerb_fgetint(fd, NULL);
01030 break;
01031
01032 default:
01033
01034
01035 gerb_ungetc(fd);
01036 done = TRUE;
01037 break;
01038 }
01039
01040 if( (temp = gerb_fgetc(fd)) == EOF) {
01041 drill_stats_add_error(stats->error_list,
01042 -1,
01043 "Unexpected EOF encountered header of drill file.\n",
01044 GERBV_MESSAGE_ERROR);
01045 }
01046 }
01047
01048
01049
01050 if(image->aperture[tool_num] == NULL) {
01051 double dia;
01052
01053 image->aperture[tool_num] =
01054 (gerbv_aperture_t *)g_malloc(sizeof(gerbv_aperture_t));
01055 if (image->aperture[tool_num] == NULL) {
01056 GERB_FATAL_ERROR("malloc tool failed\n");
01057 }
01058
01059 memset((void *)image->aperture[tool_num], 0, sizeof(gerbv_aperture_t));
01060
01061
01062 dia = gerbv_get_tool_diameter(tool_num);
01063 if (dia <= 0) {
01064
01065
01066
01067
01068 dia = (double)(16 + 8 * tool_num) / 1000;
01069
01070
01071
01072
01073
01074 if(tool_num != 0) {
01075 string = g_strdup_printf("Tool %02d used without being defined\n", tool_num);
01076 drill_stats_add_error(stats->error_list,
01077 -1,
01078 string,
01079 GERBV_MESSAGE_ERROR);
01080 g_free(string);
01081 string = g_strdup_printf("Setting a default size of %g\"\n", dia);
01082 drill_stats_add_error(stats->error_list,
01083 -1,
01084 string,
01085 GERBV_MESSAGE_WARNING);
01086 g_free(string);
01087 }
01088 }
01089
01090 image->aperture[tool_num]->type = GERBV_APTYPE_CIRCLE;
01091 image->aperture[tool_num]->nuf_parameters = 1;
01092 image->aperture[tool_num]->parameter[0] = dia;
01093
01094
01095
01096 if (tool_num != 0) {
01097
01098 stats = image->drill_stats;
01099 string = g_strdup_printf("%s",
01100 (state->unit == GERBV_UNIT_MM ? "mm" : "inch"));
01101 drill_stats_add_to_drill_list(stats->drill_list,
01102 tool_num,
01103 state->unit == GERBV_UNIT_MM ? dia*25.4 : dia,
01104 string);
01105 g_free(string);
01106 }
01107 }
01108
01109 return tool_num;
01110 }
01111
01112
01113
01114 static int
01115 drill_parse_M_code(gerb_file_t *fd, drill_state_t *state, gerbv_image_t *image)
01116 {
01117 char op[3] = " ";
01118 int read[3];
01119 gerbv_drill_stats_t *stats = image->drill_stats;
01120 int result=0;
01121
01122 dprintf("---> entering drill_parse_M_code ...\n");
01123
01124 read[0] = gerb_fgetc(fd);
01125 read[1] = gerb_fgetc(fd);
01126
01127 if ((read[0] == EOF) || (read[1] == EOF))
01128 drill_stats_add_error(stats->error_list,
01129 -1,
01130 "Unexpected EOF found while parsing M code.\n",
01131 GERBV_MESSAGE_ERROR);
01132 op[0] = read[0], op[1] = read[1], op[2] = 0;
01133
01134 if (strncmp(op, "00", 2) == 0) {
01135 stats->M00++;
01136 result = DRILL_M_END;
01137 } else if (strncmp(op, "01", 2) == 0) {
01138 stats->M01++;
01139 result = DRILL_M_ENDPATTERN;
01140 } else if (strncmp(op, "18", 2) == 0) {
01141 stats->M18++;
01142 result = DRILL_M_TIPCHECK;
01143 } else if (strncmp(op, "25", 2) == 0) {
01144 stats->M25++;
01145 result = DRILL_M_BEGINPATTERN;
01146 } else if (strncmp(op, "31", 2) == 0) {
01147 stats->M31++;
01148 result = DRILL_M_BEGINPATTERN;
01149 } else if (strncmp(op, "30", 2) == 0) {
01150 stats->M30++;
01151 result = DRILL_M_ENDREWIND;
01152 } else if (strncmp(op, "45", 2) == 0) {
01153 stats->M45++;
01154 result = DRILL_M_LONGMESSAGE;
01155 } else if (strncmp(op, "47", 2) == 0) {
01156 stats->M47++;
01157 result = DRILL_M_MESSAGE;
01158 } else if (strncmp(op, "48", 2) == 0) {
01159 stats->M48++;
01160 result = DRILL_M_HEADER;
01161 } else if (strncmp(op, "71", 2) == 0) {
01162 eat_line(fd);
01163 stats->M71++;
01164 result = DRILL_M_METRIC;
01165 } else if (strncmp(op, "72", 2) == 0) {
01166 eat_line(fd);
01167 stats->M72++;
01168 result = DRILL_M_IMPERIAL;
01169 } else if (strncmp(op, "95", 2) == 0) {
01170 stats->M95++;
01171 result = DRILL_M_ENDHEADER;
01172 } else if (strncmp(op, "97", 2) == 0) {
01173 stats->M97++;
01174 result = DRILL_M_CANNEDTEXT;
01175 } else if (strncmp(op, "98", 2) == 0) {
01176 stats->M98++;
01177 return DRILL_M_CANNEDTEXT;
01178 } else if (state->curr_section == DRILL_HEADER &&
01179 strncmp(op, "ET", 2) == 0) {
01180
01181
01182
01183
01184
01185
01186 if ('R' == gerb_fgetc(fd) &&
01187 'I' == gerb_fgetc(fd) &&
01188 'C' == gerb_fgetc(fd)) {
01189 again:
01190 if (',' == gerb_fgetc(fd)) {
01191 int c;
01192
01193
01194 switch ((c = gerb_fgetc(fd))) {
01195 case 'T':
01196 case 'L':
01197 if ('Z' != gerb_fgetc(fd))
01198 goto junk;
01199 if (c == 'L')
01200 {
01201 dprintf ("%s(): Detected a file that probably has trailing zero supression\n", __FUNCTION__);
01202 if (state->autod)
01203 {
01204 image->format->omit_zeros = GERBV_OMIT_ZEROS_TRAILING;
01205 }
01206 }
01207 else
01208 {
01209 dprintf ("%s(): Detected a file that probably has leading zero supression\n", __FUNCTION__);
01210 if (state->autod)
01211 {
01212 image->format->omit_zeros = GERBV_OMIT_ZEROS_LEADING;
01213 }
01214 }
01215 if (state->autod)
01216 {
01217
01218
01219
01220
01221 state->header_number_format =
01222 state->number_format = FMT_000_000;
01223 state->decimals = 3;
01224 }
01225 c = gerb_fgetc(fd);
01226 gerb_ungetc(fd);
01227 if (c == ',')
01228
01229 goto again;
01230 break;
01231
01232 case '0':
01233 if ('0' != gerb_fgetc(fd) ||
01234 '0' != gerb_fgetc(fd))
01235 goto junk;
01236
01237
01238 read[0] = gerb_fgetc(fd);
01239 read[1] = gerb_fgetc(fd);
01240 if (read[0] == EOF || read[1] == EOF)
01241 goto junk;
01242 op[0] = read[0];
01243 op[1] = read[1];
01244 if (strcmp(op, "0.") == 0) {
01245
01246
01247 if ('0' != gerb_fgetc(fd) ||
01248 '0' != gerb_fgetc(fd))
01249 goto junk;
01250 eat_line(fd);
01251 if (state->autod)
01252 {
01253 state->number_format = FMT_0000_00;
01254 state->decimals = 2;
01255 }
01256 break;
01257 }
01258 if (strcmp(op, ".0") != 0)
01259 goto junk;
01260
01261
01262 if ('0' != gerb_fgetc(fd))
01263 goto junk;
01264 if ('0' == gerb_fgetc(fd) && state->autod)
01265 {
01266 state->number_format = FMT_000_000;
01267 state->decimals = 3;
01268 }
01269 else {
01270 gerb_ungetc(fd);
01271 if (state->autod)
01272 {
01273 state->number_format = FMT_000_00;
01274 state->decimals = 2;
01275 }
01276 }
01277 eat_line(fd);
01278 break;
01279
01280 default:
01281 junk:
01282 drill_stats_add_error(stats->error_list,
01283 -1,
01284 "Found junk after METRIC command\n",
01285 GERBV_MESSAGE_WARNING);
01286 gerb_ungetc(fd);
01287 eat_line(fd);
01288 break;
01289 }
01290 } else {
01291 gerb_ungetc(fd);
01292 eat_line(fd);
01293 }
01294
01295 return DRILL_M_METRICHEADER;
01296 }
01297 } else {
01298 stats->M_unknown++;
01299 result = DRILL_M_UNKNOWN;
01300 }
01301
01302 dprintf("<---- ...leaving drill_parse_M_code.\n");
01303 return result;
01304 }
01305
01306
01307
01308 static int
01309 drill_parse_G_code(gerb_file_t *fd, gerbv_image_t *image)
01310 {
01311 char op[3] = " ";
01312 int read[3];
01313 gerbv_drill_stats_t *stats = image->drill_stats;
01314 int result;
01315
01316 dprintf("---> entering drill_parse_G_code ...\n");
01317
01318 read[0] = gerb_fgetc(fd);
01319 read[1] = gerb_fgetc(fd);
01320
01321 if ((read[0] == EOF) || (read[1] == EOF)) {
01322 drill_stats_add_error(stats->error_list,
01323 -1,
01324 "Unexpected EOF found while parsing G code.\n",
01325 GERBV_MESSAGE_ERROR);
01326 }
01327
01328 op[0] = read[0], op[1] = read[1], op[2] = 0;
01329
01330 if (strncmp(op, "00", 2) == 0) {
01331 stats->G00++;
01332 result = DRILL_G_ROUT;
01333 } else if (strncmp(op, "01", 2) == 0) {
01334 stats->G01++;
01335 result = DRILL_G_LINEARMOVE;
01336 } else if (strncmp(op, "02", 2) == 0) {
01337 stats->G02++;
01338 result = DRILL_G_CWMOVE;
01339 } else if (strncmp(op, "03", 2) == 0) {
01340 stats->G03++;
01341 result = DRILL_G_CCWMOVE;
01342 } else if (strncmp(op, "05", 2) == 0) {
01343 stats->G05++;
01344 result = DRILL_G_DRILL;
01345 } else if (strncmp(op, "90", 2) == 0) {
01346 stats->G90++;
01347 result = DRILL_G_ABSOLUTE;
01348 } else if (strncmp(op, "91", 2) == 0) {
01349 stats->G91++;
01350 result = DRILL_G_INCREMENTAL;
01351 } else if (strncmp(op, "93", 2) == 0) {
01352 stats->G93++;
01353 result = DRILL_G_ZEROSET;
01354 } else {
01355 stats->G_unknown++;
01356 result = DRILL_G_UNKNOWN;
01357 }
01358
01359 dprintf("<---- ...leaving drill_parse_G_code.\n");
01360 return result;
01361
01362 }
01363
01364
01365
01366
01367
01368 static void
01369 drill_parse_coordinate(gerb_file_t *fd, char firstchar,
01370 gerbv_image_t *image, drill_state_t *state)
01371
01372 {
01373 int read;
01374
01375 if(state->coordinate_mode == DRILL_MODE_ABSOLUTE) {
01376 if(firstchar == 'X') {
01377 state->curr_x = read_double(fd, state->number_format, image->format->omit_zeros, state->decimals);
01378 if((read = (char)gerb_fgetc(fd)) == 'Y') {
01379 state->curr_y = read_double(fd, state->number_format, image->format->omit_zeros, state->decimals);
01380 }
01381 } else {
01382 state->curr_y = read_double(fd, state->number_format, image->format->omit_zeros, state->decimals);
01383 }
01384 } else if(state->coordinate_mode == DRILL_MODE_INCREMENTAL) {
01385 if(firstchar == 'X') {
01386 state->curr_x += read_double(fd, state->number_format, image->format->omit_zeros, state->decimals);
01387 if((read = (char)gerb_fgetc(fd)) == 'Y') {
01388 state->curr_y += read_double(fd, state->number_format, image->format->omit_zeros, state->decimals);
01389 }
01390 } else {
01391 state->curr_y += read_double(fd, state->number_format, image->format->omit_zeros, state->decimals);
01392 }
01393 }
01394
01395 }
01396
01397
01398
01399
01400 static drill_state_t *
01401 new_state(drill_state_t *state)
01402 {
01403 state = (drill_state_t *)g_malloc(sizeof(drill_state_t));
01404 if (state != NULL) {
01405
01406 memset((void *)state, 0, sizeof(drill_state_t));
01407 state->curr_section = DRILL_NONE;
01408 state->coordinate_mode = DRILL_MODE_ABSOLUTE;
01409 state->origin_x = 0.0;
01410 state->origin_y = 0.0;
01411 state->unit = GERBV_UNIT_UNSPECIFIED;
01412 state->backup_number_format = FMT_000_000;
01413 state->header_number_format = state->number_format = FMT_00_0000;
01414 state->autod = 1;
01415 state->decimals = 4;
01416
01417 }
01418 return state;
01419 }
01420
01421
01422
01423
01424
01425 static double
01426 read_double(gerb_file_t *fd, enum number_fmt_t fmt, gerbv_omit_zeros_t omit_zeros, int decimals)
01427 {
01428 int read;
01429 char temp[0x20];
01430 int i = 0, ndigits = 0;
01431 double result;
01432 gboolean decimal_point = FALSE;
01433
01434 memset(temp, 0, sizeof(temp));
01435
01436 read = gerb_fgetc(fd);
01437 while(read != EOF && i < sizeof(temp) &&
01438 (isdigit(read) || read == '.' || read == ',' || read == '+' || read == '-')) {
01439 if(read == ',' || read == '.') decimal_point = TRUE;
01440 if(read == ',')
01441 read = '.';
01442 if(isdigit(read)) ndigits++;
01443 temp[i++] = (char)read;
01444 read = gerb_fgetc(fd);
01445 }
01446 temp[i] = 0;
01447
01448 gerb_ungetc(fd);
01449 if (decimal_point) {
01450 result = strtod(temp, NULL);
01451 } else {
01452 int wantdigits;
01453 double scale;
01454
01455
01456
01457 if (omit_zeros == GERBV_OMIT_ZEROS_TRAILING) {
01458 switch (fmt) {
01459 case FMT_00_0000:
01460 case FMT_000_000:
01461 case FMT_0000_00:
01462 wantdigits = 6;
01463 break;
01464
01465 case FMT_000_00:
01466 wantdigits = 5;
01467 break;
01468
01469 default:
01470
01471 return 0;
01472 }
01473
01474
01475 while (ndigits < wantdigits) {
01476 temp[i++] = '0';
01477 ndigits++;
01478 }
01479 temp[i] = 0;
01480 }
01481
01482 switch (fmt) {
01483 case FMT_00_0000:
01484 scale = 1E-4;
01485 break;
01486
01487 case FMT_000_000:
01488 scale = 1E-3;
01489 break;
01490
01491 case FMT_000_00:
01492 case FMT_0000_00:
01493 scale = 1E-2;
01494 break;
01495
01496 case FMT_USER:
01497 scale = pow (10.0, -1.0*decimals);
01498 break;
01499
01500 default:
01501
01502 fprintf (stderr, "%s(): Unhandled fmt ` %d\n", __FUNCTION__, fmt);
01503 exit (1);
01504 }
01505
01506 result = strtod(temp, NULL) * scale;
01507 }
01508
01509 return result;
01510 }
01511
01512
01513
01514
01515
01516 static void
01517 eat_line(gerb_file_t *fd)
01518 {
01519 int read = gerb_fgetc(fd);
01520
01521 while(read != 10 && read != 13) {
01522 if (read == EOF) return;
01523 read = gerb_fgetc(fd);
01524 }
01525 }
01526
01527
01528
01529 static char *
01530 get_line(gerb_file_t *fd)
01531 {
01532 int read = gerb_fgetc(fd);
01533 gchar *retstring = "";
01534 gchar *tmps = NULL;
01535
01536 while(read != 10 && read != 13) {
01537 if (read == EOF) return retstring;
01538 retstring = g_strdup_printf("%s%c", retstring, read);
01539
01540
01541 if (tmps) {
01542 g_free (tmps);
01543 tmps = NULL;
01544 }
01545 tmps = retstring;;
01546 read = gerb_fgetc(fd);
01547 }
01548 return retstring;
01549 }