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
27using namespace basis;
28using namespace configuration;
29using namespace loggers;
30using namespace structures;
31using namespace textual;
32
33namespace 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
43const char *PRODUCT_HEADING() { return "product"; }
44 // the string used for our startup entries as a prefix to the product.
45
46const char *ASSIGN_TOKEN() { return "="; }
47 // how we distinguish the key from the value for startup entries.
48
49const char *SEPARATOR_TOKEN() { return ","; }
50 // the character between separate key/value pairs in the startup string.
51
52const char *SEPARATOR_TEXT() { return ", "; }
53 // the string we use for the separator when printing it.
54
55const char *PARMS_HEADING() { return "parms"; }
56 // the tag for parameters in the startup entry.
57
58const char *ONESHOT_HEADING() { return "oneshot"; }
59 // the key name for startup entries' flag for once only execution.
60
62
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.
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
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
#define LOG(s)
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:760
virtual void zap(int start, int end)
Deletes the characters between "start" and "end" inclusively.
Definition astring.cpp:524
bool iequals(const astring &that) const
returns true if this is case-insensitively equal to "that".
Definition astring.cpp:568
int find(char to_find, int position=0, bool reverse=false) const
Locates "to_find" in "this".
Definition astring.cpp:577
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.
configured_applications(const basis::astring &config_file, const basis::astring &basename)
manages application settings for in the "config_file".
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.
const basis::astring & name(int index) const
returns the name held at the "index".
contents * find(const basis::astring &name) const
returns the contents held for "name" or NULL_POINTER if it wasn't found.
basis::outcome add(const basis::astring &name, const contents &storage)
Enters a symbol name into the table along with some contents.
basis::outcome whack(const basis::astring &name)
removes a symbol from the table.
int symbols() const
returns the number of symbols listed in the table.
static basis::astring substitute_env_vars(const basis::astring &text, bool leave_unknown=true)
resolves embedded environment variables in "text".
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
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 * ASSIGN_TOKEN()
const char * SEPARATOR_TEXT()
const char * PRODUCT_HEADING()
const char * PARMS_HEADING()
const char * SEPARATOR_TOKEN()
A dynamic container class that holds any kind of object via pointers.
Definition amorph.h:55