The SWORD Project  1.9.0.svnversion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
osisheadings.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * osisheadings.cpp - SWFilter descendant to hide or show headings
4  * in an OSIS module
5  *
6  * $Id: osisheadings.cpp 3646 2019-06-10 03:46:13Z scribe $
7  *
8  * Copyright 2003-2013 CrossWire Bible Society (http://www.crosswire.org)
9  * CrossWire Bible Society
10  * P. O. Box 2528
11  * Tempe, AZ 85280-2528
12  *
13  * This program is free software; you can redistribute it and/or modify it
14  * under the terms of the GNU General Public License as published by the
15  * Free Software Foundation version 2.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20  * General Public License for more details.
21  *
22  */
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <osisheadings.h>
27 #include <swmodule.h>
28 #include <utilxml.h>
29 #include <utilstr.h>
30 
31 
33 
34 namespace {
35 
36  static const char oName[] = "Headings";
37  static const char oTip[] = "Toggles Headings On and Off if they exist";
38 
39  static const StringList *oValues() {
40  static const SWBuf choices[3] = {"Off", "On", ""};
41  static const StringList oVals(&choices[0], &choices[2]);
42  return &oVals;
43  }
44 
45 
47  public:
50  const char *sID;
52  int depth;
53  int headerNum;
54  bool canonical;
55 
56  MyUserData(const SWModule *module, const SWKey *key) : BasicFilterUserData(module, key) {
57  clear();
58  }
59  void clear() {
60  currentHeadingName = "";
61  currentHeadingTag = "";
62  sID = 0;
63  heading = "";
64  depth = 0;
65  headerNum = 0;
66  canonical=false;
67  }
68  };
69 }
70 
71 
73  return new MyUserData(module, key);
74 }
75 
76 
79 }
80 
81 
82 bool OSISHeadings::handleToken(SWBuf &buf, const char *token, BasicFilterUserData *userData) {
83 
84  MyUserData *u = (MyUserData *)userData;
85  XMLTag tag(token);
86  SWBuf name = tag.getName();
87 
88  // we only care about titles and divs or if we're already in a heading
89  //
90  // are we currently in a heading?
91  if (u->currentHeadingName.size()) {
92  u->heading.append(u->lastTextNode);
93  if (SWBuf("true") == tag.getAttribute("canonical")) u->canonical = true;
94  if (name == u->currentHeadingName) {
95  if (tag.isEndTag(u->sID)) {
96  if (!u->depth-- || u->sID) {
97  // see comment below about preverse div changed and needing to preserve the <title> container tag for old school pre-verse titles
98  // we've just finished a heading. It's all stored up in u->heading
99  bool preverse = (SWBuf("x-preverse") == u->currentHeadingTag.getAttribute("subType") || SWBuf("x-preverse") == u->currentHeadingTag.getAttribute("subtype"));
100 
101  // do we want to put anything in EntryAttributes?
102  if (u->module->isProcessEntryAttributes() && (option || u->canonical || !preverse)) {
103  SWBuf hn; hn.appendFormatted("%i", u->headerNum++);
104  // leave the actual <title...> wrapper in if we're part of an old school preverse title
105  // because now frontend have to deal with preverse as a div which may or may not include <title> elements
106  // and they can't simply wrap all preverse material in <h1>, like they probably did previously
107  SWBuf heading;
108  if (u->currentHeadingName == "title") {
109  XMLTag wrapper = u->currentHeadingTag;
110  if (SWBuf("x-preverse") == wrapper.getAttribute("subType")) wrapper.setAttribute("subType", 0);
111  else if (SWBuf("x-preverse") == wrapper.getAttribute("subtype")) wrapper.setAttribute("subtype", 0);
112  heading = wrapper;
113  heading += u->heading;
114  heading += tag;
115  }
116  else heading = u->heading;
117  u->module->getEntryAttributes()["Heading"][(preverse)?"Preverse":"Interverse"][hn] = heading;
118 
119  StringList attributes = u->currentHeadingTag.getAttributeNames();
120  for (StringList::const_iterator it = attributes.begin(); it != attributes.end(); it++) {
121  u->module->getEntryAttributes()["Heading"][hn][it->c_str()] = u->currentHeadingTag.getAttribute(it->c_str());
122  }
123  // if any title in the heading was canonical, then set canonical=true.
124  // TODO: split composite headings with both canonical and non-canonical headings
125  // into two heading attributes with proper canonical value on each
126  if (u->canonical) u->module->getEntryAttributes()["Heading"][hn]["canonical"] = "true";
127  }
128 
129  // do we want the heading in the body?
130  // if we're not processing entryAttributes, then it's not going anyplace else
131  if ((!preverse || !u->module->isProcessEntryAttributes()) && (option || u->canonical)) {
132  buf.append(u->currentHeadingTag);
133  buf.append(u->heading);
134  buf.append(tag);
135  }
136  u->suspendTextPassThru = false;
137  u->clear();
138  }
139  }
140  else u->depth++;
141  }
142  u->heading.append(tag);
143  return true;
144  }
145 
146  // are we a title or a preverse div?
147  else if ( name == "title"
148  || (name == "div"
149  && ( SWBuf("x-preverse") == tag.getAttribute("subType")
150  || SWBuf("x-preverse") == tag.getAttribute("subtype")))) {
151 
152  u->currentHeadingName = name;
153  u->currentHeadingTag = tag;
154  u->heading = "";
155  u->sID = u->currentHeadingTag.getAttribute("sID");
156  u->depth = 0;
157  u->suspendTextPassThru = true;
158  u->canonical = (SWBuf("true") == tag.getAttribute("canonical"));
159 
160  return true;
161  }
162 
163  return false;
164 }
165 
166 
167 
169 
virtual BasicFilterUserData * createUserData(const SWModule *module, const SWKey *key)
#define SWORD_NAMESPACE_START
Definition: defs.h:39
SWBuf & appendFormatted(const char *format,...)
Definition: swbuf.cpp:81
Definition: swbuf.h:47
const char * setAttribute(const char *attribName, const char *attribValue, int partNum=-1, char partSplit= '|')
Definition: utilxml.cpp:248
void setPassThruUnknownToken(bool val)
const char * getName() const
Definition: utilxml.h:58
SWText * module
Definition: osis2mod.cpp:105
Definition: utilxml.h:38
virtual bool handleToken(SWBuf &buf, const char *token, BasicFilterUserData *userData)
static const StringList * oValues()
MyUserData(const SWModule *module, const SWKey *key)
std::list< SWBuf > StringList
Definition: swmodule.cpp:91
SWBuf & append(const char *str, long max=-1)
Definition: swbuf.h:274
static const char oName[]
if(cflags &REG_ICASE)
Definition: regex.c:8096
static const char * choices[4]
const char * getAttribute(const char *attribName, int partNum=-1, char partSplit= '|') const
Definition: utilxml.cpp:230
static const char oTip[]
bool isEndTag(const char *eID=0) const
Definition: utilxml.cpp:323
#define SWORD_NAMESPACE_END
Definition: defs.h:40
Definition: swkey.h:77