The SWORD Project  1.9.0.svnversion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vpl2mod.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * vpl2mod.cpp - Utility to import VPL formatted modules
4  *
5  * $Id: vpl2mod.cpp 3063 2014-03-04 13:04:11Z chrislit $
6  *
7  * Copyright 2000-2013 CrossWire Bible Society (http://www.crosswire.org)
8  * CrossWire Bible Society
9  * P. O. Box 2528
10  * Tempe, AZ 85280-2528
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License as published by the
14  * Free Software Foundation version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  */
22 
23 #ifdef _MSC_VER
24  #pragma warning( disable: 4251 )
25  #pragma warning( disable: 4996 )
26 #endif
27 
28 #include <ctype.h>
29 #include <stdio.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <sys/stat.h>
34 
35 #ifndef __GNUC__
36 #include <io.h>
37 #else
38 #include <unistd.h>
39 #endif
40 
41 #include <filemgr.h>
42 #include <swmgr.h>
43 #include <rawtext.h>
44 #include <swbuf.h>
45 #include <versekey.h>
46 
47 #ifndef NO_SWORD_NAMESPACE
48 using sword::FileMgr;
49 using sword::SWMgr;
50 using sword::RawText;
51 using sword::VerseKey;
52 using sword::SWBuf;
53 using sword::SW_POSITION;
54 #endif
55 
56 
57 char readline(int fd, char **buf) {
58  char ch;
59  if (*buf)
60  delete [] *buf;
61  *buf = 0;
62  int len;
63 
64 
65  long index = lseek(fd, 0, SEEK_CUR);
66  // clean up any preceding white space
67  while ((len = read(fd, &ch, 1)) == 1) {
68  if ((ch != 13) && (ch != ' ') && (ch != '\t'))
69  break;
70  else index++;
71  }
72 
73 
74  while (ch != 10) {
75  if ((len = read(fd, &ch, 1)) != 1)
76  break;
77  }
78 
79  int size = (lseek(fd, 0, SEEK_CUR) - index) - 1;
80 
81  *buf = new char [ size + 1 ];
82 
83  if (size > 0) {
84  lseek(fd, index, SEEK_SET);
85  read(fd, *buf, size);
86  read(fd, &ch, 1); //pop terminating char
87  (*buf)[size] = 0;
88 
89  // clean up any trailing junk on buf
90  for (char *it = *buf+(strlen(*buf)-1); it > *buf; it--) {
91  if ((*it != 10) && (*it != 13) && (*it != ' ') && (*it != '\t'))
92  break;
93  else *it = 0;
94  }
95  }
96  else **buf = 0;
97  return !len;
98 }
99 
100 
101 char *parseVReg(char *buf) {
102  char stage = 0;
103 
104  while (*buf) {
105  switch (stage) {
106  case 0:
107  if (isalpha(*buf))
108  stage++;
109  break;
110  case 1:
111  if (isdigit(*buf))
112  stage++;
113  break;
114  case 2:
115  if (*buf == ':')
116  stage++;
117  break;
118  case 3:
119  if (isdigit(*buf))
120  stage++;
121  break;
122  case 4:
123  if (*buf == ' ') {
124  *buf = 0;
125  return ++buf;
126  }
127  break;
128  }
129  buf++;
130  }
131  return (stage == 4) ? buf : 0; // if we got to stage 4 return after key buf, else return 0;
132 }
133 
134 
135 bool isKJVRef(const char *buf) {
136  VerseKey vk, test;
137  vk.setAutoNormalize(false);
138  vk.setIntros(true); // turn on mod/testmnt/book/chap headings
139  vk.setPersist(true);
140  // lets do some tests on the verse --------------
141  vk = buf;
142  test = buf;
143 
144  if (vk.getTestament() && vk.getBook() && vk.getChapter() && vk.getVerse()) { // if we're not a heading
145 // std::cerr << (const char*)vk << " == " << (const char*)test << std::endl;
146  return (vk == test);
147  }
148  else return true; // no check if we're a heading... Probably bad.
149 }
150 
151 
152 void fixText(char *text) {
153  char *to = text;
154  while(*text) {
155  *to++ = *text++;
156  *to++ = *text++;
157  if (!*text)
158  break;
159  if (*text != ' ')
160  std::cerr << "problem\n";
161  else text++;
162  }
163  *to = 0;
164 }
165 
166 int main(int argc, char **argv) {
167 
168  // Let's test our command line arguments
169  if (argc < 2) {
170 // fprintf(stderr, "usage: %s <vpl_file> </path/to/mod> [0|1 - file includes prepended verse references]\n", argv[0]);
171  fprintf(stderr, "usage: %s <source_vpl_file> </path/to/output/mod/> [0|1 - prepended verse refs] [0|1 - NT only]\n\n", argv[0]);
172  fprintf(stderr, "\tWARNING: THIS IS CURRENTLY A KJV-VERSIFICATION-ONLY UTILITY\n");
173  fprintf(stderr, "\tWith no verse refs, source file must contain exactly 31102 lines.\n");
174  fprintf(stderr, "\tThis is KJV verse count plus headings for MODULE,\n");
175  fprintf(stderr, "\tTESTAMENT, BOOK, CHAPTER. An example snippet follows:\n\n");
176  fprintf(stderr, "\t\tMODULE HEADER\n");
177  fprintf(stderr, "\t\tOLD TESTAMENT HEADER\n");
178  fprintf(stderr, "\t\tGENESIS HEADER\n");
179  fprintf(stderr, "\t\tCHAPTER 1 HEADER\n");
180  fprintf(stderr, "\t\tIn the beginning...\n\n");
181  fprintf(stderr, "\t... implying there must also be a CHAPTER2 HEADER,\n");
182  fprintf(stderr, "\tEXODUS HEADER, NEW TESTAMENT HEADER, etc. If there is no text for\n");
183  fprintf(stderr, "\tthe header, a blank line must, at least, hold place.\n\n");
184  fprintf(stderr, "\tWith verse refs, source file must simply contain any number of lines,\n");
185  fprintf(stderr, "\tthat begin with the verse reference for which it is an entry. e.g.:\n\n");
186  fprintf(stderr, "\t\tgen 1:0 CHAPTER 1 HEADER\n");
187  fprintf(stderr, "\t\tgen 1:1 In the beginning...\n\n");
188  exit(-1);
189  }
190 
191  // Let's see if we can open our input file
192  int fd = FileMgr::openFileReadOnly(argv[1]);
193  if (fd < 0) {
194  fprintf(stderr, "error: %s: couldn't open input file: %s \n", argv[0], argv[1]);
195  exit(-2);
196  }
197 
198  // Try to initialize a default set of datafiles and indicies at our
199  // datapath location passed to us from the user.
200  if (RawText::createModule(argv[2])) {
201  fprintf(stderr, "error: %s: couldn't create module at path: %s \n", argv[0], argv[2]);
202  exit(-3);
203  }
204 
205  // not used yet, but for future support of a vpl file with each line
206  // prepended with verse reference, eg. "Gen 1:1 In the beginning..."
207  bool vref = false;
208  if (argc > 3)
209  vref = (argv[3][0] == '0') ? false : true;
210 
211  // if 'nt' is the 4th arg, our vpl file only has the NT
212  bool ntonly = false;
213  if (argc > 4)
214  ntonly = (argv[4][0] == '0') ? false : true;
215 
216  // Do some initialization stuff
217  char *buffer = 0;
218  RawText mod(argv[2]); // open our datapath with our RawText driver.
219  VerseKey vk;
220  vk.setAutoNormalize(false);
221  vk.setIntros(true); // turn on mod/testmnt/book/chap headings
222  vk.setPersist(true);
223 
224  mod.setKey(vk);
225 
226  // Loop through module from TOP to BOTTOM and set next line from
227  // input file as text for this entry in the module
228  mod = TOP;
229  if (ntonly) vk = "Matthew 1:1";
230 
231  int successive = 0; //part of hack below
232  while ((!mod.popError()) && (!readline(fd, &buffer))) {
233  if (*buffer == '|') // comments, ignore line
234  continue;
235  if (vref) {
236  const char *verseText = parseVReg(buffer);
237  if (!verseText) { // if we didn't find a valid verse ref
238  std::cerr << "No valid verse ref found on line: " << buffer << "\n";
239  exit(-4);
240  }
241 
242  vk = buffer;
243  if (vk.popError()) {
244  std::cerr << "Error parsing key: " << buffer << "\n";
245  exit(-5);
246  }
247  SWBuf orig = mod.getRawEntry();
248 
249  if (!isKJVRef(buffer)) {
250  VerseKey origVK = vk;
251  /* This block is functioning improperly -- problem with AutoNormalize???
252  do {
253  vk--;
254  }
255  while (!vk.popError() && !isKJVRef(vk)); */
256  //hack to replace above:
257  successive++;
258  vk -= successive;
259  orig = mod.getRawEntry();
260 
261  std::cerr << "Not a valid KJV ref: " << origVK << "\n";
262  std::cerr << "appending to ref: " << vk << "\n";
263  orig += " [ (";
264  orig += origVK;
265  orig += ") ";
266  orig += verseText;
267  orig += " ] ";
268  verseText = orig;
269  }
270  else {
271  successive = 0;
272  }
273 
274  if (orig.length() > 1)
275  std::cerr << "Warning, overwriting verse: " << vk << std::endl;
276 
277  // ------------- End verse tests -----------------
278  mod << verseText; // save text to module at current position
279  }
280  else {
281  fixText(buffer);
282  mod << buffer; // save text to module at current position
283  mod++; // increment module position
284  }
285  }
286 
287  // clear up our buffer that readline might have allocated
288  if (buffer)
289  delete [] buffer;
290 }
#define TOP
Definition: swkey.h:68
Definition: swbuf.h:47
unsigned long length() const
Definition: swbuf.h:197
#define SEEK_CUR
Definition: zconf.h:245
static char createModule(const char *path, const char *v11n="KJV")
Definition: rawtext.h:46
static int openFileReadOnly(const char *fName)
Definition: filemgr.cpp:474
bool isKJVRef(const char *buf)
Definition: vpl2mod.cpp:135
preg buffer
Definition: regex.c:8089
virtual char setKey(const SWKey *ikey)
Definition: swmodule.cpp:298
int main(int argc, char **argv)
Definition: addcomment.cpp:32
char readline(int fd, char **buf)
Definition: vpl2mod.cpp:57
void setPersist(bool ipersist)
Definition: swkey.cpp:135
virtual void setIntros(bool val)
Definition: versekey.cpp:1663
virtual int getChapter() const
Definition: versekey.cpp:1522
virtual char getBook() const
Definition: versekey.cpp:1510
virtual int getVerse() const
Definition: versekey.cpp:1534
virtual char popError()
Definition: swmodule.cpp:185
void fixText(char *text)
Definition: vpl2mod.cpp:152
virtual char popError()
Definition: swkey.cpp:147
#define SEEK_SET
Definition: zconf.h:244
int size
Definition: regex.c:5043
const char * getRawEntry() const
Definition: swmodule.h:500
virtual void setAutoNormalize(bool iautonorm)
Definition: versekey.cpp:1648
virtual char getTestament() const
Definition: versekey.cpp:1498
char * parseVReg(char *buf)
Definition: vpl2mod.cpp:101