This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-goldedplus/golded3/gcmisc.cpp

855 lines
24 KiB
C++

// ------------------------------------------------------------------
// GoldED+
// Copyright (C) 1990-1999 Odinn Sorensen
// Copyright (C) 1999-2000 Alexander S. Aganichev
// ------------------------------------------------------------------
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307 USA
// ------------------------------------------------------------------
// $Id$
// ------------------------------------------------------------------
// Compilers for help, screen and xlat.
// ------------------------------------------------------------------
#include <golded.h>
// ------------------------------------------------------------------
int ReadHelpCfg(int force) {
char* ptr;
long offset;
char buf[1024];
FILE* ifp;
FILE* ofp;
Hlpr* HlpL;
int count;
int counter;
int comment;
if((force > 1) or (FiletimeCmp(CFG->helpcfg.fn, CFG->helpged) > 0)) {
ifp = fsopen(AddPath(CFG->goldpath, CFG->helpcfg.fn), "rb", CFG->sharemode);
if(ifp) {
setvbuf(ifp, NULL, _IOFBF, 8192);
ofp = fsopen(AddPath(CFG->goldpath, CFG->helpged), "wb", CFG->sharemode);
if (ofp)
{
offset = 0L;
CFG->helpcfg.ft = GetFiletime(AddPath(CFG->goldpath, CFG->helpcfg.fn));
if (not quiet)
STD_PRINTNL("* Reading " << AddPath(CFG->goldpath, CFG->helpcfg.fn));
setvbuf(ofp, NULL, _IOFBF, 8192);
count = 0;
rewind(ifp);
while(fgets(buf, sizeof(buf), ifp)) {
if(strnieql(buf, "*B ", 3))
count++;
}
HlpL = (Hlpr*)throw_calloc(count+2, sizeof(Hlpr));
rewind(ifp);
fputs("*I\r\n", ofp);
fwrite(HlpL, count+1, sizeof(Hlpr), ofp);
fputs("\r\n\r\n", ofp);
offset += 4 + ((count+1)*sizeof(Hlpr)) + 4;
counter = 0;
comment = YES;
while(fgets(buf, sizeof(buf), ifp)) {
if(strnieql(buf, "*B ", 3)) {
comment = NO;
HlpL[counter].help = atow(buf+3);
ptr = strchr(buf, ',');
strbtrim(strcpy(HlpL[counter].category, ptr ? ptr+1 : ""));
HlpL[counter].offset = offset + strlen(buf);
counter++;
}
if(not comment) {
fputs(buf, ofp);
offset += strlen(buf);
}
if(strnieql(buf, "*E", 2))
comment = YES;
}
HlpL[counter].offset = -1L;
fseek(ofp, 0L, SEEK_SET);
fputs("*I\r\n", ofp);
fwrite(HlpL, count+1, sizeof(Hlpr), ofp);
throw_free(HlpL);
fclose(ofp);
}
fclose(ifp);
}
}
// Init the help system
whelpdef(CFG->helpged, Key_F1, C_HELPB, C_HELPW, C_HELPQ, C_HELPS, NULL);
whelpwin(0, 0, MAXROW-2, MAXCOL-1, W_BHELP, NO);
whelpcat(H_General);
return 0;
}
// ------------------------------------------------------------------
// Window parts
const word CRC_BLOCK = 0xC10C;
const word CRC_BORDER = 0x97A7;
const word CRC_BTYPE = 0x2A2F;
const word CRC_CURSOR = 0x0D67;
const word CRC_EDIT = 0xB32D;
const word CRC_HEADER = 0x6EED;
const word CRC_HIGHLIGHT = 0x5EBF;
const word CRC_INPUT = 0xA25E;
const word CRC_KLUDHIDD = 0x222E;
const word CRC_NOSELECT = 0x950C;
const word CRC_QUOTE = 0x75DA;
const word CRC_SELECTOR = 0x5604;
const word CRC_STATUS = 0x1D36;
const word CRC_TEARORIG = 0x428E;
const word CRC_TITLE = 0x636E;
const word CRC_WINDOW = 0xCEFE;
const word CRC_FROM = 0x9290;
const word CRC_TO = 0x544F;
const word CRC_SUBJECT = 0xF861;
const word CRC_LOCATION = 0x9E67;
const word CRC_KLUDGE = 0xA600;
const word CRC_HIDDEN = 0xE465;
const word CRC_TAGLINE = 0xC328;
const word CRC_TEARLINE = 0xB385;
const word CRC_ORIGIN = 0x4CE5;
const word CRC_PAGEBAR = 0x4ECA;
const word CRC_UNREAD = 0xFE2A;
const word CRC_UNSENT = 0xC20B;
const word CRC_UNREADHIGH = 0x66D0;
const word CRC_UNSENTHIGH = 0xB4FD;
const word CRC_QUOTE2 = 0xF400;
const word CRC_QUOTE1 = 0xF403;
const word CRC_SIGNATURE = 0x1A6E;
const word CRC_URL = 0x581C;
const word CRC_B = 0x0042;
const word CRC_I = 0x0049;
const word CRC_BI = 0x4249;
const word CRC_U = 0x0055;
const word CRC_BU = 0x4255;
const word CRC_IU = 0x4955;
const word CRC_BIU = 0x21D3;
const word CRC_R = 0x0052;
const word CRC_RB = 0x5242;
const word CRC_RI = 0x5249;
const word CRC_RBI = 0x38FE;
const word CRC_RU = 0x5255;
const word CRC_RBU = 0x38E2;
const word CRC_RIU = 0x33E2;
const word CRC_RBIU = 0x490E;
const word CRC_ALL = 0x14A9;
// ------------------------------------------------------------------
// Colors
const word CRC_BLACK = 0x20C2;
const word CRC_BLUE = 0xB7A3;
const word CRC_BROWN = 0xF575;
const word CRC_CYAN = 0xD20D;
const word CRC_DARKGRAY = 0x0D32;
const word CRC_DARKGREY = 0x0932;
const word CRC_DGRAY = 0x6ED8;
const word CRC_DGREY = 0x6AD8;
const word CRC_GREEN = 0xADCF;
const word CRC_LBLUE = 0xDF6F;
const word CRC_LCYAN = 0xBAC1;
const word CRC_LGRAY = 0xC779;
const word CRC_LGREEN = 0x8C61;
const word CRC_LGREY = 0xC379;
const word CRC_LIGHTBLUE = 0x053B;
const word CRC_LIGHTCYAN = 0x6095;
const word CRC_LIGHTGRAY = 0x1D2D;
const word CRC_LIGHTGREEN = 0xB256;
const word CRC_LIGHTGREY = 0x192D;
const word CRC_LIGHTMAGENTA = 0xBEA8;
const word CRC_LIGHTRED = 0xAED2;
const word CRC_LMAGENTA = 0xDE86;
const word CRC_LRED = 0x7752;
const word CRC_MAGENTA = 0xBF75;
const word CRC_NORMAL = 0x4DA2;
const word CRC_RED = 0x3FF3;
const word CRC_REVERSE = 0xB4CD;
const word CRC_UNDERLINE = 0xDC93;
const word CRC_WHITE = 0xD293;
const word CRC_YELLOW = 0xFEAF;
// ------------------------------------------------------------------
// Window areas
const word CRC_AREA = 0x010B;
const word CRC_ASK = 0x0BAE;
const word CRC_BACKGROUND = 0x1365;
const word CRC_BRAG = 0x505E;
const word CRC_HELP = 0xD054;
const word CRC_INFO = 0x5811;
const word CRC_MENU = 0x2DA4;
const word CRC_READER = 0x1DE1;
const word CRC_SHADOW = 0x2301;
const word CRC_STYLECODE = 0x8B6C;
const word CRC_STYLECODES = 0x4CB0;
// ------------------------------------------------------------------
#if !defined(GCFG_NOSPELLDLL)
const word CRC_SPELL = 0xB8AE;
const word CRC_SCERROR = 0xAB65;
#endif
// ------------------------------------------------------------------
// Get color value
vattr GetColor(char* ink)
{
word crc;
vattr color = BLACK_|_BLACK;
crc = strCrc16(strupr(ink));
switch(crc) {
// Black is the default
case CRC_BLACK:
color = BLACK_|_BLACK;
break;
case CRC_BLUE:
color = BLUE_|_BLACK;
break;
case CRC_GREEN:
color = GREEN_|_BLACK;
break;
case CRC_CYAN:
color = CYAN_|_BLACK;
break;
case CRC_RED:
color = RED_|_BLACK;
break;
case CRC_MAGENTA:
color = MAGENTA_|_BLACK;
break;
case CRC_BROWN:
color = BROWN_|_BLACK;
break;
case CRC_LGRAY:
case CRC_LGREY:
case CRC_LIGHTGRAY:
case CRC_LIGHTGREY:
color = LGREY_|_BLACK;
break;
case CRC_DGRAY:
case CRC_DGREY:
case CRC_DARKGRAY:
case CRC_DARKGREY:
color = DGREY_|_BLACK;
break;
case CRC_LBLUE:
case CRC_LIGHTBLUE:
color = LBLUE_|_BLACK;
break;
case CRC_LGREEN:
case CRC_LIGHTGREEN:
color = LGREEN_|_BLACK;
break;
case CRC_LCYAN:
case CRC_LIGHTCYAN:
color = LCYAN_|_BLACK;
break;
case CRC_LRED:
case CRC_LIGHTRED:
color = LRED_|_BLACK;
break;
case CRC_LMAGENTA:
case CRC_LIGHTMAGENTA:
color = LMAGENTA_|_BLACK;
break;
case CRC_YELLOW:
color = YELLOW_|_BLACK;
break;
case CRC_WHITE:
color = WHITE_|_BLACK;
break;
case CRC_UNDERLINE:
color = UNDERLINE;
break;
case CRC_NORMAL:
color = NORMAL;
break;
case CRC_HIGHLIGHT:
color = HIGHLIGHT;
break;
case CRC_REVERSE:
color = REVERSE;
break;
}
return(color);
}
// ------------------------------------------------------------------
// Evaluates a color string
vattr MakeColor(char* colors) {
static int paper=0;
int ink=0, blink;
char* ink_;
char* paper_;
#if defined(__UNIX__) || defined(__USE_NCURSES__)
blink = 0;
#else
blink = (stridela("blinking", colors) ? 128 : 0);
#endif
ink_ = strtok(colors, " \t"); // Get the Ink color
if(ink_) {
ink = GetColor(ink_);
paper_ = strtok(NULL, " \t"); // Skip the "On"
if(paper_) {
paper_ = strtok(NULL, " \t"); // Get the Paper color
if(paper_)
paper = GetColor(paper_);
}
}
if(paper > 7)
CFG->intensecolors = true;
return ink | paper*16 | blink;
}
// ------------------------------------------------------------------
// Get color values
void GetColors(char* value) {
word crc;
Win* wptr;
vattr attr;
char buf[256];
char* win;
char* colors;
char* part=NULL;
*buf = NUL;
if((win = strtok(value, " \t")) == NULL)
return;
if(stricmp(win, "shadow")) {
part = strtok(NULL, " \t");
if(part == NULL)
return;
}
do {
colors = strtok(NULL, " \t\n");
if(colors != NULL) {
strcat(buf, colors);
strcat(buf, " ");
}
} while(colors != NULL);
crc = strCrc16(strupr(win));
attr = MakeColor(buf);
switch(crc) {
case CRC_SHADOW:
C_SHADOW = attr;
return;
case CRC_BACKGROUND:
wptr = &GC_BACK_;
break;
case CRC_STATUS:
wptr = &GC_STAT_;
break;
case CRC_BRAG:
wptr = &GC_BRAG_;
break;
case CRC_AREA:
wptr = &GC_AREA_;
break;
case CRC_READER:
wptr = &GC_READ_;
break;
case CRC_HEADER:
wptr = &GC_HEAD_;
break;
case CRC_ASK:
wptr = &GC_ASK__;
break;
case CRC_MENU:
wptr = &GC_MENU_;
break;
case CRC_HELP:
wptr = &GC_HELP_;
break;
case CRC_INFO:
wptr = &GC_INFO_;
break;
case CRC_STYLECODE:
case CRC_STYLECODES:
wptr = &GC_STYLE_;
break;
#if !defined(GCFG_NOSPELLDLL)
case CRC_SPELL:
wptr = &GC_SPELL_;
break;
#endif
default:
return;
}
crc = strCrc16(strupr(part));
switch(crc) {
case CRC_WINDOW:
wptr->_Window = attr;
if(wptr == &GC_HEAD_) {
wptr->_From = attr;
wptr->_To = attr;
wptr->_Subject = attr;
}
if(wptr == &GC_READ_) {
wptr->_Tagline = attr;
GC_STYLE_._Bold = attr;
GC_STYLE_._Italic = attr;
GC_STYLE_._BoldItalic = attr;
GC_STYLE_._Underscore = attr;
GC_STYLE_._BoldUnderscore = attr;
GC_STYLE_._ItalicUnderscore = attr;
GC_STYLE_._BoldItalicUnderscore = attr;
GC_STYLE_._Reverse = attr;
GC_STYLE_._ReverseBold = attr;
GC_STYLE_._ReverseItalic = attr;
GC_STYLE_._ReverseBoldItalic = attr;
GC_STYLE_._ReverseUnderscore = attr;
GC_STYLE_._ReverseBoldUnderscore = attr;
GC_STYLE_._ReverseItalicUnderscore = attr;
GC_STYLE_._ReverseBoldItalicUnderscore = attr;
}
break;
case CRC_BORDER:
wptr->_Border = attr;
wptr->_Pagebar = attr;
break;
case CRC_BTYPE:
wptr->btype = atoi(buf);
break;
case CRC_TITLE:
wptr->_Title = attr;
break;
case CRC_SELECTOR:
wptr->_Selector = attr;
break;
case CRC_HIGHLIGHT:
wptr->_Highlight = attr;
break;
case CRC_NOSELECT:
wptr->_Noselect = attr;
break;
case CRC_QUOTE:
wptr->_Quote = attr;
wptr->_Quote2 = attr;
break;
case CRC_CURSOR:
wptr->_Cursor = attr;
break;
case CRC_KLUDHIDD:
wptr->_Kludge = attr;
wptr->_Hidden = attr;
break;
case CRC_TEARORIG:
wptr->_Tearline = attr;
wptr->_Origin = attr;
break;
case CRC_EDIT:
wptr->_Edit = attr;
break;
case CRC_BLOCK:
wptr->_Block = attr;
break;
case CRC_INPUT:
wptr->_Input = attr;
break;
case CRC_FROM:
wptr->_From = attr;
break;
case CRC_TO:
wptr->_To = attr;
break;
case CRC_SUBJECT:
wptr->_Subject = attr;
break;
case CRC_LOCATION:
wptr->_Location = attr;
break;
case CRC_KLUDGE:
wptr->_Kludge = attr;
break;
case CRC_HIDDEN:
wptr->_Hidden = attr;
break;
case CRC_TAGLINE:
wptr->_Tagline = attr;
break;
case CRC_TEARLINE:
wptr->_Tearline = attr;
break;
case CRC_ORIGIN:
wptr->_Origin = attr;
break;
case CRC_PAGEBAR:
wptr->_Pagebar = attr;
break;
case CRC_UNREAD:
wptr->_WindowUnread = attr;
break;
case CRC_UNSENT:
wptr->_WindowUnsent = attr;
break;
case CRC_UNREADHIGH:
wptr->_HighlightUnread = attr;
break;
case CRC_QUOTE1:
wptr->_Quote = attr;
break;
case CRC_QUOTE2:
wptr->_Quote2 = attr;
break;
case CRC_SIGNATURE:
wptr->_Signature = attr;
break;
case CRC_URL:
wptr->_URL = attr;
break;
case CRC_UNSENTHIGH:
wptr->_HighlightUnsent = attr;
break;
case CRC_B: wptr->_Bold = attr; break;
case CRC_I: wptr->_Italic = attr; break;
case CRC_BI: wptr->_BoldItalic = attr; break;
case CRC_U: wptr->_Underscore = attr; break;
case CRC_BU: wptr->_BoldUnderscore = attr; break;
case CRC_IU: wptr->_ItalicUnderscore = attr; break;
case CRC_BIU: wptr->_BoldItalicUnderscore = attr; break;
case CRC_R: wptr->_Reverse = attr; break;
case CRC_RB: wptr->_ReverseBold = attr; break;
case CRC_RI: wptr->_ReverseItalic = attr; break;
case CRC_RBI: wptr->_ReverseBoldItalic = attr; break;
case CRC_RU: wptr->_ReverseUnderscore = attr; break;
case CRC_RBU: wptr->_ReverseBoldUnderscore = attr; break;
case CRC_RIU: wptr->_ReverseItalicUnderscore = attr; break;
case CRC_RBIU: wptr->_ReverseBoldItalicUnderscore = attr; break;
case CRC_ALL:
if(wptr == &GC_STYLE_) {
wptr->_Bold = attr;
wptr->_Italic = attr;
wptr->_BoldItalic = attr;
wptr->_Underscore = attr;
wptr->_BoldUnderscore = attr;
wptr->_ItalicUnderscore = attr;
wptr->_BoldItalicUnderscore = attr;
wptr->_Reverse = attr;
wptr->_ReverseBold = attr;
wptr->_ReverseItalic = attr;
wptr->_ReverseBoldItalic = attr;
wptr->_ReverseUnderscore = attr;
wptr->_ReverseBoldUnderscore = attr;
wptr->_ReverseItalicUnderscore = attr;
wptr->_ReverseBoldItalicUnderscore = attr;
}
break;
#if !defined(GCFG_NOSPELLDLL)
case CRC_SCERROR:
wptr->_SpellError = attr;
break;
#endif
default:
return;
}
}
// ------------------------------------------------------------------
// Compare escape table items
static int CmpEsc(const char* a, const char* b) {
return strncmp(a, b, 5);
}
// ------------------------------------------------------------------
// Read the translation tables
void ReadXlatTables() {
if(not CFG->xlatcharset.empty() or not CFG->xlatescset.empty()) {
Esc EscTable;
Chs ChsTable;
char buf[256];
char* ptr;
char* ptr2;
FILE *ifp, *ofp;
int line, n, x, y, ch=0;
ofp = fsopen(AddPath(CFG->goldpath, CFG->xlatged), "wb", CFG->sharemode);
if(ofp) {
// Compile CHARSET tables
std::vector<Map>::iterator xlt;
for(xlt = CFG->xlatcharset.begin(); xlt != CFG->xlatcharset.end(); xlt++) {
// Assign table defaults
memset(&ChsTable, 0, sizeof(Chs));
for(n=0; n<256; n++) {
ChsTable.t[n][0] = 1;
ChsTable.t[n][1] = (uint8_t)n; // The character
}
strcpy(buf, AddPath(CFG->xlatpath, xlt->mapfile));
ifp = fsopen(buf, "rb", CFG->sharemode);
if (ifp)
{
if (not quiet)
STD_PRINTNL("* Reading " << buf);
// Read the definition file
line = 1;
while(fgets(buf, sizeof(buf), ifp)) {
ptr = buf;
if(*ptr != ';' and not strblank(ptr)) {
if((ptr2 = strchr(ptr+2, ';')) != NULL)
*ptr2 = NUL;
strtrim(ptr);
if(line < 6) {
switch(line) {
case 1:
ChsTable.id = atol(ptr);
break;
case 2:
ChsTable.version = atoi(ptr);
break;
case 3:
ChsTable.level = atoi(ptr);
if((ChsTable.level == 1) or (ChsTable.id > 65535L))
ch = 0;
else
ch = 128;
break;
case 4:
strcpy(ChsTable.imp, strbtrim(ptr));
break;
case 5:
if(ChsTable.level)
sprintf(ChsTable.exp, "%s %d", strbtrim(ptr), ChsTable.level);
else
strcpy(ChsTable.exp, strbtrim(ptr));
break;
}
}
else {
ptr = strskip_wht(ptr);
if(ch > 255 or strieql(ptr, "END")) // End of table reached
break;
x = 0;
ChsTable.t[ch][0] = (byte)x;
while(*ptr and x < 3) {
if(*ptr == '\\') {
ptr++;
switch(*ptr) {
case '\\':
ChsTable.t[ch][++x] = (byte)'\\';
ChsTable.t[ch][0] = (byte)x;
ptr = strskip_txt(ptr);
break;
case 'd':
y = (uint8_t)atoi(ptr+1);
ChsTable.t[ch][++x] = (byte)y;
ChsTable.t[ch][0] = (byte)x;
ptr = strskip_txt(ptr);
break;
case 'x':
y = (uint8_t)atox(ptr+1);
ChsTable.t[ch][++x] = (byte)y;
ChsTable.t[ch][0] = (byte)x;
ptr = strskip_txt(ptr);
break;
case '0':
ptr = strskip_txt(ptr);
break;
}
}
else {
ChsTable.t[ch][++x] = (byte)*ptr++;
ChsTable.t[ch][0] = (byte)x;
}
ptr = strskip_wht(ptr);
}
ch++;
}
line++;
}
}
fclose(ifp);
}
else
STD_PRINTNL("* XLAT table " << buf << " could not be opened.");
fwrite(&ChsTable, sizeof(Chs), 1, ofp);
}
// Compile ESCSET tables
for(xlt = CFG->xlatescset.begin(); xlt != CFG->xlatescset.end(); xlt++) {
// Assign defaults
memset(&EscTable, 0, sizeof(Esc));
strcpy(buf, AddPath(CFG->xlatpath, xlt->mapfile));
ifp = fsopen(buf, "rb", CFG->sharemode);
if (ifp)
{
if (not quiet)
STD_PRINTNL("* Reading " << buf);
// Read the definition file
line = 1;
while(fgets(buf, sizeof(buf), ifp)) {
ptr = buf;
if(*ptr != ';' and not strblank(ptr)) {
if((ptr2 = strchr(ptr+2, ';')) != NULL)
*ptr2 = NUL;
strtrim(ptr);
if(line < 2) {
switch(line) {
case 1:
strcpy(EscTable.exp, strbtrim(ptr));
break;
}
}
else {
n = EscTable.size;
if(n > 255 or strieql(ptr, "END")) // End of table reached
break;
EscTable.t[n][0] = ptr[0];
EscTable.t[n][1] = ptr[1];
x = 2;
ptr += 2;
ptr = strskip_wht(ptr);
while(*ptr and x < 5) {
if(*ptr == '\\') {
ptr++;
switch(*ptr) {
case '\\':
EscTable.t[n][x++] = '\\';
ptr = strskip_txt(ptr);
break;
case 'd':
EscTable.t[n][x++] = (uint8_t)atoi(ptr+1);
ptr = strskip_txt(ptr);
break;
case 'x':
EscTable.t[n][x++] = (uint8_t)atox(ptr+1);
ptr = strskip_txt(ptr);
break;
case '0':
EscTable.t[n][x++] = NUL;
ptr = strskip_txt(ptr);
break;
}
}
else {
EscTable.t[n][x++] = *ptr++;
}
ptr = strskip_wht(ptr);
}
EscTable.size++;
}
line++;
}
}
qsort(EscTable.t, EscTable.size, 5, (StdCmpCP)CmpEsc);
fclose(ifp);
}
else
STD_PRINTNL("* XLAT table " << buf << " could not be opened.");
fwrite(&EscTable, sizeof(Esc), 1, ofp);
}
fclose(ofp);
}
}
}
// ------------------------------------------------------------------
void CookieIndex(char* textfile, char* indexfile) {
FILE* ifp = fsopen(textfile, "rb", CFG->sharemode);
if(ifp) {
setvbuf(ifp, NULL, _IOFBF, 32000);
FILE* ofp = fsopen(indexfile, "wb", CFG->sharemode);
if(ofp) {
setvbuf(ofp, NULL, _IOFBF, 16000);
char buf[256];
long fpos = 0;
long tpos = 0;
bool was_blank = false;
while(fgets(buf, sizeof(buf), ifp)) {
if(strblank(buf)) {
fwrite(&fpos, sizeof(long), 1, ofp);
fpos = tpos + strlen(buf);
was_blank = true;
}
else {
was_blank = false;
}
tpos += strlen(buf);
}
if(not was_blank)
fwrite(&fpos, sizeof(long), 1, ofp);
fclose(ofp);
}
fclose(ifp);
}
}
// ------------------------------------------------------------------