/** * Yudit Unicode Editor Source File * * GNU Copyright (C) 1997-2006 Gaspar Sinai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, * dated June 1991. See file COPYYING for details. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "stoolkit/SUtil.h" #include "stoolkit/STypes.h" #include "stoolkit/SString.h" #include "stoolkit/SStringVector.h" #include "stoolkit/SProperties.h" #include "stoolkit/SIO.h" #include "stoolkit/SIOStream.h" #include "stoolkit/SEncoder.h" #include "stoolkit/SHashtable.h" #include "swindow/SAwt.h" #include #ifdef USE_WINAPI #include #include #else #include #include #include #endif #include SString getHome () { #ifndef USE_WINAPI struct passwd * p = getpwuid(getuid()); if (p!=0) { return SString (p->pw_dir); } #endif char* henv = getenv ("HOME"); if (henv) { SString h (henv); h.replace ("\\", "/"); return SString(h); } #ifdef USE_WINAPI SString ret ="C:/HOME"; SDir dir (ret); if (dir.exists()) { fprintf (stderr, "can not determine home directory. Using %*.*s\n", SSARGS(ret)); } else { fprintf (stderr, "can not determine home directory. Creating %*.*s\n", SSARGS(ret)); if (!dir.create()) { fprintf (stderr, "Could not create %*.*s\n", SSARGS(ret)); } } return ret; #else fprintf (stderr, "can not determine home directory. Using /tmp"); return "/tmp"; #endif } #ifndef YUDIT_DATA #define YUDIT_DATA "/usr/share/yudit" #endif /* YUDIT_DATA */ #ifdef USE_WINAPI char _registryBuffer[1024]; static SString getReg (const SString& _base, const SString& _name) { /* get registry entry first */ SString key = _base; SString name = _name; key.append ("\\"); key.append (name); key.append ((char)0); DWORD datasize = sizeof (_registryBuffer); DWORD type; LONG opened; HKEY hkey=0; type = REG_SZ; if ( (opened = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, key.array(), 0, KEY_READ, &hkey) == ERROR_SUCCESS) && RegQueryValueEx ( hkey, 0, 0, &type, (unsigned char*)_registryBuffer, &datasize) == ERROR_SUCCESS && datasize > 2 && (type == REG_SZ || type == REG_EXPAND_SZ)) { SString ret = SString(_registryBuffer, (unsigned int) datasize-1); RegCloseKey (hkey); return SString(ret); } if (opened == ERROR_SUCCESS) { RegCloseKey (hkey); hkey=0; } return SString(); } static bool setReg (const SString& _base, const SString& _name, const SString& _vle) { SString key = _base; SString name = _name; key.append ("\\"); key.append (name); key.append ((char)0); DWORD datasize = sizeof (_registryBuffer); DWORD type; LONG opened; HKEY hkey=0; type = REG_SZ; SString vle = _vle; vle.append ((char)0); DWORD dispose=0; SECURITY_ATTRIBUTES sa; sa.nLength = sizeof (SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; if ( (opened = RegCreateKeyEx ( HKEY_LOCAL_MACHINE, key.array(), 0, "Why is this parameter not documented?", REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_READ, &sa, &hkey, &dispose) == ERROR_SUCCESS) && RegSetValueEx ( hkey, 0, 0, type, (unsigned char*)vle.array(), vle.size()) == ERROR_SUCCESS) { RegCloseKey (hkey); return true; } if (opened == ERROR_SUCCESS) { fprintf (stderr, "Opened [%*.*s]\n", SSARGS(key)); RegCloseKey (hkey); hkey=0; } else { fprintf (stderr, "Can not open [%*.*s]\n", SSARGS(key)); } return false; } #endif SString getPrefix () { #ifdef USE_WINAPI SString akey = SString("Software\\Inui Yuko\\Yudit"); SString key = akey; key.append ("\\"); SString version = SD_YUDIT_VERSION; key.append (version); SString data=getReg(key, "Install Directory"); if (data.size()) { data.replaceAll("\\", "/"); return SString(data); } data = getReg(akey, "Current Version"); if (data.size()) { fprintf (stderr, "Can not find current version:%*.*s. trying version %*.*s\n", SSARGS(version), SSARGS(data)); SString key = akey; key.append ("\\"); key.append (data); SString data=getReg(key, "Install Directory"); if (data.size()) { data.replaceAll("\\", "/"); return SString(data); } } fprintf (stderr, "Can not find registry entry: [%*.*s\\Install Directory]\n", SSARGS(key)); #endif return SString (YUDIT_DATA); } bool setPrefix (const SString& str) { #ifdef USE_WINAPI SString key = SString("Software\\Inui Yuko\\Yudit"); setReg(key, "Current Version", SD_YUDIT_VERSION); key.append ("\\"); key.append (SD_YUDIT_VERSION); bool ret = setReg(key, "Install Directory", str); if (!ret) { fprintf (stderr, "Can not set registry entry: [%*.*s\\Install Directory] to [%*.*s]\n", SSARGS(key), SSARGS(str)); return false; } fprintf (stderr, "Registry entry [%*.*s\\Install Directory] has been set to [%*.*s]\n", SSARGS(key), SSARGS(str)); return ret; #endif return false; } bool loadProperties (const SString& file, SProperties* in) { SFile f(file); if (f.size() < 0) return false; SFileImage im = f.getFileImage (); if (im.size()<0) return false; SProperties p(SString (im.array(), im.size())); in->merge(p); return true; } bool loadProperties (SProperties* in) { SString c1 = getHome(); c1.append ("/.yudit/yudit.properties"); SString c2 = getPrefix(); c2.append ("/config/yudit.properties"); bool ret = loadProperties (c2, in); ret = ret || loadProperties (c1, in); return ret; } bool saveProperties (const SString& file, const SProperties& out) { SProperties orig; loadProperties (file, &orig); orig.merge (out); SFile f(file); SOutputStream os = f.getOutputStream(); if (!os.isOK()) return false; SWriter writer(os); if (!writer.isOK()) return false; SString s(orig.toString()); s.append ("\n# End of Yudit-"); s.append (SD_YUDIT_VERSION); s.append (" properties\n"); if (!writer.write (s)) return false; if (!writer.close()) return false; return true; } static bool translateInited = false; static SString currentBind; static SString currentLanguage; static SStringVector defaultDomains ("/usr/lib/locale,/usr/share/locale"); static SStringVector currentDomains; static SFileImage moFileImage; static SHashtable *moCache=0; void initTranslate (const SString& bindIn, const SString& domain) { currentBind = bindIn; currentDomains = defaultDomains; currentDomains.insert (0, domain); translateInited=false; } void setLanguage (const SString& _str) { if (_str != currentLanguage) { translateInited=false; } currentLanguage = _str; return; } SString getLanguage () { return SString (currentLanguage); } /** * Get system language or fb */ SString getSystemLanguage (const SString& fb) { char* henv = getenv ("LANG"); if (henv) { SString h (henv); /* no support for country yet */ if (h.size()> 2 && h[2] == '_') h.truncate (2); return SString(h); } return SString(fb); } /* SS_WORD32 mingle */ #define reorder_bytes(b) \ (((b>>24)&0xff) \ | ((b>>8)&0xff00) \ | ((b<<8)&0xff0000) \ | ((b<<24)&0xff000000)) SString translate (const SString& str) { if (moCache == 0) moCache = new SHashtable(); if (!translateInited) { moCache->clear(); translateInited = true; SStringVector plist; for (unsigned int i=0; iget(str) != 0) { return SString(*moCache->get (str)); } /* Direct processing of gettext mo file. byte +------------------------------------------+ 0 | magic number = 0x950412de | | | 4 | file format revision = 0 | | | 8 | number of strings | == N | | 12 | offset of table with original strings | == O | | 16 | offset of table with translation strings | == T | | 20 | size of hashing table | == S | | 24 | offset of hashing table | == H | | . . . (possibly more entries later) . . . | | O | length & offset 0th string ----------------. O + 8 | length & offset 1st string ------------------. ... ... | | O + ((N-1)*8)| length & offset (N-1)th string | | | | | | | T | length & offset 0th translation ---------------. T + 8 | length & offset 1st translation -----------------. ... ... | | | | T + ((N-1)*8)| length & offset (N-1)th translation | | | | | | | | | | | H | start hash table | | | | | ... ... | | | | H + S * 4 | end hash table | | | | | | | | | | | | NUL terminated 0th string <----------------' | | | | | | | | | NUL terminated 1st string <------------------' | | | | | | ... ... | | | | | | | NUL terminated 0th translation <---------------' | | | | | NUL terminated 1st translation <-----------------' | | ... ... | | +------------------------------------------+ */ unsigned char* array = (unsigned char*)moFileImage.array(); SS_WORD32 magic = *((SS_WORD32*)&array[0]); bool swap = (magic != 0x950412de); if (swap) magic = reorder_bytes (magic); if (magic != 0x950412de) { moCache->put (str, str); return SString(str); } SS_WORD32 count = *((SS_WORD32*)&array[8]); SS_WORD32 koffset = *((SS_WORD32*)&array[12]); SS_WORD32 toffset = *((SS_WORD32*)&array[16]); if (swap) { count = reorder_bytes (count); koffset = reorder_bytes (koffset); toffset = reorder_bytes (toffset); } SString trans (str); for (unsigned int i=0; iput (str, trans); return SString(trans); } /** * print the unicode value in "U+XXXX or U+XXXXXXXX" form */ SString unicodeValueOf (const SV_UCS4& ucs4) { char a[64]; SString s; for (unsigned int i=0; i 0xffff) { sprintf (a, "%08lX", (unsigned long) ucs4[i]); } else { sprintf (a, "%04X", (unsigned int) ucs4[i]); } s.append (a); } return SString (s); } SString unicodeValueOf (const SString& str) { SEncoder enc("utf-8"); SV_UCS4 ucs4 = enc.decode (str); return unicodeValueOf (ucs4); } /** * Get the square root or if there are decimals, the value that is less * than square root. * @param sq is the square */ unsigned long ss_sqrtlong (unsigned long sq) { /* we don't check for negative. assume...*/ if (sq<2) return sq; /* zero or 1 */ register unsigned long x=sq; register unsigned long r=x-1; while (r < x) { x = r; r= (x+(sq/x))/2; } return x; } /** * arcus tanget in a scale of 32 * @param x is the vector x param * @param y is the vector y param * @return the anlge with step 1 * 0 => 12:00, 8 => 3:00, 16 => 6:00, 24 => 9:00 * returns 32 if x and y are both zero. */ int ss_atan32 (int x, int y) { if (x==0 && y ==0) return 32; /* normalize data - x and y positive and x < y */ bool xneg = x < 0; if (xneg) x = -x; bool yneg = y < 0; if (yneg) y = -y; bool xyflip = (y < x); if (xyflip) { int tmp = x; x = y; y = tmp; } int slope = (100 * x) / y; int ret = 4; /* ../bin/angle.pl data is used */ if (slope < 10) ret = 0; else if (slope < 31) ret = 1; else if (slope < 54) ret = 2; else if (slope < 83) ret = 3; /* now 0..45 degrees is nicely split up into 0..4 */ /* go back the transform we did at the begining in reverse order */ if (xyflip) ret = 8 - ret; if (yneg) ret = 16 - ret; if (xneg) ret = 32 - ret; return ret % 32; } static long maxlong=0; static long maxsqrtlong=0; /** * Get the maximum long value on the machine. * The hard way. Don't trust header files. Gaspar Sinai */ long getMaxLong() { if (maxlong==0) { long l = 1; long ml = 1; while (l>0) { maxlong = ml; l = l<<1; ml = (ml<<1)|1; } } return maxlong; } long getMaxSqrtLong () { if (maxsqrtlong==0) { getMaxLong(); maxsqrtlong = ss_sqrtlong (maxlong)-1; } return maxsqrtlong; } static long maxint=0; static long maxsqrtint=0; /** * Get the maximum long value on the machine. * The hard way. Don't trust header files. Gaspar Sinai */ int getMaxInt() { if (maxint==0) { int i = 1; int mi = 1; while (i>0) { maxint = i; i = i<<1; mi = (mi<<1)|1; } } return maxint; } int getMaxSqrtInt () { if (maxsqrtint==0) { getMaxInt(); maxsqrtint = (int)ss_sqrtlong ((long)maxlong)-1; } return maxsqrtint; } bool isWindows () { #ifdef USE_WINAPI OSVERSIONINFO ovi; ovi.dwOSVersionInfoSize = sizeof (ovi); GetVersionEx (&ovi); return (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); #else /*USE_WINAPI*/ return false; #endif } bool isWinAPI () { #ifdef USE_WINAPI return true; #else /*USE_WINAPI*/ return false; #endif } /** * check if the command could be executed in a shell as is. */ bool commandExists (const SString& str) { SString comm = str; comm.replaceAll ("\\", "/"); comm.replaceAll ("//", "/"); char* path = getenv ("PATH"); if (!path) { path = getenv ("path"); if (!path) { path = getenv ("Path"); } } SStringVector pv; if (path && path[0] != 0) { #ifdef USE_WINAPI SStringVector v(path, ";"); #else SStringVector v(path, ":"); #endif for (unsigned int i=0; i0) return true; #ifdef USE_WINAPI SString ecomm = comm; ecomm.append (".exe"); SFile f1(ecomm, pv); if (f1.size()>0) return true; comm.append (".com"); SFile f2(ecomm, pv); if (f2.size()>0) return true; #endif return false; }