root/main/trunk/greenstone2/common-src/src/lib/gsdltools.cpp @ 21461

Revision 21461, 8.9 KB (checked in by ak19, 10 years ago)

Error messages are sent to stderr, since there are linking errors in generating oaiserver and library.cgi when the graphical Messagebox method is called. We can use the Messagebox for debugging the local library server (server.exe) instead.

  • Property svn:keywords set to Author Date Id Revision
Line 
1/**********************************************************************
2 *
3 * gsdltools.cpp --
4 * A component of the Greenstone digital library software
5 * from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Copyright (C) 1999  The New Zealand Digital Library Project
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *********************************************************************/
25
26#include "gsdltools.h"
27#include "fileutil.h"
28#include "stdlib.h"
29
30
31#if defined(GSDL_USE_OBJECTSPACE)
32#  include <ospace/std/iostream>
33#elif defined(GSDL_USE_IOS_H)
34#  include <iostream.h>
35#else
36#  include <iostream>
37using namespace std;
38#endif
39
40
41#if defined(__WIN32__)
42#include <windows.h>
43#include <process.h>
44#endif
45
46#if !defined (__WIN32__)
47#include <sys/utsname.h>
48#include <unistd.h>
49#endif
50
51
52bool littleEndian() {
53  char s[2] = {'\xFE', '\xEF'};
54
55  if (sizeof(unsigned short) == 2)
56    return *(unsigned short*)s == 0xEFFE;
57  else if (sizeof(unsigned int) == 2)
58    return *(unsigned int*)s == 0xEFFE;
59}
60
61text_t dm_safe (const text_t &instring) {
62
63  text_t outstring;
64  text_t::const_iterator here = instring.begin();
65  text_t::const_iterator end = instring.end();
66  while (here != end) {
67    if (*here == '_' || *here == '\\') outstring.push_back('\\');
68    outstring.push_back(*here);
69    ++here;
70  }
71  return outstring;
72}
73
74void dm_js_safe(const text_t &instring, text_t &outstring)
75{
76  text_t::const_iterator here = instring.begin();
77  text_t::const_iterator end = instring.end();
78  while (here != end) {
79    if (*here == '_') outstring.push_back('\\');
80    else if (*here == '\\' || *here == '\'') {
81      outstring.push_back('\\');
82      outstring.push_back('\\');
83    }
84    outstring.push_back(*here);
85    ++here;
86  }
87}
88
89text_t xml_safe(const text_t &text_string)
90{
91  text_t text_string_safe;
92  text_t::const_iterator here = text_string.begin();
93  text_t::const_iterator end = text_string.end();
94  while (here != end) {
95    if (*here == '&') text_string_safe += "&amp;";
96    else if (*here == '<') text_string_safe += "&lt;";
97    else if (*here == '>') text_string_safe += "&gt;";
98    else text_string_safe.push_back(*here);
99    ++here;
100  }
101  return text_string_safe;
102}
103
104
105// gsdl_system creates a new process for the cmd command (which
106// may contain arguments).
107// cmd should contain the full path of the program to run.
108// The child process inherits the environment of the calling
109// process.
110// If sync is true a synchronous call will be made, otherwise
111// an asyncronous call.
112// If sync is true the return value will be the exit code of
113// the child process or -1 if the child process wasn't started.
114// If sync is false the return value will be 0 if the process
115// was started ok or -1 if it failed.
116int gsdl_system (const text_t &cmd, bool sync, ostream &logout) {
117  if (cmd.empty()) return -1;
118  char *cmd_c = cmd.getcstr();
119
120#if defined (__WIN32__)
121  // the windows version - this is implemented this way
122  // to prevent windows popping up all over the place when
123  // we call a console application (like perl)
124  STARTUPINFO ps = {sizeof(STARTUPINFO), NULL, NULL, NULL,
125                    0, 0, 0, 0, 0, 0,
126                    0, STARTF_USESHOWWINDOW,
127                    SW_HIDE, 0, NULL,
128            NULL, NULL, NULL};
129  PROCESS_INFORMATION pi;
130  BOOL res = CreateProcess(NULL,
131                           cmd_c,
132                           NULL,
133                           NULL,
134                           FALSE,
135#if defined (GSDL_LOCAL_LIBRARY)
136               NULL,
137#else
138               CREATE_NO_WINDOW, // previously this was: DETACHED_PROCESS,
139               // see http://msdn.microsoft.com/en-us/library/ms682425.aspx
140               // and http://msdn.microsoft.com/en-us/library/ms684863(VS.85).aspx
141#endif
142                           NULL,
143                           NULL,
144                           &ps,
145                           &pi);
146
147  if (!res) {
148    logout << "gsdl_system failed to start " << cmd_c
149       << " process, error code " << GetLastError() << endl;
150    delete []cmd_c;
151    return -1;
152  }
153
154  DWORD ret = 0;
155  if (sync) { // synchronous system call
156    // wait until child process exits.
157    WaitForSingleObject(pi.hProcess, INFINITE);
158    // set ret to exit code of child process
159    GetExitCodeProcess(pi.hProcess, &ret);
160  }
161
162  CloseHandle(pi.hProcess);
163  CloseHandle(pi.hThread);
164
165#else
166  // the unix version
167  int ret = 0;
168  if (sync) { // synchronous system call
169    // make sure the command interpreter is found
170    if (system (NULL) == 0) {
171      logout << "gsdl_system failed to start " << cmd_c
172         << " process, command interpreter not found" << endl;
173      delete []cmd_c;
174      return -1;
175    }
176    ret = system (cmd_c);
177
178  } else { // asynchronous system call
179    int pid = fork();
180    if (pid == -1) {
181      delete []cmd_c;
182      return -1;
183    }
184    if (pid == 0) {
185      // child process
186      char *argv[4];
187      argv[0] = "sh";
188      argv[1] = "-c";
189      argv[2] = cmd_c;
190      argv[3] = 0;
191      execv("/bin/sh", argv);
192    }
193  }
194#endif
195
196  delete []cmd_c;
197  return ret;
198}
199
200
201static bool gsdl_setenv_done = false;
202static char* retain_gsdlosc   = NULL;
203static char* retain_gsdlhomec = NULL;
204static char* retain_pathc     = NULL;
205
206bool set_gsdl_env_vars (const text_t& gsdlhome)
207{
208  if (gsdl_setenv_done) { return true; }
209
210  // set up GSDLOS, GSDLHOME and PATH environment variables
211
212  text_t gsdlos, path;
213  unsigned int path_separator = ':';
214
215#if defined (__WIN32__)
216  gsdlos = "windows";
217  path_separator = ';';
218
219  path = filename_cat (gsdlhome, "bin", "windows", "perl", "bin;");
220
221#else
222  struct utsname *buf = new struct utsname();
223  int i = uname (buf);
224  if (i == -1) gsdlos = "linux"; // uname failed, default to linux
225  else gsdlos.setcstr (buf->sysname);
226  delete buf;
227  lc (gsdlos);
228#endif
229
230  // according to getenv documentation (after a bit of digging), *getenv*
231  // is responsible for the char* pointer returned, so no need for us
232  // to free it (in fact that would be a mistake!)
233
234  char* orig_pathc = getenv ("PATH");
235  path += filename_cat (gsdlhome, "bin", gsdlos);
236  path.push_back (path_separator);
237  path += filename_cat (gsdlhome, "bin", "script");
238  if (orig_pathc != NULL) {
239    path.push_back (path_separator);
240    path += orig_pathc;
241  } 
242
243  text_t putpath     = "PATH=" + path;
244  text_t putgsdlos   = "GSDLOS=" + gsdlos;
245  text_t putgsdlhome = "GSDLHOME=" + gsdlhome;
246
247  retain_gsdlosc   = putgsdlos.getcstr();
248  retain_gsdlhomec = putgsdlhome.getcstr();
249  retain_pathc     = putpath.getcstr();
250 
251  if ((putenv(retain_gsdlosc)!=0) || (putenv(retain_gsdlhomec)!=0) 
252  || (putenv(retain_pathc)!=0))
253    {
254      // Would be better if the ostream& logout was used here.
255      cerr << "Error setting Greenstone environment variables with putenv()" << endl;
256      // perror("putenv(...): "); // This didn't yield any noticable output under Windows running local library server
257      return false;
258    }
259
260  // Need to keep memory allocated setgsdlosc, setgsdlhomec or pathc around
261  // (i.e. can't delete them).  This is because putenv() doesn't take
262  // a copy, but places them in the actual environment. 
263
264  gsdl_setenv_done = true;
265
266  return true;
267}
268
269
270
271// attempts to work out if perl is functional
272bool perl_ok (ostream &logout) {
273#if defined(__WIN32__)
274  text_t cmd = "perl -e \"exit 0\"";
275#else
276  text_t cmd = "perl -e 'exit 0'";
277#endif
278  int i = gsdl_system (cmd, true, logout);
279  return (i == 0);
280}
281
282
283#if defined(__WIN32__)
284// A very useful function to call to debug mysterious heap memory errors when
285// their cause isn't clear in the Vis Studio debugger. Call it from various
286// places of the code and narrow down the point at which the heap memory becomes
287// corrupted. The title param can be the method this function is called from.
288void check_system_heap(char* title)
289{
290  int heapstatus = _heapchk();
291
292  char message[1024];
293
294  switch (heapstatus) {
295  case _HEAPOK:
296    sprintf(message,"%s","OK - heap is fine");
297    break;
298  case _HEAPEMPTY:
299    sprintf(message,"%s","OK - heap is empty");
300    break;
301  case _HEAPBADBEGIN:
302    sprintf(message,"%s","ERROR - bad start of heap");
303    break;
304  case _HEAPBADNODE:
305    sprintf(message,"%s","Error - bad node in heap");
306    break;
307  default:
308    sprintf(message,"%s: %d","Unrecognized heap status",heapstatus);
309  }
310
311  cerr << message << endl;
312
313  // When debugging w32server having the messages appear in a popup
314  // window can be more convenient
315  //MessageBox (NULL, message, title, MB_OK);
316}
317
318#endif
Note: See TracBrowser for help on using the browser.