<div dir="ltr"><div dir="ltr">Hi Alistair,<div><br></div><div>also</div><div><span style="color:rgb(0,0,0)">    var := (self getenv: (self cCode: [key] inSmalltalk: [key allButLast])) ifNil: [0].</span></div><div><font color="#000000">doesn't make sense to me.  In C nil == 0.  So ifNil: [0] is a no-op in C.  Either the genenv: simulation should answer 0 or it should answer nil.  But we shouldn't fix the primitive two handle incorrect simulation; we should instead implement the simulated getenv: to match what the primitive expects.  Make sense?</font></div><div><font color="#000000"><br></font><div class="gmail_quote"><div dir="ltr">On Mon, Oct 15, 2018 at 11:18 AM <<a href="mailto:commits@source.squeak.org">commits@source.squeak.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"> <br>
Alistair Grant uploaded a new version of VMMaker to project VM Maker:<br>
<a href="http://source.squeak.org/VMMaker/VMMaker.oscog-AlistairGrant.2455.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-AlistairGrant.2455.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-AlistairGrant.2455<br>
Author: AlistairGrant<br>
Time: 14 October 2018, 8:59:01.383815 pm<br>
UUID: 9e8e4134-b30b-4734-9477-95d556650155<br>
Ancestors: VMMaker.oscog-eem.2454<br>
<br>
VMClass strlen, strncpy and getenv<br>
<br>
Pharo stores UTF8 encoded strings in ByteArrays (ByteString, strictly speaking, expects to only store characters that can be represented as a single byte in UTF8).  ByteArrays are also used within the simulator to represent buffers allocated by the simulator.  As such, the strings may either be the length of the ByteArray or less than the ByteArray size and null terminated.<br>
<br>
These changes extend strlen: and strncpy:_:_: to handle ByteArrays and add some tests (tests for strings in the object memory are todo).<br>
<br>
InterpreterPrimitives>>primitiveGetenv: returned nil rather than 0 in the simulator when a variable that isn't defined is requested.<br>
<br>
=============== Diff against VMMaker.oscog-eem.2454 ===============<br>
<br>
Item was changed:<br>
  ----- Method: InterpreterPrimitives>>primitiveGetenv (in category 'other primitives') -----<br>
  primitiveGetenv<br>
        "Access to environment variables via getenv.  No putenv or setenv as yet."<br>
        | key var result |<br>
        <export: true><br>
        <var: #key type: #'char *'><br>
        <var: #var type: #'char *'><br>
        sHEAFn ~= 0 ifTrue: "secHasEnvironmentAccess"<br>
                [self sHEAFn ifFalse: [^self primitiveFailFor: PrimErrInappropriate]].<br>
        key := self cStringOrNullFor: self stackTop.<br>
        key = 0 ifTrue:<br>
                [self successful ifTrue:<br>
                        [^self primitiveFailFor: PrimErrBadArgument].<br>
                 ^self primitiveFailFor: primFailCode].<br>
+       var := (self getenv: (self cCode: [key] inSmalltalk: [key allButLast])) ifNil: [0].<br>
-       var := self getenv: (self cCode: [key] inSmalltalk: [key allButLast]).<br>
        self free: key.<br>
        var ~= 0 ifTrue:<br>
                [result := objectMemory stringForCString: var.<br>
                 result ifNil:<br>
                        [^self primitiveFailFor: PrimErrNoMemory]].<br>
        self assert: primFailCode = 0.<br>
        self pop: 2 thenPush: (var = 0 ifTrue: [objectMemory nilObject] ifFalse: [result])!<br>
<br>
Item was changed:<br>
  ----- Method: VMClass>>strlen: (in category 'C library simulation') -----<br>
  strlen: aCString<br>
        "Simulate strlen(3)"<br>
        <doNotGenerate><br>
        | len |<br>
        aCString isString ifTrue:<br>
                [^aCString size].<br>
+       aCString class == ByteArray ifTrue: [<br>
+               "ByteArrays may be 0 terminated or the correct length (in the simulator)"<br>
+               len := 0.<br>
+               [(len = aCString size or: [(aCString at: len+1) = 0]) ifTrue: [^len].<br>
+               len := len + 1] repeat].<br>
+       "Must be an address"<br>
        len := 0.<br>
        [(self byteAt: aCString + len) = 0 ifTrue: [^len].<br>
        len := len + 1] repeat!<br>
<br>
Item was changed:<br>
  ----- Method: VMClass>>strncpy:_:_: (in category 'C library simulation') -----<br>
  strncpy: aString _: bString _: n<br>
        <doNotGenerate><br>
        "implementation of strncpy(3)"<br>
+ <br>
+       | getBlock setBlock count |<br>
+ <br>
+       count := n.<br>
+       aString isString ifTrue: [setBlock := [ :idx :ch | aString at: idx put: ch asCharacter]].<br>
+       aString class == ByteArray ifTrue: <br>
+                       [setBlock := [ :idx :ch | aString at: idx put: ch]].<br>
+       aString isInteger ifTrue: [setBlock := [ :idx :ch | self byteAt: aString + idx - 1 put: ch]].<br>
+       bString isString ifTrue: [<br>
+               getBlock := [ :idx | (bString at: idx) asInteger ].<br>
+               count := count min: bString size].<br>
+       bString class == ByteArray ifTrue: [<br>
+               getBlock := [ :idx | bString at: idx].<br>
+               count := count min: bString size].<br>
+       bString isInteger ifTrue: [getBlock := [ :idx | self byteAt: bString + idx - 1]].<br>
+       bString class == CArray ifTrue:<br>
+                       [getBlock := [ :idx | bString at: idx - 1]].<br>
+       self assert: getBlock ~= nil.<br>
+       self assert: setBlock ~= nil.<br>
+       1 to: count do: [ :i | | v |<br>
+               v := getBlock value: i.<br>
+               setBlock value: i value: v.<br>
+               v = 0 ifTrue: [^aString] ].<br>
-       aString isString<br>
-               ifTrue:<br>
-                       [1 to: n do:<br>
-                               [:i| | v |<br>
-                               v := bString isString<br>
-                                               ifTrue: [bString at: i]<br>
-                                               ifFalse: [Character value: (self byteAt: bString + i - 1)].<br>
-                               aString at: i put: v.<br>
-                               v asInteger = 0 ifTrue: [^aString]]]<br>
-               ifFalse:<br>
-                       [1 to: n do:<br>
-                               [:i| | v |<br>
-                               v := bString isString<br>
-                                               ifTrue: [(bString at: i) asInteger]<br>
-                                               ifFalse: [self byteAt: bString + i - 1].<br>
-                               self byteAt: aString + i - 1 put: v.<br>
-                               v = 0 ifTrue: [^aString]]].<br>
        ^aString!<br>
<br>
Item was added:<br>
+ TestCase subclass: #VMClassTests<br>
+       instanceVariableNames: 'testString vmclass'<br>
+       classVariableNames: ''<br>
+       poolDictionaries: ''<br>
+       category: 'VMMaker-Tests'!<br>
<br>
Item was added:<br>
+ ----- Method: VMClassTests>>initialize (in category 'initialize-release') -----<br>
+ initialize<br>
+ <br>
+       super initialize.<br>
+       testString := 'hello world'.!<br>
<br>
Item was added:<br>
+ ----- Method: VMClassTests>>setUp (in category 'running') -----<br>
+ setUp<br>
+ <br>
+       super setUp.<br>
+       vmclass := VMClass new.<br>
+ !<br>
<br>
Item was added:<br>
+ ----- Method: VMClassTests>>testStrlen (in category 'tests') -----<br>
+ testStrlen<br>
+ <br>
+       | testByteArray |<br>
+ <br>
+       "Instances of String must be the correct length"<br>
+       self assert: (vmclass strlen: testString) equals: testString size.<br>
+ <br>
+       "Instances of ByteArray can optionally have trailing nulls"<br>
+       testByteArray := testString asByteArray.<br>
+       self assert: (vmclass strlen: testByteArray) equals: testString size.<br>
+       testByteArray := testByteArray, (ByteArray new: 3).<br>
+       self assert: (vmclass strlen: testByteArray) equals: testString size.<br>
+ !<br>
<br>
Item was added:<br>
+ ----- Method: VMClassTests>>testStrncpy (in category 'tests') -----<br>
+ testStrncpy<br>
+ <br>
+       | stringA byteArrayA |<br>
+ <br>
+       stringA := String new: 5.<br>
+       vmclass strncpy: stringA _: testString _: stringA size.<br>
+       self assert: stringA equals: 'hello'.<br>
+ <br>
+       stringA := String new: testString size + 3.<br>
+       vmclass strncpy: stringA _: testString _: stringA size.<br>
+       self assert: stringA equals: (testString, (String new: 3)).<br>
+ <br>
+       byteArrayA := ByteArray new: 5.<br>
+       vmclass strncpy: byteArrayA _: testString _: byteArrayA size.<br>
+       self assert: byteArrayA equals: 'hello' asByteArray.<br>
+ <br>
+       byteArrayA := ByteArray new: testString size + 3.<br>
+       vmclass strncpy: byteArrayA _: testString _: byteArrayA size.<br>
+       self assert: byteArrayA equals: (testString, (String new: 3)) asByteArray.<br>
+ <br>
+ !<br>
<br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><span style="font-size:small;border-collapse:separate"><div>_,,,^..^,,,_<br></div><div>best, Eliot</div></span></div></div></div></div></div></div>