OSDN Git Service

Copyright and License description for JANPA are included
[molby/Molby.git] / MolLib / Ruby_bind / ruby_bind.c
index 6df44fa..7658636 100644 (file)
@@ -76,9 +76,9 @@ static VALUE
        s_FractRSym, s_FractXSym, s_FractYSym, s_FractZSym,
        s_SigmaSym, s_SigmaXSym, s_SigmaYSym, s_SigmaZSym,
        s_VSym, s_FSym, s_OccupancySym, s_TempFactorSym,
-       s_AnisoSym, s_SymopSym, s_IntChargeSym, s_FixForceSym,
-       s_FixPosSym, s_ExclusionSym, s_MMExcludeSym, s_PeriodicExcludeSym,
-       s_HiddenSym, s_AnchorListSym, s_UFFTypeSym;
+       s_AnisoSym, s_AnisoEigvalSym, s_SymopSym, s_IntChargeSym,
+    s_FixForceSym, s_FixPosSym, s_ExclusionSym, s_MMExcludeSym,
+    s_PeriodicExcludeSym, s_HiddenSym, s_AnchorListSym, s_UFFTypeSym;
 
 /*  Symbols for parameter attributes  */
 static VALUE
@@ -120,7 +120,7 @@ Ruby_FileStringValuePtr(VALUE *valp)
 #if __WXMSW__
        char *p = strdup(StringValuePtr(*valp));
        translate_char(p, '/', '\\');
-       *valp = rb_str_new2(p);
+       *valp = Ruby_NewEncodedStringValue2(p);
        free(p);
        return StringValuePtr(*valp);
 #else
@@ -135,11 +135,11 @@ Ruby_NewFileStringValue(const char *fstr)
        VALUE retval;
        char *p = strdup(fstr);
        translate_char(p, '\\', '/');
-       retval = rb_enc_str_new(p, strlen(p), rb_default_external_encoding());
+       retval = Ruby_NewEncodedStringValue2(p);
        free(p);
        return retval;
 #else
-       return rb_str_new2(fstr);
+       return Ruby_NewEncodedStringValue2(fstr);
 #endif
 }
 
@@ -160,6 +160,12 @@ Ruby_NewEncodedStringValue(const char *str, int len)
 }
 
 VALUE
+Ruby_NewEncodedStringValue2(const char *str)
+{
+    return Ruby_NewEncodedStringValue(str, -1);
+}
+
+VALUE
 Ruby_ObjToStringObj(VALUE val)
 {
        switch (TYPE(val)) {
@@ -186,7 +192,7 @@ static VALUE
 s_Kernel_MessageBox(int argc, VALUE *argv, VALUE self)
 {
        char *str, *title, *s;
-       int buttons, icon;
+    int buttons, icon, retval;
        VALUE sval, tval, bval, ival;
        rb_scan_args(argc, argv, "22", &sval, &tval, &bval, &ival);
        str = StringValuePtr(sval);
@@ -213,8 +219,8 @@ s_Kernel_MessageBox(int argc, VALUE *argv, VALUE self)
                else
                        rb_raise(rb_eMolbyError, "the icon specification should be either :info, :warning or :error");
        } else icon = 1;
-       MyAppCallback_messageBox(str, title, buttons, icon);
-       return Qnil;
+       retval = MyAppCallback_messageBox(str, title, buttons, icon);
+    return (retval ? Qtrue : Qfalse);
 }
 
 /*
@@ -250,7 +256,7 @@ s_Kernel_Ask(int argc, VALUE *argv, VALUE self)
        } else buf[0] = 0;
        retval = MyAppCallback_getTextWithPrompt(StringValuePtr(prompt), buf, sizeof buf);
        if (retval)
-               return rb_str_new2(buf);
+               return Ruby_NewEncodedStringValue2(buf);
        else
                return Qnil;    
 }
@@ -340,8 +346,11 @@ static VALUE
 s_Kernel_ExportToClipboard(VALUE self, VALUE sval)
 {
 #if !defined(__CMDMAC__)
-       const char *s = StringValuePtr(sval);
+    const char *s;
        char *ns;
+    if (!gUseGUI)
+        return Qnil;
+    s = StringValuePtr(sval);
 #if __WXMSW__
        /*  Convert the end-of-line characters  */
        {       const char *p; int nc; char *np;
@@ -379,6 +388,84 @@ s_Kernel_ExportToClipboard(VALUE self, VALUE sval)
 
 /*
  *  call-seq:
+ *     hartree_to_kcal(val)
+ *
+ *  Convert hartree to kcal/mol
+ */
+static VALUE
+s_Kernel_HartreeToKcal(VALUE self, VALUE fval)
+{
+    double d = NUM2DBL(rb_Float(fval));
+    return rb_float_new(d * 627.5094740630557);
+}
+
+/*
+ *  call-seq:
+ *     kcal_to_hartree(val)
+ *
+ *  Convert kcal/mol to hartree
+ */
+static VALUE
+s_Kernel_KcalToHartree(VALUE self, VALUE fval)
+{
+    double d = NUM2DBL(rb_Float(fval));
+    return rb_float_new(d / 627.5094740630557);
+}
+
+/*
+ *  call-seq:
+ *     hartree_to_kj(val)
+ *
+ *  Convert hartree to kJ/mol
+ */
+static VALUE
+s_Kernel_HartreeToKJ(VALUE self, VALUE fval)
+{
+    double d = NUM2DBL(rb_Float(fval));
+    return rb_float_new(d * 2625.4996394798253);
+}
+
+/*
+ *  call-seq:
+ *     kj_to_hartree(val)
+ *
+ *  Convert kJ/mol to hartree
+ */
+static VALUE
+s_Kernel_KJToHartree(VALUE self, VALUE fval)
+{
+    double d = NUM2DBL(rb_Float(fval));
+    return rb_float_new(d / 2625.4996394798253);
+}
+
+/*
+ *  call-seq:
+ *     bohr_to_angstrom(val)
+ *
+ *  Convert bohr to angstrom
+ */
+static VALUE
+s_Kernel_BohrToAngstrom(VALUE self, VALUE fval)
+{
+    double d = NUM2DBL(rb_Float(fval));
+    return rb_float_new(d * 0.529177210903);
+}
+
+/*
+ *  call-seq:
+ *     angstrom_to_bohr(val)
+ *
+ *  Convert angstrom to bohr
+ */
+static VALUE
+s_Kernel_AngstromToBohr(VALUE self, VALUE fval)
+{
+    double d = NUM2DBL(rb_Float(fval));
+    return rb_float_new(d / 0.529177210903);
+}
+
+/*
+ *  call-seq:
  *     stdout.write(str)
  *
  *  Put the message in the main text view in black color.
@@ -431,7 +518,7 @@ static VALUE
 s_StandardInputGets(int argc, VALUE *argv, VALUE self)
 {
        VALUE pval, rval;
-       pval = rb_str_new2("Enter a line:");
+       pval = Ruby_NewEncodedStringValue2("Enter a line:");
        rval = s_Kernel_Ask(1, &pval, self);
        if (rval == Qnil)
                rb_interrupt();
@@ -519,9 +606,6 @@ s_SetInterruptFlag(VALUE self, VALUE val)
        oldval = s_interrupt_flag;
        if (val != Qundef) {
                s_interrupt_flag = val;
-               if (val == Qfalse) {
-                       s_HideProgressPanel(self);
-               }
        }
        return oldval;
 }
@@ -747,13 +831,13 @@ s_Kernel_RegisterMenu(int argc, VALUE *argv, VALUE self)
                sNonEmptySym = ID2SYM(rb_intern("non_empty"));
                sSelectionSym = ID2SYM(rb_intern("selection"));
                sMolProc = rb_eval_string("lambda { |m| m != nil }");
+        rb_define_variable("$is_a_molecule_proc", &sMolProc);
                sNonEmptyProc = rb_eval_string("lambda { |m| m.is_a?(Molecule) && m.natoms > 0 }");
+        rb_define_variable("$is_molecule_not_empty_proc", &sNonEmptyProc);
                sSelectionProc = rb_eval_string("lambda { |m| m.is_a?(Molecule) && m.selection.count > 0 }");
+        rb_define_variable("$has_molecule_selection_proc", &sSelectionProc);
                sTrueProc = rb_eval_string("lambda { |m| true }");
-               rb_global_variable(&sMolProc);
-               rb_global_variable(&sNonEmptyProc);
-               rb_global_variable(&sSelectionProc);
-               rb_global_variable(&sTrueProc);
+        rb_define_variable("$always_true_proc", &sTrueProc);
        }
        
        if (pval == Qnil) {
@@ -783,7 +867,7 @@ static VALUE
 s_Ruby_UpdateUI_handler(VALUE data)
 {
        void **p = (void **)data;
-       int index = (int)p[0];
+       int index = (intptr_t)p[0];
        Molecule *mol = (Molecule *)p[1];
        int *outChecked = (int *)p[2];
        char **outTitle = (char **)p[3];
@@ -914,6 +998,10 @@ s_Kernel_CallSubProcess_Callback(void *data)
  *
  *  Call subprocess. A progress dialog window is displayed, with a message
  *  "Running #{process_name}...".
+ *  cmd is either a single string of an array of string. If it is a single string, then
+ *  it will be given to wxExecute as a single argument. In this case, the string can be
+ *  split into arguments by whitespace. If this behavior is not intended, then use an array
+ *  containing a single string.
  *  A callback proc can be given, which is called periodically during execution. If the proc returns
  *  nil or false, then the execution will be interrupted.
  *  If stdout_file or stderr_file is a filename, then the message will be sent to the file; if the
@@ -925,8 +1013,10 @@ static VALUE
 s_Kernel_CallSubProcess(int argc, VALUE *argv, VALUE self)
 {
        VALUE cmd, procname, cproc, stdout_val, stderr_val;
+    VALUE save_interruptFlag;
        int n, exitstatus, pid;
        char *sout, *serr;
+    const char *pnamestr, **cmdargv;
        FILE *fpout, *fperr;
 
        rb_scan_args(argc, argv, "23", &cmd, &procname, &cproc, &stdout_val, &stderr_val);
@@ -969,9 +1059,28 @@ s_Kernel_CallSubProcess(int argc, VALUE *argv, VALUE self)
                                rb_raise(rb_eMolbyError, "Cannot open file for standard output (%s)", serr);
                }
        }
+    
+    save_interruptFlag = s_SetInterruptFlag(self, Qnil);
+    if (procname != Qnil)
+        pnamestr = StringValuePtr(procname);
+    else pnamestr = NULL;
+    if (rb_obj_is_kind_of(cmd, rb_cString)) {
+        cmdargv = calloc(sizeof(cmdargv[0]), 3);
+        cmdargv[0] = StringValuePtr(cmd);
+        cmdargv[1] = "";
+        cmdargv[2] = NULL;
+    } else {
+        cmd = rb_ary_to_ary(cmd);
+        cmdargv = calloc(sizeof(cmdargv[0]), RARRAY_LEN(cmd) + 1);
+        for (n = 0; n < RARRAY_LEN(cmd); n++) {
+            cmdargv[n] = StringValuePtr(RARRAY_PTR(cmd)[n]);
+        }
+        cmdargv[n] = NULL;
+    }
+       n = MyAppCallback_callSubProcess(cmdargv, pnamestr, (cproc == Qnil ? NULL : s_Kernel_CallSubProcess_Callback), (cproc == Qnil ? NULL : (void *)cproc), fpout, fperr, &exitstatus, &pid);
+    s_SetInterruptFlag(self, save_interruptFlag);
+    free(cmdargv);
 
-       n = MyAppCallback_callSubProcess(StringValuePtr(cmd), StringValuePtr(procname), (cproc == Qnil ? NULL : s_Kernel_CallSubProcess_Callback), (cproc == Qnil ? NULL : (void *)cproc), fpout, fperr, &exitstatus, &pid);
-       
        if (fpout != NULL && fpout != (FILE *)1)
                fclose(fpout);
        if (fperr != NULL && fperr != (FILE *)1)
@@ -994,7 +1103,11 @@ s_Kernel_Backquote(VALUE self, VALUE cmd)
        char *buf;
        int n, exitstatus, pid;
        VALUE val;
-       n = MyAppCallback_callSubProcess(StringValuePtr(cmd), NULL, DUMMY_CALLBACK, &buf, NULL, NULL, &exitstatus, &pid);
+    const char *cmdargv[3];
+    cmdargv[0] = StringValuePtr(cmd);
+    cmdargv[1] = "";
+    cmdargv[2] = NULL;
+       n = MyAppCallback_callSubProcess(cmdargv, NULL, DUMMY_CALLBACK, &buf, NULL, NULL, &exitstatus, &pid);
 /*     fprintf(stderr, "n = %d, exitstatus = %d, pid = %d\n", n, exitstatus, pid); */
        if (n >= 0 && buf != NULL) {
                val = Ruby_NewEncodedStringValue(buf, 0);
@@ -1253,10 +1366,10 @@ static VALUE s_ParameterRef_GetParType(VALUE self) {
        Int tp;
        s_UnionParFromValue(self, &tp, 0);
        if (tp == kElementParType)
-               return rb_str_new2("element");
+               return Ruby_NewEncodedStringValue2("element");
        tp -= kFirstParType;
        if (tp >= 0 && tp < sizeof(s_ParameterTypeNames) / sizeof(s_ParameterTypeNames[0]))
-               return rb_str_new2(s_ParameterTypeNames[tp]);
+               return Ruby_NewEncodedStringValue2(s_ParameterTypeNames[tp]);
        else rb_raise(rb_eMolbyError, "Internal error: parameter type tag is out of range (%d)", tp);
 }
 
@@ -1689,7 +1802,7 @@ static VALUE s_ParameterRef_GetName(VALUE self) {
                char name[5];
                strncpy(name, up->atom.name, 4);
                name[4] = 0;
-               return rb_str_new2(name);
+               return Ruby_NewEncodedStringValue2(name);
        } else rb_raise(rb_eMolbyError, "invalid member name");
 }
 
@@ -1724,7 +1837,7 @@ static VALUE s_ParameterRef_GetFullName(VALUE self) {
                char fullname[16];
                strncpy(fullname, up->atom.fullname, 15);
                fullname[15] = 0;
-               return rb_str_new2(fullname);
+               return Ruby_NewEncodedStringValue2(fullname);
        } else rb_raise(rb_eMolbyError, "invalid member fullname");
 }
 
@@ -1741,7 +1854,7 @@ static VALUE s_ParameterRef_GetComment(VALUE self) {
        com = up->bond.com;
        if (com == 0)
                return Qnil;
-       else return rb_str_new2(ParameterGetComment(com));
+       else return Ruby_NewEncodedStringValue2(ParameterGetComment(com));
 }
 
 /*
@@ -1760,7 +1873,7 @@ static VALUE s_ParameterRef_GetSource(VALUE self) {
                return Qfalse;  /* undefined */
        else if (src == 0)
                return Qnil;  /*  local  */
-       else return rb_str_new2(ParameterGetComment(src));
+       else return Ruby_NewEncodedStringValue2(ParameterGetComment(src));
 }
 
 static void
@@ -2518,7 +2631,7 @@ s_ParameterRef_ToString(VALUE self)
                        snprintf(buf, sizeof buf, "element %2.2s %3d %6.3f %6.3f %6.3f %6.3f %8.4f %s %6.3f", up->atom.name, up->atom.number, up->atom.radius, up->atom.red / 65535.0, up->atom.green / 65535.0, up->atom.blue / 65535.0, up->atom.weight, up->atom.fullname, up->atom.vdw_radius);
                        break;
        }
-       return rb_str_new2(buf);
+       return Ruby_NewEncodedStringValue2(buf);
 }
 
 /*
@@ -3404,10 +3517,10 @@ s_ParEnumerable_ParType(VALUE self) {
     Data_Get_Struct(self, ParEnumerable, pen);
        tp = pen->parType;
        if (tp == kElementParType)
-               return rb_str_new2("element");
+               return Ruby_NewEncodedStringValue2("element");
        tp -= kFirstParType;
        if (tp >= 0 && tp < sizeof(s_ParameterTypeNames) / sizeof(s_ParameterTypeNames[0]))
-               return rb_str_new2(s_ParameterTypeNames[tp]);
+               return Ruby_NewEncodedStringValue2(s_ParameterTypeNames[tp]);
        else rb_raise(rb_eMolbyError, "Internal error: parameter type tag is out of range (%d)", tp);
 }
 
@@ -3769,7 +3882,7 @@ static VALUE s_AtomRef_GetSegSeq(VALUE self) {
 
 static VALUE s_AtomRef_GetSegName(VALUE self) {
        char *p = s_AtomFromValue(self)->segName;
-       return rb_str_new(p, strlen_limit(p, 4));
+       return Ruby_NewEncodedStringValue(p, strlen_limit(p, 4));
 }
 
 static VALUE s_AtomRef_GetResSeq(VALUE self) {
@@ -3778,18 +3891,18 @@ static VALUE s_AtomRef_GetResSeq(VALUE self) {
 
 static VALUE s_AtomRef_GetResName(VALUE self) {
        char *p = s_AtomFromValue(self)->resName;
-       return rb_str_new(p, strlen_limit(p, 4));
+       return Ruby_NewEncodedStringValue(p, strlen_limit(p, 4));
 }
 
 static VALUE s_AtomRef_GetName(VALUE self) {
        char *p = s_AtomFromValue(self)->aname;
-       return rb_str_new(p, strlen_limit(p, 4));
+       return Ruby_NewEncodedStringValue(p, strlen_limit(p, 4));
 }
 
 static VALUE s_AtomRef_GetAtomType(VALUE self) {
        int type = s_AtomFromValue(self)->type;
        char *p = (type == 0 ? "" : AtomTypeDecodeToString(type, NULL));
-       return rb_str_new(p, strlen_limit(p, 6));
+       return Ruby_NewEncodedStringValue(p, strlen_limit(p, 6));
 }
 
 static VALUE s_AtomRef_GetCharge(VALUE self) {
@@ -3802,7 +3915,7 @@ static VALUE s_AtomRef_GetWeight(VALUE self) {
 
 static VALUE s_AtomRef_GetElement(VALUE self) {
        char *p = s_AtomFromValue(self)->element;
-       return rb_str_new(p, strlen_limit(p, 4));
+       return Ruby_NewEncodedStringValue(p, strlen_limit(p, 4));
 }
 
 static VALUE s_AtomRef_GetAtomicNumber(VALUE self) {
@@ -3915,6 +4028,18 @@ static VALUE s_AtomRef_GetAniso(VALUE self) {
        return retval;
 }
 
+static VALUE s_AtomRef_GetAnisoEigenValues(VALUE self) {
+    VALUE retval;
+    int i;
+    Atom *ap = s_AtomFromValue(self);
+    if (ap->aniso == NULL)
+        return Qnil;
+    retval = rb_ary_new();
+    for (i = 0; i < 3; i++)
+        rb_ary_push(retval, rb_float_new(ap->aniso->eigval[i]));
+    return retval;
+}
+
 static VALUE s_AtomRef_GetSymop(VALUE self) {
        VALUE retval;
        Atom *ap = s_AtomFromValue(self);
@@ -4003,7 +4128,7 @@ static VALUE s_AtomRef_GetAnchorList(VALUE self) {
 
 static VALUE s_AtomRef_GetUFFType(VALUE self) {
        char *p = s_AtomFromValue(self)->uff_type;
-       return rb_str_new(p, strlen_limit(p, 5));
+       return Ruby_NewEncodedStringValue(p, strlen_limit(p, 5));
 }
 
 static VALUE s_AtomRef_SetIndex(VALUE self, VALUE val) {
@@ -4354,6 +4479,11 @@ static VALUE s_AtomRef_SetAniso(VALUE self, VALUE val) {
        return val;
 }
 
+static VALUE s_AtomRef_SetAnisoEigenValues(VALUE self, VALUE val) {
+    rb_raise(rb_eMolbyError, "Eigenvalues of anisotropic factors are read-only.");
+    return val; /* Not reached */
+}
+
 static VALUE s_AtomRef_SetSymop(VALUE self, VALUE val) {
        Molecule *mol;
        Atom *ap;
@@ -4588,6 +4718,7 @@ static struct s_AtomAttrDef {
        {"occupancy",    &s_OccupancySym,    0, s_AtomRef_GetOccupancy,    s_AtomRef_SetOccupancy},
        {"temp_factor",  &s_TempFactorSym,   0, s_AtomRef_GetTempFactor,   s_AtomRef_SetTempFactor},
        {"aniso",        &s_AnisoSym,        0, s_AtomRef_GetAniso,        s_AtomRef_SetAniso},
+    {"aniso_eigenvalues", &s_AnisoEigvalSym, 0, s_AtomRef_GetAnisoEigenValues,        s_AtomRef_SetAnisoEigenValues},
        {"symop",        &s_SymopSym,        0, s_AtomRef_GetSymop,        s_AtomRef_SetSymop},
        {"int_charge",   &s_IntChargeSym,    0, s_AtomRef_GetIntCharge,    s_AtomRef_SetIntCharge},
        {"fix_force",    &s_FixForceSym,     0, s_AtomRef_GetFixForce,     s_AtomRef_SetFixForce},
@@ -4697,7 +4828,7 @@ s_MolEnumerable_Aref(VALUE self, VALUE arg1)
                        if (idx2 < 0 || idx2 >= mol->nresidues)
                                rb_raise(rb_eIndexError, "residue index out of range (%d; should be %d..%d)", idx1, -mol->nresidues, mol->nresidues - 1);
                        p = mol->residues[idx2];
-                       return rb_str_new(p, strlen_limit(p, 4));
+                       return Ruby_NewEncodedStringValue(p, strlen_limit(p, 4));
                }
        }
        return Qnil;
@@ -4904,10 +5035,13 @@ static IntGroup *
 s_Molecule_AtomGroupFromValue(VALUE self, VALUE val)
 {
        IntGroup *ig;
+    Molecule *mp1;
+    Data_Get_Struct(self, Molecule, mp1);
        val = rb_funcall(self, rb_intern("atom_group"), 1, val);
        if (!rb_obj_is_kind_of(val, rb_cIntGroup))
                rb_raise(rb_eMolbyError, "IntGroup instance is expected");
        Data_Get_Struct(val, IntGroup, ig);
+    IntGroupRemove(ig, mp1->natoms, ATOMS_MAX_NUMBER); /* Limit the group member to existing atoms */
        IntGroupRetain(ig);
        return ig;
 }
@@ -5262,7 +5396,7 @@ s_Molecule_Savedcd(VALUE self, VALUE fname)
 static VALUE
 s_Molecule_LoadSave(int argc, VALUE *argv, VALUE self, int loadFlag)
 {
-       VALUE rval;
+    VALUE rval, argv0;
        char *argstr, *methname, *p, *type = "";
        ID mid = 0;
        int i;
@@ -5272,7 +5406,8 @@ s_Molecule_LoadSave(int argc, VALUE *argv, VALUE self, int loadFlag)
        if (argc == 0)
                return Qnil;
 
-       if (argc == 0 || (argstr = StringValuePtr(argv[0])) == NULL)
+    argv0 = argv[0]; /* Keep as a local variable to avoid GC  */
+       if (argc == 0 || (argstr = StringValuePtr(argv0)) == NULL)
                rb_raise(rb_eMolbyError, "the first argument must be either filename or \":filetype\"");
        if (argstr[0] == ':') {
                /*  Call "loadXXX" (or "saveXXX") for type ":XXX"  */
@@ -5327,7 +5462,7 @@ s_Molecule_LoadSave(int argc, VALUE *argv, VALUE self, int loadFlag)
                }
        }
 failure:
-       rval = rb_str_to_str(argv[0]);
+       rval = rb_str_to_str(argv0);
        asprintf(&p, "Failed to %s file %s", (loadFlag ? "load" : "save"), type);
        s_Molecule_RaiseOnLoadSave(1, loadFlag, p, StringValuePtr(rval));
        return Qnil;  /*  Does not reach here  */
@@ -5338,7 +5473,7 @@ success:
                Molecule *mol;
        /*      Atom *ap; */
                Data_Get_Struct(self, Molecule, mol);
-               MoleculeSetPath(mol, StringValuePtr(argv[0]));
+               MoleculeSetPath(mol, StringValuePtr(argv0));
                
                /*  Check if all occupancy factors are zero; if that is the case, then all set to 1.0  */
        /*      for (i = 0, ap = mol->atoms; i < mol->natoms; i++, ap = ATOM_NEXT(ap)) {
@@ -5395,6 +5530,11 @@ s_Molecule_Open(int argc, VALUE *argv, VALUE self)
        const char *p;
        Molecule *mp;
        VALUE iflag;
+    
+    if (!gUseGUI) {
+        rb_raise(rb_eMolbyError, "Molecule.open is not usable in non-GUI mode. Use Molecule.new instead.");
+    }
+    
        rb_scan_args(argc, argv, "01", &fname);
        if (NIL_P(fname))
                p = NULL;
@@ -5438,7 +5578,7 @@ s_Molecule_ErrorMessage(VALUE klass)
 {
        if (gLoadSaveErrorMessage == NULL)
                return Qnil;
-       else return rb_str_new2(gLoadSaveErrorMessage);
+       else return Ruby_NewEncodedStringValue2(gLoadSaveErrorMessage);
 }
 
 /*
@@ -5499,7 +5639,7 @@ s_Molecule_Name(VALUE self)
        if (buf[0] == 0)
                return Qnil;
        else
-               return rb_str_new2(buf);
+               return Ruby_NewEncodedStringValue2(buf);
 }
 
 /*
@@ -5563,7 +5703,7 @@ s_Molecule_Dir(VALUE self)
                p = strrchr(buf, '/');
                if (p != NULL)
                        *p = 0;
-               return rb_str_new2(buf);
+               return Ruby_NewEncodedStringValue2(buf);
        }
 }
 
@@ -5585,7 +5725,7 @@ s_Molecule_Inspect(VALUE self)
        if (buf[0] == 0) {
                /*  No associated document  */
                snprintf(buf, sizeof buf, "#<Molecule:0x%lx>", self);
-               return rb_str_new2(buf);
+               return Ruby_NewEncodedStringValue2(buf);
        } else {
                /*  Check whether the document name is duplicate  */
                char buf2[256];
@@ -5604,7 +5744,7 @@ s_Molecule_Inspect(VALUE self)
                } else {
                        snprintf(buf2, sizeof buf2, "Molecule[\"%s\"]", buf);
                }
-               return rb_str_new2(buf2);
+               return Ruby_NewEncodedStringValue2(buf2);
        }
 }
 
@@ -6089,12 +6229,14 @@ s_Molecule_Remove(VALUE self, VALUE group)
        Int i;
        IntGroupIterator iter;
 
-    Data_Get_Struct(self, Molecule, mol1);
+    ig = s_Molecule_AtomGroupFromValue(self, group);
+/*    Data_Get_Struct(self, Molecule, mol1);
        group = rb_funcall(self, rb_intern("atom_group"), 1, group);
        if (!rb_obj_is_kind_of(group, rb_cIntGroup))
                rb_raise(rb_eMolbyError, "IntGroup instance is expected");
-       Data_Get_Struct(group, IntGroup, ig);
-
+       Data_Get_Struct(group, IntGroup, ig); */
+    Data_Get_Struct(self, Molecule, mol1);
+    
        /*  Remove the bonds between the two fragments  */
        /*  (This is necessary for undo to work correctly)  */
        IntGroupIteratorInit(ig, &iter);
@@ -8589,7 +8731,7 @@ s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
        VALUE gval, rval, wval;
        IntGroup *ig;
        IntGroupIterator iter;
-       int nn, errno, i, j, in, status;
+       int nn, errnum, i, j, in, status;
        Vector *ref;
        Double *weights, dval[3];
        Transform tr;
@@ -8599,7 +8741,7 @@ s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
        if (gval == Qnil)
                ig = IntGroupNewWithPoints(0, mol->natoms, -1);
        else
-               ig = IntGroupFromValue(gval);
+               ig = s_Molecule_AtomGroupFromValue(self, gval);
        if (ig == NULL || (nn = IntGroupGetCount(ig)) == 0) {
                IntGroupRelease(ig);
                rb_raise(rb_eMolbyError, "atom group is not given correctly");
@@ -8610,7 +8752,7 @@ s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
        if (rb_obj_is_kind_of(rval, rb_cNumeric)) {
                int fn = NUM2INT(rb_Integer(rval));
                if (fn < 0 || fn >= MoleculeGetNumberOfFrames(mol)) {
-                       errno = 1;
+                       errnum = 1;
                        status = fn;
                        goto err;
                }
@@ -8623,7 +8765,7 @@ s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
        } else if (rb_obj_is_kind_of(rval, rb_cLAMatrix)) {
                LAMatrix *m = LAMatrixFromValue(rval, NULL, 0, 0);
                if (m->row * m->column < nn * 3) {
-                       errno = 2;
+                       errnum = 2;
                        goto err;
                }
                for (i = 0; i < nn; i++) {
@@ -8635,24 +8777,24 @@ s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
                VALUE aval;
                rval = rb_protect(rb_ary_to_ary, rval, &status);
                if (status != 0) {
-                       errno = 3;
+                       errnum = 3;
                        goto err;
                }
                if (RARRAY_LEN(rval) < nn) {
-                       errno = 2;
+                       errnum = 2;
                        goto err;
                }
                if (rb_obj_is_kind_of((RARRAY_PTR(rval))[0], rb_cNumeric)) {
                        /*  Array of 3*nn numbers  */
                        if (RARRAY_LEN(rval) < nn * 3) {
-                               errno = 2;
+                               errnum = 2;
                                goto err;
                        }
                        for (i = 0; i < nn; i++) {
                                for (j = 0; j < 3; j++) {
                                        aval = rb_protect(rb_Float, (RARRAY_PTR(rval))[i * 3 + j], &status);
                                        if (status != 0) {
-                                               errno = 3;
+                                               errnum = 3;
                                                goto err;
                                        }
                                        dval[j] = NUM2DBL(aval);
@@ -8670,18 +8812,18 @@ s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
                                } else {
                                        aval = rb_protect(rb_ary_to_ary, aval, &status);
                                        if (status != 0) {
-                                               errno = 3;
+                                               errnum = 3;
                                                goto err;
                                        }
                                        if (RARRAY_LEN(aval) < 3) {
-                                               errno = 4;
+                                               errnum = 4;
                                                status = i;
                                                goto err;
                                        }
                                        for (j = 0; j < 3; j++) {
                                                VALUE aaval = rb_protect(rb_Float, (RARRAY_PTR(aval))[j], &status);
                                                if (status != 0) {
-                                                       errno = 3;
+                                                       errnum = 3;
                                                        goto err;
                                                }
                                                dval[j] = NUM2DBL(aaval);
@@ -8703,17 +8845,17 @@ s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
        } else {
                wval = rb_protect(rb_ary_to_ary, wval, &status);
                if (status != 0) {
-                       errno = 3;
+                       errnum = 3;
                        goto err;
                }
                if (RARRAY_LEN(wval) < nn) {
-                       errno = 5;
+                       errnum = 5;
                        goto err;
                }
                for (i = 0; i < nn; i++) {
                        VALUE wwval = rb_protect(rb_Float, (RARRAY_PTR(wval))[i], &status);
                        if (status != 0) {
-                               errno = 3;
+                               errnum = 3;
                                goto err;
                        }
                        weights[i] = NUM2DBL(wwval);
@@ -8721,27 +8863,27 @@ s_Molecule_FitCoordinates(int argc, VALUE *argv, VALUE self)
        }
        dval[0] = s_Molecule_FitCoordinates_Sub(mol, ig, ref, weights, tr);
        if (dval[0] < 0) {
-               errno = 6;
+               errnum = 6;
                goto err;
        }
-       errno = 0;
+       errnum = 0;
 err:
        IntGroupIteratorRelease(&iter);
        free(ref);
        free(weights);
-       if (errno == 0) {
+       if (errnum == 0) {
                return rb_ary_new3(2, ValueFromTransform(&tr), rb_float_new(dval[0]));
-       } else if (errno == 1) {
+       } else if (errnum == 1) {
                rb_raise(rb_eMolbyError, "frame index (%d) is out of range", status);
-       } else if (errno == 2) {
+       } else if (errnum == 2) {
                rb_raise(rb_eMolbyError, "insufficient number of reference coordinates");
-       } else if (errno == 3) {
+       } else if (errnum == 3) {
                rb_jump_tag(status);
-       } else if (errno == 4) {
+       } else if (errnum == 4) {
                rb_raise(rb_eMolbyError, "less than 3 elements for index %d of reference coordinates", status);
-       } else if (errno == 5) {
+       } else if (errnum == 5) {
                rb_raise(rb_eMolbyError, "insufficient number of weight values");
-       } else if (errno == 6) {
+       } else if (errnum == 6) {
                rb_raise(rb_eMolbyError, "matrix calculation failed during coordinate fitting");
        }
        return Qnil;  /*  Not reached  */
@@ -10549,22 +10691,56 @@ s_Molecule_ClearBasisSet(VALUE self)
 
 /*
  *  call-seq:
- *     add_gaussian_orbital_shell(atom_index, sym, no_of_primitives)
+ *     add_gaussian_orbital_shell(atom_index, sym, no_of_primitives[, additional_exponent])
  *
  *  To be used internally. Add a gaussian orbital shell with the atom index, symmetry code,
- *  and the number of primitives. Symmetry code: 0, S-type; 1, P-type; -1, SP-type; 2, D-type;
- *  -2, D5-type.
+ *  and the number of primitives.
+ *  Additional exponent is for JANPA only; implements an additinal r^N component that
+ *  appears in cartesian->spherical conversion.
+ *  Symmetry code: 0, S-type; 1, P-type; -1, SP-type; 2, D-type; -2, D5-type;
+ *                 3, F-type; -3, F7-type; 4, G-type; -4, G9-type.
+ *  Or: "s", S-type; "p", P-type; "sp", SP-type; "d", D-type; "d5", D5-type;
+ *      "f", F-type; "f7", F7-type; "g", G-type; "g9", G9-type
  */
 static VALUE
-s_Molecule_AddGaussianOrbitalShell(VALUE self, VALUE aval, VALUE symval, VALUE npval)
+s_Molecule_AddGaussianOrbitalShell(int argc, VALUE *argv, VALUE self)
 {
        Molecule *mol;
-       int sym, nprims, a_idx, n;
-    Data_Get_Struct(self, Molecule, mol);
+    int sym, nprims, a_idx, n, add_exp;
+    VALUE aval, symval, npval, addval;
+    Data_Get_Struct(self, Molecule, mol);
+    rb_scan_args(argc, argv, "31", &aval, &symval, &npval, &addval);
+    if (rb_obj_is_kind_of(symval, rb_cString)) {
+        const char *p = StringValuePtr(symval);
+        if (strcasecmp(p, "s") == 0)
+            sym = 0;
+        else if (strcasecmp(p, "p") == 0)
+            sym = 1;
+        else if (strcasecmp(p, "sp") == 0)
+            sym = -1;
+        else if (strcasecmp(p, "d") == 0)
+            sym = 2;
+        else if (strcasecmp(p, "d5") == 0)
+            sym = -2;
+        else if (strcasecmp(p, "f") == 0)
+            sym = 3;
+        else if (strcasecmp(p, "f7") == 0)
+            sym = -3;
+        else if (strcasecmp(p, "g") == 0)
+            sym = 4;
+        else if (strcasecmp(p, "g9") == 0)
+            sym = -4;
+        else
+            rb_raise(rb_eArgError, "Unknown orbital type '%s'", p);
+    } else {
+        sym = NUM2INT(rb_Integer(symval));
+    }
        a_idx = NUM2INT(rb_Integer(aval));
-       sym = NUM2INT(rb_Integer(symval));
        nprims = NUM2INT(rb_Integer(npval));
-       n = MoleculeAddGaussianOrbitalShell(mol, a_idx, sym, nprims);
+    if (addval != Qnil)
+        add_exp = NUM2INT(rb_Integer(addval));
+    else add_exp = 0;
+       n = MoleculeAddGaussianOrbitalShell(mol, a_idx, sym, nprims, add_exp);
        if (n == -1)
                rb_raise(rb_eMolbyError, "Molecule is emptry");
        else if (n == -2)
@@ -10698,7 +10874,7 @@ s_Molecule_GetGaussianComponentInfo(VALUE self, VALUE cval)
        n = MoleculeGetGaussianComponentInfo(mol, c, &atom_idx, label, &shell_idx);
        if (n != 0)
                rb_raise(rb_eMolbyError, "Cannot get the shell info for component index (%d)", c);
-       return rb_ary_new3(3, INT2NUM(atom_idx), INT2NUM(shell_idx), rb_str_new2(label));
+       return rb_ary_new3(3, INT2NUM(atom_idx), INT2NUM(shell_idx), Ruby_NewEncodedStringValue2(label));
 }
 
 /*
@@ -10906,9 +11082,9 @@ s_Molecule_GetMOInfo(VALUE self, VALUE kval)
                return Qnil;
        if (kval == sTypeSym) {
                switch (mol->bset->rflag) {
-                       case 0: return rb_str_new2("UHF");
-                       case 1: return rb_str_new2("RHF");
-                       case 2: return rb_str_new2("ROHF");
+                       case 0: return Ruby_NewEncodedStringValue2("UHF");
+                       case 1: return Ruby_NewEncodedStringValue2("RHF");
+                       case 2: return Ruby_NewEncodedStringValue2("ROHF");
                        default: return rb_str_to_str(INT2NUM(mol->bset->rflag));
                }
        } else if (kval == sAlphaSym) {
@@ -10958,7 +11134,7 @@ s_Molecule_SearchEquivalentAtoms(int argc, VALUE *argv, VALUE self)
                return Qnil;
        rb_scan_args(argc, argv, "01", &val);
        if (val != Qnil)
-               ig = IntGroupFromValue(val);
+               ig = s_Molecule_AtomGroupFromValue(self, val);
        else ig = NULL;
        result = MoleculeSearchEquivalentAtoms(mol, ig);
        if (result == NULL)
@@ -11005,7 +11181,12 @@ s_Molecule_CreatePiAnchor(int argc, VALUE *argv, VALUE self)
        gval = *argv++;
        argc -= 2;
     Data_Get_Struct(self, Molecule, mol);
-       ig = IntGroupFromValue(gval);
+    if (gval == Qnil)
+        ig = NULL;
+    else
+        ig = s_Molecule_AtomGroupFromValue(self, gval);
+    if (ig == NULL || IntGroupGetCount(ig) == 0)
+    rb_raise(rb_eMolbyError, "atom group is not given correctly");
        memset(&a, 0, sizeof(a));
        memset(&an, 0, sizeof(an));
        strncpy(a.aname, StringValuePtr(nval), 4);
@@ -11223,7 +11404,7 @@ s_Molecule_PropertyNames(VALUE self)
     Data_Get_Struct(self, Molecule, mol);
        rval = rb_ary_new();
        for (i = mol->nmolprops - 1; i >= 0; i--) {
-               nval = rb_str_new2(mol->molprops[i].propname);
+               nval = Ruby_NewEncodedStringValue2(mol->molprops[i].propname);
                rb_ary_store(rval, i, nval);
        }
        return rval;
@@ -11287,7 +11468,7 @@ s_Molecule_MoleculeAtIndex(int argc, VALUE *argv, VALUE klass)
                for (idx = 0; (mol = MoleculeCallback_moleculeAtIndex(idx)) != NULL; idx++) {
                        VALUE name;
                        MoleculeCallback_displayName(mol, buf, sizeof buf);
-                       name = rb_str_new2(buf);
+                       name = Ruby_NewEncodedStringValue2(buf);
                        if (rb_reg_match(val, name) != Qnil && --k == 0)
                                break;
                }       
@@ -11382,6 +11563,10 @@ s_Molecule_CallSubProcessAsync_TimerCallback(Molecule *mol, int tcount)
  *     call_subprocess_async(cmd [, end_callback [, timer_callback [, standard_output_file [, error_output_file]]]])
  *
  *  Call subprocess asynchronically.
+ *  cmd is either a single string of an array of string. If it is a single string, then
+ *  it will be given to wxExecute as a single argument. In this case, the string can be
+ *  split into arguments by whitespace. If this behavior is not intended, then use an array
+ *  containing a single string.
  *  If end_callback is given, it will be called (with two arguments self and termination status)
  *  when the subprocess terminated.
  *  If timer_callback is given, it will be called (also with two arguments, self and timer count).
@@ -11398,6 +11583,7 @@ s_Molecule_CallSubProcessAsync(int argc, VALUE *argv, VALUE self)
        VALUE cmd, end_proc, timer_proc, stdout_val, stderr_val;
        Molecule *mol;
        char *sout, *serr;
+    const char **cmdargv;
        int n;
        FILE *fpout, *fperr;
        rb_scan_args(argc, argv, "14", &cmd, &end_proc, &timer_proc, &stdout_val, &stderr_val);
@@ -11445,7 +11631,21 @@ s_Molecule_CallSubProcessAsync(int argc, VALUE *argv, VALUE self)
        /*  Register procs as instance variables  */
        rb_ivar_set(self, rb_intern("end_proc"), end_proc);
        rb_ivar_set(self, rb_intern("timer_proc"), timer_proc);
-       n = MoleculeCallback_callSubProcessAsync(mol, StringValuePtr(cmd), s_Molecule_CallSubProcessAsync_EndCallback, (timer_proc == Qnil ? NULL : s_Molecule_CallSubProcessAsync_TimerCallback), fpout, fperr);
+    
+    if (rb_obj_is_kind_of(cmd, rb_cString)) {
+        cmdargv = calloc(sizeof(cmdargv[0]), 3);
+        cmdargv[0] = StringValuePtr(cmd);
+        cmdargv[1] = "";
+        cmdargv[2] = NULL;
+    } else {
+        cmd = rb_ary_to_ary(cmd);
+        cmdargv = calloc(sizeof(cmdargv[0]), RARRAY_LEN(cmd) + 1);
+        for (n = 0; n < RARRAY_LEN(cmd); n++) {
+            cmdargv[n] = StringValuePtr(RARRAY_PTR(cmd)[n]);
+        }
+        cmdargv[n] = NULL;
+    }
+       n = MoleculeCallback_callSubProcessAsync(mol, cmdargv, s_Molecule_CallSubProcessAsync_EndCallback, (timer_proc == Qnil ? NULL : s_Molecule_CallSubProcessAsync_TimerCallback), fpout, fperr);
        if (fpout != NULL && fpout != (FILE *)1)
                fclose(fpout);
        if (fperr != NULL && fperr != (FILE *)1)
@@ -11717,7 +11917,7 @@ Init_Molby(void)
        rb_define_method(rb_cMolecule, "nelpots", s_Molecule_NElpots, 0);
        rb_define_method(rb_cMolecule, "elpot", s_Molecule_Elpot, 1);
        rb_define_method(rb_cMolecule, "clear_basis_set", s_Molecule_ClearBasisSet, 0);
-       rb_define_method(rb_cMolecule, "add_gaussian_orbital_shell", s_Molecule_AddGaussianOrbitalShell, 3);
+       rb_define_method(rb_cMolecule, "add_gaussian_orbital_shell", s_Molecule_AddGaussianOrbitalShell, -1);
        rb_define_method(rb_cMolecule, "add_gaussian_primitive_coefficients", s_Molecule_AddGaussianPrimitiveCoefficients, 3);
        rb_define_method(rb_cMolecule, "get_gaussian_shell_info", s_Molecule_GetGaussianShellInfo, 1);
        rb_define_method(rb_cMolecule, "get_gaussian_primitive_coefficients", s_Molecule_GetGaussianPrimitiveCoefficients, 1);
@@ -11768,7 +11968,7 @@ Init_Molby(void)
        rb_define_alias(rb_cAtomRef, "set_attr", "[]=");
        rb_define_method(rb_cAtomRef, "[]", s_AtomRef_GetAttr, 1);
        rb_define_alias(rb_cAtomRef, "get_attr", "[]");
-       s_SetAtomAttrString = rb_str_new2("set_atom_attr");
+       s_SetAtomAttrString = Ruby_NewEncodedStringValue2("set_atom_attr");
        rb_global_variable(&s_SetAtomAttrString);
        rb_define_method(rb_cAtomRef, "molecule", s_AtomRef_GetMolecule, 0);
        rb_define_method(rb_cAtomRef, "==", s_AtomRef_Equal, 1);
@@ -11893,6 +12093,12 @@ Init_Molby(void)
        rb_define_method(rb_mKernel, "play_sound", s_Kernel_PlaySound, -1);
        rb_define_method(rb_mKernel, "stop_sound", s_Kernel_StopSound, 0);
        rb_define_method(rb_mKernel, "export_to_clipboard", s_Kernel_ExportToClipboard, 1);
+    rb_define_method(rb_mKernel, "hartree_to_kcal", s_Kernel_HartreeToKcal, 1);
+    rb_define_method(rb_mKernel, "hartree_to_kj", s_Kernel_HartreeToKJ, 1);
+    rb_define_method(rb_mKernel, "kcal_to_hartree", s_Kernel_KcalToHartree, 1);
+    rb_define_method(rb_mKernel, "kj_to_hartree", s_Kernel_KJToHartree, 1);
+    rb_define_method(rb_mKernel, "bohr_to_angstrom", s_Kernel_BohrToAngstrom, 1);
+    rb_define_method(rb_mKernel, "angstrom_to_bohr", s_Kernel_AngstromToBohr, 1);
 
        /*  class IO  */
        rb_define_method(rb_cIO, "gets_any_eol", s_IO_gets_any_eol, 0);
@@ -11975,12 +12181,12 @@ s_evalRubyScriptOnMoleculeSub(VALUE val)
 #else
                asprintf(&scr, "#coding:utf-8\n%s", (char *)ptr[0]);
 #endif
-               sval = rb_str_new2(scr);
+               sval = Ruby_NewEncodedStringValue2(scr);
                free(scr);
-               fnval = rb_str_new2("(eval)");
+               fnval = Ruby_NewEncodedStringValue2("(eval)");
                lnval = INT2FIX(0);
        } else {
-               sval = rb_str_new2((char *)ptr[0]);
+               sval = Ruby_NewEncodedStringValue2((char *)ptr[0]);
                fnval = Ruby_NewFileStringValue((char *)ptr[2]);
                lnval = INT2FIX(1);
        }
@@ -12034,6 +12240,26 @@ Molby_evalRubyScriptOnMolecule(const char *script, Molecule *mol, const char *fn
        return retval;
 }
 
+/*  For debug  */
+char *
+Ruby_inspectValue(RubyValue value)
+{
+    int status;
+    static char buf[256];
+    VALUE val = (VALUE)value;
+    gMolbyRunLevel++;
+    val = rb_protect(rb_inspect, val, &status);
+    gMolbyRunLevel--;
+    if (status == 0) {
+        char *str = StringValuePtr(val);
+        strncpy(buf, str, sizeof(buf) - 1);
+        buf[sizeof(buf) - 1] = 0;
+    } else {
+        snprintf(buf, sizeof(buf), "Error status = %d", status);
+    }
+    return buf;
+}
+
 int
 Ruby_showValue(RubyValue value, char **outValueString)
 {
@@ -12065,31 +12291,68 @@ void
 Ruby_showError(int status)
 {
        static const int tag_raise = 6;
+    char *main_message = "Molby script error";
        char *msg = NULL, *msg2;
        VALUE val, backtrace;
        int interrupted = 0;
+    int exit_status = -1;
        if (status == tag_raise) {
                VALUE errinfo = rb_errinfo();
                VALUE eclass = CLASS_OF(errinfo);
                if (eclass == rb_eInterrupt) {
-                       msg = "Interrupt";
+            main_message = "Molby script interrupted";
+            msg = "Interrupt";
                        interrupted = 1;
-               }
+        } else if (eclass == rb_eSystemExit) {
+            main_message = "Molby script exit";
+            interrupted = 2;
+            val = rb_eval_string_protect("$!.status", &status);
+            if (status == 0) {
+                exit_status = NUM2INT(rb_Integer(val));
+                asprintf(&msg, "Molby script exit with status %d", exit_status);
+            } else {
+                asprintf(&msg, "Molby script exit with unknown status");
+            }
+        }
        }
        gMolbyRunLevel++;
-       backtrace = rb_eval_string_protect("$backtrace = $!.backtrace.join(\"\\n\")", &status);
-       if (msg == NULL) {
-               val = rb_eval_string_protect("$!.to_s", &status);
-               if (status == 0)
-                       msg = RSTRING_PTR(val);
-               else msg = "(message not available)";
-       }
-       asprintf(&msg2, "%s\n%s", msg, RSTRING_PTR(backtrace));
-       MyAppCallback_messageBox(msg2, (interrupted == 0 ? "Molby script error" : "Molby script interrupted"), 0, 3);
+    if (exit_status != 0) {
+        backtrace = rb_eval_string_protect("$backtrace = $!.backtrace.join(\"\\n\")", &status);
+        if (msg == NULL) {
+            val = rb_eval_string_protect("$!.to_s", &status);
+            if (status == 0)
+                msg = RSTRING_PTR(val);
+            else
+                msg = "(message not available)";
+        }
+        asprintf(&msg2, "%s\n%s", msg, RSTRING_PTR(backtrace));
+    } else {
+        msg2 = strdup(msg);
+    }
+       MyAppCallback_messageBox(msg2, main_message, 0, 3);
        free(msg2);
+    if (interrupted == 2) {
+        free(msg);
+        if (!gUseGUI && exit_status == 0)
+            exit(0);  // Capture exit(0) here and force exit
+    }
        gMolbyRunLevel--;
 }
 
+/*  Wrapper function for rb_load_protect or rb_eval_string_protect. Used only in non-GUI mode.  */
+int
+Molby_loadScript(const char *script, int from_file)
+{
+    int status;
+    gMolbyRunLevel++;
+    if (from_file)
+        rb_load_protect(Ruby_NewEncodedStringValue2(script), 0, &status);
+    else
+        rb_eval_string_protect(script, &status);
+    gMolbyRunLevel--;
+    return status;
+}
+
 void
 Molby_getDescription(char **versionString, char **auxString)
 {
@@ -12113,23 +12376,32 @@ Molby_getDescription(char **versionString, char **auxString)
              "Molby",
 #endif
              gVersionString, revisionString, gCopyrightString, gLastBuildString);
-    asprintf(&s2,
-#if !defined(__CMDMAC__)
-                        "\nIncluding:\n"
-                        "%s"
-#else
-                        "Including "
-#endif
-                        "ruby %s, http://www.ruby-lang.org/\n"
-                        "%s\n"
-                        "FFTW 3.3.2, http://www.fftw.org/\n"
-                        "  Copyright (C) 2003, 2007-11 Matteo Frigo"
-                        "  and Massachusetts Institute of Technology",
-                        
-#if !defined(__CMDMAC__)
-                        MyAppCallback_getGUIDescriptionString(),
-#endif
-                        gRubyVersion, gRubyCopyright);
+    if (gUseGUI) {
+        asprintf(&s2,
+                 "\nIncluding:\n"
+                 "%s"
+                 "ruby %s, http://www.ruby-lang.org/\n"
+                 "%s\n"
+                 "FFTW 3.3.2, http://www.fftw.org/\n"
+                 "  Copyright (C) 2003, 2007-11 Matteo Frigo"
+                 "  and Massachusetts Institute of Technology\n"
+                 "JANPA 2.01, https://janpa.sourceforge.net/\n"
+                 "  Copyright (C) 2014, Tymofii Nikolaienko",
+                 MyAppCallback_getGUIDescriptionString(),
+                 gRubyVersion, gRubyCopyright);
+    } else {
+        asprintf(&s2,
+                 "Including "
+                 "ruby %s, http://www.ruby-lang.org/\n"
+                 "%s\n"
+                 "FFTW 3.3.2, http://www.fftw.org/\n"
+                 "  Copyright (C) 2003, 2007-11 Matteo Frigo"
+                 "  and Massachusetts Institute of Technology\n"
+                 "JANPA 2.01, https://janpa.sourceforge.net/\n"
+                 "  Copyright (C) 2014, Tymofii Nikolaienko",
+                 gRubyVersion, gRubyCopyright);
+
+    }
        if (revisionString[0] != 0)
                free(revisionString);
        if (versionString != NULL)
@@ -12150,11 +12422,7 @@ Molby_startup(const char *script, const char *dir)
        {
                gRubyVersion = strdup(ruby_version);
                asprintf(&gRubyCopyright, "%sCopyright (C) %d-%d %s",
-#if defined(__CMDMAC__)
-                                "",
-#else
                                 "  ",  /*  Indent for displaying in About dialog  */
-#endif
                                 RUBY_BIRTH_YEAR, RUBY_RELEASE_YEAR, RUBY_AUTHOR);
        }
        
@@ -12187,44 +12455,34 @@ Molby_startup(const char *script, const char *dir)
                }
     } */
 
-#if defined(__CMDMAC__)
-    {
+    if (!gUseGUI) {
         char *wbuf2;
         Molby_getDescription(&wbuf, &wbuf2);
-        printf("%s\n%s\n", wbuf, wbuf2);
+        MyAppCallback_showScriptMessage("%s\n%s\n", wbuf, wbuf2);
         free(wbuf);
         free(wbuf2);
     }
-#endif
        
        /*  Read atom display parameters  */
        if (ElementParameterInitialize("element.par", &wbuf) != 0) {
-#if defined(__CMDMAC__)
-               fprintf(stderr, "%s\n", wbuf);
-#else
-               MyAppCallback_setConsoleColor(1);
-               MyAppCallback_showScriptMessage("%s", wbuf);
-               MyAppCallback_setConsoleColor(0);
-#endif
+        MyAppCallback_setConsoleColor(1);
+        MyAppCallback_showScriptMessage("%s", wbuf);
+        MyAppCallback_setConsoleColor(0);
                free(wbuf);
        }
        
        /*  Read default parameters  */
        ParameterReadFromFile(gBuiltinParameters, "default.par", &wbuf, NULL);
        if (wbuf != NULL) {
-#if defined(__CMDMAC__)
-               fprintf(stderr, "%s\n", wbuf);
-#else
-               MyAppCallback_setConsoleColor(1);
-               MyAppCallback_showScriptMessage("%s", wbuf);
-               MyAppCallback_setConsoleColor(0);
-#endif
+        MyAppCallback_setConsoleColor(1);
+        MyAppCallback_showScriptMessage("%s", wbuf);
+        MyAppCallback_setConsoleColor(0);
                free(wbuf);
        }
                
        /*  Initialize Ruby interpreter  */
 #if __WXMSW__
-       {
+       if (gUseGUI) {
                /*  On Windows, fileno(stdin|stdout|stderr) returns -2 and
                    it causes rb_bug() (= fatal error) during ruby_init().
                    As a workaround, these standard streams are reopend as
@@ -12237,11 +12495,31 @@ Molby_startup(const char *script, const char *dir)
        ruby_init();
 
        {
-               extern void Init_shift_jis(void), Init_trans_japanese_sjis(void);
-               Init_shift_jis();
-               Init_trans_japanese_sjis();
+        /*  Initialize CP932/Windows-31J encodings  */
+               extern void Init_shift_jis(void), Init_windows_31j(void),  Init_trans_japanese_sjis(void);
+        extern int rb_enc_alias(const char *, const char *);
+        Init_shift_jis();
+        Init_windows_31j();
+        Init_trans_japanese_sjis();
+        rb_enc_alias("CP932", "Windows-31J");
+    }
+    
+#if defined(__WXMSW__)
+    {
+        /*  Set default external encoding  */
+        /*  The following snippet is taken from encoding.c  */
+        extern void rb_enc_set_default_external(VALUE encoding);
+        char cp[sizeof(int) * 8 / 3 + 22];
+        int status;
+        VALUE enc;
+        snprintf(cp, sizeof cp, "Encoding.find('CP%d')", AreFileApisANSI() ? GetACP() : GetOEMCP());
+        enc = rb_eval_string_protect(cp, &status);
+        if (status == 0 && !NIL_P(enc)) {
+            rb_enc_set_default_external(enc);
+        }
        }
-       
+#endif
+
        /*  Initialize loadpath; the specified directory, "lib" subdirectory, and "."  */
        ruby_incpush(".");
        asprintf(&libpath, "%s%clib", dir, PATH_SEPARATOR);
@@ -12264,7 +12542,8 @@ Molby_startup(const char *script, const char *dir)
 
        /*  Define Molby classes  */
        Init_Molby();
-       RubyDialogInitClass();
+    if (gUseGUI)
+        RubyDialogInitClass();
 
        rb_define_const(rb_mMolby, "ResourcePath", val);
        val = Ruby_NewFileStringValue(dir);
@@ -12283,32 +12562,29 @@ Molby_startup(const char *script, const char *dir)
        rb_define_const(rb_mMolby, "DocumentDirectory", val);
        free(p);
        
-#if defined(__CMDMAC__)
-       rb_define_const(rb_mMolby, "HasGUI", Qfalse);
-#else
-       rb_define_const(rb_mMolby, "HasGUI", Qtrue);
-#endif
+    if (gUseGUI)
+        rb_define_const(rb_mMolby, "HasGUI", Qtrue);
+    else
+        rb_define_const(rb_mMolby, "HasGUI", Qfalse);
 
-#if !__CMDMAC__
-       
-       /*  Create objects for stdout and stderr  */
-       val = rb_funcall(rb_cObject, rb_intern("new"), 0);
-       rb_define_singleton_method(val, "write", s_StandardOutput, 1);
-       rb_define_singleton_method(val, "flush", s_FlushConsoleOutput, 0);
-       rb_gv_set("$stdout", val);
-       val = rb_funcall(rb_cObject, rb_intern("new"), 0);
-       rb_define_singleton_method(val, "write", s_StandardErrorOutput, 1);
-       rb_define_singleton_method(val, "flush", s_FlushConsoleOutput, 0);
-       rb_gv_set("$stderr", val);
-
-       /*  Create objects for stdin  */
-       val = rb_funcall(rb_cObject, rb_intern("new"), 0);
-       rb_define_singleton_method(val, "gets", s_StandardInputGets, -1);
-       rb_define_singleton_method(val, "readline", s_StandardInputGets, -1);
-       rb_define_singleton_method(val, "method_missing", s_StandardInputMethodMissing, -1);
-       rb_gv_set("$stdin", val);
-       
-#endif
+    {
+        /*  Create objects for stdout and stderr  */
+        val = rb_funcall(rb_cObject, rb_intern("new"), 0);
+        rb_define_singleton_method(val, "write", s_StandardOutput, 1);
+        rb_define_singleton_method(val, "flush", s_FlushConsoleOutput, 0);
+        rb_gv_set("$stdout", val);
+        val = rb_funcall(rb_cObject, rb_intern("new"), 0);
+        rb_define_singleton_method(val, "write", s_StandardErrorOutput, 1);
+        rb_define_singleton_method(val, "flush", s_FlushConsoleOutput, 0);
+        rb_gv_set("$stderr", val);
+
+        /*  Create objects for stdin  */
+        val = rb_funcall(rb_cObject, rb_intern("new"), 0);
+        rb_define_singleton_method(val, "gets", s_StandardInputGets, -1);
+        rb_define_singleton_method(val, "readline", s_StandardInputGets, -1);
+        rb_define_singleton_method(val, "method_missing", s_StandardInputMethodMissing, -1);
+        rb_gv_set("$stdin", val);
+    }
        
        /*  Global variable to hold error information  */
        rb_define_variable("$backtrace", &gMolbyBacktrace);
@@ -12321,21 +12597,18 @@ Molby_startup(const char *script, const char *dir)
        gScriptMenuCommands = rb_ary_new();
        gScriptMenuEnablers = rb_ary_new();
        
-#if !__CMDMAC__
-       /*  Register interrupt check code  */
-       rb_add_event_hook(s_Event_Callback, RUBY_EVENT_ALL, Qnil);
-#endif
-       
-#if !__CMDMAC__
-       /*  Start interval timer (for periodic polling of interrupt); firing every 50 msec  */
-       s_SetIntervalTimer(0, 50);
-#endif
+    if (gUseGUI) {
+        /*  Register interrupt check code  */
+        rb_add_event_hook(s_Event_Callback, RUBY_EVENT_ALL, Qnil);
+        /*  Start interval timer (for periodic polling of interrupt); firing every 50 msec  */
+        s_SetIntervalTimer(0, 50);
+    }
        
        /*  Read the startup script  */
        if (script != NULL && script[0] != 0) {
                MyAppCallback_showScriptMessage("Evaluating %s...\n", script);
                gMolbyRunLevel++;
-               rb_load_protect(rb_str_new2(script), 0, &status);
+               rb_load_protect(Ruby_NewEncodedStringValue2(script), 0, &status);
                gMolbyRunLevel--;
                if (status != 0)
                        Ruby_showError(status);