Unix.st
changeset 813 1f9611434418
parent 811 6fbd6e7fdb74
child 827 3eb3911cb63e
--- a/Unix.st	Sat Dec 23 12:49:50 1995 +0100
+++ b/Unix.st	Sat Dec 23 14:54:00 1995 +0100
@@ -14,7 +14,8 @@
 	instanceVariableNames:''
 	classVariableNames:'HostName DomainName LastErrorNumber LastExecStatus OSSignals
 		SlowFork ForkFailed ErrorSignal AccessDeniedErrorSignal
-		FileNotFoundErrorSignal'
+		FileNotFoundErrorSignal
+		LocaleInfo'
 	poolDictionaries:''
 	category:'System-Support'
 !
@@ -162,6 +163,17 @@
 
 # include <fcntl.h>
 
+# if defined(LINUX)
+#  define HAS_LOCALECONV
+# endif
+
+# if defined (HAS_LOCALECONV)
+#  ifndef _LOCALE_H_INCLUDED_
+#   include <locale.h>
+#   define _LOCALE_H_INCLUDED_
+#  endif
+# endif
+
 /* 
  * posix systems should define these ... 
  * but on some (older) systems, they are not.
@@ -197,7 +209,7 @@
 #   include <sys/param.h>
 #  endif
 #  ifndef MAXPATHLEN
-#   ifdef FILENAME_MAX	/* i.e. MSDOS_LIKE */
+#   ifdef FILENAME_MAX  /* i.e. MSDOS_LIKE */
 #    define MAXPATHLEN FILENAME_MAX
 #   else
 #    define MAXPATHLEN 1024
@@ -217,10 +229,10 @@
  * sigaction dummies (you won't believe these call themself ``POSIC'' systems ...)
  */
 # ifndef SA_RESTART
-#  define SA_RESTART	0
+#  define SA_RESTART    0
 # endif
 # ifndef SA_SIGINFO
-#  define SA_SIGINFO	0
+#  define SA_SIGINFO    0
 # endif
 
 #endif /* ! transputer */
@@ -404,7 +416,7 @@
 	    do {
 		__BEGIN_INTERRUPTABLE__
 		child = __wait (&status);
-	        __END_INTERRUPTABLE__
+		__END_INTERRUPTABLE__
 		if (child < 0 && errno != EINTR) {
 		    DPRINTF(("5: errno=%d\n", errno));
 		    status = -1;
@@ -418,7 +430,7 @@
 	    do {
 		__BEGIN_INTERRUPTABLE__
 		child = __waitpid (pid, &status, 0);
-	        __END_INTERRUPTABLE__
+		__END_INTERRUPTABLE__
 	    } while ((child != pid) && (errno == EINTR));
 	    if (child != pid) {
 		DPRINTF(("6: errno=%d\n", errno));
@@ -645,6 +657,11 @@
 	AccessDeniedErrorSignal
 
 	FileNotFoundErrorSignal
+
+	LocaleInfo	<Dictionary>    if non nil, that is taken instead of the operating
+					systems locale definitions (allows for overwriting
+					these, or provide a compatible info on systems which do
+					not support locales)
 "
 ! !
 
@@ -1768,16 +1785,16 @@
 exec:aPath withArguments:argArray fork:doFork
     "Internal combined fork & exec;
      If fork is false:
-         execute the unix command specified by the argument, aPath, with
-         arguments in argArray (no arguments, if nil).
-         If successful, this method does not return and smalltalk is gone.
-         If not successful, false is returned. Normal use is with forkForCommand.
+	 execute the unix command specified by the argument, aPath, with
+	 arguments in argArray (no arguments, if nil).
+	 If successful, this method does not return and smalltalk is gone.
+	 If not successful, false is returned. Normal use is with forkForCommand.
      if its true:
 	for a child to do the above.
 	The id of the child process is returned; -1 if fork failed.
 
     Notice: this used to be two separate ST-methods; however, in order to use
-   	    vfork on some machines, it had to be merged into one, to avoid write
+	    vfork on some machines, it had to be merged into one, to avoid write
 	    accesses to ST/X memory from the vforked-child. The code below only does
 	    read accesses."
 
@@ -1808,20 +1825,20 @@
 		id = fork();
 #endif
 		if (id == 0) {
-	            execv(_stringVal(aPath), argv);
+		    execv(_stringVal(aPath), argv);
 		    /* should not be reached */
 		    _exit(1);
 		}
 		free(argv);
 		RETURN (__MKSMALLINT(id));
 	    } else {
-	        execv(_stringVal(aPath), argv);
-	        /* 
-	         * should not be reached
-	         * (well, it is, if you pass a wrong command-path)
-	         */
-	        free(argv);
-	        RETURN ( false );
+		execv(_stringVal(aPath), argv);
+		/* 
+		 * should not be reached
+		 * (well, it is, if you pass a wrong command-path)
+		 */
+		free(argv);
+		RETURN ( false );
 	    }
 	}
     }
@@ -3191,12 +3208,12 @@
 	    sigaction(THESIGNAL, &act, 0);
 #else
 # ifdef HAS_SIGVEC
-            struct sigvec vec;
-
-            vec.sv_flags = 0;
-            sigemptyset(&vec.sv_mask);
-            vec.sv_handler = __signalIoInterrupt;
-            sigvec(THESIGNAL, &vec, NULL);
+	    struct sigvec vec;
+
+	    vec.sv_flags = 0;
+	    sigemptyset(&vec.sv_mask);
+	    vec.sv_handler = __signalIoInterrupt;
+	    sigvec(THESIGNAL, &vec, NULL);
 # else
 	    signal(THESIGNAL, __signalIoInterrupt);
 # endif
@@ -3372,7 +3389,7 @@
 
 	{
 #ifdef HAS_SIGACTION
-            struct sigaction act;
+	    struct sigaction act;
 
 	    act.sa_flags = SA_RESTART | SA_SIGINFO; /* <- if you add more, remember dummys at the top */
 	    sigemptyset(&act.sa_mask);
@@ -3380,12 +3397,12 @@
 	    sigaction(sigNr, &act, 0);
 #else
 # ifdef HAS_SIGVEC
-            struct sigvec vec;
-
-            vec.sv_flags = 0;
-            sigemptyset(&vec.sv_mask);
-            vec.sv_handler = handler;
-            sigvec(sigNr, &vec, NULL);
+	    struct sigvec vec;
+
+	    vec.sv_flags = 0;
+	    sigemptyset(&vec.sv_mask);
+	    vec.sv_handler = handler;
+	    sigvec(sigNr, &vec, NULL);
 # else
 	    signal(sigNr, handler);
 # endif
@@ -3428,12 +3445,12 @@
 	sigaction(SIGALRM, &act, 0);
 #else
 # ifdef HAS_SIGVEC
-        struct sigvec vec;
-
-        vec.sv_flags = 0;
-        sigemptyset(&vec.sv_mask);
-        vec.sv_handler = __signalTimerInterrupt;
-        sigvec(SIGALRM, &vec, NULL);
+	struct sigvec vec;
+
+	vec.sv_flags = 0;
+	sigemptyset(&vec.sv_mask);
+	vec.sv_handler = __signalTimerInterrupt;
+	sigvec(SIGALRM, &vec, NULL);
 # else
 	signal(SIGALRM, __signalTimerInterrupt);
 # endif
@@ -4350,6 +4367,286 @@
 %}
 .
     ^ true
+!
+
+getLocaleInfo
+    "return a dictionary filled with values from the locale information;
+     Not all fields may be present, depending on the OS's setup and capabilities.
+     Possible fields are:
+	decimalPoint			<String>
+
+        thousandsSep			<String>
+
+        internationalCurrencySymbol	<String>
+
+	currencySymbol			<String>
+
+	monetaryDecimalPoint		<String>
+
+	monetaryThousandsSeparator	<String>
+
+	positiveSign			<String>
+
+	negativeSign			<String>
+
+	internationalFractionalDigits	<Integer>
+
+	fractionalDigits		<Integer>
+
+	positiveSignPrecedesCurrencySymbol	<Boolean>
+
+	negativeSignPrecedesCurrencySymbol	<Boolean>
+
+	positiveSignSeparatedBySpaceFromCurrencySymbol	<Boolean>
+
+	negativeSignSeparatedBySpaceFromCurrencySymbol	<Boolean>
+
+	positiveSignPosition				<Symbol>
+							one of: #parenthesesAround, 
+							        #signPrecedes, 
+							        #signSuceeds, 
+							        #signPrecedesCurrencySymbol,
+								#signSuceedsCurrencySymbol
+
+	negativeSignPosition				<like above>
+
+     it is up to the application to deal with undefined values.
+
+     Notice, that (for now), the system does not use this information;
+     it should be used by applications as required.
+    "
+
+    |info val|
+
+    LocaleInfo notNil ifTrue:[
+	"/ return the internal info; useful on systems which do not
+	"/ support this.
+	^ LocaleInfo
+    ].
+
+    info := IdentityDictionary new.
+%{
+    char *decimalPoint;         /* something like "." (US) or "," (german) */
+    char *thousandsSep;         /* something like "," (US) or "." (german) */
+    char *intCurrencySymbol;    /* international currency symbol; something like "USD "  "DM  " */
+    char *currencySymbol;       /* local currency symbol;         something like "USD "  "DM  " */
+    char *monDecimalPoint;      /* money: decimal point */
+    char *monThousandsSep;      /* money: thousands sep */
+    char *positiveSign;
+    char *negativeSign;
+    int   intFractDigits;       /* money: international digits after decPoint */
+    int   fractDigits;          /* money: local digits after decPoint */
+    int   csPosPrecedes;        /* money: 1 if currency symbol precedes a positive value; 0 if it sceeds */
+    int   csNegPrecedes;        /* money: 1 if currency symbol precedes a negative value; 0 if it sceeds */
+    int   csPosSepBySpace;      /* money: 1 if currency symbol should be separated by a space from a positive value; 0 if no space */
+    int   csNegSepBySpace;      /* money: 1 if currency symbol should be separated by a space from a negative value; 0 if no space */
+    int   csPosSignPosition;    /* money: 0: ()'s around the value & currency symbol */
+    int   csNegSignPosition;    /*        1: sign precedes the value & currency symbol */
+				/*        2: sign succeeds the value & currency symbol */
+				/*        3: sign immediately precedes the currency symbol */
+				/*        4: sign immediately suceeds the currency symbol */
+
+#if defined(HAS_LOCALECONV)
+    struct lconv *conf;
+
+    conf = localeconv();
+    if (conf) {
+	decimalPoint = conf->decimal_point;
+	thousandsSep = conf->thousands_sep;
+	intCurrencySymbol = conf->int_curr_symbol;
+	currencySymbol = conf->currency_symbol;
+	monDecimalPoint = conf->mon_decimal_point;
+	monThousandsSep = conf->mon_thousands_sep;
+	positiveSign = conf->positive_sign;
+	negativeSign = conf->negative_sign;
+	intFractDigits = conf->int_frac_digits;
+	fractDigits = conf->frac_digits;
+	csPosPrecedes = conf->p_cs_precedes; 
+	csNegPrecedes = conf->n_cs_precedes; 
+	csPosSepBySpace = conf->p_sep_by_space; 
+	csNegSepBySpace = conf->n_sep_by_space; 
+	csPosSignPosition = conf->p_sign_posn;
+	csNegSignPosition = conf->n_sign_posn;
+    }
+#else
+    decimalPoint = (char *)0;
+    thousandsSep = (char *)0;
+    intCurrencySymbol = (char *)0;
+    currencySymbol = (char *)0;
+    monDecimalPoint = (char *)0;
+    monThousandsSep = (char *)0;
+    positiveSign =  (char *)0;
+    negativeSign =(char *)0;
+    intFractDigits = -1;
+    fractDigits = -1;
+    csPosPrecedes = -1; 
+    csNegPrecedes = -1; 
+    csPosSepBySpace = -1; 
+    csNegSepBySpace = -1; 
+    csPosSignPosition = -1;
+    csNegSignPosition = -1;
+#endif
+    if (decimalPoint) {
+	val = _MKSTRING(decimalPoint);
+	__AT_PUT_(info, @symbol(decimalPoint), val);
+    }
+    if (thousandsSep) {
+	val = _MKSTRING(thousandsSep);
+	__AT_PUT_(info, @symbol(thousandsSeparator), val);
+    }
+    if (intCurrencySymbol) {
+	val = _MKSTRING(intCurrencySymbol);
+	__AT_PUT_(info, @symbol(internationCurrencySymbol), val);
+    }
+    if (currencySymbol) {
+	val = _MKSTRING(currencySymbol);
+	__AT_PUT_(info, @symbol(currencySymbol), val);
+    }
+    if (monDecimalPoint) {
+	val = _MKSTRING(monDecimalPoint);
+	__AT_PUT_(info, @symbol(monetaryDecimalPoint), val);
+    }
+    if (monThousandsSep) {
+	val = _MKSTRING(monThousandsSep);
+	__AT_PUT_(info, @symbol(monetaryThousandsSeparator), val);
+    }
+    if (positiveSign) {
+	val = _MKSTRING(positiveSign);
+	__AT_PUT_(info, @symbol(positiveSign), val);
+    }
+    if (negativeSign) {
+	val = _MKSTRING(negativeSign);
+	__AT_PUT_(info, @symbol(negativeSign), val);
+    }
+    if (intFractDigits >= 0) {
+	__AT_PUT_(info, @symbol(internationalFractionalDigits),  __MKSMALLINT(intFractDigits));
+    }
+    if (fractDigits >= 0) {
+	__AT_PUT_(info, @symbol(fractionalDigits),  __MKSMALLINT(fractDigits));
+    }
+    if (csPosPrecedes >= 0) {
+	if (csPosPrecedes == 0) {
+	    val = false;
+	} else {
+	    val = true;
+	}
+	__AT_PUT_(info, @symbol(positiveSignPrecedesCurrencySymbol), val );
+    }
+    if (csNegPrecedes >= 0) {
+	if (csNegPrecedes == 0) {
+	    val = false;
+	} else {
+	    val = true;
+	}
+	__AT_PUT_(info, @symbol(negativeSignPrecedesCurrencySymbol), val );
+    }
+    if (csPosSepBySpace >= 0) {
+	if (csPosSepBySpace == 0) {
+	    val = false;
+	} else {
+	    val = true;
+	}
+	__AT_PUT_(info, @symbol(positiveSignSeparatedBySpaceFromCurrencySymbol), val);
+    }
+    if (csNegSepBySpace >= 0) {
+	if (csNegSepBySpace == 0) {
+	    val = false;
+	} else {
+	    val = true;
+	}
+	__AT_PUT_(info, @symbol(negativeSignSeparatedBySpaceFromCurrencySymbol), val);
+    }
+    switch (csPosSignPosition) {
+	case 0:
+	    val = @symbol(parenthesesAround);
+	    break;
+
+	case 1:
+	    val = @symbol(signPrecedes);
+	    break;
+
+	case 2:
+	    val = @symbol(signSuceeds);
+	    break;
+
+	case 3:
+	    val = @symbol(signPrecedesCurrencySymbol);
+	    break;
+
+	case 4:
+	    val = @symbol(signSuceedsCurrencySymbol);
+	    break;
+
+	default:
+	    val = nil;
+    }
+    if (val != nil) {
+        __AT_PUT_(info, @symbol(positiveSignPosition), val);
+    }
+
+    switch (csNegSignPosition) {
+	case 0:
+	    val = @symbol(parenthesesAround);
+	    break;
+
+	case 1:
+	    val = @symbol(signPrecedes);
+	    break;
+
+	case 2:
+	    val = @symbol(signSuceeds);
+	    break;
+
+	case 3:
+	    val = @symbol(signPrecedesCurrencySymbol);
+	    break;
+
+	case 4:
+	    val = @symbol(signSuceedsCurrencySymbol);
+	    break;
+
+	default:
+	    val = nil;
+    }
+    if (val != nil) {
+	__AT_PUT_(info, @symbol(negativeSignPosition), val);
+    }
+%}.
+    ^ info
+
+    "
+     OperatingSystem getLocaleInfo
+    "
+
+    "Created: 23.12.1995 / 14:19:20 / cg"
+!
+
+setLocaleInfo:anInfoDictionary
+    "set the locale information; if set, this oerrides the OS's settings.
+     (internal in ST/X only - the OS's settings remain unaffected)
+     See description of fields in #getLocaleInfo.
+
+     Notice, that (for now), the system does not use this information;
+     it should be used by applications as required."
+
+    LocaleInfo := anInfoDictionary
+
+    "
+     |d|
+
+     d := IdentityDictionary new.
+     d at:#decimalPoint                 put:'.'		.
+     d at:#thousandsSeparator           put:','		.
+     d at:#currencySymbol               put:'USD'	.
+     d at:#monetaryDecimalPoint         put:'.'		.
+     d at:#monetaryThousandsSeparator   put:'.'		.
+     d at:#fractionalDigits		put:2		.
+     d at:#positiveSign  		put:'+'		.
+     d at:#negativeSign  		put:'-'		.
+     d at:#positiveSignPrecedesCurrencySymbol put:true		.
+     d at:#negativeSignPrecedesCurrencySymbol put:false		.
+     OperatingSystem setLocaleInfo:d
+    "
 ! !
 
 !OperatingSystem class methodsFor:'shared memory access'!
@@ -4479,29 +4776,29 @@
     long t;
 
 #ifdef ultrix /* mhmh - isnt this ifdef BSD ? */
-#   define TIMEZONE	tmPtr->tm_gmtoff
+#   define TIMEZONE     tmPtr->tm_gmtoff
 #else
-#   define TIMEZONE	timezone
+#   define TIMEZONE     timezone
 #endif
 
     if (__bothSmallInteger(low, hi)) {
-        t = (_intVal(hi) << 16) | _intVal(low);
-        tmPtr = localtime(&t);
-        hours = _MKSMALLINT(tmPtr->tm_hour);
-        minutes = _MKSMALLINT(tmPtr->tm_min);
-        seconds = _MKSMALLINT(tmPtr->tm_sec);
-
-        year = _MKSMALLINT(tmPtr->tm_year + 1900);
-        month = _MKSMALLINT(tmPtr->tm_mon + 1);
-        day = _MKSMALLINT(tmPtr->tm_mday);
-
-        if (tmPtr->tm_isdst == 0) {
+	t = (_intVal(hi) << 16) | _intVal(low);
+	tmPtr = localtime(&t);
+	hours = _MKSMALLINT(tmPtr->tm_hour);
+	minutes = _MKSMALLINT(tmPtr->tm_min);
+	seconds = _MKSMALLINT(tmPtr->tm_sec);
+
+	year = _MKSMALLINT(tmPtr->tm_year + 1900);
+	month = _MKSMALLINT(tmPtr->tm_mon + 1);
+	day = _MKSMALLINT(tmPtr->tm_mday);
+
+	if (tmPtr->tm_isdst == 0) {
 	    dst = false;
-            utcOffset = _MKSMALLINT(TIMEZONE);
-        } else {
+	    utcOffset = _MKSMALLINT(TIMEZONE);
+	} else {
 	    dst = true;
 #ifdef HAS_ALTZONE
-            utcOffset = _MKSMALLINT(altzone);
+	    utcOffset = _MKSMALLINT(altzone);
 #else
 	    utcOffset = _MKSMALLINT(TIMEZONE) + 3600;
 #endif
@@ -4509,17 +4806,17 @@
     }
 %}.
     year notNil ifTrue:[
-        "I would love to have SELF-like inline objects ..."
-        ret := Array new:8.
-        ret at:1 put:year.
-        ret at:2 put:month.
-        ret at:3 put:day.
-        ret at:4 put:hours.
-        ret at:5 put:minutes.
-        ret at:6 put:seconds.
-        ret at:7 put:utcOffset.
-        ret at:8 put:dst.
-        ^ ret
+	"I would love to have SELF-like inline objects ..."
+	ret := Array new:8.
+	ret at:1 put:year.
+	ret at:2 put:month.
+	ret at:3 put:day.
+	ret at:4 put:hours.
+	ret at:5 put:minutes.
+	ret at:6 put:seconds.
+	ret at:7 put:utcOffset.
+	ret at:8 put:dst.
+	^ ret
     ].
     ^ self primitiveFailed
 !
@@ -5293,13 +5590,13 @@
 	    } while ((ret < 0) && (errno == EINTR));
 	} else {
 	    do {
-	        ret = select(maxF+1, &rset, &wset, &eset, &wt);
-	        /* 
-	         * for now: dont loop; if we did, we had to adjust the vt-timeval;
-	         * could otherwise stay in this loop forever ...
-	         * Premature return (before the time expired) must be handled by the caller.
+		ret = select(maxF+1, &rset, &wset, &eset, &wt);
+		/* 
+		 * for now: dont loop; if we did, we had to adjust the vt-timeval;
+		 * could otherwise stay in this loop forever ...
+		 * Premature return (before the time expired) must be handled by the caller.
 		 * A good solution is to update the wt-timeval and redo the select.
-	         */
+		 */
 	    } while (0 /* (ret < 0) && (errno == EINTR) */ );
 	}
 	__END_INTERRUPTABLE__
@@ -5376,6 +5673,6 @@
 !OperatingSystem class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Attic/Unix.st,v 1.108 1995-12-23 11:10:30 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Attic/Unix.st,v 1.109 1995-12-23 13:54:00 cg Exp $'
 ! !
 OperatingSystem initialize!