#!/usr/bin/env python3


# Preprocessor for serto font for the use with LaTeX.
# Copyright 2001-2020 by Johannes Heinecke
# you can use this and change it as you wish, under the condition
# that the original copyright line is not deleted

# Last changes:
#  2 Nov 2003: major reconstruction, use of three fontfiles
#  12 July 2003: correction on stretch
#  29 September 2007: Possibility to typeset two identical letters without a qusshaya
#  31 March 2013: add SERTOFONTDIR environment variable
#  18 April 2020: finally adapted to python3
#  15 December 2020: minor corrections

import re
import sys
import os

version="1.3.2"

mydir = os.path.dirname(__file__)
if not mydir:
    mydir = "."
FONTFILESERTO = mydir + "/serto.font" # specify absolute path
FONTFILECHALD = mydir + "/assyr.font"
#FONTFILEESTRA = mydir + "/estrangelo.font"

print(FONTFILESERTO, file=sys.stderr)
# use the environment variable SERTOFONTDIR to specify the directory of the *.font files



# translating syriac unicode points to serto codings

class Letter:
    def __init__(self, 
                 coding, # what coding to use in .ptex-file
                 name,   # name of the letter
                 isolated, # what character to take in isolated usage
                 initial, # what character to take in word-initial usage
                 medial,  # what character to take in word-medial usage
                 final,  # what character to take in word-final usage
                 link): # does it link to the following (# link 0: next letter is initial, 1: next letter is medial, 2: ignore,  8: character is a superscript symbol  9: character is a subscript symbol

        self.coding = coding
        self.name = name
        self.isolated = list(map(int, isolated.split('+')))
        self.initial = list(map(int, initial.split('+')))
        self.medial = list(map(int, medial.split('+')))
        self.final = list(map(int, final.split('+')))
        self.link = int(link)
        
        if self.isolated[0] == -1: self.isolated = None
        if self.initial[0] == -1: self.initial = None
        if self.medial[0] == -1: self.medial = None
        if self.final[0] == -1: self.final = None
        #sys.stderr.write("%s:%s-%s-%s-%s\n" \
        #                 % (name,self.isolated,self.initial,self.medial,self.final))
        
    def getcontext(self, ctx):
        if ctx == 0: return   self.isolated[0]
        elif ctx == 1: return self.initial[0]
        elif ctx == 2: return self.medial[0]
        elif ctx == 3: return self.final[0]

    def getChar(self, ctx):
        if ctx == 0: 
            if not self.isolated: return ['']
            return map(lambda x: "%c" % x, self.isolated)
            #return int(self.isolated[0])
        elif ctx == 1: 
            if not self.initial: return ['']
            return map(lambda x: "%c" % x, self.initial)
            #return int(self.initial[0])
        elif ctx == 2: 
            #sys.stderr.write("MEDIAL %s\n" % self.medial)
            if not self.medial: 
                #sys.stderr.write("NONE:e\n")
                return ['']
            return map(lambda x: "%c" % x, self.medial)
            #return int(self.medial[0])
        elif ctx == 3:
            if not self.final: return ['']
            return map(lambda x: "%c" % x, self.final)
            #return int(self.final[0])

class Serto:
    def __init__(self, elatex=0):
        self.elatex=elatex # eLaTeX needs \TeXXeTstate=1
        self.tabelle = {} # style: {"_d": Letter-Object}
        self.transtabelle = {} # style: "_d": \d{d}
        #self.usingUTF8 = False

        self.inlineS = re.compile("(<S>)(.*?)(</S>)")
        self.inlineT = re.compile("(<T>)(.*?)(</T>)")
        self.inlineST = re.compile("(<ST>)(.*?)(</ST>)")

        self.inlineC = re.compile("(<C>)(.*?)(</C>)")
        self.inlineCT = re.compile("(<CT>)(.*?)(</CT>)")

        self.inlineE = re.compile("(<E>)(.*?)(</E>)")
        self.inlineET = re.compile("(<ET>)(.*?)(</ET>)")

        self.tabelle["serto"] = {}
        self.transtabelle["serto"] = {}
        self.readfont(FONTFILESERTO, 
                      self.tabelle["serto"],
                      self.transtabelle["serto"])
        #print  self.tabelle["serto"]

        self.tabelle["chaldean"] = {}
        self.transtabelle["chaldean"] = {}
        self.readfont(FONTFILECHALD, 
                      self.tabelle["chaldean"],
                      self.transtabelle["chaldean"])

        self.UnicodeTable = { 0x0710: "'",
                0x0712: "b",
                0x0713: "g",
                0x0714: "G", #gamal garshuni
                0x0715: "d",
                0x0717: "h",
                0x0718: "w",
                0x0719: "z",
                0x071a: ".h",
                0x071b: ".t",
                0x071c: ".T", # teth garshuni
                0x071d: "y",
                0x071f: "k",
                0x0720: "l",
                0x0721: "m",
                0x0722: "n",
                0x0723: "s",
                0x0724: "s", # final semkath
                0x0725: "`",
                0x0726: "p",
                0x0728: ".s",
                0x0729: "q",
                0x072a: "r",
                0x072b: "^s",
                0x072c: "t",
                0x0308: "P", # syame 
                0x0730: "a",
                0x0731: "A",
                0x0732: ":a",
                0x0733: "=a",
                0x0734: "=A",
                0x0735: ":=a",
                0x0736: "e",
                0x0737: "E",
                0x0738: ":e",
                0x0739: ":e",
                0x073a: "i",
                0x073b: "I",
                0x073c: ":i",
                0x073d: "u",
                0x073e: "U",
                0x073f: ":u",
                0x0740: ":=a",
                0x0741: "*",
                0x0742: "+",
                #punctuation listed in unicode not completed implemented in serto
                0x0700: ".:.",
                0x0701: ".",
                0x0702: ".",
                0x0703: ":",
                0x0704: ":",
                0x0705: ":",
                0x0706: ":",
                0x0707: ":",
                0x0708: ":",
                0x0709: ":",
                0x070D: ".X.",
        }


        # used for unicode encoded fonts (xelatex) which
        # chose initial/middle/final forms automatically
        self.code2Unicode = {
            "'": (0x710,),
            "b": (0x712,),
            "g": (0x713,),
            "G": (0x714,), # gamal garshuni
            "d": (0x715,),
            "D": (0x716,), # dotless dalath (ambiguous with dotles rish)
            "h": (0x717,),
            "w": (0x718,),
            "z": (0x719,),
            ".h": (0x71a,),
            ".t": (0x71b,),
            ".T": (0x71c,), # teth garshuni
            "y": (0x71d,),
            "Y": (0x71e,),
            "k": (0x71f,),
            "l": (0x720,),
            "m": (0x721,),
            "n": (0x722,),
            "s": (0x723,),
            "S": (0x724,), # semkath final
            "`": (0x725,),
            "p": (0x726,),
            ".s": (0x728,),
            "q": (0x729,),
            "r": (0x72a,),
            "R": (0x716,), # dotless rish (ambiguous with dotles dalath)
            #"R": (0x72a,),
            "^s": (0x72b,),
            "t": (0x72c,),

            # greek vowel symbols above
            "a": (0x730,),
            "e": (0x736,),
            "i": (0x73a,),
            "=a": (0x733,),
            "o": (0x718, 0x741), 
            "u": (0x73d,),            

            # greek vowel symbols below
            "A": (0x731,),
            "E": (0x737,),
            "I": (0x73b,),
            "=A": (0x734,),
            "U": (0x73e,),
            "P": (0x735,),

            # eastern vowels
            ":a": (0x732,),
            ":e": (0x739,),
            ":i": (0x73c,),
            ":iy": (0x71d, 0x73c),
            ":=a": (0x735,),
            ":o": (0x741,),
            ":ow": (0x718, 0x741),
            ":u": (0x73c,),
            ":uw": (0x718, 0x73c),

            # tatweel
            "-": (0x640,),

            # linea occultans (not in the font)
            "=": [],

            # punctuation
            ".": (0x701, ),
            ":": (0x703, ),
            ".X.": (0x70d, ),
            ".:.": (0x700, ),
            }
        

        #print "zzzzzz",UnicodeTable

    def readfont(self, filename, tabelle, transtabelle):
        dirname = os.environ.get("SERTOFONTDIR")        
        if not dirname:
            # no environment variable
            fp = open("%s" % (filename), "r")
        else:
            fp = open("%s/%s" % (dirname, os.path.basename(filename)), "r") 
        lines = fp.readlines()
        fp.close()


        #self.tabelle = {} # "_d": (isol, init, med, fin, link)
        #self.tabelle = {} # "_d": Letter-Object
        #self.transtabelle = {} # "_d": \d{d}
        self.fontname = ""
        status = "syriac"
        self.errct = 0
        for z in lines:
            if len(z) < 2:
                continue
            if z[0] == "#":
                if z[:6] == "#FONT:":
                    a = z.split()
                    self.fontname = a[1].strip()
                    #self.textframe.thetext.config(font=self.fontname)
                    #self.testlabel.config(font=self.fontname)
                elif z[:7] == "#TRANS:":
                    status = "transliterate"
                continue

            felder = z.split()
            if status == "syriac":
                if len(felder) < 7:
                    self.errct = self.errct + 1
                    print("ERROR:", z, file=sys.stderr)
                else:
                    #print ("rrr",felder)
                    #self.tabelle[felder[0]] = (int(felder[2]), 
                        #                       int(felder[3]), 
                        #                       int(felder[4]),
                        #                       int(felder[5]),
                        #                       int(felder[6]))
                    tabelle[felder[0]] = Letter(felder[0], 
                                                felder[1], 
                                                felder[2], 
                                                felder[3], 
                                                felder[4],
                                                felder[5],
                                                felder[6])
            else:
                if len(felder) < 2:
                    #print "WARNING:", z
                    transtabelle[felder[0]] = felder[0]
                else:
                    transtabelle[felder[0]] = felder[1]


    def tokenize(self, str, xlen, style="serto"):
        ix = 0
        self.tokens = []
        self.digits = []
        number = 0 # 

        while(ix < xlen): #for ix in range(xlen):
            #print "IX", ix, str
            if str[ix] == "\\":
                command = "\\"
                ix = ix + 1
                while(ix < xlen):
                    if not str[ix] in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
                        break
                    else:
                        command = command + str[ix]
                        ix = ix + 1
                self.tokens.append(command)
            elif str[ix] in "{}":
                self.tokens.append(str[ix])
                ix = ix + 1
            else:
                for ll in range(5, 0, -1):
                    if str[ix:ix+ll] in self.tabelle[style]:
                        if ll == 1 and str[ix:ix+ll] in "aeiou" \
                           and (len(self.tokens) == 0 \
                                or self.tokens[-1] == "~"):
                            #self.tokens.append("'" + str[ix:ix+ll])
                            self.tokens.extend(["'", str[ix:ix+ll]])
                            #pass
                        else:
                            if len(self.tokens) \
                               and str[ix:ix+ll] == self.tokens[-1] \
                               and self.tabelle[style][str[ix:ix+ll]].link != 3 \
                               and str[ix:ix+ll] not in ["~", "0", "1", 
                                                         "2", "3", "4", 
                                                         "5", "6", "7", 
                                                         "8", "9", "--"]:
                                # insert shadda
                                self.tokens.append("Q")
                            else:
                                self.tokens.append(str[ix:ix+ll])
                        ix = ix + ll
                        break # for-loop
                else:
                    ix = ix + 1
        
        #print "TOKENS",self.tokens

    def transtokenize(self, str, xlen, style="serto"):
        ix = 0
        self.tokens = []
        self.digits = []
        number = 0 # 
        while(ix < xlen): #for ix in range(xlen):
            #print "IX", ix,
            for ll in range(5, 0, -1):
                if str[ix:ix+ll] in self.transtabelle[style]:
                    if ll == 1 and str[ix:ix+ll] in "aeiou" \
                       and (len(self.tokens) == 0 \
                            or self.tokens[-1] == "~"):
                        self.tokens.append("'" + str[ix:ix+ll])
                        #self.tokens.extend(["'", str[ix:ix+ll]])
                    else:
                        #if len(self.tokens) \
                        #   and str[ix:ix+ll] == self.tokens[-1] \
                        #   and self.tabelle[str[ix:ix+ll]][4] != 3 \
                        #   and str[ix:ix+ll] not in ["~", "0", "1", "2", "3", "4", 
                        #                             "5", "6", "7", "8", "9"]:
                        #    """insert shadda"""
                        #    self.tokens.append("Q")
                        #else:
                            self.tokens.append(str[ix:ix+ll])
                    ix = ix + ll
                    break # for-loop
            else:
                ix = ix + 1
        
        #print "TRANSTOKENS",self.tokens
 


    def transliterate(self, syrisch, style="serto"):
        if True: #self.usingUTF8
            #line = unicode(syrisch, "utf8")
            line = syrisch
            newline = ""
            for c in line:
                #print "eee %x" % ord(c), self.UnicodeTable.has_key(ord(c)), 
                #print c.encode("utf8")
                sertocode = self.UnicodeTable.get(ord(c), c) 
                newline += sertocode
                #print "[%s]"  % sertocode, newline
            syrisch = newline

        syrisch = syrisch.replace(" ", "~")
        self.transtokenize(syrisch, len(syrisch), style)
        #self.err("TOKEN %s" %self.tokens)
        ret = []
        oldtok = ""
        for tok in self.tokens:
            if tok == "~": # blank
                ret.append(" ")
            #elif tok == "Q": # shadda
                #ret.append(ret[-1])
            #elif tok == "+": # soft sign under begadkefat
                #if len(ret):
                #    ret[-1] = self.spec.get(oldtok+tok, oldtok+tok)
            else:
                ret.append(self.transtabelle[style].get(tok, tok))
            #oldtok = tok
        
        return "".join(ret)

    def syriacise(self, style="serto"):
        # replace tokens by serto letters, take into account context
        ix = 0
        out = []
        digits = []
        self.maxlen = len(self.tokens)
        #sys.stderr.write("%s\n" % self.tokens)
        number = 0
        for i in range(self.maxlen):
            if self.tokens[i][0] in "\\{}":
                out.append(self.tokens[i])

            elif self.tabelle[style][self.tokens[i]].medial == -1: 
                #print "skipping letter"
                continue
            else:
                form = self.context(i, style=style)

                if self.tokens[i] in ["0", "1", "2", "3", "4", 
                                      "5", "6", "7", "8", "9"]:
                    number = 1
                    digits.append(chr(self.tabelle[style][self.tokens[i]].getcontext(form)))
                else:
                    if number == 1:
                        number = 0
                        digits.reverse()
                        out.extend(digits)
                        digits = []
                    #out.append(chr(self.tabelle[self.tokens[i]][form]))
                    #out.append("%c" %(self.tabelle[self.tokens[i]].getcontext(form)))
                    for c in self.tabelle[style][self.tokens[i]].getChar(form):
                        #sys.stderr.write("LETTER: %s\n" % c)
                        out.append(c)
                #print self.tokens[i], form, self.tabelle[self.tokens[i]][form]

        if number:
            number = 0
            digits.reverse()
            out.extend(digits)


        #for i in out: print "%d" % ord(i),
        #print
        #if not self.elatex:
        #    out.reverse()

        # This kills empty letters, caused by -1 in .font-file
        return "".join(out) 
        

    def context(self, ix, style="serto"):
        """returns 0 if letter is isolated
        1 if letter is initial
        2 if letter is medial
        3 if letter is final"""

        if self.before(ix, style) and self.next(ix, style):
            return 2
        elif self.before(ix, style) and not self.next(ix, style):
            return 3
        elif not self.before(ix, style) and self.next(ix, style):
            return 1
        else:
            return 0


    def next(self, ix, style="serto"):
        """returns 1 if next token is a letter"""
        for i in range(ix+1, self.maxlen):
            if self.tokens[i][0] in "\\{}":
                return 0
            elif self.tabelle[style][self.tokens[i]].link in [2,3]:
                continue
            elif self.tokens[i] not in ["~", "!", ",", ".", ";", "?"] :
                return 1
            else:
                return 0
        return 0

    def before(self, ix, style="serto"):
        """returns 1 if preceding token is a letter"""
        for i in range(ix-1, -1, -1):
            if self.tokens[i][0] in "\\{}":
                return 0
            elif self.tabelle[style][self.tokens[i]].link == 2:
                continue
            elif  self.tokens[i] != "~":
                if self.tabelle[style][self.tokens[i]].link == 0:
                    return 0
                else:
                    return 1
            else:
                return 0
        return 0





    def convert(self, transcript, style="serto"):
        # interface function
        # dummy blank
        if style == "estra":
            XXXX
        else: #if True: #self.usingUTF8:
            line = transcript # unicode(transcript, "utf8")
            newline = ""
            for c in line:
                #sys.stderr.write( "eee %d %s\n" % (ord(c), self.UnicodeTable.has_key(ord(c))))
                #sys.stderr.write( c.encode("utf8") + "\n")
                sertocode = self.UnicodeTable.get(ord(c), c) 
                newline += sertocode
                #sys.stderr.write( "[%s]\n"  % sertocode)
            transcript = newline #.encode("utf8")
                
        transcript = transcript.replace(" ", "~")
        self.tokenize(transcript, len(transcript), style)
        return self.syriacise(style)


    def texify(self, word, style="serto"):
        if style== "estra":
            return self.texifyUnicodefont(word)
        
        res = []
        for ll in serto.convert(word, style):
            # ll: position of current syriac character in font table
            #sys.stdout.write("LETTER: 0x%x\n" % (ord(ll)))
            #sys.stderr.write("LETTER: %s\n" % ord(ll))

            if ord(ll) < 16:
                #print "WWWWWWWWW", len(res), res
                if len(res):
                    res[-1] = "\\uppersyriac{%d}{%s}" % (ord(ll), res[-1])
                else:
                    res.append("\\uppersyriac{%d}{A}" % (ord(ll))) # A: Olaf
            elif ord(ll) < 32:
                if len(res):
                    res[-1] = "\\lowersyriac{%d}{%s}" % (ord(ll), res[-1])
                else:
                    res.append("\\lowersyriac{%d}{A}" % (ord(ll)))
            elif ord(ll) < 127 and ord(ll) not in [34,35,36,37,38,95]: 
                res.append(ll)
            else:
                # special (active) TeX-characters, charactes > 127
                res.append("\\char%d{}" % ord(ll))
        if not self.elatex:
            res.reverse()
        return "".join(res)

    def inlineserto(self, matchobject):
        return "{\\serto\\beginR %s\\endR}" % self.texify(matchobject.group(2))

    def inlinechaldean(self, matchobject):
        return "{\\assyr\\beginR %s\\endR}" \
               % self.texify(matchobject.group(2), "chaldean")

    def texifyUnicodefont(self, line):
        line += "  "
        out = ""
        i = 0
        while i < len(line)-2:
            if line[i:i+3] in self.code2Unicode:
                codes = self.code2Unicode[line[i:i+3]]
                #out += "^^^%x" % self.code2Unicode[line[i:i+3]]
                i += 3
            elif line[i:i+2] in self.code2Unicode:
                codes = self.code2Unicode[line[i:i+2]]
                #out += "^^^%x" % self.code2Unicode[line[i:i+2]]
                i += 2
            elif line[i:i+1] in self.code2Unicode:
                codes = self.code2Unicode[line[i:i+1]]
                #out += "^^^%x" % self.code2Unicode[line[i:i+1]]
                i += 1
            else:
                codes = None
                if line[i] != "\n":
                    out += line[i]
                i += 1
            if codes:
                for x in codes:
                    out += "^^^%x" % x
        return out

    def inlineestra(self, matchobject):
        return "{\\beginR\\estra %s\\endR}" % self.texifyUnicodefont(matchobject.group(2))

#        line = matchobject.group(2) + "  "
#        out = ""
#        i = 0
#        while i < len(line)-2:
#            if line[i:i+3] in self.code2Unicode:
#                codes = self.code2Unicode[line[i:i+3]]
#                #out += "^^^%x" % self.code2Unicode[line[i:i+3]]
#                i += 3
#            elif line[i:i+2] in self.code2Unicode:
#                codes = self.code2Unicode[line[i:i+2]]
#                #out += "^^^%x" % self.code2Unicode[line[i:i+2]]
#                i += 2
#            elif line[i:i+1] in self.code2Unicode:
#                codes = self.code2Unicode[line[i:i+1]]
#                #out += "^^^%x" % self.code2Unicode[line[i:i+1]]
#                i += 1
#            else:
#                codes = None
#                out += line[i]
#                i += 1
#            if codes:
#                for x in codes:
#                    out += "^^^%x" % x
#                
#        
#        return "{\\beginR\\estra %s\\endR}" % out

    def inlinetrans(self, matchobject):
        return "\\emph{%s}" % self.transliterate(matchobject.group(2))

    def inlinesertotrans(self, matchobject):
        return "{\\serto\\beginR %s\\endR} \\emph{%s}" \
               % (self.texify(matchobject.group(2)),
                  self.transliterate(matchobject.group(2)))
    def inlinechaldeantrans(self, matchobject):
        return "{\\assyr\\beginR %s\\endR} \\emph{%s}" \
               % (self.texify(matchobject.group(2), "chaldean"),
                  self.transliterate(matchobject.group(2), "chaldean"))

    def inlineestratrans(self, matchobject):
        return "%s \\emph{%s}" \
               % (self.inlineestra(matchobject),
                  self.transliterate(matchobject.group(2)))

    def err(self, s):
        sys.stderr.write(s + "\n")

#-------------------------------------------------------
if __name__ == "__main__":
    sys.stderr.write("serto - LaTeX - preprocessor V %s\n(c) Johannes Heinecke\n" % version)

    if len(sys.argv) < 2:
        sys.stderr.write("usage:\n  serto.py [-o] inputfile\n")
        sys.stderr.write("    -o: for usage with an older version of LaTeX which cannot typeset right-to-left scripts elatex\n\n")
        sys.exit(1)

    else:
        sys.stderr.write("\n")
        import getopt

        elatex = 1
        optlist,comargs = getopt.getopt(sys.argv[1:], "")

        for (o,a) in optlist:
            if o == "-o":
                elatex = 0

        serto = Serto(elatex=elatex)
        fp = open(comargs[0])

        #mode = "latin"
        mode = ["latin"]
        z = fp.readline()
        while (z):
            #print "LINE", z,
            #if z.find("\usepackage[utf8]{inputenc}") > -1:
            #    serto.usingUTF8 = True
            #print 'QQQ',z, mode
            if z[:-1] == "<SERTO>":
                # must be on a single line (will be deleted)
                if not elatex:
                    sys.stderr.write("using <SERTO> without the -e option (and elatex) may not work!\n")
                #mode = "serto"
                mode.append("serto")
                print('{\\serto\\beginR %')

            elif z[:-1].strip() == "</SERTO>":
                del mode[-1]
                #print '\\endR}%'  # causes problems in last line
                print('}%')

            elif z[:-1] == "<ESTRANGELO>":
                # must be on a single line (will be deleted)
                mode.append("estra")
                print('{\\beginR\\estra %')

            elif z[:-1].strip() == "</ESTRANGELO>":
                del mode[-1]
                print('}%')



            elif z[:-1] == "<CHALDEAN>":
                # must be on a single line (will be deleted)
                if not elatex:
                    sys.stderr.write("using <CHALDEAN> without the -e option (and elatex) may not work!\n")
                #mode = "chaldean"
                mode.append("chaldean")
                print('{\\assyr\\beginR %')

            elif z[:-1].strip() == "</CHALDEAN>":
                #mode = "latin"
                del mode[-1]
                #print '\\endR}%'  # causes problems in last line
                print('}%')


            elif z[:-1] == "<TRANS>":
                #mode = "trans"
                mode.append("trans")
                print('{\\it %')

            elif z[:-1].strip() == "</TRANS>":
                #mode = "latin"
                del mode[-1]
                print('}%')



            else:
                #print "mmm", mode, z
                if mode[-1] == "latin":
                    #sys.stdout.write(serto.inlineS.sub(serto.inlineserto, z))
                    a = serto.inlineS.sub(serto.inlineserto, z)
                    b = serto.inlineT.sub(serto.inlinetrans, a)
                    c = serto.inlineST.sub(serto.inlinesertotrans, b)
                    d = serto.inlineC.sub(serto.inlinechaldean, c)
                    e = serto.inlineCT.sub(serto.inlinechaldeantrans, d)
                    f = serto.inlineE.sub(serto.inlineestra, e)
                    g = serto.inlineET.sub(serto.inlineestratrans, f)

                    sys.stdout.write(g)
                elif mode[-1] == "trans":
                    print(serto.transliterate(z))
                else:
                    if z[:-1] == "": print("\n\\beginR ", end="")
                    else:
                        print(serto.texify(z, mode[-1]))


            #print "rrrrr", mode
            z = fp.readline()


        fp.close()
        sys.exit(serto.errct)