1 // ---------------------------------------------------------------------------- 2 // Copyright (C) 2014 3 // David Freese, W1HKJ 4 // 5 // This file is part of fldigi 6 // 7 // fldigi is free software; you can redistribute it and/or modify 8 // it under the terms of the GNU General Public License as published by 9 // the Free Software Foundation; either version 3 of the License, or 10 // (at your option) any later version. 11 // 12 // fldigi is distributed in the hope that it will be useful, 13 // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 // GNU General Public License for more details. 16 // 17 // You should have received a copy of the GNU General Public License 18 // along with this program. If not, see <http://www.gnu.org/licenses/>. 19 // ---------------------------------------------------------------------------- 20 21 #ifndef QRZHEADER 22 23 // To include the email code remove the comment specifier from the following line 24 #define HAVE_EMAIL 25 26 // QRZ CDROM data structures 27 28 /* 29 ** Index Header Block Definition (Version 2) 30 ** (applies to all QRZ CDROMS from Version 2 onward) 31 ** 32 ** This block is located at the start of each index 33 */ 34 35 typedef struct { 36 char dataname[16]; /* Name of the data file */ 37 char bytesperkey[8]; /* Data Bytes per Index Item */ 38 char numkeys[8]; /* Number of items in this index */ 39 char keylen[8]; /* Length of each key item in bytes */ 40 char version[8]; /* Database Version ID */ 41 } index_header; 42 43 /* 44 45 Index Usage 46 47 The name index is set to a maximum of 16 characters with longer names 48 being truncated. Names are stored in last-first format with a space 49 between the names. The city/state index uses 12 characters per entry, 50 the callsign index 6 characters and the zip code index 5 characters. 51 52 The data which follows the header is simply a long list of single field 53 records. The records are tightly packed on 'bytesperkey' boundaries 54 without separators. There is no guarantee of a null terminator on any 55 index record entry. 56 57 When the program qrz.exe is run it first searches for a drive 58 containing the base directory \CALLBK . Next, it loads all four index 59 files (callbkc.idx, callbkn.idx, callbks.idx and callbkz.idx) into 60 tables in memory. These tables were kept small so as not to place an 61 undue RAM requirement on the user's system. 62 63 Next, when a user specifies a field and key to search, the program 64 searches the relevant index table and returns the closest match lower 65 (or equal to) the supplied key. The table position of this key is then 66 taken and multiplied by the 'bytesperkey' value to arrive at a database 67 file offset. This offset is then used to perform the first and only 68 seek into the database. Once on position within the file, a sequential 69 search is performed to return the match. The search terminates at the 70 next index key value if the field is not found. 71 72 The database files all have the same format. The records each consist 73 of comma separated fields which end with a single newline '\n' (ASCII 74 0xa) character. Blank fields are simply stored as a comma. Every 75 record has the same number of commas in it. Actual comma's in the data 76 field are stored as a semi-colon ';' which should be replaced by a 77 comma in the user's output formatting routine. 78 79 80 Example: 81 82 AA7BQ ,LLOYD,,FRED L,,53340,90009,00009,8215 E WOOD DR,SCOTTSDALE,AZ, 83 85260,E,KJ6RK,A 84 85 The callsign database is sorted by SUFFIX, AREA, PREFIX. 86 87 For example, the following order would be observed: 88 89 QE24AA 90 ... 91 ZZ99ZZ 92 ... 93 A 0A 94 ... 95 AA0AAA 96 ... 97 ZZ9ZZZ 98 99 This ordering also pertains to the index file since it is just a snaphot of 100 every nth record in the database. 101 102 */ 103 104 /* 105 ** Standard Record Field Offsets 106 */ 107 #define QRZLIB_CALL 0 108 #define QRZLIB_LNAME 1 109 #define QRZLIB_JR 2 110 #define QRZLIB_FNAME 3 111 #define QRZLIB_MI 4 112 #define QRZLIB_DOB 5 113 #define QRZLIB_EFDATE 6 114 #define QRZLIB_EXPDATE 7 115 #define QRZLIB_MAIL_STR 8 116 #define QRZLIB_MAIL_CITY 9 117 #define QRZLIB_MAIL_ST 10 118 #define QRZLIB_MAIL_ZIP 11 119 #define QRZLIB_CLASS 12 120 #define QRZLIB_P_CALL 13 121 #define QRZLIB_P_CLASS 14 122 123 /* 124 125 The fields JR and MI were obsoleted by the FCC in July 1994. 126 127 The callsign fields are arranged in a strict "ccdccc" columnar format 128 where 'c' represents a letter and 'd' a digit. Callsigns which do not 129 conform to the "ccdccc" format are space filled in the relevant 130 positions. This field is rearranged to the proper layout by the user 131 program's output formatting routines. 132 133 All dates are stored in 5 character Julian format, e.g. 93003 equals 134 January 3, 1993. Dates before 1900 or after year 2000 must be 135 determined by their context usage. In other words, if the resultant 136 age does not make sense, then it's wrong. For example, all licenses 137 expire in the future so 02 is 2002. Birthdays are more difficult 138 but most can be determined to be greater than 10 years old. This is 139 not a perfect method, but it does yield satisfactory results. 140 141 Some folks may notice that the database no longer contains station 142 location information. This information is no longer supplied nor 143 available from the FCC since it is no longer a part of their record 144 keeping (See the May 1993 QST for more info). 145 146 147 Cross Reference Information 148 149 Callsigns in the database are now cross-referenced to both the current 150 and the previous call sign for each entry in which they are available. 151 A cross reference record takes the form of 'old,new' with no other 152 information in the record. A record can be identified as a cross 153 reference either one of two ways: 154 155 First, if the record length is less than 15 characters, then 156 it is a cross reference record. 157 158 Secondly, if the record contains only one comma "," , then 159 it is a cross reference record. 160 161 It is not necessary to test for both cases, either will do. 162 163 When a cross reference record is encountered, you must fetch the second 164 field and restart the search to return the primary reference. 165 166 */ 167 168 #include <stdlib.h> 169 #include <stdio.h> 170 #include <string.h> 171 172 extern char *Composite( char * ); 173 174 class QRZ 175 { 176 private: 177 char criteria; 178 index_header idxhdr; 179 char *data; 180 char *index; 181 char *top; 182 FILE *idxfile; 183 long idxsize; 184 FILE *datafile; 185 long dataoffset; 186 long databytesread; 187 char *dfptr; 188 char *endofline; 189 char *idxptr; 190 int found; 191 char recbuffer[512]; 192 unsigned int datarecsize; 193 long numkeys; 194 int keylen; 195 void OpenQRZFiles( const char * ); 196 int FindCallsign( char * ); 197 int FindName( char * ); 198 int FindState( char * ); 199 int FindZip( char * ); 200 int ReadDataBlock( long ); 201 int nextrec(); 202 bool hasImage; 203 204 char *Qcall; 205 char *Qlname; 206 char *Qfname; 207 char *Qdob; 208 char *Qefdate; 209 char *Qexpdate; 210 char *Qmail_str; 211 char *Qmail_city; 212 char *Qmail_st; 213 char *Qmail_zip; 214 char *Qopclass; 215 char *Qp_call; 216 char *Qimagefname; 217 char *Qp_class; 218 219 int QRZvalid; 220 221 public: 222 QRZ( const char * ); 223 QRZ( const char *, char ); 224 ~QRZ(); 225 226 int CallComp( char *, char * ); 227 int CompState( const char *, const char *, const char * ); 228 229 int getQRZvalid(); 230 void NewDBpath( const char * ); 231 232 int FindRecord( char * ); 233 int NextRecord(); 234 int ReadRec(); 235 int GetCount( char * ); 236 char *GetCall(); 237 const char *GetLname(); 238 const char *GetFname(); 239 const char *GetDOB(); 240 const char *GetEFdate(); 241 const char *GetEXPdate(); 242 const char *GetStreet(); 243 const char *GetCity(); 244 const char *GetState(); 245 const char *GetZIP(); 246 const char *GetOPclass(); 247 const char *GetPriorCall(); 248 const char *GetPriorClass(); 249 const char *GetImageFileName(); 250 char *CSV_Record(); 251 char *Fmt_Record(); 252 bool ImageExists(); ImageFileName()253 const char *ImageFileName() {return Qimagefname;}; 254 }; 255 256 extern void SetQRZdirectory(char *dir); 257 extern int filename_expand(char *to,int tolen, const char *from); 258 259 #define QRZHEADER 260 261 #endif 262