gcmd.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. """!
  2. @package core.gcmd
  3. @brief wxGUI command interface
  4. Classes:
  5. - gcmd::GError
  6. - gcmd::GWarning
  7. - gcmd::GMessage
  8. - gcmd::GException
  9. - gcmd::Popen (from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554)
  10. - gcmd::Command
  11. - gcmd::CommandThread
  12. Functions:
  13. - RunCommand
  14. - GetDefaultEncoding
  15. (C) 2007-2008, 2010-2011 by the GRASS Development Team
  16. This program is free software under the GNU General Public License
  17. (>=v2). Read the file COPYING that comes with GRASS for details.
  18. @author Jachym Cepicky
  19. @author Martin Landa <landa.martin gmail.com>
  20. """
  21. import os
  22. import sys
  23. import time
  24. import errno
  25. import signal
  26. import traceback
  27. import locale
  28. import subprocess
  29. if subprocess.mswindows:
  30. from win32file import ReadFile, WriteFile
  31. from win32pipe import PeekNamedPipe
  32. import msvcrt
  33. else:
  34. import select
  35. import fcntl
  36. from threading import Thread
  37. import wx
  38. from grass.script import core as grass
  39. from core import globalvar
  40. from core.debug import Debug
  41. def GetRealCmd(cmd):
  42. """!Return real command name - only for MS Windows
  43. """
  44. if sys.platform == 'win32':
  45. for ext in globalvar.grassScripts.keys():
  46. if cmd in globalvar.grassScripts[ext]:
  47. return cmd + ext
  48. return cmd
  49. def DecodeString(string):
  50. """!Decode string using system encoding
  51. @param string string to be decoded
  52. @return decoded string
  53. """
  54. if not string:
  55. return string
  56. if _enc:
  57. Debug.msg(5, "DecodeString(): enc=%s" % _enc)
  58. return string.decode(_enc)
  59. return string
  60. def EncodeString(string):
  61. """!Return encoded string using system locales
  62. @param string string to be encoded
  63. @return encoded string
  64. """
  65. if not string:
  66. return string
  67. if _enc:
  68. Debug.msg(5, "EncodeString(): enc=%s" % _enc)
  69. return string.encode(_enc)
  70. return string
  71. class GError:
  72. def __init__(self, message, parent = None, caption = None, showTraceback = True):
  73. """!Show error message window
  74. @param message error message
  75. @param parent centre window on parent if given
  76. @param caption window caption (if not given "Error")
  77. @param showTraceback True to show also Python traceback
  78. """
  79. if not caption:
  80. caption = _('Error')
  81. style = wx.OK | wx.ICON_ERROR | wx.CENTRE
  82. exc_type, exc_value, exc_traceback = sys.exc_info()
  83. if exc_traceback:
  84. exception = traceback.format_exc()
  85. reason = exception.splitlines()[-1].split(':', 1)[-1].strip()
  86. if Debug.GetLevel() > 0 and exc_traceback:
  87. sys.stderr.write(exception)
  88. if showTraceback and exc_traceback:
  89. wx.MessageBox(parent = parent,
  90. message = message + '\n\n%s: %s\n\n%s' % \
  91. (_('Reason'),
  92. reason, exception),
  93. caption = caption,
  94. style = style)
  95. else:
  96. wx.MessageBox(parent = parent,
  97. message = message,
  98. caption = caption,
  99. style = style)
  100. class GWarning:
  101. def __init__(self, message, parent = None):
  102. caption = _('Warning')
  103. style = wx.OK | wx.ICON_WARNING | wx.CENTRE
  104. wx.MessageBox(parent = parent,
  105. message = message,
  106. caption = caption,
  107. style = style)
  108. class GMessage:
  109. def __init__(self, message, parent = None):
  110. caption = _('Message')
  111. style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE
  112. wx.MessageBox(parent = parent,
  113. message = message,
  114. caption = caption,
  115. style = style)
  116. class GException(Exception):
  117. def __init__(self, value = ''):
  118. self.value = value
  119. def __str__(self):
  120. return self.value
  121. class Popen(subprocess.Popen):
  122. """!Subclass subprocess.Popen"""
  123. def __init__(self, args, **kwargs):
  124. if subprocess.mswindows:
  125. args = map(EncodeString, args)
  126. subprocess.Popen.__init__(self, args, **kwargs)
  127. def recv(self, maxsize = None):
  128. return self._recv('stdout', maxsize)
  129. def recv_err(self, maxsize = None):
  130. return self._recv('stderr', maxsize)
  131. def send_recv(self, input = '', maxsize = None):
  132. return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
  133. def get_conn_maxsize(self, which, maxsize):
  134. if maxsize is None:
  135. maxsize = 1024
  136. elif maxsize < 1:
  137. maxsize = 1
  138. return getattr(self, which), maxsize
  139. def _close(self, which):
  140. getattr(self, which).close()
  141. setattr(self, which, None)
  142. def kill(self):
  143. """!Try to kill running process"""
  144. if subprocess.mswindows:
  145. import win32api
  146. handle = win32api.OpenProcess(1, 0, self.pid)
  147. return (0 != win32api.TerminateProcess(handle, 0))
  148. else:
  149. try:
  150. os.kill(-self.pid, signal.SIGTERM) # kill whole group
  151. except OSError:
  152. pass
  153. if subprocess.mswindows:
  154. def send(self, input):
  155. if not self.stdin:
  156. return None
  157. try:
  158. x = msvcrt.get_osfhandle(self.stdin.fileno())
  159. (errCode, written) = WriteFile(x, input)
  160. except ValueError:
  161. return self._close('stdin')
  162. except (subprocess.pywintypes.error, Exception), why:
  163. if why[0] in (109, errno.ESHUTDOWN):
  164. return self._close('stdin')
  165. raise
  166. return written
  167. def _recv(self, which, maxsize):
  168. conn, maxsize = self.get_conn_maxsize(which, maxsize)
  169. if conn is None:
  170. return None
  171. try:
  172. x = msvcrt.get_osfhandle(conn.fileno())
  173. (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
  174. if maxsize < nAvail:
  175. nAvail = maxsize
  176. if nAvail > 0:
  177. (errCode, read) = ReadFile(x, nAvail, None)
  178. except ValueError:
  179. return self._close(which)
  180. except (subprocess.pywintypes.error, Exception), why:
  181. if why[0] in (109, errno.ESHUTDOWN):
  182. return self._close(which)
  183. raise
  184. if self.universal_newlines:
  185. read = self._translate_newlines(read)
  186. return read
  187. else:
  188. def send(self, input):
  189. if not self.stdin:
  190. return None
  191. if not select.select([], [self.stdin], [], 0)[1]:
  192. return 0
  193. try:
  194. written = os.write(self.stdin.fileno(), input)
  195. except OSError, why:
  196. if why[0] == errno.EPIPE: #broken pipe
  197. return self._close('stdin')
  198. raise
  199. return written
  200. def _recv(self, which, maxsize):
  201. conn, maxsize = self.get_conn_maxsize(which, maxsize)
  202. if conn is None:
  203. return None
  204. flags = fcntl.fcntl(conn, fcntl.F_GETFL)
  205. if not conn.closed:
  206. fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
  207. try:
  208. if not select.select([conn], [], [], 0)[0]:
  209. return ''
  210. r = conn.read(maxsize)
  211. if not r:
  212. return self._close(which)
  213. if self.universal_newlines:
  214. r = self._translate_newlines(r)
  215. return r
  216. finally:
  217. if not conn.closed:
  218. fcntl.fcntl(conn, fcntl.F_SETFL, flags)
  219. message = "Other end disconnected!"
  220. def recv_some(p, t = .1, e = 1, tr = 5, stderr = 0):
  221. if tr < 1:
  222. tr = 1
  223. x = time.time()+t
  224. y = []
  225. r = ''
  226. pr = p.recv
  227. if stderr:
  228. pr = p.recv_err
  229. while time.time() < x or r:
  230. r = pr()
  231. if r is None:
  232. if e:
  233. raise Exception(message)
  234. else:
  235. break
  236. elif r:
  237. y.append(r)
  238. else:
  239. time.sleep(max((x-time.time())/tr, 0))
  240. return ''.join(y)
  241. def send_all(p, data):
  242. while len(data):
  243. sent = p.send(data)
  244. if sent is None:
  245. raise Exception(message)
  246. data = buffer(data, sent)
  247. class Command:
  248. """!Run command in separate thread. Used for commands launched
  249. on the background.
  250. If stdout/err is redirected, write() method is required for the
  251. given classes.
  252. @code
  253. cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=3, wait=True)
  254. if cmd.returncode == None:
  255. print 'RUNNING?'
  256. elif cmd.returncode == 0:
  257. print 'SUCCESS'
  258. else:
  259. print 'FAILURE (%d)' % cmd.returncode
  260. @endcode
  261. """
  262. def __init__ (self, cmd, stdin = None,
  263. verbose = None, wait = True, rerr = False,
  264. stdout = None, stderr = None):
  265. """
  266. @param cmd command given as list
  267. @param stdin standard input stream
  268. @param verbose verbose level [0, 3] (--q, --v)
  269. @param wait wait for child execution terminated
  270. @param rerr error handling (when GException raised).
  271. True for redirection to stderr, False for GUI dialog,
  272. None for no operation (quiet mode)
  273. @param stdout redirect standard output or None
  274. @param stderr redirect standard error output or None
  275. """
  276. Debug.msg(1, "gcmd.Command(): %s" % ' '.join(cmd))
  277. self.cmd = cmd
  278. self.stderr = stderr
  279. #
  280. # set verbosity level
  281. #
  282. verbose_orig = None
  283. if ('--q' not in self.cmd and '--quiet' not in self.cmd) and \
  284. ('--v' not in self.cmd and '--verbose' not in self.cmd):
  285. if verbose is not None:
  286. if verbose == 0:
  287. self.cmd.append('--quiet')
  288. elif verbose == 3:
  289. self.cmd.append('--verbose')
  290. else:
  291. verbose_orig = os.getenv("GRASS_VERBOSE")
  292. os.environ["GRASS_VERBOSE"] = str(verbose)
  293. #
  294. # create command thread
  295. #
  296. self.cmdThread = CommandThread(cmd, stdin,
  297. stdout, stderr)
  298. self.cmdThread.start()
  299. if wait:
  300. self.cmdThread.join()
  301. if self.cmdThread.module:
  302. self.cmdThread.module.wait()
  303. self.returncode = self.cmdThread.module.returncode
  304. else:
  305. self.returncode = 1
  306. else:
  307. self.cmdThread.join(0.5)
  308. self.returncode = None
  309. if self.returncode is not None:
  310. Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=%d, alive=%s" % \
  311. (' '.join(cmd), wait, self.returncode, self.cmdThread.isAlive()))
  312. if rerr is not None and self.returncode != 0:
  313. if rerr is False: # GUI dialog
  314. raise GException("%s '%s'%s%s%s %s%s" % \
  315. (_("Execution failed:"),
  316. ' '.join(self.cmd),
  317. os.linesep, os.linesep,
  318. _("Details:"),
  319. os.linesep,
  320. _("Error: ") + self.__GetError()))
  321. elif rerr == sys.stderr: # redirect message to sys
  322. stderr.write("Execution failed: '%s'" % (' '.join(self.cmd)))
  323. stderr.write("%sDetails:%s%s" % (os.linesep,
  324. _("Error: ") + self.__GetError(),
  325. os.linesep))
  326. else:
  327. pass # nop
  328. else:
  329. Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=?, alive=%s" % \
  330. (' '.join(cmd), wait, self.cmdThread.isAlive()))
  331. if verbose_orig:
  332. os.environ["GRASS_VERBOSE"] = verbose_orig
  333. elif "GRASS_VERBOSE" in os.environ:
  334. del os.environ["GRASS_VERBOSE"]
  335. def __ReadOutput(self, stream):
  336. """!Read stream and return list of lines
  337. @param stream stream to be read
  338. """
  339. lineList = []
  340. if stream is None:
  341. return lineList
  342. while True:
  343. line = stream.readline()
  344. if not line:
  345. break
  346. line = line.replace('%s' % os.linesep, '').strip()
  347. lineList.append(line)
  348. return lineList
  349. def __ReadErrOutput(self):
  350. """!Read standard error output and return list of lines"""
  351. return self.__ReadOutput(self.cmdThread.module.stderr)
  352. def __ProcessStdErr(self):
  353. """
  354. Read messages/warnings/errors from stderr
  355. @return list of (type, message)
  356. """
  357. if self.stderr is None:
  358. lines = self.__ReadErrOutput()
  359. else:
  360. lines = self.cmdThread.error.strip('%s' % os.linesep). \
  361. split('%s' % os.linesep)
  362. msg = []
  363. type = None
  364. content = ""
  365. for line in lines:
  366. if len(line) == 0:
  367. continue
  368. if 'GRASS_' in line: # error or warning
  369. if 'GRASS_INFO_WARNING' in line: # warning
  370. type = "WARNING"
  371. elif 'GRASS_INFO_ERROR' in line: # error
  372. type = "ERROR"
  373. elif 'GRASS_INFO_END': # end of message
  374. msg.append((type, content))
  375. type = None
  376. content = ""
  377. if type:
  378. content += line.split(':', 1)[1].strip()
  379. else: # stderr
  380. msg.append((None, line.strip()))
  381. return msg
  382. def __GetError(self):
  383. """!Get error message or ''"""
  384. if not self.cmdThread.module:
  385. return _("Unable to exectute command: '%s'") % ' '.join(self.cmd)
  386. for type, msg in self.__ProcessStdErr():
  387. if type == 'ERROR':
  388. if _enc:
  389. return unicode(msg, _enc)
  390. return msg
  391. return ''
  392. class CommandThread(Thread):
  393. """!Create separate thread for command. Used for commands launched
  394. on the background."""
  395. def __init__ (self, cmd, env = None, stdin = None,
  396. stdout = sys.stdout, stderr = sys.stderr):
  397. """
  398. @param cmd command (given as list)
  399. @param env environmental variables
  400. @param stdin standard input stream
  401. @param stdout redirect standard output or None
  402. @param stderr redirect standard error output or None
  403. """
  404. Thread.__init__(self)
  405. self.cmd = cmd
  406. self.stdin = stdin
  407. self.stdout = stdout
  408. self.stderr = stderr
  409. self.env = env
  410. self.module = None
  411. self.error = ''
  412. self._want_abort = False
  413. self.aborted = False
  414. self.setDaemon(True)
  415. # set message formatting
  416. self.message_format = os.getenv("GRASS_MESSAGE_FORMAT")
  417. os.environ["GRASS_MESSAGE_FORMAT"] = "gui"
  418. def __del__(self):
  419. if self.message_format:
  420. os.environ["GRASS_MESSAGE_FORMAT"] = self.message_format
  421. else:
  422. del os.environ["GRASS_MESSAGE_FORMAT"]
  423. def run(self):
  424. """!Run command"""
  425. if len(self.cmd) == 0:
  426. return
  427. Debug.msg(1, "gcmd.CommandThread(): %s" % ' '.join(self.cmd))
  428. self.startTime = time.time()
  429. # TODO: replace ugly hack bellow
  430. args = self.cmd
  431. if sys.platform == 'win32':
  432. ext = os.path.splitext(self.cmd[0])[1] == globalvar.SCT_EXT
  433. if ext or self.cmd[0] in globalvar.grassScripts[globalvar.SCT_EXT]:
  434. os.chdir(os.path.join(os.getenv('GISBASE'), 'scripts'))
  435. if not ext:
  436. args = [sys.executable, self.cmd[0] + globalvar.SCT_EXT] + self.cmd[1:]
  437. else:
  438. args = [sys.executable, self.cmd[0]] + self.cmd[1:]
  439. try:
  440. self.module = Popen(args,
  441. stdin = subprocess.PIPE,
  442. stdout = subprocess.PIPE,
  443. stderr = subprocess.PIPE,
  444. shell = sys.platform == "win32",
  445. env = self.env)
  446. except OSError, e:
  447. self.error = str(e)
  448. print >> sys.stderr, e
  449. return 1
  450. if self.stdin: # read stdin if requested ...
  451. self.module.stdin.write(self.stdin)
  452. self.module.stdin.close()
  453. # redirect standard outputs...
  454. self._redirect_stream()
  455. def _redirect_stream(self):
  456. """!Redirect stream"""
  457. if self.stdout:
  458. # make module stdout/stderr non-blocking
  459. out_fileno = self.module.stdout.fileno()
  460. if not subprocess.mswindows:
  461. flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
  462. fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK)
  463. if self.stderr:
  464. # make module stdout/stderr non-blocking
  465. out_fileno = self.module.stderr.fileno()
  466. if not subprocess.mswindows:
  467. flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
  468. fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags| os.O_NONBLOCK)
  469. # wait for the process to end, sucking in stuff until it does end
  470. while self.module.poll() is None:
  471. if self._want_abort: # abort running process
  472. self.module.terminate()
  473. self.aborted = True
  474. return
  475. if self.stdout:
  476. line = recv_some(self.module, e = 0, stderr = 0)
  477. self.stdout.write(line)
  478. if self.stderr:
  479. line = recv_some(self.module, e = 0, stderr = 1)
  480. self.stderr.write(line)
  481. if len(line) > 0:
  482. self.error = line
  483. # get the last output
  484. if self.stdout:
  485. line = recv_some(self.module, e = 0, stderr = 0)
  486. self.stdout.write(line)
  487. if self.stderr:
  488. line = recv_some(self.module, e = 0, stderr = 1)
  489. self.stderr.write(line)
  490. if len(line) > 0:
  491. self.error = line
  492. def abort(self):
  493. """!Abort running process, used by main thread to signal an abort"""
  494. self._want_abort = True
  495. def _formatMsg(text):
  496. """!Format error messages for dialogs
  497. """
  498. message = ''
  499. for line in text.splitlines():
  500. if len(line) == 0:
  501. continue
  502. elif 'GRASS_INFO_MESSAGE' in line:
  503. message += line.split(':', 1)[1].strip() + '\n'
  504. elif 'GRASS_INFO_WARNING' in line:
  505. message += line.split(':', 1)[1].strip() + '\n'
  506. elif 'GRASS_INFO_ERROR' in line:
  507. message += line.split(':', 1)[1].strip() + '\n'
  508. elif 'GRASS_INFO_END' in line:
  509. return message
  510. else:
  511. message += line.strip() + '\n'
  512. return message
  513. def RunCommand(prog, flags = "", overwrite = False, quiet = False, verbose = False,
  514. parent = None, read = False, parse = None, stdin = None, getErrorMsg = False, **kwargs):
  515. """!Run GRASS command
  516. @param prog program to run
  517. @param flags flags given as a string
  518. @param overwrite, quiet, verbose flags
  519. @param parent parent window for error messages
  520. @param read fetch stdout
  521. @param parse fn to parse stdout (e.g. grass.parse_key_val) or None
  522. @param stdin stdin or None
  523. @param getErrorMsg get error messages on failure
  524. @param kwargs program parameters
  525. @return returncode (read == False and getErrorMsg == False)
  526. @return returncode, messages (read == False and getErrorMsg == True)
  527. @return stdout (read == True and getErrorMsg == False)
  528. @return returncode, stdout, messages (read == True and getErrorMsg == True)
  529. @return stdout, stderr
  530. """
  531. cmdString = ' '.join(grass.make_command(prog, flags, overwrite,
  532. quiet, verbose, **kwargs))
  533. Debug.msg(1, "gcmd.RunCommand(): %s" % cmdString)
  534. kwargs['stderr'] = subprocess.PIPE
  535. if read:
  536. kwargs['stdout'] = subprocess.PIPE
  537. if stdin:
  538. kwargs['stdin'] = subprocess.PIPE
  539. if parent:
  540. messageFormat = os.getenv('GRASS_MESSAGE_FORMAT', 'gui')
  541. os.environ['GRASS_MESSAGE_FORMAT'] = 'standard'
  542. Debug.msg(2, "gcmd.RunCommand(): command started")
  543. start = time.time()
  544. ps = grass.start_command(GetRealCmd(prog), flags, overwrite, quiet, verbose, **kwargs)
  545. if stdin:
  546. ps.stdin.write(stdin)
  547. ps.stdin.close()
  548. ps.stdin = None
  549. Debug.msg(3, "gcmd.RunCommand(): decoding string")
  550. stdout, stderr = map(DecodeString, ps.communicate())
  551. if parent: # restore previous settings
  552. os.environ['GRASS_MESSAGE_FORMAT'] = messageFormat
  553. ret = ps.returncode
  554. Debug.msg(1, "gcmd.RunCommand(): get return code %d (%.6f sec)" % \
  555. (ret, (time.time() - start)))
  556. Debug.msg(3, "gcmd.RunCommand(): print error")
  557. if ret != 0 and parent:
  558. Debug.msg(2, "gcmd.RunCommand(): error %s" % stderr)
  559. if (stderr == None):
  560. Debug.msg(2, "gcmd.RunCommand(): nothing to print ???")
  561. else:
  562. GError(parent = parent,
  563. caption = _("Error in %s") % prog,
  564. message = stderr)
  565. Debug.msg(3, "gcmd.RunCommand(): print read error")
  566. if not read:
  567. if not getErrorMsg:
  568. return ret
  569. else:
  570. return ret, _formatMsg(stderr)
  571. if stdout:
  572. Debug.msg(2, "gcmd.RunCommand(): return stdout\n'%s'" % stdout)
  573. else:
  574. Debug.msg(2, "gcmd.RunCommand(): return stdout = None")
  575. if parse:
  576. stdout = parse(stdout)
  577. if not getErrorMsg:
  578. return stdout
  579. Debug.msg(2, "gcmd.RunCommand(): return ret, stdout")
  580. if read and getErrorMsg:
  581. return ret, stdout, _formatMsg(stderr)
  582. Debug.msg(2, "gcmd.RunCommand(): return result")
  583. return stdout, _formatMsg(stderr)
  584. def GetDefaultEncoding(forceUTF8 = False):
  585. """!Get default system encoding
  586. @param forceUTF8 force 'UTF-8' if encoding is not defined
  587. @return system encoding (can be None)
  588. """
  589. enc = locale.getdefaultlocale()[1]
  590. if forceUTF8 and (enc is None or enc == 'UTF8'):
  591. return 'UTF-8'
  592. Debug.msg(1, "GetSystemEncoding(): %s" % enc)
  593. return enc
  594. _enc = GetDefaultEncoding() # define as global variable