alpar@1: /* glpsdf.c (plain data file reading routines) */ alpar@1: alpar@1: /*********************************************************************** alpar@1: * This code is part of GLPK (GNU Linear Programming Kit). alpar@1: * alpar@1: * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, alpar@1: * 2009, 2010 Andrew Makhorin, Department for Applied Informatics, alpar@1: * Moscow Aviation Institute, Moscow, Russia. All rights reserved. alpar@1: * E-mail: . alpar@1: * alpar@1: * GLPK is free software: you can redistribute it and/or modify it alpar@1: * under the terms of the GNU General Public License as published by alpar@1: * the Free Software Foundation, either version 3 of the License, or alpar@1: * (at your option) any later version. alpar@1: * alpar@1: * GLPK is distributed in the hope that it will be useful, but WITHOUT alpar@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY alpar@1: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public alpar@1: * License for more details. alpar@1: * alpar@1: * You should have received a copy of the GNU General Public License alpar@1: * along with GLPK. If not, see . alpar@1: ***********************************************************************/ alpar@1: alpar@1: #define GLPSDF_H alpar@1: alpar@1: #define GLP_DATA_DEFINED alpar@1: typedef struct glp_data glp_data; alpar@1: alpar@1: #include "glpapi.h" alpar@1: alpar@1: struct glp_data alpar@1: { /* plain data file */ alpar@1: char *fname; alpar@1: /* name of data file */ alpar@1: XFILE *fp; alpar@1: /* stream assigned to data file */ alpar@1: void *jump; /* jmp_buf jump; */ alpar@1: /* label for go to in case of error */ alpar@1: int count; alpar@1: /* line count */ alpar@1: int c; alpar@1: /* current character of XEOF */ alpar@1: char item[255+1]; alpar@1: /* current data item */ alpar@1: }; alpar@1: alpar@1: static void next_char(glp_data *data); alpar@1: alpar@1: glp_data *glp_sdf_open_file(const char *fname) alpar@1: { /* open plain data file */ alpar@1: glp_data *data = NULL; alpar@1: XFILE *fp; alpar@1: jmp_buf jump; alpar@1: fp = xfopen(fname, "r"); alpar@1: if (fp == NULL) alpar@1: { xprintf("Unable to open `%s' - %s\n", fname, xerrmsg()); alpar@1: goto done; alpar@1: } alpar@1: data = xmalloc(sizeof(glp_data)); alpar@1: data->fname = xmalloc(strlen(fname)+1); alpar@1: strcpy(data->fname, fname); alpar@1: data->fp = fp; alpar@1: data->jump = NULL; alpar@1: data->count = 0; alpar@1: data->c = '\n'; alpar@1: data->item[0] = '\0'; alpar@1: /* read the very first character */ alpar@1: if (setjmp(jump)) alpar@1: { glp_sdf_close_file(data); alpar@1: data = NULL; alpar@1: goto done; alpar@1: } alpar@1: data->jump = jump; alpar@1: next_char(data); alpar@1: data->jump = NULL; alpar@1: done: return data; alpar@1: } alpar@1: alpar@1: void glp_sdf_set_jump(glp_data *data, void *jump) alpar@1: { /* set up error handling */ alpar@1: data->jump = jump; alpar@1: return; alpar@1: } alpar@1: alpar@1: void glp_sdf_error(glp_data *data, const char *fmt, ...) alpar@1: { /* print error message */ alpar@1: va_list arg; alpar@1: xprintf("%s:%d: ", data->fname, data->count); alpar@1: va_start(arg, fmt); alpar@1: xvprintf(fmt, arg); alpar@1: va_end(arg); alpar@1: if (data->jump == NULL) alpar@1: xerror(""); alpar@1: else alpar@1: longjmp(data->jump, 1); alpar@1: /* no return */ alpar@1: } alpar@1: alpar@1: void glp_sdf_warning(glp_data *data, const char *fmt, ...) alpar@1: { /* print warning message */ alpar@1: va_list arg; alpar@1: xprintf("%s:%d: warning: ", data->fname, data->count); alpar@1: va_start(arg, fmt); alpar@1: xvprintf(fmt, arg); alpar@1: va_end(arg); alpar@1: return; alpar@1: } alpar@1: alpar@1: static void next_char(glp_data *data) alpar@1: { /* read next character */ alpar@1: int c; alpar@1: if (data->c == XEOF) alpar@1: glp_sdf_error(data, "unexpected end of file\n"); alpar@1: else if (data->c == '\n') alpar@1: data->count++; alpar@1: c = xfgetc(data->fp); alpar@1: if (c < 0) alpar@1: { if (xferror(data->fp)) alpar@1: glp_sdf_error(data, "read error - %s\n", xerrmsg()); alpar@1: else if (data->c == '\n') alpar@1: c = XEOF; alpar@1: else alpar@1: { glp_sdf_warning(data, "missing final end of line\n"); alpar@1: c = '\n'; alpar@1: } alpar@1: } alpar@1: else if (c == '\n') alpar@1: ; alpar@1: else if (isspace(c)) alpar@1: c = ' '; alpar@1: else if (iscntrl(c)) alpar@1: glp_sdf_error(data, "invalid control character 0x%02X\n", c); alpar@1: data->c = c; alpar@1: return; alpar@1: } alpar@1: alpar@1: static void skip_pad(glp_data *data) alpar@1: { /* skip uninteresting characters and comments */ alpar@1: loop: while (data->c == ' ' || data->c == '\n') alpar@1: next_char(data); alpar@1: if (data->c == '/') alpar@1: { next_char(data); alpar@1: if (data->c != '*') alpar@1: glp_sdf_error(data, "invalid use of slash\n"); alpar@1: next_char(data); alpar@1: for (;;) alpar@1: { if (data->c == '*') alpar@1: { next_char(data); alpar@1: if (data->c == '/') alpar@1: { next_char(data); alpar@1: break; alpar@1: } alpar@1: } alpar@1: next_char(data); alpar@1: } alpar@1: goto loop; alpar@1: } alpar@1: return; alpar@1: } alpar@1: alpar@1: static void next_item(glp_data *data) alpar@1: { /* read next item */ alpar@1: int len; alpar@1: skip_pad(data); alpar@1: len = 0; alpar@1: while (!(data->c == ' ' || data->c == '\n')) alpar@1: { data->item[len++] = (char)data->c; alpar@1: if (len == sizeof(data->item)) alpar@1: glp_sdf_error(data, "data item `%.31s...' too long\n", alpar@1: data->item); alpar@1: next_char(data); alpar@1: } alpar@1: data->item[len] = '\0'; alpar@1: return; alpar@1: } alpar@1: alpar@1: int glp_sdf_read_int(glp_data *data) alpar@1: { /* read integer number */ alpar@1: int x; alpar@1: next_item(data); alpar@1: switch (str2int(data->item, &x)) alpar@1: { case 0: alpar@1: break; alpar@1: case 1: alpar@1: glp_sdf_error(data, "integer `%s' out of range\n", alpar@1: data->item); alpar@1: case 2: alpar@1: glp_sdf_error(data, "cannot convert `%s' to integer\n", alpar@1: data->item); alpar@1: default: alpar@1: xassert(data != data); alpar@1: } alpar@1: return x; alpar@1: } alpar@1: alpar@1: double glp_sdf_read_num(glp_data *data) alpar@1: { /* read floating-point number */ alpar@1: double x; alpar@1: next_item(data); alpar@1: switch (str2num(data->item, &x)) alpar@1: { case 0: alpar@1: break; alpar@1: case 1: alpar@1: glp_sdf_error(data, "number `%s' out of range\n", alpar@1: data->item); alpar@1: case 2: alpar@1: glp_sdf_error(data, "cannot convert `%s' to number\n", alpar@1: data->item); alpar@1: default: alpar@1: xassert(data != data); alpar@1: } alpar@1: return x; alpar@1: } alpar@1: alpar@1: const char *glp_sdf_read_item(glp_data *data) alpar@1: { /* read data item */ alpar@1: next_item(data); alpar@1: return data->item; alpar@1: } alpar@1: alpar@1: const char *glp_sdf_read_text(glp_data *data) alpar@1: { /* read text until end of line */ alpar@1: int c, len = 0; alpar@1: for (;;) alpar@1: { c = data->c; alpar@1: next_char(data); alpar@1: if (c == ' ') alpar@1: { /* ignore initial spaces */ alpar@1: if (len == 0) continue; alpar@1: /* and multiple ones */ alpar@1: if (data->item[len-1] == ' ') continue; alpar@1: } alpar@1: else if (c == '\n') alpar@1: { /* remove trailing space */ alpar@1: if (len > 0 && data->item[len-1] == ' ') len--; alpar@1: /* and stop reading */ alpar@1: break; alpar@1: } alpar@1: /* add current character to the buffer */ alpar@1: data->item[len++] = (char)c; alpar@1: if (len == sizeof(data->item)) alpar@1: glp_sdf_error(data, "line too long\n", data->item); alpar@1: } alpar@1: data->item[len] = '\0'; alpar@1: return data->item; alpar@1: } alpar@1: alpar@1: int glp_sdf_line(glp_data *data) alpar@1: { /* determine current line number */ alpar@1: return data->count; alpar@1: } alpar@1: alpar@1: void glp_sdf_close_file(glp_data *data) alpar@1: { /* close plain data file */ alpar@1: xfclose(data->fp); alpar@1: xfree(data->fname); alpar@1: xfree(data); alpar@1: return; alpar@1: } alpar@1: alpar@1: /* eof */