2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $TOG: EnvMgr.C /main/18 1998/04/17 11:52:44 mgreess $
26 * Copyright (c) 1992 HaL Computer Systems, Inc. All rights reserved.
27 * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
28 * States. Use of a copyright notice is precautionary only and does not
29 * imply publication or disclosure.
31 * This software contains confidential information and trade secrets of HaL
32 * Computer Systems, Inc. Use, disclosure, or reproduction is prohibited
33 * without the prior express written permission of HaL Computer Systems, Inc.
35 * RESTRICTED RIGHTS LEGEND
36 * Use, duplication, or disclosure by the Government is subject to
37 * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
38 * Technical Data and Computer Software clause at DFARS 252.227-7013.
39 * HaL Computer Systems, Inc.
40 * 1315 Dell Avenue, Campbell, CA 95008
49 #include <lib/DtSvc/DtUtil2/LocaleXlate.h>
51 // xList, NodeViewInfo, NodeWindowAgent & NodeMgr used only for
52 // getting sections from NodeMgr
54 #define C_NodeViewInfo
57 #define C_WindowSystem
61 #define C_NodeWindowAgent
76 #include "Managers/CatMgr.hh"
79 LONG_LIVED_CC(EnvMgr, env);
81 // a legacy global moved from WindowSystemMotif.C
84 // infolib string-list separator
86 // section string-list separator
90 EnvMgr::EnvMgr() : f_argv(NULL),
98 if ((lang = getenv("LC_ALL")) == NULL)
99 if ((lang = getenv("LC_CTYPE")) == NULL)
100 if ((lang = getenv("LANG")) == NULL)
103 _DtXlateDb db = NULL;
104 char platform[_DtPLATFORM_MAX_LEN + 1];
105 int execver, compver;
107 if (_DtLcxOpenAllDbs(&db) == 0)
109 if (_DtXlateGetXlateEnv(db, platform, &execver, &compver) == 0) {
111 char* std_locale = NULL;
113 _DtLcxXlateOpToStd(db, platform, compver, DtLCX_OPER_SETLOCALE,
114 lang, &std_locale, NULL, NULL, NULL);
117 fprintf(stderr, "(DEBUG) standard locale=\"%s\"\n", std_locale);
119 f_lang = XtNewString(std_locale);
128 // If OpToStd conversion failed, use non-std name
130 f_lang = XtNewString(lang);
132 // tell mmdb info_lib to load info_base only if it matches to f_lang
133 static char mmdb_lang[_POSIX_PATH_MAX];
134 sprintf(mmdb_lang, "MMDB_LANG=%s", f_lang);
137 f_home = XtNewString( getenv("HOME") );
140 sprintf (dirname, "%s/.dt/dtinfo/%s", f_home, f_lang);
141 f_user_path = XtNewString(dirname);
144 // if $HOME/.dt/dtinfo/$LANG does not exist, create it,
145 // display auto help.
146 if(!check_user_path())
149 help_agent().display_help ((char*)"doc_list_help");
152 UAS_Collection::request(
153 (UAS_Receiver<UAS_CollectionRetrievedMsg> *)this) ;
155 (UAS_Receiver<UAS_LibraryDestroyedMsg> *)this) ;
160 // free our generated/abbreviated arguments array
161 for (int i=0; i < f_argc; i++) XtFree(f_argv[i]);
162 XtFree((char*)f_argv);
168 // initialize the environment class
170 // place as much as possible in the constructor for the class,
171 // reserving for here those things that have window system dependencies.
172 // parse_cmdline is here only because it might be re-written to use
173 // Xrm Options handling, and because there is a use of XtResolvePathname
174 // for one arg which needs the "display" value...
177 EnvMgr::init(int argc_i, char** argv_i)
179 if( parse_cmdline(argc_i, argv_i) >= 0)
181 // See if any infolibs entered on command line. If not,
182 // check environment for the default infolib.
184 if (f_infolibsStr.length() == 0)
186 char *tmp = infolibDefault();
190 // finally, try back door, which works better for non-CDE users
191 // displaying dtinfo from a CDE system to a different desktop,
192 // since all the Dt searchpath stuff won't be much help...
193 const char *directpath = getenv ("DTINFO_INFOLIB_PATH");
195 if (directpath != NULL && isInfolib(directpath))
197 f_infolibsStr = directpath ; // UAS_String promotion
201 // invalid infolib--display error message
202 message_mgr().error_dialog (
203 (char*)UAS_String(CATGETS(Set_AddLibraryAgent, 7,
204 "No infolibs found or specified.")));
208 else f_infolibsStr = tmp;
219 // link up indirect paths to mmdb code... ;-)
220 static char buffer[256];
221 sprintf (buffer, "MMDB_PATH=%s", (char *)f_infolibsStr );
224 char *where = getenv ("DTINFO_MARKSPECPATH");
227 static char markref[256];
228 sprintf (markref, "DTINFO_MARKSPECPATH=%s", "/usr/dt/infolib/etc" );
232 if (f_sectionsArg.length() == 0)
234 const char *locator = getenv ("DTINFO_FIRSTDOC");
237 f_sectionsArg = UAS_String(locator) ; // UAS_String promotion
241 if (f_verbose) echoEnvState();
246 // infolibStringToList()
248 // parse a string of colon-separated infolib paths and return as a list.
251 EnvMgr::infolibStringToList( const UAS_String & s_infolibs )
253 return s_infolibs.splitFields (ILSEP);
258 EnvMgr::sectionStringToList( const UAS_String & s_sections )
260 // ... currently only handles a comma-separated list
261 // ... for section "range" specifiers, need to make second pass
262 // on results of following, which will require some kind of
263 // dive into the UAS to interpret what a "range" of sections
264 // means, at the moment. This was to only apply with "-print",
266 return s_sections.splitFields (SLSEP);
268 // UAS_List initial_cut = s_sections.splitFields (SLSEP);
269 // UAS_String doc_locator, start_doc, end_doc ;
271 // for (int i = 0; i < docs.length(); i++)
273 // (*(initial_cut[i])).split( '-', start_doc, end_doc ) ;
274 // initial_cut.insert( start_doc.length() ? start_doc : end_doc ) ;
275 // ... duely process rest of any range here to build "expanded_list" ...
277 // return expanded_list;
283 // Extracts info from command line and sets up internal flags.
284 // -1 returned on error. Innocuous problems ignored, like if no arg
285 // provided where we might have a default or environment variable
286 // specified. Caller should do "usage()" on error return, as this
287 // method flags rather than performs it.
290 EnvMgr::parse_cmdline( int argc_i,
293 for (int i = 1; i < argc_i; i++)
295 if(strcmp(argv_i[i], "-help") == 0 ||
296 strcmp(argv_i[i], "-h") == 0)
298 // Print a summary of the command's syntax.
301 else if (strcmp(argv_i[i], "-l") == 0 ||
302 strcmp(argv_i[i], "-lib") == 0 )
304 // get infolibs from command line
306 if( ( i < argc_i ) && ( argv_i[i][0] != '-' ) )
308 // This arg gives an absolute file path to an information
309 // library, or the short name of the library (which will be
310 // used for substitution into the search path specified by
311 // DTINFOLIBSEARCHPATH in order to locate the infolib).
312 // If the -l option is not provided, the browser displays
313 // the default information library by path obtained from
314 // substituting DTINFOLIBDEFAULT into DTINFOLIBSEARCHPATH.
315 // [DTINFOLIBDEFAULT should be a single library short name.]
316 // The "-l" option may be specified more than once.
320 if( !strchr( argv_i[i], ':' ) )
322 char *tmp = infolibStringToPath(argv_i[i]);
325 pathname = UAS_String(tmp);
326 if( tmp != argv_i[i] ) XtFree(tmp); // clean-up case
329 else // defer validation if arg contains colon separators
330 pathname = UAS_String(argv_i[i]);
332 if( pathname.length() != 0 )
333 if( f_infolibsStr.length() != 0 )
335 // need to concatenate
336 f_infolibsStr = f_infolibsStr + ":" + pathname ;
341 f_infolibsStr = pathname ;
345 // invalid infolib--display error message, but not fatal
346 message_mgr().error_dialog (
347 (char*)UAS_String(CATGETS(Set_AddLibraryAgent, 5,
348 "Infolib specification format error.")));
351 //else ... ignore this one
353 else if (strcmp(argv_i[i], "-sect") == 0 ||
354 strcmp(argv_i[i], "-section") == 0 )
356 // get a list of sections from the command line
358 if( ( i < argc_i ) && ( argv_i[i][0] != '-' ) )
360 // This arg specifies the infolib section (or a comma-separated
361 // list of sections) via their unique locator IDs to either
363 // Sections can be specified using the hyphen character to
364 // represent a range of sections, although it is up the print
365 // interface to resolve what such a range means. Note that a
366 // section "range" is only predictable within the same version
367 // of an infolib from which it was mapped.
368 // If the -print option is specified, the sections are printed;
369 // otherwise, they are displayed (if a range is specified without
370 // "-print", only the first ID in the range will be processed).
371 // If a specified location ID is not at the top of a section,
372 // the section containing the location is printed.
374 f_sectionsArg = UAS_String(argv_i[i]);
375 // (we actually build the sections "list" later, based
376 // on document windows actually displayed)
378 //else ... ignore this one
380 else if (strcmp(argv_i[i], "-secondary") == 0)
382 // Run this dtinfo instance without tooltalk session participation.
383 // Secondary instances do not respond to ToolTalk messages.
386 else if (strcmp(argv_i[i], "-verbose") == 0 ||
387 strcmp(argv_i[i], "-v") == 0)
389 // make verbose a boolean flag
392 #ifdef UseSessionMgmt
393 else if (strcmp(argv_i[i], "-session") == 0)
395 // Get special session save-state file name
396 // This option will usually result only from programmatic insertion
397 // for purpose of session restart.
399 if(argv_i[i][0] != '-')
401 session().file( argv_i[i] ) ;
403 //else, ignore any errors for this arg, which is usually transparent
406 else if (strcmp(argv_i[i], "-Debug") == 0 ||
407 strcmp(argv_i[i], "-D") == 0)
409 // Undocumented flag: turn on debugging
412 cerr << "\nInternal debugging activated." << endl;
416 cerr << CATGETS(Set_EnvMgr, 2, "Invalid argument") << endl;
421 // do any argument consistency/cross-validation here
423 // make sure that if print option was specified that some sections
424 // to print were also specified.
425 if ( (window_system().videoShell()->print_only) && (f_sectionsArg == (UAS_String)NULL)) {
426 cerr << CATGETS(Set_EnvMgr, 3, "ERROR: The -sect option must be specified with the -print option.") << endl;
438 cerr << CATGETS(Set_EnvMgr, 4, "Usage: dtinfo") << endl;
439 cerr << " [-help]" << endl;
440 cerr << " [-l infolib1] [-l infolib2] [...]" << endl;
441 cerr << " [-sect section[-section][,section[-section]]]" << endl;
442 cerr << " [-secondary]" << endl;
443 cerr << " [-verbose]" << endl;
444 cerr << " [[-print] [[-copies number]" << endl;
445 cerr << " [-hierarchy]" << endl;
446 cerr << " [-outputFile]" << endl;
447 cerr << " [-paperSize]" << endl;
448 cerr << " [-printer x_print_server]]]" << endl;
450 cerr << CATGETS(Set_EnvMgr, 5,
451 "This application understands all standard X Toolkit command-line options.") << endl;
457 EnvMgr::echoEnvState()
459 // need to display environment variables and
460 // other information that would be useful
462 cerr << " -l = " << (char*)f_infolibsStr << endl;
463 cerr << "-sect = " << (char*)f_sectionsArg << endl;
465 if (getenv("DTINFOLIBSEARCHPATH") == NULL)
466 cerr << "DTINFOLIBSEARCHPATH = " << endl;
468 cerr << "DTINFOLIBSEARCHPATH = " << getenv("DTINFOLIBSEARCHPATH") << endl;
470 if (getenv("DTINFOLIBDEFAULT") == NULL)
471 cerr << " DTINFOLIBDEFAULT = " << endl;
473 cerr << " DTINFOLIBDEFAULT = " << getenv("DTINFOLIBDEFAULT") << endl;
475 if (getenv("DTHELPSEARCHPATH") == NULL)
476 cerr << " DTHELPSEARCHPATH = " << endl;
478 cerr << " DTHELPSEARCHPATH = " << getenv("DTHELPSEARCHPATH") << endl;
480 if (getenv("XUSERFILESEARCHPATH") == NULL)
481 cerr << "XUSERFILESEARCHPATH = " << endl;
483 cerr << "XUSERFILESEARCHPATH = " << getenv("XUSERFILESEARCHPATH") << endl;
485 if (getenv("LANG") == NULL)
486 cerr << " LANG = " << endl;
488 cerr << " LANG = " << getenv("LANG") << endl;
489 cerr << " LANG(CDE) = " << lang() << endl;
494 if (getenv("XAPPLRESDIR") == NULL)
495 cerr << " XAPPLRESDIR = " << endl;
497 cerr << " XAPPLRESDIR = " << getenv("XAPPLRESDIR") << endl;
499 if (getenv("XFILESEARCHPATH") == NULL)
500 cerr << " XFILESEARCHPATH = " << endl;
502 cerr << " XFILESEARCHPATH = " << getenv("XFILESEARCHPATH") << endl;
504 if (getenv("NLSPATH") == NULL)
505 cerr << " NLSPATH = " << endl;
507 cerr << " NLSPATH = " << getenv("NLSPATH") << endl;
514 // Function to pass to the XtResolvePathname call in place of
515 // the default predicate, which does not allow for directories.
522 // just check to see if it's a directory
523 if(access(dirname, R_OK) == 0)
525 stat(dirname, &status);
526 return (S_ISDIR(status.st_mode));
535 // determine whether an [assumed] absolute path specification
536 // matches basic file layout criteria for an infolib installation.
537 // (ignores search engine and index files, which would be more
538 // appropriately tested by a separate function, according to the
539 // search engine type)
542 EnvMgr::isInfolib( const char* path )
544 if (path == NULL || *path == '\0')
547 struct stat stat_buf;
548 if (stat(path, &stat_buf) < 0)
551 if ((stat_buf.st_mode & S_IFMT & S_IFDIR) == 0)
554 if (access((char*)path, R_OK) < 0)
557 UAS_String map = path;
558 map = map + "/" + "bookcase.map";
560 if (access((char*)map, R_OK) < 0)
567 // get the default infolib per the environemnt variables
568 // DTINFOLIBDEFAULT and DTINFOLIBSEARCHPATH.
569 // Neither are tested for validity, which is assumed.
571 // Caller must free any returned string with XtFree()
574 EnvMgr::infolibDefault()
576 return infolibNameToPath( getenv("DTINFOLIBDEFAULT") );
580 // infolibNameToPath()
582 // Take the "short name" of an infolib (like "cde" in its dir name
583 // "cde.dti", and return the full path to library, if found in the
584 // default infolib search path set. Else, return NULL for no match.
586 // Caller must free any returned string with XtFree(),
587 // per XtResolvePathName
590 EnvMgr::infolibNameToPath(char* path)
592 SubstitutionRec subs[1];
596 subs[0].substitution = path;
597 FileName = XtResolvePathname(
598 window_system().display(),
600 getenv("DTINFOLIBSEARCHPATH"),
601 subs, XtNumber(subs),
602 (XtFilePredicate)isDir);
608 // infolibPathIsLocale()
610 // Attempt to match the immediate parent dir to the current locale or
611 // cde-normalized locale.
612 // Return false if no match, but caller must realize that this alone is
613 // inconclusive evidence.
615 EnvMgr::infolibPathIsLocale(char* ilpath)
617 // ... implement check of path head
622 // infolibStringToPath()
624 // Takes string representing a single infolib and attempts to convert
625 // it to an absolute infolib file path.
627 // Uses function isInfolib() for testing whether a result actually
628 // meets infolib criteria.
630 // Caller should test for NULL since valid infolib may not be found.
631 // Caller should free the result with XtFree() if returned pointer is
632 // not null AND not equal to the pointer supplied.
635 EnvMgr::infolibStringToPath(char* path)
639 if( *path == '/' && isDir(path) )
641 filename = path ; // assume input already absolute path
643 else if ( strchr( path, '/' ) )
645 // relative path... could get curr dir and build an absolute path
648 else // assume a name and do path look-up
650 filename = infolibNameToPath(path) ;
653 if( !isInfolib( filename ) ) filename = NULL ;
659 // UAS_DocumentRetrievedMsg message handler
662 // EnvMgr::receive (UAS_DocumentRetrievedMsg &msg,
663 // void * client_data)
665 // manipulate msg.fDoc ==> UAS_Pointer<UAS_Common> type
669 // UAS_CollectionRetrievedMsg message handler
671 EnvMgr::receive (UAS_CollectionRetrievedMsg &msg,
674 infolibAdd( fqlToFilePath(msg.fCol->root()->locator()) );
678 // UAS_LibraryDestroyedMsg message handler
680 EnvMgr::receive (UAS_LibraryDestroyedMsg &msg,
683 infolibRemove( fqlToFilePath(msg.fLib->locator()) );
689 // Maintains state of browser in terms of infolibs actually loaded.
690 // The intent is for this function to be called only if the infolib
691 // has been successfully loaded (and thus appears in the booklist)
694 EnvMgr::infolibAdd( UAS_String pathname )
696 if ( f_infolibsStr.length() != 0 )
698 // this is the init case, where the first infolib has actually been
699 // loaded successfully by the browser. The init str is now superfluous.
702 f_infolibs.insert_item(new UAS_String(pathname));
708 // Maintains state of browser in terms of infolibs actually loaded.
709 // The intent is for this function to be called only if the infolib
710 // has been removed, once previously and successfully loaded
713 EnvMgr::infolibRemove( UAS_String pathname )
715 if ( f_infolibsStr.length() != 0 )
717 // this entry case should never occur, so the remove is ignored
718 cerr << "Invalid argument" << endl;
720 f_infolibs.remove_item(new UAS_String(pathname));
726 // Return a list of infolibs known to browser.
727 // Any call to this function prior to the first infolib actually being
728 // loaded will get the list of infolibs initially requested at startup.
729 // Subsequent calls will be returned a list of the infolibs loaded at
732 // The list entries are in the form of absolute path (as resolved and
733 // validated) to the infolib, and will be used for any session restart
734 // states saved with XSetCommand, as "-l" options to dtinfo.
736 // Prerequisite: command line args must have been processed (which
737 // will always have been the case for any call, since EnvMgr is "LongLived").
742 // after initialization, there is always at least one infolib loaded
743 if( infolibCount() == 0 )
744 return infolibStringToList( f_infolibsStr ) ;
750 // get current infolib list as arg value string
753 EnvMgr::infolibsArg()
755 if( ( infolibCount() == 0 ) && ( f_infolibsStr.length() != 0 ) )
757 return f_infolibsStr ;
759 else // convert current list of sections to an arg
761 return cvtListToString( f_infolibs, ":", True ) ;
768 // Return a list of sections/nodes currently on display by the browser.
769 // Any call to this function prior to the first section actually displayed
770 // will get the list of sections initially requested at startup.
771 // Subsequent calls will be returned a list of the sections loaded at
774 // The list entries are in the form of vaildated unique ids, and
775 // will be used for any session restart states saved with XSetCommand,
776 // as the argument to the "-sect" option to dtinfo.
778 // Prerequisite: command line args must have been processed (which
779 // will always have been the case for any call, since Env is "LongLived").
784 // check infolibCount to determine if in post-init phase...
785 if( infolibCount() == 0 )
786 return sectionStringToList( f_sectionsArg ) ;
787 else // post-init phase
789 return getCurrentSections() ;
794 // get current section list as arg string
797 EnvMgr::sectionsArg()
799 if( infolibCount() == 0 )
800 return f_sectionsArg;
801 else // convert current list of sections to an arg
802 return cvtListToString( getCurrentSections(), ",", True ) ;
806 // getCurrentSections()
808 // get the sections actually on display [right now] in all known
809 // node view windows, in their unique id format (i.e., not fully-qualified)
812 EnvMgr::getCurrentSections()
814 UAS_List<UAS_String> f_sections ;
816 // get current section IDs from each node view visible
817 xList<NodeWindowAgent *> &nwl = node_mgr().windows() ;
819 List_Iterator<NodeWindowAgent *> nwli (nwl) ;
820 for ( ; nwli; nwli ++)
822 f_sections.insert_item(
823 new UAS_String(nwli.item()->node_view_info()->node_ptr()->id()) ) ;
831 // convert a fully qualified locator to the infolib's absolute path,
832 // as resolved during the load phase. This function is expecting only
833 // fully qualified forms which include the "INFOLIB=<path>" part, such
834 // as are returned by the UAS_Common method "locator()", and serves to
835 // extract the "path".
837 // Caution: An fql does not have to have the "INFOLIB=" part...
838 // Could add insurance check for that here to be more robust.
841 EnvMgr::fqlToFilePath( UAS_String fulloc )
845 fulloc.split ('=', discard, fulloc);
846 fulloc.split ('&', fulloc, discard);
853 // construct and return an arglist which could restart the browser
854 // in its current state.
860 int p_argc = 5 ; // always have an arg0, a "-l <path>", and a
861 // "-sect <list>" (even though list may be empty)
865 // augment count for any other necessary options here
866 if( secondary() ) ++p_argc ;
868 f_argv = (char **)XtMalloc( p_argc*sizeof(char *) ) ;
871 f_argv[ia++] = XtNewString( "dtinfo" ) ;
874 f_argv[ia++] = XtNewString( "-secondary" ) ;
877 f_argv[ia++] = XtNewString( "-l" ) ;
878 tmp = (char *)(infolibsArg()) ;
879 f_argv[ia++] = XtNewString( tmp ) ;
881 // always insert the -sect key and its arg, even if the arg
882 // is zero length. This saves us from any re-malloc and copy.
883 f_argv[ia++] = XtNewString( "-sect" ) ;
884 tmp = (char *)(sectionsArg()) ; // can be empty here
885 f_argv[ia++] = XtNewString( tmp ) ;
893 // free then reset the infolibs/sections arg values per current state
894 for( int i=1; i < f_argc && (il == 0 || is == 0) ; i++ )
896 if( strcmp(f_argv[i], "-l") == 0 )
898 XtFree( f_argv[++i] ) ;
899 tmp = (char *)(infolibsArg()) ;
900 f_argv[i] = XtNewString( tmp ) ;
903 else if( strcmp(f_argv[i], "-sect") == 0 )
905 XtFree( f_argv[++i] ) ;
906 tmp = (char *)(sectionsArg()) ;
907 f_argv[i] = XtNewString( tmp ) ;
913 return (const char **)f_argv ;
930 EnvMgr::mkdirs(char *pathname)
934 strcpy(buffer, pathname);
936 if(mkdir(buffer, 0777) == -1)
938 c = strrchr(buffer, '/');
941 (void)mkdirs(buffer);
944 if(mkdir(buffer, 0777) == -1)
951 EnvMgr::check_user_path()
953 struct stat file_info;
955 int status = stat (f_user_path, &file_info);
959 if (!S_ISDIR (file_info.st_mode))
960 throw (CASTEXCEPT Exception());
966 EnvMgr::create_user_path()
968 if (mkdirs (f_user_path) == False)
969 throw (CASTEXCEPT Exception());
975 if(!check_user_path())
981 // each element of theList is concatenated into a single string using
982 // the "delimiter" character for separation. Delimiter is treated as
983 // a prefix if "infix" is False, in which case it initiates the string.
986 EnvMgr::cvtListToString( UAS_List<UAS_String> theList,
987 UAS_String delimiter,
990 UAS_String aggregate ;
992 int len = theList.length();
995 if( infix ) aggregate = *(theList[0]);
996 else aggregate = delimiter + *(theList[0]); // prefix
997 for (int i = 1; i < len; i++)
999 // concatenate each additional item using the separator
1000 aggregate = aggregate + delimiter + *(theList[i]) ;