git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@222 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
743 lines
16 KiB
C++
743 lines
16 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: utilscmn.cpp
|
|
// Purpose: Miscellaneous utility functions and classes
|
|
// Author: Julian Smart
|
|
// Modified by:
|
|
// Created: 29/01/98
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) 1998 Julian Smart
|
|
// Licence: wxWindows license
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef __GNUG__
|
|
#pragma implementation "utils.h"
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/defs.h"
|
|
#include "wx/utils.h"
|
|
#include "wx/window.h"
|
|
#include "wx/menu.h"
|
|
#include "wx/frame.h"
|
|
#endif
|
|
|
|
#if USE_IOSTREAMH
|
|
#include <iostream.h>
|
|
#else
|
|
#include <iostream>
|
|
#endif
|
|
|
|
#include <fstream.h>
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#if !defined(__WATCOMC__)
|
|
#if !(defined(_MSC_VER) && (_MSC_VER > 800))
|
|
#include <errno.h>
|
|
#endif
|
|
#endif
|
|
#include <time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
// Pattern matching code.
|
|
// Yes, this path is deliberate (for Borland compilation)
|
|
#ifdef wx_mac /* MATTHEW: [5] Mac doesn't like paths with "/" */
|
|
#include "glob.inc"
|
|
#else
|
|
#include "../common/glob.inc"
|
|
#endif
|
|
|
|
#ifdef __WINDOWS__
|
|
#include "windows.h"
|
|
#endif
|
|
|
|
#define _MAXPATHLEN 500
|
|
|
|
extern char *wxBuffer;
|
|
|
|
#ifdef __VMS__
|
|
// we have no strI functions under VMS, therefore I have implemented
|
|
// an inefficient but portable version: convert copies of strings to lowercase
|
|
// and then use the normal comparison
|
|
static void myLowerString(char *s)
|
|
{
|
|
while(*s){
|
|
if(isalpha(*s)) *s = (char)tolower(*s);
|
|
s++;
|
|
}
|
|
}
|
|
|
|
int strcasecmp(const char *str_1, const char *str_2)
|
|
{
|
|
char *temp1 = new char[strlen(str_1)+1];
|
|
char *temp2 = new char[strlen(str_2)+1];
|
|
strcpy(temp1,str_1);
|
|
strcpy(temp2,str_2);
|
|
myLowerString(temp1);
|
|
myLowerString(temp2);
|
|
|
|
int result = strcmp(temp1,temp2);
|
|
delete[] temp1;
|
|
delete[] temp2;
|
|
|
|
return(result);
|
|
}
|
|
|
|
int strncasecmp(const char *str_1, const char *str_2, size_t maxchar)
|
|
{
|
|
char *temp1 = new char[strlen(str_1)+1];
|
|
char *temp2 = new char[strlen(str_2)+1];
|
|
strcpy(temp1,str_1);
|
|
strcpy(temp2,str_2);
|
|
myLowerString(temp1);
|
|
myLowerString(temp2);
|
|
|
|
int result = strncmp(temp1,temp2,maxchar);
|
|
delete[] temp1;
|
|
delete[] temp2;
|
|
|
|
return(result);
|
|
}
|
|
#endif
|
|
|
|
#ifdef __WINDOWS__
|
|
|
|
#ifndef __GNUWIN32__
|
|
#define strcasecmp stricmp
|
|
#define strncasecmp strnicmp
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning (disable : 4245)
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning (default : 4245)
|
|
#endif
|
|
|
|
#else
|
|
// This declaration is missing in SunOS!
|
|
// (Yes, I know it is NOT ANSI-C but its in BSD libc)
|
|
#if defined(__xlC) || defined(__AIX__) || defined(__GNUG__)
|
|
extern "C"
|
|
{
|
|
int strcasecmp (const char *, const char *);
|
|
int strncasecmp (const char *, const char *, size_t);
|
|
}
|
|
#endif
|
|
#endif /* __WINDOWS__ */
|
|
|
|
|
|
char *
|
|
copystring (const char *s)
|
|
{
|
|
if (s == NULL) s = "";
|
|
size_t len = strlen (s) + 1;
|
|
|
|
char *news = new char[len];
|
|
memcpy (news, s, len); // Should be the fastest
|
|
|
|
return news;
|
|
}
|
|
|
|
// Id generation
|
|
static long wxCurrentId = 100;
|
|
|
|
long
|
|
wxNewId (void)
|
|
{
|
|
return wxCurrentId++;
|
|
}
|
|
|
|
long
|
|
wxGetCurrentId(void) { return wxCurrentId; }
|
|
|
|
void
|
|
wxRegisterId (long id)
|
|
{
|
|
if (id >= wxCurrentId)
|
|
wxCurrentId = id + 1;
|
|
}
|
|
|
|
void
|
|
StringToFloat (char *s, float *number)
|
|
{
|
|
if (s && *s && number)
|
|
*number = (float) strtod (s, NULL);
|
|
}
|
|
|
|
void
|
|
StringToDouble (char *s, double *number)
|
|
{
|
|
if (s && *s && number)
|
|
*number = strtod (s, NULL);
|
|
}
|
|
|
|
char *
|
|
FloatToString (float number, const char *fmt)
|
|
{
|
|
static char buf[256];
|
|
|
|
// sprintf (buf, "%.2f", number);
|
|
sprintf (buf, fmt, number);
|
|
return buf;
|
|
}
|
|
|
|
char *
|
|
DoubleToString (double number, const char *fmt)
|
|
{
|
|
static char buf[256];
|
|
|
|
sprintf (buf, fmt, number);
|
|
return buf;
|
|
}
|
|
|
|
void
|
|
StringToInt (char *s, int *number)
|
|
{
|
|
if (s && *s && number)
|
|
*number = (int) strtol (s, NULL, 10);
|
|
}
|
|
|
|
void
|
|
StringToLong (char *s, long *number)
|
|
{
|
|
if (s && *s && number)
|
|
*number = strtol (s, NULL, 10);
|
|
}
|
|
|
|
char *
|
|
IntToString (int number)
|
|
{
|
|
static char buf[20];
|
|
|
|
sprintf (buf, "%d", number);
|
|
return buf;
|
|
}
|
|
|
|
char *
|
|
LongToString (long number)
|
|
{
|
|
static char buf[20];
|
|
|
|
sprintf (buf, "%ld", number);
|
|
return buf;
|
|
}
|
|
|
|
// Array used in DecToHex conversion routine.
|
|
static char hexArray[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
|
|
'C', 'D', 'E', 'F' };
|
|
|
|
// Convert 2-digit hex number to decimal
|
|
int wxHexToDec(char *buf)
|
|
{
|
|
int firstDigit, secondDigit;
|
|
|
|
if (buf[0] >= 'A')
|
|
firstDigit = buf[0] - 'A' + 10;
|
|
else
|
|
firstDigit = buf[0] - '0';
|
|
|
|
if (buf[1] >= 'A')
|
|
secondDigit = buf[1] - 'A' + 10;
|
|
else
|
|
secondDigit = buf[1] - '0';
|
|
|
|
return firstDigit * 16 + secondDigit;
|
|
}
|
|
|
|
// Convert decimal integer to 2-character hex string
|
|
void wxDecToHex(int dec, char *buf)
|
|
{
|
|
int firstDigit = (int)(dec/16.0);
|
|
int secondDigit = (int)(dec - (firstDigit*16.0));
|
|
buf[0] = hexArray[firstDigit];
|
|
buf[1] = hexArray[secondDigit];
|
|
buf[2] = 0;
|
|
}
|
|
|
|
// Match a string INDEPENDENT OF CASE
|
|
bool
|
|
StringMatch (char *str1, char *str2, bool subString, bool exact)
|
|
{
|
|
if (str1 == NULL || str2 == NULL)
|
|
return FALSE;
|
|
if (str1 == str2)
|
|
return TRUE;
|
|
|
|
if (subString)
|
|
{
|
|
int len1 = strlen (str1);
|
|
int len2 = strlen (str2);
|
|
int i;
|
|
|
|
// Search for str1 in str2
|
|
// Slow .... but acceptable for short strings
|
|
for (i = 0; i <= len2 - len1; i++)
|
|
{
|
|
if (strncasecmp (str1, str2 + i, len1) == 0)
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if (exact)
|
|
{
|
|
if (strcasecmp (str1, str2) == 0)
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
int len1 = strlen (str1);
|
|
int len2 = strlen (str2);
|
|
|
|
if (strncasecmp (str1, str2, wxMin (len1, len2)) == 0)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Return the current date/time
|
|
// [volatile]
|
|
wxString wxNow( void )
|
|
{
|
|
time_t now = time(NULL);
|
|
char *date = ctime(&now);
|
|
date[24] = '\0';
|
|
return wxString(date);
|
|
}
|
|
|
|
/* Get Full RFC822 style email address */
|
|
bool
|
|
wxGetEmailAddress (char *address, int maxSize)
|
|
{
|
|
char host[65];
|
|
char user[65];
|
|
|
|
if (wxGetHostName(host, 64) == FALSE)
|
|
return FALSE;
|
|
if (wxGetUserId(user, 64) == FALSE)
|
|
return FALSE;
|
|
|
|
char tmp[130];
|
|
strcpy(tmp, user);
|
|
strcat(tmp, "@");
|
|
strcat(tmp, host);
|
|
|
|
strncpy(address, tmp, maxSize - 1);
|
|
address[maxSize-1] = '\0';
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Strip out any menu codes
|
|
*/
|
|
|
|
char *wxStripMenuCodes (char *in, char *out)
|
|
{
|
|
if (!in)
|
|
return NULL;
|
|
|
|
if (!out)
|
|
out = copystring(in);
|
|
|
|
char *tmpOut = out;
|
|
|
|
while (*in)
|
|
{
|
|
if (*in == '&')
|
|
{
|
|
// Check && -> &, &x -> x
|
|
if (*++in == '&')
|
|
*out++ = *in++;
|
|
}
|
|
else if (*in == '\t')
|
|
{
|
|
// Remove all stuff after \t in X mode, and let the stuff as is
|
|
// in Windows mode.
|
|
// Accelerators are handled in wx_item.cc for Motif, and are not
|
|
// YET supported in XView
|
|
break;
|
|
}
|
|
else
|
|
*out++ = *in++;
|
|
} // while
|
|
|
|
*out = '\0';
|
|
|
|
return tmpOut;
|
|
}
|
|
|
|
|
|
/*
|
|
* Window search functions
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* If parent is non-NULL, look through children for a label or title
|
|
* matching the specified string. If NULL, look through all top-level windows.
|
|
*
|
|
*/
|
|
|
|
static wxWindow *wxFindWindowByLabel1 (const wxString& title, wxWindow * parent);
|
|
|
|
wxWindow *
|
|
wxFindWindowByLabel (const wxString& title, wxWindow * parent)
|
|
{
|
|
if (parent)
|
|
{
|
|
return wxFindWindowByLabel1 (title, parent);
|
|
}
|
|
else
|
|
{
|
|
for (wxNode * node = wxTopLevelWindows.First (); node; node = node->Next ())
|
|
{
|
|
wxWindow *win = (wxWindow *) node->Data ();
|
|
wxWindow *retwin = wxFindWindowByLabel1 (title, win);
|
|
if (retwin)
|
|
return retwin;
|
|
} // for()
|
|
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// Recursive
|
|
static wxWindow *
|
|
wxFindWindowByLabel1 (const wxString& title, wxWindow * parent)
|
|
{
|
|
if (parent)
|
|
{
|
|
if (parent->GetLabel() == title)
|
|
return parent;
|
|
}
|
|
|
|
if (parent)
|
|
{
|
|
for (wxNode * node = parent->GetChildren()->First (); node; node = node->Next ())
|
|
{
|
|
wxWindow *win = (wxWindow *) node->Data ();
|
|
wxWindow *retwin = wxFindWindowByLabel1 (title, win);
|
|
if (retwin)
|
|
return retwin;
|
|
} // for()
|
|
|
|
}
|
|
|
|
return NULL; // Not found
|
|
|
|
}
|
|
|
|
/*
|
|
* If parent is non-NULL, look through children for a name
|
|
* matching the specified string. If NULL, look through all top-level windows.
|
|
*
|
|
*/
|
|
|
|
static wxWindow *wxFindWindowByName1 (const wxString& title, wxWindow * parent);
|
|
|
|
wxWindow *
|
|
wxFindWindowByName (const wxString& title, wxWindow * parent)
|
|
{
|
|
if (parent)
|
|
{
|
|
return wxFindWindowByName1 (title, parent);
|
|
}
|
|
else
|
|
{
|
|
for (wxNode * node = wxTopLevelWindows.First (); node; node = node->Next ())
|
|
{
|
|
wxWindow *win = (wxWindow *) node->Data ();
|
|
wxWindow *retwin = wxFindWindowByName1 (title, win);
|
|
if (retwin)
|
|
return retwin;
|
|
} // for()
|
|
|
|
}
|
|
// Failed? Try by label instead.
|
|
return wxFindWindowByLabel(title, parent);
|
|
}
|
|
|
|
// Recursive
|
|
static wxWindow *
|
|
wxFindWindowByName1 (const wxString& title, wxWindow * parent)
|
|
{
|
|
if (parent)
|
|
{
|
|
if ( parent->GetName() == title )
|
|
return parent;
|
|
}
|
|
|
|
if (parent)
|
|
{
|
|
for (wxNode * node = parent->GetChildren()->First (); node; node = node->Next ())
|
|
{
|
|
wxWindow *win = (wxWindow *) node->Data ();
|
|
wxWindow *retwin = wxFindWindowByName1 (title, win);
|
|
if (retwin)
|
|
return retwin;
|
|
} // for()
|
|
|
|
}
|
|
|
|
return NULL; // Not found
|
|
|
|
}
|
|
|
|
// Returns menu item id or -1 if none.
|
|
int
|
|
wxFindMenuItemId (wxFrame * frame, const wxString& menuString, const wxString& itemString)
|
|
{
|
|
wxMenuBar *menuBar = frame->GetMenuBar ();
|
|
if (!menuBar)
|
|
return -1;
|
|
return menuBar->FindMenuItem (menuString, itemString);
|
|
}
|
|
|
|
/*
|
|
* wxDebugStreamBuf
|
|
*/
|
|
#if !defined(_WINDLL)
|
|
|
|
wxDebugStreamBuf::wxDebugStreamBuf(void)
|
|
{
|
|
if (allocate()) setp(base(),ebuf());
|
|
}
|
|
|
|
int wxDebugStreamBuf::overflow(int WXUNUSED(i))
|
|
{
|
|
int len = pptr() - pbase();
|
|
char *txt = new char[len+1];
|
|
strncpy(txt, pbase(), len);
|
|
txt[len] = '\0';
|
|
#ifdef __WINDOWS__
|
|
OutputDebugString((LPCSTR)txt);
|
|
#else
|
|
fprintf(stderr, txt);
|
|
#endif
|
|
setp(pbase(), epptr());
|
|
delete[] txt;
|
|
return EOF;
|
|
}
|
|
|
|
int wxDebugStreamBuf::sync(void)
|
|
{
|
|
int len = pptr() - pbase();
|
|
char *txt = new char[len+1];
|
|
strncpy(txt, pbase(), len);
|
|
txt[len] = '\0';
|
|
#ifdef __WINDOWS__
|
|
OutputDebugString((LPCSTR)txt);
|
|
#else
|
|
fprintf(stderr, txt);
|
|
#endif
|
|
setp(pbase(), epptr());
|
|
delete[] txt;
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
On Fri, 21 Jul 1995, Paul Craven wrote:
|
|
|
|
> Is there a way to find the path of running program's executable? I can get
|
|
> my home directory, and the current directory, but I don't know how to get the
|
|
> executable directory.
|
|
>
|
|
|
|
The code below (warty as it is), does what you want on most Unix,
|
|
DOS, and Mac platforms (it's from the ALS Prolog main).
|
|
|
|
|| Ken Bowen Applied Logic Systems, Inc. PO Box 180,
|
|
||==== Voice: +1 (617)965-9191 Newton Centre,
|
|
|| FAX: +1 (617)965-1636 MA 02159 USA
|
|
Email: ken@als.com WWW: http://www.als.com
|
|
------------------------------------------------------------------------
|
|
*/
|
|
|
|
// This code is commented out but it may be integrated with wxWin at
|
|
// a later date, after testing. Thanks Ken!
|
|
#if 0
|
|
|
|
/*--------------------------------------------------------------------*
|
|
| whereami is given a filename f in the form: whereami(argv[0])
|
|
| It returns the directory in which the executable file (containing
|
|
| this code [main.c] ) may be found. A dot will be returned to indicate
|
|
| the current directory.
|
|
*--------------------------------------------------------------------*/
|
|
|
|
static void
|
|
whereami(name)
|
|
char *name;
|
|
{
|
|
register char *cutoff = NULL; /* stifle -Wall */
|
|
register char *s;
|
|
register char *t;
|
|
int cc;
|
|
char ebuf[4096];
|
|
|
|
/*
|
|
* See if the file is accessible either through the current directory
|
|
* or through an absolute path.
|
|
*/
|
|
|
|
if (access(name, R_OK) == 0) {
|
|
|
|
/*-------------------------------------------------------------*
|
|
* The file was accessible without any other work. But the current
|
|
* working directory might change on us, so if it was accessible
|
|
* through the cwd, then we should get it for later accesses.
|
|
*-------------------------------------------------------------*/
|
|
|
|
t = imagedir;
|
|
if (!absolute_pathname(name)) {
|
|
#if defined(DOS) || defined(__WIN32__)
|
|
int drive;
|
|
char *newrbuf;
|
|
|
|
newrbuf = imagedir;
|
|
#ifndef __DJGPP__
|
|
if (*(name + 1) == ':') {
|
|
if (*name >= 'a' && *name <= 'z')
|
|
drive = (int) (*name - 'a' + 1);
|
|
else
|
|
drive = (int) (*name - 'A' + 1);
|
|
*newrbuf++ = *name;
|
|
*newrbuf++ = *(name + 1);
|
|
*newrbuf++ = DIR_SEPARATOR;
|
|
}
|
|
else {
|
|
drive = 0;
|
|
*newrbuf++ = DIR_SEPARATOR;
|
|
}
|
|
if (getcwd(newrbuf, drive) == 0) { /* } */
|
|
#else
|
|
if (getcwd(newrbuf, 1024) == 0) { /* } */
|
|
#endif
|
|
#else /* DOS */
|
|
#ifdef HAVE_GETWD
|
|
if (getwd(imagedir) == 0) { /* } */
|
|
#else /* !HAVE_GETWD */
|
|
if (getcwd(imagedir, 1024) == 0) {
|
|
#endif /* !HAVE_GETWD */
|
|
#endif /* DOS */
|
|
fatal_error(FE_GETCWD, 0);
|
|
}
|
|
for (; *t; t++) /* Set t to end of buffer */
|
|
;
|
|
if (*(t - 1) == DIR_SEPARATOR) /* leave slash if already
|
|
* last char
|
|
*/
|
|
cutoff = t - 1;
|
|
else {
|
|
cutoff = t; /* otherwise put one in */
|
|
*t++ = DIR_SEPARATOR;
|
|
}
|
|
}
|
|
#if (!defined(__MAC__) && !defined(__DJGPP__) && !defined(__GO32__) && !defined(__WIN32__))
|
|
else
|
|
(*t++ = DIR_SEPARATOR);
|
|
#endif
|
|
|
|
/*-------------------------------------------------------------*
|
|
* Copy the rest of the string and set the cutoff if it was not
|
|
* already set. If the first character of name is a slash, cutoff
|
|
* is not presently set but will be on the first iteration of the
|
|
* loop below.
|
|
*-------------------------------------------------------------*/
|
|
|
|
for ((*name == DIR_SEPARATOR ? (s = name+1) : (s = name));;) {
|
|
if (*s == DIR_SEPARATOR)
|
|
cutoff = t;
|
|
if (!(*t++ = *s++))
|
|
break;
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
/*-------------------------------------------------------------*
|
|
* Get the path list from the environment. If the path list is
|
|
* inaccessible for any reason, leave with fatal error.
|
|
*-------------------------------------------------------------*/
|
|
|
|
#ifdef __MAC__
|
|
if ((s = getenv("Commands")) == (char *) 0)
|
|
#else
|
|
if ((s = getenv("PATH")) == (char *) 0)
|
|
#endif
|
|
fatal_error(FE_PATH, 0);
|
|
|
|
/*
|
|
* Copy path list into ebuf and set the source pointer to the
|
|
* beginning of this buffer.
|
|
*/
|
|
|
|
strcpy(ebuf, s);
|
|
s = ebuf;
|
|
|
|
for (;;) {
|
|
t = imagedir;
|
|
while (*s && *s != PATH_SEPARATOR)
|
|
*t++ = *s++;
|
|
if (t > imagedir && *(t - 1) == DIR_SEPARATOR)
|
|
; /* do nothing -- slash already is in place */
|
|
else
|
|
*t++ = DIR_SEPARATOR; /* put in the slash */
|
|
cutoff = t - 1; /* set cutoff */
|
|
strcpy(t, name);
|
|
if (access(imagedir, R_OK) == 0)
|
|
break;
|
|
|
|
if (*s)
|
|
s++; /* advance source pointer */
|
|
else
|
|
fatal_error(FE_INFND, 0);
|
|
}
|
|
|
|
}
|
|
|
|
/*-------------------------------------------------------------*
|
|
| At this point the full pathname should exist in imagedir and
|
|
| cutoff should be set to the final slash. We must now determine
|
|
| whether the file name is a symbolic link or not and chase it down
|
|
| if it is. Note that we reuse ebuf for getting the link.
|
|
*-------------------------------------------------------------*/
|
|
|
|
#ifdef HAVE_SYMLINK
|
|
while ((cc = readlink(imagedir, ebuf, 512)) != -1) {
|
|
ebuf[cc] = 0;
|
|
s = ebuf;
|
|
if (*s == DIR_SEPARATOR) {
|
|
t = imagedir;
|
|
}
|
|
else {
|
|
t = cutoff + 1;
|
|
}
|
|
for (;;) {
|
|
if (*s == DIR_SEPARATOR)
|
|
cutoff = t; /* mark the last slash seen */
|
|
if (!(*t++ = *s++)) /* copy the character */
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif /* HAVE_SYMLINK */
|
|
|
|
strcpy(imagename, cutoff + 1); /* keep the image name */
|
|
*(cutoff + 1) = 0; /* chop off the filename part */
|
|
}
|
|
|
|
#endif
|
|
|