[Vm-dev] [commit] r2379 - OSCogVM as per VMMaker.oscog-eem.55. Implement shallowCopy (primitiveClone) and

commits at squeakvm.org commits at squeakvm.org
Tue Apr 26 19:24:16 UTC 2011


Author: eliot
Date: 2011-04-26 12:24:15 -0700 (Tue, 26 Apr 2011)
New Revision: 2379

Removed:
   branches/Cog/platforms/unix/plugins/LocalePlugin/sqUnixLocale.h
Modified:
   branches/Cog/image/VMMaker-Squeak4.1.changes
   branches/Cog/image/VMMaker-Squeak4.1.image
   branches/Cog/platforms/unix/plugins/LocalePlugin/sqUnixLocale.c
   branches/Cog/platforms/unix/vm/sqUnixVMProfile.c
   branches/Cog/src/vm/cointerp.c
   branches/Cog/src/vm/cointerp.h
   branches/Cog/src/vm/gcc3x-cointerp.c
Log:
OSCogVM as per VMMaker.oscog-eem.55.  Implement shallowCopy (primitiveClone) and
copyFrom: (primitiveCopyObject) correctly for contexts.  Change package name to
correct Monticello branch  convention.  Use trunk linux LocalePlugin source.


Modified: branches/Cog/image/VMMaker-Squeak4.1.changes
===================================================================
--- branches/Cog/image/VMMaker-Squeak4.1.changes	2011-04-01 20:00:15 UTC (rev 2378)
+++ branches/Cog/image/VMMaker-Squeak4.1.changes	2011-04-26 19:24:15 UTC (rev 2379)
@@ -178019,4 +178019,224 @@
 					FFIPlugin ReentrantARMFFIPlugin ReentrantFFIPlugin ReentrantPPCBEFFIPlugin
 					NewsqueakIA32ABIPlugin NewsqueakIA32ABIPluginAttic)!
 
-----QUIT----{1 April 2011 . 12:31:53 pm} VMMaker-Squeak4.1.image priorSource: 7347139!
\ No newline at end of file
+----QUIT----{1 April 2011 . 12:31:53 pm} VMMaker-Squeak4.1.image priorSource: 7347139!
+
+----STARTUP----{26 April 2011 . 11:37:37 am} as /Users/eliot/Cog/oscogvm/image/VMMaker-Squeak4.1.image!
+
+
+InterpreterPrimitives removeSelector: #primitiveContextAt!
+
+InterpreterPrimitives removeSelector: #primitiveContextAtPut!
+
+InterpreterPrimitives removeSelector: #primitiveContextSize!
+!InterpreterPrimitives methodsFor: 'object access primitives' stamp: 'eem 4/25/2011 17:02' prior: 36472637!
+primitiveCopyObject
+	"Primitive. Copy the state of the receiver from the argument. 
+		Fail if receiver and argument are of a different class. 
+		Fail if the receiver or argument are non-pointer objects.
+		Fail if receiver and argument have different lengths (for indexable objects).
+	"
+	| rcvr arg length |
+	self methodArgumentCount = 1 ifFalse:
+		[^self primitiveFail].
+	arg := self stackObjectValue: 0.
+	rcvr := self stackObjectValue: 1.
+
+	self failed ifTrue:[^nil].
+	(objectMemory isPointers: rcvr) ifFalse:
+		[^self primitiveFail].
+	(objectMemory fetchClassOfNonInt: rcvr) = (objectMemory fetchClassOfNonInt: arg) ifFalse:
+		[^self primitiveFail].
+	length := objectMemory lengthOf: rcvr.
+	length = (objectMemory lengthOf: arg) ifFalse:
+		[^self primitiveFail].
+	
+	"Now copy the elements"
+	0 to: length-1 do:[:i|
+		objectMemory storePointer: i ofObject: rcvr withValue: (objectMemory fetchPointer: i ofObject: arg)].
+
+	"Note: The above could be faster for young receivers but I don't think it'll matter"
+	self pop: 1. "pop arg; answer receiver"
+! !
+!StackInterpreter class methodsFor: 'translation' stamp: 'eem 4/25/2011 19:08'!
+prepareToBeAddedToCodeGenerator: aCodeGen
+	"Override to delete InterpreterPrimitives methods we override."
+	aCodeGen removeVariable: 'cogit'.
+	self selectors do:
+		[:sel|
+		 (superclass whichClassIncludesSelector: sel) ifNotNil:
+			[aCodeGen removeMethodForSelector: sel]]! !
+!StackInterpreterPrimitives methodsFor: 'primitive support' stamp: 'eem 4/26/2011 10:10'!
+cloneContext: aContext 
+	| cloned spouseFP sp |
+	<var: #spouseFP type: #'char *'>
+	cloned := objectMemory clone: aContext.
+	cloned ~= 0 ifTrue:
+		[0 to: StackPointerIndex do:
+			[:i|
+			objectMemory
+				storePointerUnchecked: i
+				ofObject: cloned
+				withValue: (self externalInstVar: i ofContext: aContext)].
+		MethodIndex to: ReceiverIndex do:
+			[:i|
+			objectMemory
+				storePointerUnchecked: i
+				ofObject: cloned
+				withValue: (self fetchPointer: i ofObject: aContext)].
+		(self isStillMarriedContext: aContext)
+			ifTrue:
+				[spouseFP := self frameOfMarriedContext: aContext.
+				 sp := (self stackPointerIndexForFrame: spouseFP) - 1.
+				 0 to: sp do:
+					[:i|
+					objectMemory
+						storePointerUnchecked: i + CtxtTempFrameStart
+						ofObject: cloned
+						withValue: (self temporary: i in: spouseFP)]]
+			ifFalse:
+				[sp := (self fetchStackPointerOf: aContext) - 1.
+				 0 to: sp do:
+					[:i|
+					objectMemory
+						storePointerUnchecked: i + CtxtTempFrameStart
+						ofObject: cloned
+						withValue: (self fetchPointer: i ofObject: aContext)]].
+			sp + CtxtTempFrameStart + 1 to: (objectMemory lengthOf: aContext) - 1 do:
+				[:i|
+				objectMemory
+					storePointerUnchecked: i
+					ofObject: cloned
+					withValue: objectMemory nilObject]].
+	^cloned! !
+!StackInterpreterPrimitives methodsFor: 'object access primitives' stamp: 'eem 4/25/2011 17:30'!
+primitiveClone
+	"Return a shallow copy of the receiver.
+	 Special-case non-single contexts (because of context-to-stack mapping).
+	 Can't fail for contexts cuz of image context instantiation code (sigh)."
+
+	| receiver newCopy |
+	receiver := self stackTop.
+	(objectMemory isIntegerObject: receiver)
+		ifTrue:
+			[newCopy := receiver]
+		ifFalse:
+			[(self isContextNonInt: receiver)
+				ifTrue:
+					[newCopy := self cloneContext: receiver]
+				ifFalse:
+					[newCopy := objectMemory clone: receiver].
+			newCopy = 0 ifTrue:
+				[^self primitiveFailFor: PrimErrNoMemory]].
+	self pop: 1 thenPush: newCopy! !
+!StackInterpreterPrimitives methodsFor: 'indexing primitives' stamp: 'eem 6/9/2010 19:16'!
+primitiveContextAt
+	| index value aContext spouseFP hdr fmt totalLength fixedFields stSize |
+	<var: #spouseFP type: #'char *'>
+	index := self stackTop.
+	(objectMemory isIntegerObject: index) ifFalse:
+		[^self primitiveFail].
+	index := objectMemory integerValueOf: index.
+	aContext := self stackValue: 1.
+	"Duplicating much of stObject:at:put: here allows stObject:at:put: to omit tests for contexts."
+	hdr := objectMemory baseHeader: aContext.
+	(objectMemory isContextHeader: hdr) ifFalse: "might be an instance of a subclass"
+		[value := self stObject: aContext at: index.
+		 ^self pop: 2 thenPush: value].
+	self externalWriteBackHeadFramePointers.
+	(self isStillMarriedContext: aContext) ifFalse:
+		[fmt := objectMemory formatOfHeader: hdr.
+		 totalLength := objectMemory lengthOf: aContext baseHeader: hdr format: fmt.
+		 fixedFields := objectMemory fixedFieldsOf: aContext format: fmt length: totalLength.
+		 stSize := self stackPointerForMaybeMarriedContext: aContext.
+		 (index between: 1 and: stSize) ifFalse:
+			[^self primitiveFail].			
+		value := self subscript: aContext with: (index + fixedFields) format: fmt.
+		^self pop: 2 thenPush: value].
+	spouseFP := self frameOfMarriedContext: aContext.
+	(index between: 1 and: (self stackPointerIndexForFrame: spouseFP)) ifFalse:
+		[^self primitiveFail].
+	value := self temporary: index - 1 in: spouseFP.
+	self pop: 2 thenPush: value! !
+!StackInterpreterPrimitives methodsFor: 'indexing primitives' stamp: 'eem 6/9/2010 19:16'!
+primitiveContextAtPut
+	| index value aContext spouseFP hdr fmt totalLength fixedFields stSize |
+	<var: #spouseFP type: #'char *'>
+	value := self stackTop.
+	index := self stackValue: 1.
+	aContext := self stackValue: 2.
+	(objectMemory isIntegerObject: index) ifFalse:
+		[^self primitiveFail].
+	"Duplicating much of stObject:at:put: here allows stObject:at:put: to omit tests for contexts."
+	hdr := objectMemory baseHeader: aContext.
+	index := objectMemory integerValueOf: index.
+	(objectMemory isContextHeader: hdr) ifFalse: "might be an instance of a subclass"
+		[self stObject: aContext at: index put: value.
+		 ^self pop: 3 thenPush: value].
+	self externalWriteBackHeadFramePointers.
+	(self isStillMarriedContext: aContext) ifFalse:
+		[fmt := objectMemory formatOfHeader: hdr.
+		 totalLength := objectMemory lengthOf: aContext baseHeader: hdr format: fmt.
+		 fixedFields := objectMemory fixedFieldsOf: aContext format: fmt length: totalLength.
+		 stSize := self stackPointerForMaybeMarriedContext: aContext.
+		 (index between: 1 and: stSize) ifFalse:
+			[^self primitiveFail].			
+		self subscript: aContext with: (index + fixedFields) storing: value format: fmt.
+		^self pop: 3 thenPush: value].
+	spouseFP := self frameOfMarriedContext: aContext.
+	(index between: 1 and: (self stackPointerIndexForFrame: spouseFP)) ifFalse:
+		[^self primitiveFail].
+	self temporary: index - 1 in: spouseFP put: value.
+	^self pop: 3 thenPush: value! !
+!StackInterpreterPrimitives methodsFor: 'indexing primitives' stamp: 'eem 6/9/2010 19:16'!
+primitiveContextSize
+	| rcvr sz hdr fmt totalLength fixedFields |
+	rcvr := self stackTop.
+	hdr := objectMemory baseHeader: rcvr.
+	fmt := objectMemory formatOfHeader: hdr.
+	totalLength := objectMemory lengthOf: rcvr baseHeader: hdr format: fmt.
+	fixedFields := objectMemory fixedFieldsOf: rcvr format: fmt length: totalLength.
+	(objectMemory isContextHeader: hdr)
+		ifTrue:
+			[self externalWriteBackHeadFramePointers.
+			sz := self stackPointerForMaybeMarriedContext: rcvr]
+		ifFalse: [sz := totalLength - fixedFields].
+	self successful ifTrue:
+		[self pop: 1 thenPush: (objectMemory integerObjectOf: sz)]! !
+!StackInterpreterPrimitives methodsFor: 'object access primitives' stamp: 'eem 4/25/2011 17:04'!
+primitiveCopyObject
+	"Primitive. Copy the state of the receiver from the argument. 
+		Fail if receiver and argument are of a different class.
+		Fail if the receiver or argument are non-pointer objects.
+		Fail if the receiver or argument are contexts (because of context-to-stack mapping).
+		Fail if receiver and argument have different lengths (for indexable objects).
+	"
+	| rcvr arg length |
+	self methodArgumentCount = 1 ifFalse:
+		[^self primitiveFail].
+	arg := self stackObjectValue: 0.
+	rcvr := self stackObjectValue: 1.
+
+	self failed ifTrue:[^nil].
+	(objectMemory isPointers: rcvr) ifFalse:
+		[^self primitiveFail].
+	((self isContextNonInt: rcvr)
+	 or: [self isContextNonInt: arg]) ifTrue:
+		[^self primitiveFail].
+	(objectMemory fetchClassOfNonInt: rcvr) = (objectMemory fetchClassOfNonInt: arg) ifFalse:
+		[^self primitiveFail].
+	length := objectMemory lengthOf: rcvr.
+	length = (objectMemory lengthOf: arg) ifFalse:
+		[^self primitiveFail].
+	
+	"Now copy the elements"
+	0 to: length-1 do:[:i|
+		objectMemory storePointer: i ofObject: rcvr withValue: (objectMemory fetchPointer: i ofObject: arg)].
+
+	"Note: The above could be faster for young receivers but I don't think it'll matter"
+	self pop: 1. "pop arg; answer receiver"
+! !
+
+"VMMaker"!
+
+----QUIT----{26 April 2011 . 12:13:26 pm} VMMaker-Squeak4.1.image priorSource: 7348282!
\ No newline at end of file

Modified: branches/Cog/image/VMMaker-Squeak4.1.image
===================================================================
(Binary files differ)

Modified: branches/Cog/platforms/unix/plugins/LocalePlugin/sqUnixLocale.c
===================================================================
--- branches/Cog/platforms/unix/plugins/LocalePlugin/sqUnixLocale.c	2011-04-01 20:00:15 UTC (rev 2378)
+++ branches/Cog/platforms/unix/plugins/LocalePlugin/sqUnixLocale.c	2011-04-26 19:24:15 UTC (rev 2379)
@@ -1,137 +1,751 @@
-/*
- *  sqUnixLocale.c
- *     SqueakLocale stubs for Unix, so we can have the timezone.
+/* sqUnixLocale.c -- support for POSIX locales
+ * 
+ *   Copyright (C) 1996-2005 by Ian Piumarta and other authors/contributors
+ *                              listed elsewhere in this file.
+ *   All rights reserved.
+ *   
+ *   This file is part of Unix Squeak.
+ * 
+ *   Permission is hereby granted, free of charge, to any person obtaining a copy
+ *   of this software and associated documentation files (the "Software"), to deal
+ *   in the Software without restriction, including without limitation the rights
+ *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *   copies of the Software, and to permit persons to whom the Software is
+ *   furnished to do so, subject to the following conditions:
+ * 
+ *   The above copyright notice and this permission notice shall be included in
+ *   all copies or substantial portions of the Software.
+ * 
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ *   SOFTWARE.
  */
 
-#include "sqUnixLocale.h"
+/* Author: Ian.Piumarta at inria.fr
+ * 
+ * Last edited: 2008-11-10 13:25:18 by piumarta on ubuntu.piumarta.com
+ */
 
-sqInt sqLocInitialize(void) {
-	return 1;
+#include "sq.h"
+#include "LocalePlugin.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <locale.h>
+#include <langinfo.h>
+
+
+#define CODELEN			2	/* 2 for ISO two-letter codes, 3 for UN three-letter codes */
+
+
+#define DEFAULT_LOCALE		"en_US.ISO8859-1"
+
+#if (CODELEN == 2)
+#  define DEFAULT_COUNTRY	"US"
+#  define DEFAULT_LANGUAGE	"en"
+#elif (CODELEN == 3)
+#  define DEFAULT_COUNTRY	"USA"
+#  define DEFAULT_LANGUAGE	"eng"
+#else
+#  error -- CODELEN must be 2 or 3
+#endif
+
+
+static const char *localeString= 0;
+static struct lconv *localeConv= 0;
+
+
+/*** SUNDRY STUPIDITY ***/
+
+
+#if (CODELEN == 3)
+
+static struct CountryCode
+{
+  const char *iso, *un;
 }
+countryCodes[] = {
+  /* ISO   UN		   COUNTRY */
+  { "AD", "AND" },	/* Andorra */
+  { "AE", "ARE" },	/* United Arab Emirates */
+  { "AF", "AFG" },	/* Afghanistan */
+  { "AG", "ATG" },	/* Antigua and Barbuda */
+  { "AI", "AIA" },	/* Anguilla */
+  { "AL", "ALB" },	/* Albania */
+  { "AM", "ARM" },	/* Armenia */
+  { "AN", "ANT" },	/* Netherlands Antilles */
+  { "AO", "AGO" },	/* Angola */
+  { "AQ", "ATA" },	/* Antarctica */
+  { "AR", "ARG" },	/* Argentina */
+  { "AS", "ASM" },	/* American Samoa */
+  { "AT", "AUT" },	/* Austria */
+  { "AU", "AUS" },	/* Australia */
+  { "AW", "ABW" },	/* Aruba */
+  { "AX", "ALA" },	/* Aland Islands */
+  { "AZ", "AZE" },	/* Azerbaijan */
+  { "BA", "BIH" },	/* Bosnia and Herzegovina */
+  { "BB", "BRB" },	/* Barbados */
+  { "BD", "BGD" },	/* Bangladesh */
+  { "BE", "BEL" },	/* Belgium */
+  { "BF", "BFA" },	/* Burkina Faso */
+  { "BG", "BGR" },	/* Bulgaria */
+  { "BH", "BHR" },	/* Bahrain */
+  { "BI", "BDI" },	/* Burundi */
+  { "BJ", "BEN" },	/* Benin */
+  { "BM", "BMU" },	/* Bermuda */
+  { "BN", "BRN" },	/* Brunei Darussalam */
+  { "BO", "BOL" },	/* Bolivia */
+  { "BR", "BRA" },	/* Brazil */
+  { "BS", "BHS" },	/* Bahamas */
+  { "BT", "BTN" },	/* Bhutan */
+  { "BV", "BVT" },	/* Bouvet Island */
+  { "BW", "BWA" },	/* Botswana */
+  { "BY", "BLR" },	/* Belarus */
+  { "BZ", "BLZ" },	/* Belize */
+  { "CA", "CAN" },	/* Canada */
+  { "CC", "CCK" },	/* Cocos (Keeling) Islands */
+  { "CD", "COD" },	/* Congo, Democratic Republic of the */
+  { "CF", "CAF" },	/* Central African Republic */
+  { "CG", "COG" },	/* Congo, Republic of the */
+  { "CH", "CHE" },	/* Switzerland */
+  { "CI", "CIV" },	/* Cote D'Ivoire */
+  { "CK", "COK" },	/* Cook Islands */
+  { "CL", "CHL" },	/* Chile */
+  { "CM", "CMR" },	/* Cameroon */
+  { "CN", "CHN" },	/* China */
+  { "CO", "COL" },	/* Colombia */
+  { "CR", "CRI" },	/* Costa Rica */
+  { "CS", "SCG" },	/* Serbia and Montenegro */
+  { "CU", "CUB" },	/* Cuba */
+  { "CV", "CPV" },	/* Cape Verde */
+  { "CX", "CXR" },	/* Christmas Island */
+  { "CY", "CYP" },	/* Cyprus */
+  { "CZ", "CZE" },	/* Czech Republic */
+  { "DE", "DEU" },	/* Germany */
+  { "DJ", "DJI" },	/* Djibouti */
+  { "DK", "DNK" },	/* Denmark */
+  { "DM", "DMA" },	/* Dominica */
+  { "DO", "DOM" },	/* Dominican Republic */
+  { "DZ", "DZA" },	/* Algeria */
+  { "EC", "ECU" },	/* Ecuador */
+  { "EE", "EST" },	/* Estonia */
+  { "EG", "EGY" },	/* Egypt */
+  { "EH", "ESH" },	/* Western Sahara */
+  { "ER", "ERI" },	/* Eritrea */
+  { "ES", "ESP" },	/* Spain */
+  { "ET", "ETH" },	/* Ethiopia */
+  { "FI", "FIN" },	/* Finland */
+  { "FJ", "FJI" },	/* Fiji */
+  { "FK", "FLK" },	/* Falkland Islands (Islas Malvinas) */
+  { "FM", "FSM" },	/* Micronesia, Federated States of */
+  { "FO", "FRO" },	/* Faroe Islands */
+  { "FR", "FRA" },	/* France */
+  { "FX", "FXX" },	/* France, Metropolitan */
+  { "GA", "GAB" },	/* Gabon */
+  { "GB", "GBR" },	/* United Kingdom */
+  { "GD", "GRD" },	/* Grenada */
+  { "GE", "GEO" },	/* Georgia */
+  { "GF", "GUF" },	/* French Guiana */
+  { "GH", "GHA" },	/* Ghana */
+  { "GI", "GIB" },	/* Gibraltar */
+  { "GL", "GRL" },	/* Greenland */
+  { "GM", "GMB" },	/* Gambia */
+  { "GN", "GIN" },	/* Guinea */
+  { "GP", "GLP" },	/* Guadeloupe */
+  { "GQ", "GNQ" },	/* Equatorial Guinea */
+  { "GR", "GRC" },	/* Greece */
+  { "GS", "SGS" },	/* South Georgia and the South Sandwich Islands */
+  { "GT", "GTM" },	/* Guatemala */
+  { "GU", "GUM" },	/* Guam */
+  { "GW", "GNB" },	/* Guinea-Bissau */
+  { "GY", "GUY" },	/* Guyana */
+  { "HK", "HKG" },	/* Hong Kong */
+  { "HM", "HMD" },	/* Heard Island and McDonald Islands */
+  { "HN", "HND" },	/* Honduras */
+  { "HR", "HRV" },	/* Croatia */
+  { "HT", "HTI" },	/* Haiti */
+  { "HU", "HUN" },	/* Hungary */
+  { "ID", "IDN" },	/* Indonesia */
+  { "IE", "IRL" },	/* Ireland */
+  { "IL", "ISR" },	/* Israel */
+  { "IN", "IND" },	/* India */
+  { "IO", "IOT" },	/* British Indian Ocean Territory */
+  { "IQ", "IRQ" },	/* Iraq */
+  { "IR", "IRN" },	/* Iran */
+  { "IS", "ISL" },	/* Iceland */
+  { "IT", "ITA" },	/* Italy */
+  { "JM", "JAM" },	/* Jamaica */
+  { "JO", "JOR" },	/* Jordan */
+  { "JP", "JPN" },	/* Japan */
+  { "KE", "KEN" },	/* Kenya */
+  { "KG", "KGZ" },	/* Kyrgyzstan */
+  { "KH", "KHM" },	/* Cambodia */
+  { "KI", "KIR" },	/* Kiribati */
+  { "KM", "COM" },	/* Comoros */
+  { "KN", "KNA" },	/* Saint Kitts and Nevis */
+  { "KP", "PRK" },	/* North Korea */
+  { "KR", "KOR" },	/* South Korea */
+  { "KW", "KWT" },	/* Kuwait */
+  { "KY", "CYM" },	/* Cayman Islands */
+  { "KZ", "KAZ" },	/* Kazakstan */
+  { "LA", "LAO" },	/* Lao People's Democratic Republic */
+  { "LB", "LBN" },	/* Lebanon */
+  { "LC", "LCA" },	/* Saint Lucia */
+  { "LI", "LIE" },	/* Liechtenstein */
+  { "LK", "LKA" },	/* Sri Lanka */
+  { "LR", "LBR" },	/* Liberia */
+  { "LS", "LSO" },	/* Lesotho */
+  { "LT", "LTU" },	/* Lithuania */
+  { "LU", "LUX" },	/* Luxembourg */
+  { "LV", "LVA" },	/* Latvia */
+  { "LY", "LBY" },	/* Libya */
+  { "MA", "MAR" },	/* Morocco */
+  { "MC", "MCO" },	/* Monaco */
+  { "MD", "MDA" },	/* Moldova */
+  { "MG", "MDG" },	/* Madagascar */
+  { "MH", "MHL" },	/* Marshall Islands */
+  { "MK", "MKD" },	/* Macedonia */
+  { "ML", "MLI" },	/* Mali */
+  { "MM", "MMR" },	/* Burma */
+  { "MN", "MNG" },	/* Mongolia */
+  { "MO", "MAC" },	/* Macau */
+  { "MP", "MNP" },	/* Northern Mariana Islands */
+  { "MQ", "MTQ" },	/* Martinique */
+  { "MR", "MRT" },	/* Mauritania */
+  { "MS", "MSR" },	/* Montserrat */
+  { "MT", "MLT" },	/* Malta */
+  { "MU", "MUS" },	/* Mauritius */
+  { "MV", "MDV" },	/* Maldives */
+  { "MW", "MWI" },	/* Malawi */
+  { "MX", "MEX" },	/* Mexico */
+  { "MY", "MYS" },	/* Malaysia */
+  { "MZ", "MOZ" },	/* Mozambique */
+  { "NA", "NAM" },	/* Namibia */
+  { "NC", "NCL" },	/* New Caledonia */
+  { "NE", "NER" },	/* Niger */
+  { "NF", "NFK" },	/* Norfolk Island */
+  { "NG", "NGA" },	/* Nigeria */
+  { "NI", "NIC" },	/* Nicaragua */
+  { "NL", "NLD" },	/* Netherlands */
+  { "NO", "NOR" },	/* Norway */
+  { "NP", "NPL" },	/* Nepal */
+  { "NR", "NRU" },	/* Nauru */
+  { "NU", "NIU" },	/* Niue */
+  { "NZ", "NZL" },	/* New Zealand */
+  { "OM", "OMN" },	/* Oman */
+  { "PA", "PAN" },	/* Panama */
+  { "PE", "PER" },	/* Peru */
+  { "PF", "PYF" },	/* French Polynesia */
+  { "PG", "PNG" },	/* Papua New Guinea */
+  { "PH", "PHL" },	/* Philippines */
+  { "PK", "PAK" },	/* Pakistan */
+  { "PL", "POL" },	/* Poland */
+  { "PM", "SPM" },	/* Saint Pierre and Miquelon */
+  { "PN", "PCN" },	/* Pitcairn Island */
+  { "PR", "PRI" },	/* Puerto Rico */
+  { "PS", "PSE" },	/* Palestinian Territory, Occupied */
+  { "PT", "PRT" },	/* Portugal */
+  { "PW", "PLW" },	/* Palau */
+  { "PY", "PRY" },	/* Paraguay */
+  { "QA", "QAT" },	/* Qatar */
+  { "RE", "REU" },	/* Reunion */
+  { "RO", "ROU" },	/* Romania */
+  { "RU", "RUS" },	/* Russia */
+  { "RW", "RWA" },	/* Rwanda */
+  { "SA", "SAU" },	/* Saudi Arabia */
+  { "SB", "SLB" },	/* Solomon Islands */
+  { "SC", "SYC" },	/* Seychelles */
+  { "SD", "SDN" },	/* Sudan */
+  { "SE", "SWE" },	/* Sweden */
+  { "SG", "SGP" },	/* Singapore */
+  { "SH", "SHN" },	/* Saint Helena */
+  { "SI", "SVN" },	/* Slovenia */
+  { "SJ", "SJM" },	/* Svalbard */
+  { "SK", "SVK" },	/* Slovakia */
+  { "SL", "SLE" },	/* Sierra Leone */
+  { "SM", "SMR" },	/* San Marino */
+  { "SN", "SEN" },	/* Senegal */
+  { "SO", "SOM" },	/* Somalia */
+  { "SR", "SUR" },	/* Suriname */
+  { "ST", "STP" },	/* Sao Tome and Principe */
+  { "SV", "SLV" },	/* El Salvador */
+  { "SY", "SYR" },	/* Syria */
+  { "SZ", "SWZ" },	/* Swaziland */
+  { "TC", "TCA" },	/* Turks and Caicos Islands */
+  { "TD", "TCD" },	/* Chad */
+  { "TF", "ATF" },	/* French Southern and Antarctic Lands */
+  { "TG", "TGO" },	/* Togo */
+  { "TH", "THA" },	/* Thailand */
+  { "TJ", "TJK" },	/* Tajikistan */
+  { "TK", "TKL" },	/* Tokelau */
+  { "TM", "TKM" },	/* Turkmenistan */
+  { "TN", "TUN" },	/* Tunisia */
+  { "TO", "TON" },	/* Tonga */
+  { "TL", "TLS" },	/* East Timor */
+  { "TR", "TUR" },	/* Turkey */
+  { "TT", "TTO" },	/* Trinidad and Tobago */
+  { "TV", "TUV" },	/* Tuvalu */
+  { "TW", "TWN" },	/* Taiwan */
+  { "TZ", "TZA" },	/* Tanzania */
+  { "UA", "UKR" },	/* Ukraine */
+  { "UG", "UGA" },	/* Uganda */
+  { "UM", "UMI" },	/* United States Minor Outlying Islands */
+  { "US", "USA" },	/* United States of America */
+  { "UY", "URY" },	/* Uruguay */
+  { "UZ", "UZB" },	/* Uzbekistan */
+  { "VA", "VAT" },	/* Holy See (Vatican City) */
+  { "VC", "VCT" },	/* Saint Vincent and the Grenadines */
+  { "VE", "VEN" },	/* Venezuela */
+  { "VG", "VGB" },	/* British Virgin Islands */
+  { "VI", "VIR" },	/* Virgin Islands, U.S. */
+  { "VN", "VNM" },	/* Vietnam */
+  { "VU", "VUT" },	/* Vanuatu */
+  { "WF", "WLF" },	/* Wallis and Futuna */
+  { "WS", "WSM" },	/* Samoa */
+  { "YE", "YEM" },	/* Yemen */
+  { "YT", "MYT" },	/* Mayotte */
+  { "ZA", "ZAF" },	/* South Africa */
+  { "ZM", "ZMB" },	/* Zambia */
+  { "ZW", "ZWE" },	/* Zimbabwe */
+  { 0, 0 }
+};
 
-/************** Country and language ******************/
+static struct LanguageCode
+{
+  const char *iso, *un;
+}
+languageCodes[] = {
+  /* ISO   UN		   LANGUAGE */
+  { "ab", "abk" },	/* Abkhazian */
+  { "aa", "aar" },	/* Afar */
+  { "af", "afr" },	/* Afrikaans */
+  { "sq", "alb" },      /* Albanian */
+  { "sq", "sqi" },      /* Albanian */
+  { "am", "amh" },      /* Amharic */
+  { "ar", "ara" },      /* Arabic */
+  { "hy", "arm" },      /* Armenian */
+  { "hy", "hye" },      /* Armenian */
+  { "as", "asm" },      /* Assamese */
+  { "ay", "aym" },      /* Aymara */
+  { "az", "aze" },      /* Azerbaijani */
+  { "ba", "bak" },      /* Bashkir */
+  { "eu", "baq" },      /* Basque */
+  { "eu", "eus" },      /* Basque */
+  { "bn", "ben" },      /* Bengali */
+  { "bh", "bih" },      /* Bihari */
+  { "bi", "bis" },      /* Bislama */
+  { "be", "bre" },      /* Breton */
+  { "bg", "bul" },      /* Bulgarian */
+  { "my", "bur" },      /* Burmese */
+  { "my", "mya" },      /* Burmese */
+  { "be", "bel" },      /* Byelorussian */
+  { "ca", "cat" },      /* Catalan */
+  { "zh", "chi" },      /* Chinese */
+  { "zh", "zho" },      /* Chinese */
+  { "co", "cos" },      /* Corsican */
+  { "cs", "ces" },      /* Czech */
+  { "cs", "cze" },      /* Czech */
+  { "da", "dan" },      /* Danish */
+  { "nl", "dut" },      /* Dutch */
+  { "nl", "nla" },      /* Dutch */
+  { "dz", "dzo" },      /* Dzongkha */
+  { "en", "eng" },      /* English */
+  { "eo", "epo" },      /* Esperanto */
+  { "et", "est" },      /* Estonian */
+  { "fo", "fao" },      /* Faroese */
+  { "fj", "fij" },      /* Fijian */
+  { "fi", "fin" },      /* Finnish */
+  { "fr", "fra" },      /* French */
+  { "fr", "fre" },      /* French */
+  { "fy", "fry" },      /* Frisian */
+  { "gl", "glg" },      /* Gallegan */
+  { "ka", "geo" },      /* Georgian */
+  { "ka", "kat" },      /* Georgian */
+  { "de", "deu" },      /* German */
+  { "de", "ger" },      /* German */
+  { "el", "ell" },      /* Greek, Modern (1453-) */
+  { "el", "gre" },      /* Greek, Modern (1453-) */
+  { "kl", "kal" },      /* Greenlandic */
+  { "gn", "grn" },      /* Guarani */
+  { "gu", "guj" },      /* Gujarati */
+  { "ha", "hau" },      /* Hausa */
+  { "he", "heb" },      /* Hebrew */
+  { "hi", "hin" },      /* Hindi */
+  { "hu", "hun" },      /* Hungarian */
+  { "is", "ice" },      /* Icelandic */
+  { "is", "isl" },      /* Icelandic */
+  { "id", "ind" },      /* Indonesian */
+  { "ia", "ina" },      /* Interlingua (International Auxiliary language Association) */
+  { "iu", "iku" },      /* Inuktitut */
+  { "ik", "ipk" },      /* Inupiak */
+  { "ga", "gai" },      /* Irish */
+  { "ga", "iri" },      /* Irish */
+  { "it", "ita" },      /* Italian */
+  { "ja", "jpn" },      /* Japanese */
+  { "jv", "jav" },      /* Javanese */
+  { "jw", "jaw" },      /* Javanese */
+  { "kn", "kan" },      /* Kannada */
+  { "ks", "kas" },      /* Kashmiri */
+  { "kk", "kaz" },      /* Kazakh */
+  { "km", "khm" },      /* Khmer */
+  { "rw", "kin" },      /* Kinyarwanda */
+  { "ky", "kir" },      /* Kirghiz */
+  { "ko", "kor" },      /* Korean */
+  { "ku", "kur" },      /* Kurdish */
+  { "oc", "oci" },      /* Langue d'Oc (post 1500) */
+  { "lo", "lao" },      /* Lao */
+  { "la", "lat" },      /* Latin */
+  { "lv", "lav" },      /* Latvian */
+  { "ln", "lin" },      /* Lingala */
+  { "lt", "lit" },      /* Lithuanian */
+  { "mk", "mac" },      /* Macedonian */
+  { "mk", "mak" },      /* Macedonian */
+  { "mg", "mlg" },      /* Malagasy */
+  { "ms", "may" },      /* Malay */
+  { "ms", "msa" },      /* Malay */
+  { "ml", "mlt" },      /* Maltese */
+  { "mi", "mao" },      /* Maori */
+  { "mi", "mri" },      /* Maori */
+  { "mr", "mar" },      /* Marathi */
+  { "mo", "mol" },      /* Moldavian */
+  { "mn", "mon" },      /* Mongolian */
+  { "na", "nau" },      /* Nauru */
+  { "ne", "nep" },      /* Nepali */
+  { "no", "nor" },      /* Norwegian */
+  { "or", "ori" },      /* Oriya */
+  { "om", "orm" },      /* Oromo */
+  { "pa", "pan" },      /* Panjabi */
+  { "fa", "fas" },      /* Persian */
+  { "fa", "per" },      /* Persian */
+  { "pl", "pol" },      /* Polish */
+  { "pt", "por" },      /* Portuguese */
+  { "ps", "pus" },      /* Pushto */
+  { "qu", "que" },      /* Quechua */
+  { "rm", "roh" },      /* Rhaeto-Romance */
+  { "ro", "ron" },      /* Romanian */
+  { "ro", "rum" },      /* Romanian */
+  { "rn", "run" },      /* Rundi */
+  { "ru", "rus" },      /* Russian */
+  { "sm", "smo" },      /* Samoan */
+  { "sg", "sag" },      /* Sango */
+  { "sa", "san" },      /* Sanskrit */
+  { "sh", "scr" },      /* Serbo-Croatian */
+  { "sn", "sna" },      /* Shona */
+  { "sd", "snd" },      /* Sindhi */
+  { "si", "sin" },      /* Singhalese */
+  { "ss", "ssw" },      /* Siswant */
+  { "sk", "slk" },      /* Slovak */
+  { "sk", "slo" },      /* Slovak */
+  { "sl", "slv" },      /* Slovenian */
+  { "so", "som" },      /* Somali */
+  { "st", "sot" },      /* Sotho, Southern */
+  { "es", "esl" },      /* Spanish */
+  { "es", "spa" },      /* Spanish */
+  { "su", "sun" },      /* Sudanese */
+  { "sw", "swa" },      /* Swahili */
+  { "sv", "sve" },      /* Swedish */
+  { "sv", "swe" },      /* Swedish */
+  { "tl", "tgl" },      /* Tagalog */
+  { "tg", "tgk" },      /* Tajik */
+  { "ta", "tam" },      /* Tamil */
+  { "tt", "tat" },      /* Tatar */
+  { "te", "tel" },      /* Telugu */
+  { "th", "tha" },      /* Thai */
+  { "bo", "bod" },      /* Tibetan */
+  { "bo", "tib" },      /* Tibetan */
+  { "ti", "tir" },      /* Tigrinya */
+  { "to", "tog" },      /* Tonga (Nyasa) */
+  { "ts", "tso" },      /* Tsonga */
+  { "tn", "tsn" },      /* Tswana */
+  { "tr", "tur" },      /* Turkish */
+  { "tk", "tuk" },      /* Turkmen */
+  { "tw", "twi" },      /* Twi */
+  { "ug", "uig" },      /* Uighur */
+  { "uk", "ukr" },      /* Ukrainian */
+  { "ur", "urd" },      /* Urdu */
+  { "uz", "uzb" },      /* Uzbek */
+  { "vi", "vie" },      /* Vietnamese */
+  { "vo", "vol" },      /* Volapük */
+  { "cy", "cym" },      /* Welsh */
+  { "cy", "wel" },      /* Welsh */
+  { "wo", "wol" },      /* Wolof */
+  { "xh", "xho" },      /* Xhosa */
+  { "yi", "yid" },      /* Yiddish */
+  { "yo", "yor" },      /* Yoruba */
+  { "za", "zha" },      /* Zhuang */
+  { "zu", "zul" },      /* Zulu */
+  { 0, 0 }
+};
+  
+#endif /* CODELEN == 3 */
 
-/* write the country code into the string ptr. ISO 3166 is the relevant source
- * here; see http://www.unicode.org/onlinedat/countries.html for details.
- * Using the 3 character Alpha-3 codes */
-void	sqLocGetCountryInto(char * str) {
-	str[0]=0;
-	str[1]=0;
-	str[2]=0;
+
+/* Answer a canonical, sanitised locale string.
+ */
+static const char *getlocale(void)
+{
+  const char *locale= 0;
+
+  /* Use LC_ALL or LANG or current OS locale or some suitable default,
+     in that order.  Convert "C" and POSIX locales to the default,
+     along with anything else that seems malformed. */
+
+  if ((   !(locale= getenv("LC_ALL")))
+      && (!(locale= getenv("LANG")))
+      && (!(locale= setlocale(LC_ALL, 0))))
+    return DEFAULT_LOCALE;
+  else if ((!strcmp(locale, "C")) || (!strcmp(locale, "POSIX"))
+	   || strchr(locale, ' ') || strchr(locale, '/'))
+    return DEFAULT_LOCALE;
+
+  return locale;
 }
 
-/* write the 3 char string describing the language in use into string ptr.
- * ISO 639 is the relevant source here;
- * see http://www.w3.org/WAI/ER/IG/ert/iso639.html
- * for details */
-void	sqLocGetLanguageInto(char * str) {
-	str[0]=0;
-	str[1]=0;
-	str[2]=0;
+
+/* Answer the 2- or 3-letter country code CC within one of:
+ *	_CC
+ *	_CC.PP
+ *	ll_CC
+ *	ll_CC.PP
+ */
+static const char *getCountry(void)
+{
+  static const char *country= 0;
+
+  if (!country)
+    {
+      static char buf[4]= { 0, 0, 0, 0 };
+      const char *l, *r;
+
+      if ((l= strrchr(localeString, '_')))
+	{
+	  ++l;
+	  if (!(r= strchr(l, '.'))) r= strchr(l, '\0');
+#        if (CODELEN == 2)
+	  if (r - l == 2)
+	    {
+	      strncpy(buf, l, 2);
+	      country= buf;
+	    }
+#        else /* CODELEN == 3 */
+	  if (r - l == 3)
+	    {
+	      strncpy(buf, l, 3);
+	      country= buf;
+	    }
+	  else if (r - l == 2)
+	    {
+	      struct CountryCode *cc= countryCodes;
+	      strncpy(buf, l, 2);
+	      while ((!country) && cc->iso)
+		if (!strcasecmp(cc->iso, buf))
+		  country= cc->un;
+		else
+		  ++cc;
+	    }
+#        endif /* CODELEN == 3 */
+	}
+
+      if (!country)
+	country= DEFAULT_COUNTRY;
+    }
+
+  return country;
 }
 
-/***************** Currency ********************/
 
-/* return 1 (true) if the currency symbol is to be placed in front of the
- *currency amount */
-sqInt	sqLocCurrencyNotation(void) {
-	return 1;
+/* Answer the 2- or 3-letter language code ll within one of:
+ *	ll
+ *	ll.PP
+ *	ll_CC
+ *	ll_CC.PP
+ */
+static const char *getLanguage(void)
+{
+  static const char *language= 0;
+
+  if (!language)
+    {
+      static char buf[4]= { 0, 0, 0, 0 };
+
+      if (isalpha(localeString[0]) && isalpha(localeString[1])
+	  && ((localeString[2] == '.') || (localeString[2] == '_') || !localeString[2]))
+	{
+	  strncpy(buf, localeString, 2);
+#        if (CODELEN == 2)
+	  language= buf;
+#        elif (CODELEN == 3)
+	  {
+	    struct LanguageCode *lc= languageCodes;
+	    while ((!language) && lc->iso)
+	      if (!strcasecmp(lc->iso, buf))
+		language= lc->un;
+	      else
+		++lc;
+	  }
+#        endif /* CODELEN == 3 */
+	}
+      if (!language)
+	language= DEFAULT_LANGUAGE;
+    }
+  return language;
 }
 
-/* return the length in chars of the curency symbol string */
-sqInt	sqLocCurrencySymbolSize(void) {
-	return 1;
+
+/* CURRENCY */
+
+/* Answer true if the currency symbol is to be placed in front of the
+ * currency value */
+sqInt sqLocCurrencyNotation(void)
+{
+  return localeConv->p_cs_precedes;
 }
-/* write the currency symbol into the string ptr */
-void	sqLocGetCurrencySymbolInto(char * str) {
-	strcpy(str, "$");
+
+/* Store the currency symbol into the given string.
+ */
+void sqLocGetCurrencySymbolInto(char *str)
+{
+  strcpy(str, localeConv->currency_symbol);
 }
 
+sqInt	sqLocCurrencySymbolSize(void)
+{
+  return strlen(localeConv->currency_symbol); 
+}
 
-/***************** Numbers and measurements **************/
 
-/* return true if the metric measurements system is to be used, false otherwise
- * (USA is about it) */
-sqInt	sqLocMeasurementMetric(void) {
-	return 1;
+
+/* NUMBERS AND MEASUREMENTS */
+
+
+/* Answer true if the metric measurements system is to be used.
+ */
+sqInt sqLocMeasurementMetric(void)
+{
+  return 1;
 }
 
-/* write the 1 char used for digit grouping into string ptr.
- * Usually this is . or ,  as in 1,000,000 */
-void	sqLocGetDigitGroupingSymbolInto(char * str) {
-	strncpy(str, ",", 1);
+
+/* Store the seperator for thousands into the given string.
+ */
+void sqLocGetDigitGroupingSymbolInto(char *str)
+{
+  strcpy(str, localeConv->thousands_sep);
 }
 
-/* write the 1 char used for decimal separation into string ptr.
- * Usually this is . or , */
-void	sqLocGetDecimalSymbolInto(char * str) {
-	strncpy(str, ".", 1);
+
+/* Store the decimal point into the given string.
+ */
+void sqLocGetDecimalSymbolInto(char *str)
+{
+  strcpy(str, localeConv->decimal_point);
 }
 
 
-/****************** time and date *********************/
+/* TIME AND DATE */
 
-sqInt	sqLocGetVMOffsetToUTC(void) {
-	/* return 0 for now */
-	return 0;
+
+/* Answer the offset between local time and VM time.  (Despite the
+ * function name, this is how it is used.)
+ */
+sqInt sqLocGetVMOffsetToUTC(void)
+{
+  return 0;
 }
 
-sqInt	sqLocGetTimezoneOffset(void) {
+/* Answer the offset to (number of minutes EAST of) GMT.
+ */
+sqInt sqLocGetTimezoneOffset(void)
+{
+  /* Match the behaviour of convertToSqueakTime(). */
+#ifdef HAVE_TM_GMTOFF
+  time_t now= time(0);
+  return localtime(&now)->tm_gmtoff / 60;
+#else
+# ifdef HAVE_TIMEZONE
+  extern long timezone;
+  extern int daylight;
+  return daylight * 60 - timezone / 60;
+# else
+#  error: cannot determine timezone correction
+# endif
+#endif
+}
 
-	struct tm * timeBlock;
-	time_t theTime;
-	theTime = time((time_t)NULL);
-	timeBlock = localtime(&theTime);
-	return timeBlock->tm_gmtoff / 60;
+/* Answer true if DST is in use.
+ */
+sqInt sqLocDaylightSavings(void)
+{
+  time_t now= time(0);
+  return localtime(&now)->tm_isdst > 0;
 }
 
-/* return true if DST is in use, false otherwise */
-sqInt	sqLocDaylightSavings(void) {
-	struct tm * timeBlock;
-	time_t theTime;
-	theTime = time((time_t)NULL);
-	timeBlock = localtime(&theTime);
-	return timeBlock->tm_isdst;
+/* Answer the number of characters in the long date format.
+ */
+sqInt sqLocLongDateFormatSize(void)
+{
+  return strlen(nl_langinfo(D_FMT));
 }
 
-/* return the size in chars of the long date format string */
-sqInt	sqLocLongDateFormatSize(void) {
-	return 0;
+/* Store the long date format into the given string.
+*/
+void sqLocGetLongDateFormatInto(char *str)
+{
+  strcpy(str, nl_langinfo(D_FMT));
 }
 
-/*Write the string describing the long date formatting into string ptr.
- * Format is made up of
- * 		d day, m month, y year,
- * 		double symbol is null padded, single not padded (m=6, mm=06)
- * 		dddd weekday
- * 		mmmm month name */
-void	sqLocGetLongDateFormatInto(char * str) {
-	strcpy(str, "");
+/* Answer the number of characters in the short date format.
+ */
+sqInt sqLocShortDateFormatSize(void)
+{
+  return strlen(nl_langinfo(D_FMT));
 }
 
-/* return the size in chars of the short date format string */
-sqInt	sqLocShortDateFormatSize(void) {
-	return 0;
+/* Store the short date format into the given string.
+ */
+void sqLocGetShortDateFormatInto(char *str)
+{
+  strcpy(str, nl_langinfo(D_FMT));
 }
 
-/*Write the string describing the short date formatting into string ptr.
- * Format is made up of
- * 		d day, m month, y year,
- * 		double symbol is null padded, single not padded (m=6, mm=06)
- * 		dddd weekday
- * 		mmmm month name */
-void	sqLocGetShortDateFormatInto(char * str) {
-	strcpy(str, "");
+/* Answer the number of characters in the time format.
+ */
+sqInt sqLocTimeFormatSize(void)
+{
+  return strlen(nl_langinfo(T_FMT));
 }
 
-/* return the size in chars of the time format string */
-sqInt	sqLocTimeFormatSize(void) {
-	return 0;
+/* Store the time format into the given string.
+ */
+void sqLocGetTimeFormatInto(char *str)
+{
+  strcpy(str, nl_langinfo(T_FMT));
 }
-/* write the string describing the time formatting into string ptr.
- * Format is made up of
- * 		h hour (h 12, H 24), m minute, s seconds, x (am/pm String)
- * 		double symbol is null padded, single not padded (h=6, hh=06)  */
-void	sqLocGetTimeFormatInto(char * str) {
-	strcpy(str, "");
+
+
+sqInt sqLocInitialize(void)
+{
+  if (!(localeString= setlocale(LC_ALL, "")))
+    setlocale(LC_ALL, localeString= getlocale());
+  localeConv= localeconv();
+  return 1;
 }
+
+
+void sqLocGetCountryInto(char * str)
+{
+  strcpy(str, getCountry());
+}
+
+void sqLocGetLanguageInto(char * str)
+{
+  strcpy(str, getLanguage());
+}
+

Deleted: branches/Cog/platforms/unix/plugins/LocalePlugin/sqUnixLocale.h
===================================================================
--- branches/Cog/platforms/unix/plugins/LocalePlugin/sqUnixLocale.h	2011-04-01 20:00:15 UTC (rev 2378)
+++ branches/Cog/platforms/unix/plugins/LocalePlugin/sqUnixLocale.h	2011-04-26 19:24:15 UTC (rev 2379)
@@ -1,10 +0,0 @@
-/*
- *  sqUnixLocale.h
- *  SqueakLocale stubs
- */
-
-#include "sqMemoryAccess.h"
-#include <time.h>
-#include <locale.h>
-#include "sq.h"
-

Modified: branches/Cog/platforms/unix/vm/sqUnixVMProfile.c
===================================================================
--- branches/Cog/platforms/unix/vm/sqUnixVMProfile.c	2011-04-01 20:00:15 UTC (rev 2378)
+++ branches/Cog/platforms/unix/vm/sqUnixVMProfile.c	2011-04-26 19:24:15 UTC (rev 2379)
@@ -184,12 +184,16 @@
 static void
 histogramSIGPROFhandler(int sig, siginfo_t *info, ucontext_t *uap)
 {
-#if __APPLE__ && __MACH__ && __i386__
+#if __DARWIN_UNIX03 && __APPLE__ && __MACH__ && __i386__
+	pctype pc = uap->uc_mcontext->__ss.__eip;
+#elif __APPLE__ && __MACH__ && __i386__
 	pctype pc = uap->uc_mcontext->ss.eip;
 #elif __APPLE__ && __MACH__ && __ppc__
 	pctype pc = uap->uc_mcontext->ss.srr0;
 #elif __linux__ && __i386__
 	pctype pc = uap->uc_mcontext.gregs[REG_EIP];
+#elif __FreeBSD__ && __i386__
+	pctype pc = uap->uc_mcontext.mc_eip;
 #else
 # error need to implement extracting pc from a ucontext_t on this system
 #endif
@@ -302,6 +306,8 @@
 	pctype pc = uap->uc_mcontext->ss.srr0;
 #elif __linux__ && __i386__
 	pctype pc = uap->uc_mcontext.gregs[REG_EIP];
+#elif __FreeBSD__ && __i386__
+	pctype pc = uap->uc_mcontext.mc_eip;
 #else
 # error need to implement extracting pc from a ucontext_t on this system
 #endif

Modified: branches/Cog/src/vm/cointerp.c
===================================================================
--- branches/Cog/src/vm/cointerp.c	2011-04-01 20:00:15 UTC (rev 2378)
+++ branches/Cog/src/vm/cointerp.c	2011-04-26 19:24:15 UTC (rev 2379)
@@ -1,9 +1,9 @@
 /* Automatically generated by
-	CCodeGeneratorGlobalStructure VMMaker-oscog.54 uuid: 73c095bd-7fa5-4ef9-b9fc-60378cae64c7
+	CCodeGeneratorGlobalStructure VMMaker.oscog-eem.55 uuid: 315353fc-7f75-4b5b-8a43-3a636cb1aa0b
    from
-	CoInterpreter VMMaker-oscog.54 uuid: 73c095bd-7fa5-4ef9-b9fc-60378cae64c7
+	CoInterpreter VMMaker.oscog-eem.55 uuid: 315353fc-7f75-4b5b-8a43-3a636cb1aa0b
  */
-static char __buildInfo[] = "CoInterpreter VMMaker-oscog.54 uuid: 73c095bd-7fa5-4ef9-b9fc-60378cae64c7 " __DATE__ ;
+static char __buildInfo[] = "CoInterpreter VMMaker.oscog-eem.55 uuid: 315353fc-7f75-4b5b-8a43-3a636cb1aa0b " __DATE__ ;
 char *__interpBuildInfo = __buildInfo;
 
 
@@ -746,7 +746,7 @@
 EXPORT(sqInt) primitiveCompareBytes(void);
 static void primitiveConstantFill(void);
 static void primitiveContextAt(void);
-static void primitiveContextAtPut(void);
+static sqInt primitiveContextAtPut(void);
 static void primitiveContextSize(void);
 static void primitiveContextXray(void);
 static void primitiveControlVMProfiling(void);
@@ -1865,7 +1865,7 @@
 	/* 575 */ (void (*)(void))0,
  0 };
 static void (*externalPrimitiveTable[MaxExternalPrimitiveTableSize + 1 /* 4097 */])(void);
-const char *interpreterVersion = "Croquet Closure Cog VM [CoInterpreter VMMaker-oscog.54]";
+const char *interpreterVersion = "Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.55]";
 sqInt minBackwardJumpCountForCompile = MinBackwardJumpCountForCompile /* 10 */;
 static volatile int sendTrace;
 
@@ -24225,21 +24225,82 @@
 }
 
 
-/*	Return a shallow copy of the receiver. */
+/*	Return a shallow copy of the receiver.
+	Special-case non-single contexts (because of context-to-stack mapping).
+	Can't fail for contexts cuz of image context instantiation code (sigh). */
 
 static void
 primitiveClone(void)
 {   DECL_MAYBE_SQ_GLOBAL_STRUCT
+    sqInt cloned;
+    sqInt frameNumArgs;
+    sqInt frameNumArgs1;
+    sqInt i;
     sqInt newCopy;
+    sqInt receiver;
     char *sp;
+    sqInt sp1;
+    char *spouseFP;
+    sqInt value;
+    sqInt valuePointer;
+    sqInt valuePointer1;
 
-	newCopy = clone(longAt(GIV(stackPointer)));
-	if (newCopy == 0) {
-		/* begin primitiveFail */
-		if (GIV(primFailCode) == 0) {
-			GIV(primFailCode) = 1;
+	receiver = longAt(GIV(stackPointer));
+	if ((receiver & 1)) {
+		newCopy = receiver;
+	}
+	else {
+		if (((((usqInt) (longAt(receiver))) >> 12) & 31) == ClassMethodContextCompactIndex) {
+			/* begin cloneContext: */
+			VM_LABEL(0cloneContext);
+			cloned = clone(receiver);
+			if (cloned != 0) {
+				for (i = 0; i <= StackPointerIndex; i += 1) {
+					/* begin storePointerUnchecked:ofObject:withValue: */
+					valuePointer = externalInstVarofContext(i, receiver);
+					longAtput((cloned + BaseHeaderSize) + (i << ShiftForWord), valuePointer);
+				}
+				for (i = MethodIndex; i <= ReceiverIndex; i += 1) {
+					longAtput((cloned + BaseHeaderSize) + (i << ShiftForWord), longAt((receiver + BaseHeaderSize) + (i << ShiftForWord)));
+				}
+				if ((((longAt((receiver + BaseHeaderSize) + (SenderIndex << ShiftForWord))) & 1))
+				 && (!(isWidowedContext(receiver)))) {
+					/* begin frameOfMarriedContext: */
+					value = longAt((receiver + BaseHeaderSize) + (SenderIndex << ShiftForWord));
+					/* begin withoutSmallIntegerTags: */
+					assert((value & 1));
+					spouseFP = pointerForOop(value - 1);
+					sp1 = (stackPointerIndexForFrame(spouseFP)) - 1;
+					for (i = 0; i <= sp1; i += 1) {
+						/* begin storePointerUnchecked:ofObject:withValue: */
+						valuePointer1 = ((((usqInt)(longAt(spouseFP + FoxMethod)))) < heapBase
+							? (i < ((frameNumArgs = (mframeCogMethod(spouseFP)->cmNumArgs)))
+	? longAt((spouseFP + FoxCallerSavedIP) + ((frameNumArgs - i) * BytesPerWord))
+	: longAt(((spouseFP + FoxMFReceiver) - BytesPerWord) + ((frameNumArgs - i) * BytesPerWord)))
+							: (i < ((frameNumArgs1 = byteAt((spouseFP + FoxIFrameFlags) + 1)))
+	? longAt((spouseFP + FoxCallerSavedIP) + ((frameNumArgs1 - i) * BytesPerWord))
+	: longAt(((spouseFP + FoxIFReceiver) - BytesPerWord) + ((frameNumArgs1 - i) * BytesPerWord))));
+						longAtput((cloned + BaseHeaderSize) + ((i + CtxtTempFrameStart) << ShiftForWord), valuePointer1);
+					}
+				}
+				else {
+					sp1 = (fetchStackPointerOf(receiver)) - 1;
+					for (i = 0; i <= sp1; i += 1) {
+						longAtput((cloned + BaseHeaderSize) + ((i + CtxtTempFrameStart) << ShiftForWord), longAt((receiver + BaseHeaderSize) + (i << ShiftForWord)));
+					}
+				}
+				for (i = ((sp1 + CtxtTempFrameStart) + 1); i <= ((lengthOf(receiver)) - 1); i += 1) {
+					longAtput((cloned + BaseHeaderSize) + (i << ShiftForWord), GIV(nilObj));
+				}
+			}
+			newCopy = cloned;
 		}
-		return;
+		else {
+			newCopy = clone(receiver);
+		}
+		if (newCopy == 0) {
+			GIV(primFailCode) = PrimErrNoMemory; return;
+		}
 	}
 	/* begin pop:thenPush: */
 	longAtput(sp = GIV(stackPointer) + ((1 - 1) * BytesPerWord), newCopy);
@@ -25333,7 +25394,7 @@
 	GIV(stackPointer) = sp2;
 }
 
-static void
+static sqInt
 primitiveContextAtPut(void)
 {   DECL_MAYBE_SQ_GLOBAL_STRUCT
     sqInt aContext;
@@ -25367,7 +25428,7 @@
 		if (GIV(primFailCode) == 0) {
 			GIV(primFailCode) = 1;
 		}
-		return;
+		return null;
 	}
 	hdr = longAt(aContext);
 	index = (index >> 1);
@@ -25376,7 +25437,7 @@
 		/* begin pop:thenPush: */
 		longAtput(sp = GIV(stackPointer) + ((3 - 1) * BytesPerWord), value);
 		GIV(stackPointer) = sp;
-		return;
+		return null;
 	}
 	/* begin externalWriteBackHeadFramePointers */
 	assert((GIV(framePointer) - GIV(stackPointer)) < LargeContextSize);
@@ -25460,7 +25521,7 @@
 			if (GIV(primFailCode) == 0) {
 				GIV(primFailCode) = 1;
 			}
-			return;
+			return null;
 		}
 		/* begin subscript:with:storing:format: */
 		VM_LABEL(0subscriptwithstoringformat);
@@ -25514,7 +25575,7 @@
 		/* begin pop:thenPush: */
 		longAtput(sp1 = GIV(stackPointer) + ((3 - 1) * BytesPerWord), value);
 		GIV(stackPointer) = sp1;
-		return;
+		return null;
 	}
 	/* begin frameOfMarriedContext: */
 	value1 = longAt((aContext + BaseHeaderSize) + (SenderIndex << ShiftForWord));
@@ -25526,7 +25587,7 @@
 		if (GIV(primFailCode) == 0) {
 			GIV(primFailCode) = 1;
 		}
-		return;
+		return null;
 	}
 	/* begin temporary:in:put: */
 	VM_LABEL(0temporaryinput);
@@ -25549,7 +25610,7 @@
 	/* begin pop:thenPush: */
 	longAtput(sp2 = GIV(stackPointer) + ((3 - 1) * BytesPerWord), value);
 	GIV(stackPointer) = sp2;
-	return;
+	return null;
 }
 
 static void
@@ -25775,10 +25836,12 @@
 
 
 /*	Primitive. Copy the state of the receiver from the argument. 
-	Fail if receiver and argument are of a different class. 
+	Fail if receiver and argument are of a different class.
 	Fail if the receiver or argument are non-pointer objects.
-	Fail if receiver and argument have different lengths (for indexable
-	objects).  */
+	Fail if the receiver or argument are contexts (because of context-to-stack
+	mapping). Fail if receiver and argument have different lengths (for
+	indexable objects).
+	 */
 
 static void
 primitiveCopyObject(void)
@@ -25834,13 +25897,21 @@
 		}
 		return;
 	}
-	if (!((fetchClassOf(rcvr)) == (fetchClassOf(arg)))) {
+	if ((((((usqInt) (longAt(rcvr))) >> 12) & 31) == ClassMethodContextCompactIndex)
+	 || (((((usqInt) (longAt(arg))) >> 12) & 31) == ClassMethodContextCompactIndex)) {
 		/* begin primitiveFail */
 		if (GIV(primFailCode) == 0) {
 			GIV(primFailCode) = 1;
 		}
 		return;
 	}
+	if (!((fetchClassOfNonInt(rcvr)) == (fetchClassOfNonInt(arg)))) {
+		/* begin primitiveFail */
+		if (GIV(primFailCode) == 0) {
+			GIV(primFailCode) = 1;
+		}
+		return;
+	}
 	/* begin lengthOf: */
 	header = longAt(rcvr);
 	/* begin lengthOf:baseHeader:format: */
@@ -25863,7 +25934,7 @@
 		length = (sz - BaseHeaderSize) - (((((usqInt) header) >> 8) & 15) & 3);
 		goto l3;
 	}
-l3:	/* end lengthOf:baseHeader:format: */;
+l3:	/* end lengthOf: */;
 	if (!(length == (lengthOf(arg)))) {
 		/* begin primitiveFail */
 		if (GIV(primFailCode) == 0) {

Modified: branches/Cog/src/vm/cointerp.h
===================================================================
--- branches/Cog/src/vm/cointerp.h	2011-04-01 20:00:15 UTC (rev 2378)
+++ branches/Cog/src/vm/cointerp.h	2011-04-26 19:24:15 UTC (rev 2379)
@@ -1,5 +1,5 @@
 /* Automatically generated by
-	CCodeGeneratorGlobalStructure VMMaker-oscog.54 uuid: 73c095bd-7fa5-4ef9-b9fc-60378cae64c7
+	CCodeGeneratorGlobalStructure VMMaker.oscog-eem.55 uuid: 315353fc-7f75-4b5b-8a43-3a636cb1aa0b
  */
 
 

Modified: branches/Cog/src/vm/gcc3x-cointerp.c
===================================================================
--- branches/Cog/src/vm/gcc3x-cointerp.c	2011-04-01 20:00:15 UTC (rev 2378)
+++ branches/Cog/src/vm/gcc3x-cointerp.c	2011-04-26 19:24:15 UTC (rev 2379)
@@ -2,11 +2,11 @@
 
 
 /* Automatically generated by
-	CCodeGeneratorGlobalStructure VMMaker-oscog.54 uuid: 73c095bd-7fa5-4ef9-b9fc-60378cae64c7
+	CCodeGeneratorGlobalStructure VMMaker.oscog-eem.55 uuid: 315353fc-7f75-4b5b-8a43-3a636cb1aa0b
    from
-	CoInterpreter VMMaker-oscog.54 uuid: 73c095bd-7fa5-4ef9-b9fc-60378cae64c7
+	CoInterpreter VMMaker.oscog-eem.55 uuid: 315353fc-7f75-4b5b-8a43-3a636cb1aa0b
  */
-static char __buildInfo[] = "CoInterpreter VMMaker-oscog.54 uuid: 73c095bd-7fa5-4ef9-b9fc-60378cae64c7 " __DATE__ ;
+static char __buildInfo[] = "CoInterpreter VMMaker.oscog-eem.55 uuid: 315353fc-7f75-4b5b-8a43-3a636cb1aa0b " __DATE__ ;
 char *__interpBuildInfo = __buildInfo;
 
 
@@ -749,7 +749,7 @@
 EXPORT(sqInt) primitiveCompareBytes(void);
 static void primitiveConstantFill(void);
 static void primitiveContextAt(void);
-static void primitiveContextAtPut(void);
+static sqInt primitiveContextAtPut(void);
 static void primitiveContextSize(void);
 static void primitiveContextXray(void);
 static void primitiveControlVMProfiling(void);
@@ -1868,7 +1868,7 @@
 	/* 575 */ (void (*)(void))0,
  0 };
 static void (*externalPrimitiveTable[MaxExternalPrimitiveTableSize + 1 /* 4097 */])(void);
-const char *interpreterVersion = "Croquet Closure Cog VM [CoInterpreter VMMaker-oscog.54]";
+const char *interpreterVersion = "Croquet Closure Cog VM [CoInterpreter VMMaker.oscog-eem.55]";
 sqInt minBackwardJumpCountForCompile = MinBackwardJumpCountForCompile /* 10 */;
 static volatile int sendTrace;
 
@@ -24229,21 +24229,82 @@
 }
 
 
-/*	Return a shallow copy of the receiver. */
+/*	Return a shallow copy of the receiver.
+	Special-case non-single contexts (because of context-to-stack mapping).
+	Can't fail for contexts cuz of image context instantiation code (sigh). */
 
 static void
 primitiveClone(void)
 {   DECL_MAYBE_SQ_GLOBAL_STRUCT
+    sqInt cloned;
+    sqInt frameNumArgs;
+    sqInt frameNumArgs1;
+    sqInt i;
     sqInt newCopy;
+    sqInt receiver;
     char *sp;
+    sqInt sp1;
+    char *spouseFP;
+    sqInt value;
+    sqInt valuePointer;
+    sqInt valuePointer1;
 
-	newCopy = clone(longAt(GIV(stackPointer)));
-	if (newCopy == 0) {
-		/* begin primitiveFail */
-		if (GIV(primFailCode) == 0) {
-			GIV(primFailCode) = 1;
+	receiver = longAt(GIV(stackPointer));
+	if ((receiver & 1)) {
+		newCopy = receiver;
+	}
+	else {
+		if (((((usqInt) (longAt(receiver))) >> 12) & 31) == ClassMethodContextCompactIndex) {
+			/* begin cloneContext: */
+			VM_LABEL(0cloneContext);
+			cloned = clone(receiver);
+			if (cloned != 0) {
+				for (i = 0; i <= StackPointerIndex; i += 1) {
+					/* begin storePointerUnchecked:ofObject:withValue: */
+					valuePointer = externalInstVarofContext(i, receiver);
+					longAtput((cloned + BaseHeaderSize) + (i << ShiftForWord), valuePointer);
+				}
+				for (i = MethodIndex; i <= ReceiverIndex; i += 1) {
+					longAtput((cloned + BaseHeaderSize) + (i << ShiftForWord), longAt((receiver + BaseHeaderSize) + (i << ShiftForWord)));
+				}
+				if ((((longAt((receiver + BaseHeaderSize) + (SenderIndex << ShiftForWord))) & 1))
+				 && (!(isWidowedContext(receiver)))) {
+					/* begin frameOfMarriedContext: */
+					value = longAt((receiver + BaseHeaderSize) + (SenderIndex << ShiftForWord));
+					/* begin withoutSmallIntegerTags: */
+					assert((value & 1));
+					spouseFP = pointerForOop(value - 1);
+					sp1 = (stackPointerIndexForFrame(spouseFP)) - 1;
+					for (i = 0; i <= sp1; i += 1) {
+						/* begin storePointerUnchecked:ofObject:withValue: */
+						valuePointer1 = ((((usqInt)(longAt(spouseFP + FoxMethod)))) < heapBase
+							? (i < ((frameNumArgs = (mframeCogMethod(spouseFP)->cmNumArgs)))
+	? longAt((spouseFP + FoxCallerSavedIP) + ((frameNumArgs - i) * BytesPerWord))
+	: longAt(((spouseFP + FoxMFReceiver) - BytesPerWord) + ((frameNumArgs - i) * BytesPerWord)))
+							: (i < ((frameNumArgs1 = byteAt((spouseFP + FoxIFrameFlags) + 1)))
+	? longAt((spouseFP + FoxCallerSavedIP) + ((frameNumArgs1 - i) * BytesPerWord))
+	: longAt(((spouseFP + FoxIFReceiver) - BytesPerWord) + ((frameNumArgs1 - i) * BytesPerWord))));
+						longAtput((cloned + BaseHeaderSize) + ((i + CtxtTempFrameStart) << ShiftForWord), valuePointer1);
+					}
+				}
+				else {
+					sp1 = (fetchStackPointerOf(receiver)) - 1;
+					for (i = 0; i <= sp1; i += 1) {
+						longAtput((cloned + BaseHeaderSize) + ((i + CtxtTempFrameStart) << ShiftForWord), longAt((receiver + BaseHeaderSize) + (i << ShiftForWord)));
+					}
+				}
+				for (i = ((sp1 + CtxtTempFrameStart) + 1); i <= ((lengthOf(receiver)) - 1); i += 1) {
+					longAtput((cloned + BaseHeaderSize) + (i << ShiftForWord), GIV(nilObj));
+				}
+			}
+			newCopy = cloned;
 		}
-		return;
+		else {
+			newCopy = clone(receiver);
+		}
+		if (newCopy == 0) {
+			GIV(primFailCode) = PrimErrNoMemory; return;
+		}
 	}
 	/* begin pop:thenPush: */
 	longAtput(sp = GIV(stackPointer) + ((1 - 1) * BytesPerWord), newCopy);
@@ -25337,7 +25398,7 @@
 	GIV(stackPointer) = sp2;
 }
 
-static void
+static sqInt
 primitiveContextAtPut(void)
 {   DECL_MAYBE_SQ_GLOBAL_STRUCT
     sqInt aContext;
@@ -25371,7 +25432,7 @@
 		if (GIV(primFailCode) == 0) {
 			GIV(primFailCode) = 1;
 		}
-		return;
+		return null;
 	}
 	hdr = longAt(aContext);
 	index = (index >> 1);
@@ -25380,7 +25441,7 @@
 		/* begin pop:thenPush: */
 		longAtput(sp = GIV(stackPointer) + ((3 - 1) * BytesPerWord), value);
 		GIV(stackPointer) = sp;
-		return;
+		return null;
 	}
 	/* begin externalWriteBackHeadFramePointers */
 	assert((GIV(framePointer) - GIV(stackPointer)) < LargeContextSize);
@@ -25464,7 +25525,7 @@
 			if (GIV(primFailCode) == 0) {
 				GIV(primFailCode) = 1;
 			}
-			return;
+			return null;
 		}
 		/* begin subscript:with:storing:format: */
 		VM_LABEL(0subscriptwithstoringformat);
@@ -25518,7 +25579,7 @@
 		/* begin pop:thenPush: */
 		longAtput(sp1 = GIV(stackPointer) + ((3 - 1) * BytesPerWord), value);
 		GIV(stackPointer) = sp1;
-		return;
+		return null;
 	}
 	/* begin frameOfMarriedContext: */
 	value1 = longAt((aContext + BaseHeaderSize) + (SenderIndex << ShiftForWord));
@@ -25530,7 +25591,7 @@
 		if (GIV(primFailCode) == 0) {
 			GIV(primFailCode) = 1;
 		}
-		return;
+		return null;
 	}
 	/* begin temporary:in:put: */
 	VM_LABEL(0temporaryinput);
@@ -25553,7 +25614,7 @@
 	/* begin pop:thenPush: */
 	longAtput(sp2 = GIV(stackPointer) + ((3 - 1) * BytesPerWord), value);
 	GIV(stackPointer) = sp2;
-	return;
+	return null;
 }
 
 static void
@@ -25779,10 +25840,12 @@
 
 
 /*	Primitive. Copy the state of the receiver from the argument. 
-	Fail if receiver and argument are of a different class. 
+	Fail if receiver and argument are of a different class.
 	Fail if the receiver or argument are non-pointer objects.
-	Fail if receiver and argument have different lengths (for indexable
-	objects).  */
+	Fail if the receiver or argument are contexts (because of context-to-stack
+	mapping). Fail if receiver and argument have different lengths (for
+	indexable objects).
+	 */
 
 static void
 primitiveCopyObject(void)
@@ -25838,13 +25901,21 @@
 		}
 		return;
 	}
-	if (!((fetchClassOf(rcvr)) == (fetchClassOf(arg)))) {
+	if ((((((usqInt) (longAt(rcvr))) >> 12) & 31) == ClassMethodContextCompactIndex)
+	 || (((((usqInt) (longAt(arg))) >> 12) & 31) == ClassMethodContextCompactIndex)) {
 		/* begin primitiveFail */
 		if (GIV(primFailCode) == 0) {
 			GIV(primFailCode) = 1;
 		}
 		return;
 	}
+	if (!((fetchClassOfNonInt(rcvr)) == (fetchClassOfNonInt(arg)))) {
+		/* begin primitiveFail */
+		if (GIV(primFailCode) == 0) {
+			GIV(primFailCode) = 1;
+		}
+		return;
+	}
 	/* begin lengthOf: */
 	header = longAt(rcvr);
 	/* begin lengthOf:baseHeader:format: */
@@ -25867,7 +25938,7 @@
 		length = (sz - BaseHeaderSize) - (((((usqInt) header) >> 8) & 15) & 3);
 		goto l3;
 	}
-l3:	/* end lengthOf:baseHeader:format: */;
+l3:	/* end lengthOf: */;
 	if (!(length == (lengthOf(arg)))) {
 		/* begin primitiveFail */
 		if (GIV(primFailCode) == 0) {



More information about the Vm-dev mailing list