1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/os2/utils.cpp
3// Purpose:     Various utilities
4// Author:      David Webster
5// Modified by:
6// Created:     09/17/99
7// RCS-ID:      $Id: utils.cpp 54228 2008-06-15 11:22:52Z VZ $
8// Copyright:   (c) David Webster
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#include "wx/utils.h"
16
17#ifndef WX_PRECOMP
18    #include "wx/intl.h"
19    #include "wx/log.h"
20#endif  //WX_PRECOMP
21
22#include "wx/os2/private.h"
23#include "wx/apptrait.h"
24#include "wx/filename.h"
25
26#include <ctype.h>
27#ifdef __EMX__
28#include <dirent.h>
29#endif
30
31
32#include <io.h>
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <errno.h>
38#include <stdarg.h>
39
40#define PURE_32
41
42#if defined(__WATCOMC__)
43extern "C"
44{
45    #include <upm.h>
46}
47#elif !defined(__EMX__)
48    #include <upm.h>
49    #include <netcons.h>
50    #include <netbios.h>
51#endif
52
53static const wxChar WX_SECTION[] = _T("wxWidgets");
54static const wxChar eHOSTNAME[]  = _T("HostName");
55
56// For the following functions we SHOULD fill in support
57// for Windows-NT (which I don't know) as I assume it begin
58// a POSIX Unix (so claims MS) that it has some special
59// functions beyond those provided by WinSock
60
61// Get full hostname (eg. DoDo.BSn-Germany.crg.de)
62bool wxGetHostName( wxChar* zBuf, int nMaxSize )
63{
64    if (!zBuf) return false;
65
66#if defined(wxUSE_NET_API) && wxUSE_NET_API
67    char           zServer[256];
68    char           zComputer[256];
69    unsigned long  ulLevel = 0;
70    unsigned char* zBuffer = NULL;
71    unsigned long  ulBuffer = 256;
72    unsigned long* pulTotalAvail = NULL;
73
74    NetBios32GetInfo( (const unsigned char*)zServer
75                     ,(const unsigned char*)zComputer
76                     ,ulLevel
77                     ,zBuffer
78                     ,ulBuffer
79                     ,pulTotalAvail
80                    );
81    strcpy(zBuf, zServer);
82#else
83    wxChar*        zSysname;
84    const wxChar*  zDefaultHost = _T("noname");
85
86    if ((zSysname = wxGetenv(_T("SYSTEM_NAME"))) == NULL &&
87	(zSysname = wxGetenv(_T("HOSTNAME"))) == NULL)
88    {
89        ::PrfQueryProfileString( HINI_PROFILE
90                                ,(PSZ)WX_SECTION
91                                ,(PSZ)eHOSTNAME
92                                ,(PSZ)zDefaultHost
93                                ,(void*)zBuf
94                                ,(ULONG)nMaxSize - 1
95                               );
96    }
97    else
98    {
99        wxStrncpy(zBuf, zSysname, nMaxSize - 1);
100    }
101
102    zBuf[nMaxSize] = _T('\0');
103#endif
104
105    return *zBuf ? true : false;
106}
107
108// Get user ID e.g. jacs
109bool wxGetUserId(wxChar* zBuf, int nType)
110{
111#if defined(__VISAGECPP__) || defined(__WATCOMC__)
112    // UPM procs return 0 on success
113    long lrc = U32ELOCU((PUCHAR)zBuf, (PULONG)&nType);
114    if (lrc == 0) return true;
115#endif
116    return false;
117}
118
119bool wxGetUserName( wxChar* zBuf, int nMaxSize )
120{
121#ifdef USE_NET_API
122    wxGetUserId( zBuf, nMaxSize );
123#else
124    wxStrncpy(zBuf, _T("Unknown User"), nMaxSize);
125#endif
126    return true;
127}
128
129int wxKill(long         lPid,
130           wxSignal     WXUNUSED(eSig),
131           wxKillError* WXUNUSED(peError),
132           int          WXUNUSED(flags))
133{
134    return((int)::DosKillProcess(0, (PID)lPid));
135}
136
137//
138// Execute a program in an Interactive Shell
139//
140bool wxShell( const wxString& rCommand )
141{
142    wxChar*     zShell = _T("CMD.EXE");
143    wxString    sInputs;
144    STARTDATA   SData = {0};
145    PSZ         PgmTitle = "Command Shell";
146    APIRET      rc;
147    PID         vPid = 0;
148    ULONG       ulSessID = 0;
149    UCHAR       achObjBuf[256] = {0}; //error data if DosStart fails
150    RESULTCODES vResult;
151
152    SData.Length   = sizeof(STARTDATA);
153    SData.Related  = SSF_RELATED_INDEPENDENT;
154    SData.FgBg     = SSF_FGBG_FORE;
155    SData.TraceOpt = SSF_TRACEOPT_NONE;
156    SData.PgmTitle = PgmTitle;
157    SData.PgmName  = (char*)zShell;
158
159    sInputs = _T("/C ") + rCommand;
160    SData.PgmInputs     = (BYTE*)sInputs.c_str();
161    SData.TermQ         = 0;
162    SData.Environment   = 0;
163    SData.InheritOpt    = SSF_INHERTOPT_SHELL;
164    SData.SessionType   = SSF_TYPE_WINDOWABLEVIO;
165    SData.IconFile      = 0;
166    SData.PgmHandle     = 0;
167    SData.PgmControl    = SSF_CONTROL_VISIBLE | SSF_CONTROL_MAXIMIZE;
168    SData.InitXPos      = 30;
169    SData.InitYPos      = 40;
170    SData.InitXSize     = 200;
171    SData.InitYSize     = 140;
172    SData.Reserved      = 0;
173    SData.ObjectBuffer  = (char*)achObjBuf;
174    SData.ObjectBuffLen = (ULONG)sizeof(achObjBuf);
175
176    rc = ::DosStartSession(&SData, &ulSessID, &vPid);
177    if (rc == 0 || rc == 457) // NO_ERROR or SMG_START_IN_BACKGROUND
178    {
179        PTIB                            ptib;
180        PPIB                            ppib;
181
182        ::DosGetInfoBlocks(&ptib, &ppib);
183
184        ::DosWaitChild( DCWA_PROCESS
185                       ,DCWW_WAIT
186                       ,&vResult
187                       ,&ppib->pib_ulpid
188                       ,vPid
189                      );
190    }
191    return (rc != 0);
192}
193
194// Shutdown or reboot the PC
195bool wxShutdown(wxShutdownFlags WXUNUSED(wFlags))
196{
197    // TODO
198    return false;
199}
200
201// Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
202wxMemorySize wxGetFreeMemory()
203{
204    void* pMemptr = NULL;
205    LONG  lSize;
206    ULONG lMemFlags;
207    APIRET rc;
208
209    lMemFlags = PAG_FREE;
210    rc = ::DosQueryMem(pMemptr, (PULONG)&lSize, &lMemFlags);
211    if (rc != 0)
212        lSize = -1L;
213    return (wxMemorySize)lSize;
214}
215
216// Get Process ID
217unsigned long wxGetProcessId()
218{
219    return (unsigned long)getpid();
220}
221
222// ----------------------------------------------------------------------------
223// env vars
224// ----------------------------------------------------------------------------
225
226bool wxGetEnv(const wxString& var, wxString *value)
227{
228    // wxGetenv is defined as getenv()
229    wxChar *p = wxGetenv(var);
230    if ( !p )
231        return false;
232
233    if ( value )
234    {
235        *value = p;
236    }
237
238    return true;
239}
240
241bool wxSetEnv(const wxString& variable, const wxChar *value)
242{
243#if defined(HAVE_SETENV)
244    if ( !value )
245    {
246#ifdef HAVE_UNSETENV
247        return unsetenv(variable.mb_str()) == 0;
248#else
249        value = _T(""); // mustn't pass NULL to setenv()
250#endif
251    }
252    return setenv(variable.mb_str(),
253                  wxString(value).mb_str(),
254                  1 /* overwrite */) == 0;
255#elif defined(HAVE_PUTENV)
256    wxString s = variable;
257    if ( value )
258        s << _T('=') << value;
259
260    // transform to ANSI
261    const char *p = s.mb_str();
262
263    // the string will be free()d by libc
264    char *buf = (char *)malloc(strlen(p) + 1);
265    strcpy(buf, p);
266
267    return putenv(buf) == 0;
268#else // no way to set an env var
269    wxUnusedVar(variable);
270    wxUnusedVar(value);
271    return false;
272#endif
273}
274
275void wxMilliSleep(
276  unsigned long                     ulMilliseconds
277)
278{
279    ::DosSleep(ulMilliseconds);
280}
281
282void wxMicroSleep(
283  unsigned long                     ulMicroseconds
284)
285{
286    ::DosSleep(ulMicroseconds/1000);
287}
288
289void wxSleep(
290  int                               nSecs
291)
292{
293    ::DosSleep(1000 * nSecs);
294}
295
296// Consume all events until no more left
297void wxFlushEvents()
298{
299//  wxYield();
300}
301
302// Emit a beeeeeep
303void wxBell()
304{
305    DosBeep(1000,1000); // 1kHz during 1 sec.
306}
307
308wxString wxGetOsDescription()
309{
310    wxString strVer(_T("OS/2"));
311    ULONG ulSysInfo = 0;
312
313    if (::DosQuerySysInfo( QSV_VERSION_MINOR,
314                           QSV_VERSION_MINOR,
315                           (PVOID)&ulSysInfo,
316                           sizeof(ULONG)
317                         ) == 0L )
318    {
319        wxString ver;
320        ver.Printf( _T(" ver. %d.%d"),
321                    int(ulSysInfo / 10),
322                    int(ulSysInfo % 10)
323                  );
324        strVer += ver;
325    }
326
327    return strVer;
328}
329
330bool wxIsPlatform64Bit()
331{
332    // FIXME: No idea how to test for 64 bit processor
333    //        (Probably irrelevant anyhow, though).
334    return false;
335}
336
337void wxAppTraits::InitializeGui(unsigned long &WXUNUSED(ulHab))
338{
339}
340
341void wxAppTraits::TerminateGui(unsigned long WXUNUSED(ulHab))
342{
343}
344
345wxOperatingSystemId wxGetOsVersion(int *verMaj, int *verMin)
346{
347    ULONG                 ulSysInfo = 0;
348    APIRET                ulrc;
349
350    ulrc = ::DosQuerySysInfo( QSV_VERSION_MINOR,
351                              QSV_VERSION_MINOR,
352                              (PVOID)&ulSysInfo,
353                              sizeof(ULONG)
354                            );
355
356    if (ulrc == 0L)
357    {
358        if ( verMaj )
359            *verMaj = ulSysInfo / 10;
360        if ( verMin )
361            *verMin = ulSysInfo % 10;
362    }
363
364    return wxOS_OS2;
365}
366
367
368// ---------------------------------------------------------------------------
369const wxChar* wxGetHomeDir(
370  wxString*                         pStr
371)
372{
373    wxString&                       rStrDir = *pStr;
374
375    // OS/2 has no idea about home,
376    // so use the working directory instead.
377    // However, we might have a valid HOME directory,
378    // as is used on many machines that have unix utilities
379    // on them, so we should use that, if available.
380
381    // 256 was taken from os2def.h
382#ifndef MAX_PATH
383#  define MAX_PATH  256
384#endif
385
386    const wxChar *szHome = wxGetenv((wxChar*)"HOME");
387    if ( szHome == NULL ) {
388      // we're homeless, use current directory.
389      rStrDir = wxT(".");
390    }
391    else
392       rStrDir = szHome;
393
394    return rStrDir.c_str();
395}
396
397// Hack for OS/2
398#if wxUSE_UNICODE
399const wxMB2WXbuf wxGetUserHome( const wxString &rUser )
400#else // just for binary compatibility -- there is no 'const' here
401wxChar* wxGetUserHome ( const wxString &rUser )
402#endif
403{
404    wxChar*    zHome;
405    wxString   sUser1(rUser);
406
407    wxChar *wxBuffer = new wxChar[256];
408#ifndef __EMX__
409    if (!sUser1.empty())
410    {
411        wxChar                      zTmp[64];
412
413        if (wxGetUserId( zTmp
414                        ,sizeof(zTmp)/sizeof(char)
415                       ))
416        {
417            // Guests belong in the temp dir
418            if (wxStricmp(zTmp, _T("annonymous")) == 0)
419            {
420                if ((zHome = wxGetenv(_T("TMP"))) != NULL    ||
421                    (zHome = wxGetenv(_T("TMPDIR"))) != NULL ||
422                    (zHome = wxGetenv(_T("TEMP"))) != NULL)
423                    delete[] wxBuffer;
424                    return *zHome ? zHome : (wxChar*)_T("\\");
425            }
426            if (wxStricmp(zTmp, WXSTRINGCAST sUser1) == 0)
427                sUser1 = wxEmptyString;
428        }
429    }
430#endif
431    if (sUser1.empty())
432    {
433        if ((zHome = wxGetenv(_T("HOME"))) != NULL)
434        {
435            wxStrcpy(wxBuffer, zHome);
436            wxUnix2DosFilename(wxBuffer);
437#if wxUSE_UNICODE
438            wxWCharBuffer retBuffer (wxBuffer);
439            delete[] wxBuffer;
440            return retBuffer;
441#else
442            wxStrcpy(zHome, wxBuffer);
443            delete[] wxBuffer;
444            return zHome;
445#endif
446        }
447    }
448    delete[] wxBuffer;
449    return (wxChar*)wxEmptyString; // No home known!
450}
451
452bool wxGetDiskSpace(const wxString& path,
453                    wxDiskspaceSize_t *pTotal,
454                    wxDiskspaceSize_t *pFree)
455{
456    if (path.empty())
457        return false;
458
459    wxFileName fn(path);
460    FSALLOCATE fsaBuf = {0};
461    APIRET rc = NO_ERROR;
462    ULONG disknum = 0;
463
464    fn.MakeAbsolute();
465
466    if (wxDirExists(fn.GetFullPath()) == false)
467        return false;
468
469    disknum = 1 + wxToupper(fn.GetVolume().GetChar(0)) - _T('A');
470
471    rc = ::DosQueryFSInfo(disknum,             // 1 = A, 2 = B, 3 = C, ...
472                          FSIL_ALLOC,          // allocation info
473                          (PVOID)&fsaBuf,
474                          sizeof(FSALLOCATE));
475
476    if (rc != NO_ERROR)
477        return false;
478    else
479    {
480        if(pTotal)
481        {
482           // to try to avoid 32-bit overflow, let's not multiply right away
483            // (num of alloc units)
484            *pTotal = fsaBuf.cUnit;
485            // * (num of sectors per alloc unit) * (num of bytes per sector)
486            (*pTotal) *= fsaBuf.cSectorUnit * fsaBuf.cbSector;
487        }
488        if(pFree)
489        {
490            *pFree = fsaBuf.cUnitAvail;
491            (*pFree) *= fsaBuf.cSectorUnit * fsaBuf.cbSector;
492        }
493        return true;
494    }
495}
496
497wxString wxPMErrorToStr(ERRORID vError)
498{
499    wxString sError;
500
501    //
502    // Remove the high order byte -- it is useless
503    //
504    vError &= 0x0000ffff;
505    switch(vError)
506    {
507        case PMERR_INVALID_HWND:
508            sError = wxT("Invalid window handle specified");
509            break;
510
511        case PMERR_INVALID_FLAG:
512            sError = wxT("Invalid flag bit set");
513            break;
514
515        case PMERR_NO_MSG_QUEUE:
516            sError = wxT("No message queue available");
517            break;
518
519        case PMERR_INVALID_PARM:
520            sError = wxT("Parameter contained invalid data");
521            break;
522
523        case PMERR_INVALID_PARAMETERS:
524            sError = wxT("Parameter value is out of range");
525            break;
526
527        case PMERR_PARAMETER_OUT_OF_RANGE:
528            sError = wxT("Parameter value is out of range");
529            break;
530
531        case PMERR_INVALID_INTEGER_ATOM:
532            sError = wxT("Not a valid atom");
533            break;
534
535        case PMERR_INVALID_HATOMTBL:
536            sError = wxT("Atom table handle is invalid");
537            break;
538
539        case PMERR_INVALID_ATOM_NAME:
540            sError = wxT("Not a valid atom name");
541            break;
542
543        case PMERR_ATOM_NAME_NOT_FOUND:
544            sError = wxT("Valid name format, but cannot find name in atom table");
545            break;
546
547        case PMERR_INV_HPS:
548            sError = wxT("PMERR_INV_HPS");
549            break;
550
551        case PMERR_PS_BUSY:
552            sError = wxT("PMERR_PS_BUSY");
553            break;
554
555        case PMERR_INV_PRIMITIVE_TYPE:
556            sError = wxT("PMERR_INV_PRIMITIVE_TYPE");
557            break;
558
559        case PMERR_UNSUPPORTED_ATTR:
560            sError = wxT("PMERR_UNSUPPORTED_ATTR");
561            break;
562
563        case PMERR_INV_COLOR_ATTR:
564            sError = wxT("PMERR_INV_COLOR_ATTR");
565            break;
566
567        case PMERR_INV_BACKGROUND_COL_ATTR:
568            sError = wxT("PMERR_INV_BACKGROUND_COL_ATTR");
569            break;
570
571        case PMERR_INV_MIX_ATTR:
572            sError = wxT("PMERR_INV_MIX_ATTR");
573            break;
574
575        case PMERR_INV_LINE_WIDTH_ATTR:
576            sError = wxT("PMERR_INV_LINE_WIDTH_ATTR");
577            break;
578
579        case PMERR_INV_GEOM_LINE_WIDTH_ATTR:
580            sError = wxT("PMERR_INV_GEOM_LINE_WIDTH_ATTR");
581            break;
582
583        case PMERR_INV_LINE_TYPE_ATTR:
584            sError = wxT("PMERR_INV_LINE_TYPE_ATTR");
585            break;
586
587        case PMERR_INV_LINE_END_ATTR:
588            sError = wxT("PMERR_INV_LINE_END_ATTR");
589            break;
590
591        case PMERR_INV_LINE_JOIN_ATTR:
592            sError = wxT("PMERR_INV_LINE_JOIN_ATTR");
593            break;
594
595        case PMERR_INV_CHAR_SET_ATTR:
596            sError = wxT("PMERR_INV_CHAR_SET_ATTR");
597            break;
598
599        case PMERR_INV_CHAR_MODE_ATTR:
600            sError = wxT("PMERR_INV_CHAR_MODE_ATTR");
601            break;
602
603        case PMERR_INV_CHAR_DIRECTION_ATTR:
604            sError = wxT("PMERR_INV_CHAR_DIRECTION_ATTR");
605            break;
606
607        case PMERR_INV_CHAR_SHEAR_ATTR:
608            sError = wxT("PMERR_INV_CHAR_SHEAR_ATTR");
609            break;
610
611        case PMERR_INV_CHAR_ANGLE_ATTR:
612            sError = wxT("PMERR_INV_CHAR_ANGLE_ATTR");
613            break;
614
615        case PMERR_INV_MARKER_SET_ATTR:
616            sError = wxT("PMERR_INV_MARKER_SET_ATTR");
617            break;
618
619        case PMERR_INV_MARKER_SYMBOL_ATTR:
620            sError = wxT("PMERR_INV_MARKER_SYMBOL_ATTR");
621            break;
622
623        case PMERR_INV_PATTERN_SET_ATTR:
624            sError = wxT("PMERR_INV_PATTERN_SET_ATTR");
625            break;
626
627        case PMERR_INV_PATTERN_ATTR:
628            sError = wxT("PMERR_INV_PATTERN_ATTR");
629            break;
630
631        case PMERR_INV_COORDINATE:
632            sError = wxT("PMERR_INV_COORDINATE");
633            break;
634
635        case PMERR_UNSUPPORTED_ATTR_VALUE:
636            sError = wxT("PMERR_UNSUPPORTED_ATTR_VALUE");
637            break;
638
639        case PMERR_INV_PATTERN_SET_FONT:
640            sError = wxT("PMERR_INV_PATTERN_SET_FONT");
641            break;
642
643        case PMERR_HUGE_FONTS_NOT_SUPPORTED:
644            sError = wxT("PMERR_HUGE_FONTS_NOT_SUPPORTED");
645            break;
646
647        default:
648            sError = wxT("Unknown error");
649    }
650    return sError;
651} // end of wxPMErrorToStr
652
653// replacement for implementation in unix/utilsunx.cpp,
654// to be used by all X11 based ports.
655struct wxEndProcessData;
656
657void wxHandleProcessTermination(wxEndProcessData *WXUNUSED(proc_data))
658{
659    // For now, just do nothing. To be filled in as needed.
660}
661