feisty meow concerns codebase  2.140
configured_applications.cpp
Go to the documentation of this file.
1 /*****************************************************************************\
2 * *
3 * Name : configured_applications
4 * Author : Chris Koeritz
5 * *
6 *******************************************************************************
7 * Copyright (c) 2000 By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
14 
16 
17 #include <basis/astring.h>
18 #include <basis/mutex.h>
23 #include <structures/set.h>
25 #include <textual/parser_bits.h>
26 
27 using namespace basis;
28 using namespace configuration;
29 using namespace loggers;
30 using namespace structures;
31 using namespace textual;
32 
33 namespace processes {
34 
35 //#define DEBUG_APP_CONFIG
36  // uncomment for noisier debugging version.
37 
38 #undef LOG
39 #define LOG(to_print) program_wide_logger::get().log(to_print, ALWAYS_PRINT)
40 
42 
43 const char *PRODUCT_HEADING() { return "product"; }
44  // the string used for our startup entries as a prefix to the product.
45 
46 const char *ASSIGN_TOKEN() { return "="; }
47  // how we distinguish the key from the value for startup entries.
48 
49 const char *SEPARATOR_TOKEN() { return ","; }
50  // the character between separate key/value pairs in the startup string.
51 
52 const char *SEPARATOR_TEXT() { return ", "; }
53  // the string we use for the separator when printing it.
54 
55 const char *PARMS_HEADING() { return "parms"; }
56  // the tag for parameters in the startup entry.
57 
58 const char *ONESHOT_HEADING() { return "oneshot"; }
59  // the key name for startup entries' flag for once only execution.
60 
62 
63 configured_applications::configured_applications(const astring &config_file,
64  const astring &basename)
65 : _lock(new mutex),
66  _config(new ini_configurator(config_file, ini_configurator::RETURN_ONLY,
67  ini_configurator::APPLICATION_DIRECTORY)),
68  _sector(new section_manager(*_config, astring(basename) + "_TOC",
69  astring(PRODUCT_HEADING()) + "_"))
70 {
71  FUNCDEF("constructor");
72  string_table startup_info;
73  if (!find_section(STARTUP_SECTION(), startup_info)) {
74  // if there's no startup section, we do nothing right now.
75  LOG(astring("the startup section doesn't exist yet; adding it now."));
76  astring entry = make_startup_entry(basename, "", false);
77  startup_info.add(STARTUP_APP_NAME(), entry);
78  add_section(STARTUP_SECTION(), startup_info);
79  }
80 }
81 
83 {
84  WHACK(_sector);
85  WHACK(_config);
86  WHACK(_lock);
87 }
88 
90 { return "PRIVATE_STARTUP_LNCH1.0"; }
91 
93 { return "placeholder"; }
94 
96 {
97  auto_synchronizer l(*_lock);
98  if (!_sector->section_exists(product)) return false;
99  return true;
100 }
101 
103  const astring &app_name, int &level)
104 {
105  auto_synchronizer l(*_lock);
106  astring heading = _sector->make_section_heading(product);
107  astring found = _sector->config().load(heading, app_name, "");
109 //overly specific bits here...
110 //hmmm: add this in as a specialization provided by real owner of class.
111  if (!found) {
112  // we didn't find the entry under the section we wanted to find it in.
113  // there are a couple cases where we can kludge this section to a
114  // different name, based on legacy requirements, and still find the
115  // right item possibly.
116  if (product.iequals("supervisor")) {
117  // for some older installs, they say "supervisor" but mean "core".
118  heading = _sector->make_section_heading("core");
119  found = _sector->config().load(heading, app_name, "");
120  } else if (product.iequals("lightlink")) {
121  heading = _sector->make_section_heading("core");
122  found = _sector->config().load(heading, app_name, "");
123  if (!found) {
124  // we can take one more remedial step for this phrase.
125  heading = _sector->make_section_heading("server");
126  found = _sector->config().load(heading, app_name, "");
127  }
128  }
129  }
130 //end of overly specific.
132  found = parser_bits::substitute_env_vars(found);
133 
134  int comma_loc = found.find(",");
135  if (negative(comma_loc)) return ""; // couldn't find our priority.
136  level = found.convert(0);
137  found.zap(0, comma_loc);
138 
139  return found;
140 }
141 
143  const astring &app_name, const astring &full_path, int level)
144 {
145 #ifdef DEBUG_APP_CONFIG
146  FUNCDEF("add_program");
147 #endif
148  auto_synchronizer l(*_lock);
149  bool existed = true;
150  // lookup the section, if it exists.
151  string_table info_table;
152  if (!_sector->section_exists(product)) {
153  existed = false;
154  } else
155  find_section(product, info_table);
156 #ifdef DEBUG_APP_CONFIG
157  if (existed) {
158  LOG(astring("section for ") + product + " found:");
159  for (int i = 0; i < info_table.symbols(); i++)
160  LOG(astring("key=") + info_table.name(i) + " value=" + info_table[i]);
161  } else LOG(astring("section for ") + product + " not found.");
162 #endif
163  // remove any existing entry.
164  info_table.whack(app_name);
165  // plug in our new entry.
166  a_sprintf full_entry("%d,%s", level, full_path.s());
167  info_table.add(app_name, full_entry);
168 #ifdef DEBUG_APP_CONFIG
169  LOG(astring("new section for ") + product + " has:");
170  for (int i = 0; i < info_table.symbols(); i++)
171  LOG(astring("key=") + info_table.name(i) + " value=" + info_table[i]);
172 #endif
173  // now call the proper storage function based on whether the section
174  // existed before or not.
175  if (existed) return replace_section(product, info_table);
176  else return add_section(product, info_table);
177 }
178 
180  const astring &app_name)
181 {
182  FUNCDEF("remove_program");
183  auto_synchronizer l(*_lock);
184  // if the section's missing, there's nothing to remove...
185  string_table info_table;
186  if (!find_section(product, info_table)) return true;
187  // the section did exist, so remove any existing entry.
188  info_table.whack(app_name);
189  // now call the proper storage function based on whether the section
190  // existed before or not.
191  return replace_section(product, info_table);
192 }
193 
195  string_table &info_found)
196 {
197  FUNCDEF("find_section");
198  info_found.reset();
199  auto_synchronizer l(*_lock);
200  if (!_sector->find_section(section_name, info_found)) {
201  LOG(section_name + " was not found in the configuration.");
202  return false;
203  }
204  return true;
205 }
206 
208  const string_table &info_found)
209 {
210  auto_synchronizer l(*_lock);
211  return _sector->add_section(section_name, info_found);
212 }
213 
215  const string_table &info_found)
216 {
217  auto_synchronizer l(*_lock);
218  return _sector->replace_section(section_name, info_found);
219 }
220 
222  const astring &parms, bool one_shot)
223 {
224  return astring(PRODUCT_HEADING()) + ASSIGN_TOKEN() + product
226  + parms + SEPARATOR_TEXT() + ONESHOT_HEADING() + ASSIGN_TOKEN()
227  + astring(astring::SPRINTF, "%d", one_shot);
228 }
229 
231  astring &product, astring &parms, bool &one_shot)
232 {
233  FUNCDEF("parse_startup_section");
234  // parse the items that are in the entry for this program.
236  entry_parser.parse(info);
237  // grab the pertinent bits for the program to be started.
238  product = entry_parser.find(PRODUCT_HEADING());
239  parms = entry_parser.find(PARMS_HEADING());
240 //LOG(astring("parms=") + parms);
241  astring once = entry_parser.find(ONESHOT_HEADING());
242  one_shot = (bool)once.convert(0);
243  // we require the product part at least.
244  if (!product) return false;
245  return true;
246 }
247 
249  const astring &name, astring &location)
250 {
251  // seek the entry in the table specified.
252  astring *found = table.find(name);
253  if (!found) return false;
254  // found the entry using the name.
255  location = *found;
256  return true;
257 }
258 
260  const astring &app_name, const astring &parameters, int one_shot)
261 {
262  FUNCDEF("add_startup_entry");
263  auto_synchronizer l(*_lock);
264 
265  LOG(astring("product \"") + product + "\", application \"" + app_name
266  + (one_shot? astring("\", OneShot") : astring("\", MultiUse")));
267 
268  string_table startup_info;
269  if (!find_section(STARTUP_SECTION(), startup_info)) {
270  // if there's no startup section, we can't go on. that should have been
271  // created during startup of this program.
272  LOG(astring("internal startup section not found!"));
273  return false;
274  }
275 
276  astring new_entry = make_startup_entry(product, parameters,
277  one_shot);
278  startup_info.add(app_name, new_entry);
279  if (!replace_section(STARTUP_SECTION(), startup_info))
280  return false;
281 //hmmm: that's a bogus error; this is really an internal fup error.
282 
283  return true;
284 }
285 
287  const astring &app_name)
288 {
289  FUNCDEF("remove_startup_entry");
290  auto_synchronizer l(*_lock);
291 
292  LOG(astring("product \"") + product + "\", application \"" + app_name + "\"");
293 
294  string_table startup_info;
295  if (!find_section(STARTUP_SECTION(), startup_info)) {
296  // if there's no startup section, we try to add one.
297  add_section(STARTUP_SECTION(), startup_info);
298  // if it still doesn't exist afterwards, we're hosed.
299  if (!find_section(STARTUP_SECTION(), startup_info)) {
301 //massive fup of some unanticipated sort.
302 //complain.
303  return false;
304  }
305  }
306 
307  // check that the entry already exists for this program.
308  astring entry_found;
309  if (!find_entry(startup_info, app_name, entry_found)) {
310 // COMPLAIN_APPLICATION;
311  LOG(astring("no entry was found for ") + app_name);
312  return false;
313  }
314 
315  startup_info.whack(app_name);
316  if (!replace_section(STARTUP_SECTION(), startup_info)) {
317 //what happened with that?
318  return false;
319  }
320 
321  return true;
322 }
323 
324 } //namespace.
325 
326 
a_sprintf is a specialization of astring that provides printf style support.
Definition: astring.h:440
Provides a dynamically resizable ASCII character string.
Definition: astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition: astring.h:113
int convert(int default_value) const
Converts the string into a corresponding integer.
Definition: astring.cpp:757
virtual void zap(int start, int end)
Deletes the characters between "start" and "end" inclusively.
Definition: astring.cpp:521
bool iequals(const astring &that) const
returns true if this is case-insensitively equal to "that".
Definition: astring.cpp:565
int find(char to_find, int position=0, bool reverse=false) const
Locates "to_find" in "this".
Definition: astring.cpp:574
auto_synchronizer simplifies concurrent code by automatically unlocking.
Definition: mutex.h:113
basis::astring load(const basis::astring &section, const basis::astring &entry, const basis::astring &default_value)
a synonym for get that implements the auto-store behavior.
Supports a configurator-based interface on text initialization files.
Tracks a collection of related configurations in a configurator.
basis::astring make_section_heading(const basis::astring &section)
provides the appropriate heading string for the "section" name.
bool add_section(const basis::astring &section_name, const structures::string_table &to_add)
stores a new section for "section_name" using the table "to_add".
bool section_exists(const basis::astring &section_name)
returns true if the section called "section_name" exists in the config.
bool replace_section(const basis::astring &section, const structures::string_table &replacement)
replaces the contents of "section" with the "replacement" table.
bool find_section(const basis::astring &section_name, structures::string_table &found)
loads the data from "section_name" into the table "found".
configurator & config()
allows access to the configurator we operate on.
Manages a bank of textual definitions of variables.
basis::astring find(const basis::astring &name) const
locates the value for a variable named "name" if it exists.
bool parse(const basis::astring &to_tokenize)
parses the string using our established sentinel characters.
bool replace_section(const basis::astring &section_name, const structures::string_table &info)
replaces the section for "section_name" with "info".
bool remove_startup_entry(const basis::astring &product, const basis::astring &app_name)
takes an existing entry for the "app_name" out of the startup section.
bool add_program(const basis::astring &product, const basis::astring &app_name, const basis::astring &full_path, int level)
registers a program "app_name" into the "product" section.
static const char * STARTUP_SECTION()
the section where startup info is stored.
bool add_startup_entry(const basis::astring &product, const basis::astring &app_name, const basis::astring &parameters, int one_shot)
establishes the "app_name" as a program launched at object startup.
static const char * STARTUP_APP_NAME()
a special placeholder name that will appear in the startup list.
bool add_section(const basis::astring &section_name, const structures::string_table &info)
puts a chunk of "info" into the section for "section_name".
static bool parse_startup_entry(const basis::astring &info, basis::astring &product, basis::astring &parms, bool &one_shot)
processes the items in "info" as an application startup list.
bool product_exists(const basis::astring &product)
returns true if the section for "product" exists in the TOC.
static basis::astring make_startup_entry(const basis::astring &product, const basis::astring &parms, bool one_shot)
returns the appropriate string for a startup record.
bool remove_program(const basis::astring &product, const basis::astring &app_name)
takes a previously registered "app_name" out of the list for "product".
basis::astring find_program(const basis::astring &product, const basis::astring &app_name, int &level)
seeks out the entry for the "product" and "app_name" in our info.
bool find_section(const basis::astring &section_name, structures::string_table &info_found)
locates the entries for "section_name" and stores them in "info_found".
static bool find_entry(const structures::string_table &table, const basis::astring &name, basis::astring &location)
returns true if the key "name" for a program is found in the "table".
Provides a symbol_table that holds strings as the content.
Definition: string_table.h:32
const basis::astring & name(int index) const
returns the name held at the "index".
Definition: symbol_table.h:272
contents * find(const basis::astring &name) const
returns the contents held for "name" or NULL_POINTER if it wasn't found.
Definition: symbol_table.h:313
basis::outcome add(const basis::astring &name, const contents &storage)
Enters a symbol name into the table along with some contents.
Definition: symbol_table.h:383
basis::outcome whack(const basis::astring &name)
removes a symbol from the table.
Definition: symbol_table.h:410
int symbols() const
returns the number of symbols listed in the table.
Definition: symbol_table.h:241
#define LOG(to_print)
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition: enhance_cpp.h:57
The guards collection helps in testing preconditions and reporting errors.
Definition: array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
bool negative(const type &a)
negative returns true if "a" is less than zero.
Definition: functions.h:43
A logger that sends to the console screen using the standard output device.
const char * ONESHOT_HEADING()
const char * PARMS_HEADING()
const char * ASSIGN_TOKEN()
const char * PRODUCT_HEADING()
const char * SEPARATOR_TEXT()
const char * SEPARATOR_TOKEN()
A dynamic container class that holds any kind of object via pointers.
Definition: amorph.h:55