0

so I've written this code which allows the user to search for a text file with a specific name, then enter the first name from the text file and actually edit what's written in that line. i.e. search for a text file called lions, and then edit the line where the name equals Michael.\ the only problem is that while it is edited the name just writes over what was previously there. What I mean is that if the original first name is Alexander, and then I edit that record to change that name to mike, the text file will keep the remaining letters so that the name in the text file is Mikeander. It kept the remaining letters. This happens for all entries in the record.

type
    TCustomer = Record
      FirstName : String[15];
      LastName : String[15];
      EventDate : String[15];
      SeatNumber : String[100];
      PhoneNumber : String [100];
      Adress : String[100]
    end;

var
Form4 : TForm4;
FirstName : string;
LastName : String;
EventDate : String;
SeatNumber : String;
PhoneNumber : String;
Adress : String; 




 begin
            usersFilename := Inputbox('Which event needs its details edited?', '', '');
            oldname := inputbox('Old Name','Input old name','');
            newname := inputbox('New Name','Input new name','');

            AssignFile(myFile, usersFilename);
            Reset(myFile);

            //Find the right record position by searching the file for the namne
            count := 0;
            while not Eof(myFile) do
            begin
              Read(myFile, Customer);
              if Customer.FirstName = oldname then
                recordNumber := count;
              count := count+1;
            end;

            //Seek finds that record in the file and points at it, the read will read the current record
            Seek(myFile, recordNumber) ;
            Read(myFile,Customer) ;
            //Set the new name for that record into our customer record
            Customer.FirstName := newName;
            Customer.LastName := Inputbox('Last Name', '', '');
            Customer.EventDate := Inputbox('Event Date', '', '');
            Customer.SeatNumber := Inputbox('Seat Number', '', '');
            Customer.PhoneNumber := Inputbox('Phone Number', '', '');
            Customer.Adress := Inputbox('Adress', '', '');
            //read moves to the next record, so we have to go back again to the original record, then write
            Seek(myFile, recordNumber);
            //Write the current record which just has the name updated
            Write(myFile, Customer);

            showmessage('Successfully updated name');
            CloseFile(myFile);
        end;

If you could tell me how to make sure it completely removes the original word, instead of just mashing it together with the new word I would greatly appreciate it. Thanks

  • "so that the name in the text file is Mikeander" How are you telling that, from what the program displays next time, or what you can see in the file using e.g. a Hex editor/viewer? – MartynA Jun 05 '14 at 11:25
  • These letters are insignificant anyways because of length indicator. But if you insist, you can "zeroize" desired field with `FillChar`. – Free Consulting Jun 05 '14 at 12:50

1 Answers1

0

If you are talking about the bytes in the actual file, like MartynA and Free Consulting are wondering, then I used to use this procedure to "clean up" garbage in a short string's memory after the actual contents:

{$IFDEF CPUX64 }
PROCEDURE TidyString(VAR STR : OpenString);
  BEGIN
    IF LENGTH(STR)<>HIGH(STR) THEN FillChar(STR[SUCC(LENGTH(STR))],HIGH(STR)-LENGTH(STR),0)
  END;
{$ELSE }
PROCEDURE TidyString(VAR STR : OpenString); ASSEMBLER; PASCAL;
  ASM
            PUSH    EBX
            PUSH    ESI
            PUSH    EDI

            MOV     EDI,STR
            MOVZX   EBX,BYTE PTR [EDI]
            MOV     EDX,EDI
            LEA     EDI,[EDI+EBX+1]
            MOV     ESI,DWORD PTR STR-4
            CMP     ESI,EBX
            JAE     @OK
            MOV     EBX,ESI
            MOV     EDI,EDX
    @LOOP:  MOV     [EDI],BL
            MOV     AL,[EDI+EBX]
            DEC     EBX
            OR      AL,AL
            JZ      @LOOP
            JMP     @OUT
    @OK:    NEG     EBX
            LEA     ECX,[ESI+EBX]
            XOR     AL,AL
            CLD
            REP     STOSB

    @OUT:   POP     EDI
            POP     ESI
            POP     EBX
  END;
{$ENDIF }

Just call TidyString(Customer.FirstName) after setting it, but before saving it. Likewise for all the other fields in the record.

Disclaimer: Only works for Short Strings and thus not for mobile compilers.

HeartWare
  • 7,464
  • 2
  • 26
  • 30
  • I bet that Win32 assembler is not good for most mobile computers anyway. FWIW, the assembler keyword is obsolete, and I don't even know if the pascal keyword has any effect. If it has, it would be pretty non-standard. – Rudy Velthuis Jun 05 '14 at 14:57
  • In this limited version, the PASCAL keyword probably isn't necessary, but in other cases, it ensures that the parameters are passed on the stack, and thus that the routine can start using EAX, EDX and ECX without risking messing up the parameters passed into the routine. If PASCAL isn't specified, the parameter would - in this case - be passed in the EAX register, which would mean that my MOV EDI,STR would actually be taken as MOV EDI,EAX instead of MOV EDI,[EBP+8]. Yes - the ASSEMBLER keyword is optional (I wouldn't call it "obsolete"), but as I said it's a very old routine from long time ago – HeartWare Jun 05 '14 at 15:56
  • Are the mobile compilers 32-bit? Or are they 64-bit? (I don't know - just asking...) – HeartWare Jun 05 '14 at 15:58
  • The mobile Delphi compilers compile to (32 bit, AFAIK) ARM code. That is quite different (and, IMO, a little complicated), and they don't have a built-in assembler. – Rudy Velthuis Jun 05 '14 at 16:00
  • Dunno, this is the first time I have seen the pascal keyword being used since decades ago. I prefer the usual `register` calling convention for my assembly. – Rudy Velthuis Jun 05 '14 at 16:02
  • Yes - the register calling convention is also my preferred use for newer routines. This one was made (as you say) "decades ago" :-). And there's a few instances (even now) where PASCAL calling convention can be more convenient than register calling convention - especially if your code (for some other reason) starts by loading a value into EAX. If, f.ex., you code MOV EAX,12 followed by MOV EDX,Parm1 then using PASCAL calling convention EDX will contain the 1st parameter, whereas in register calling convention, EDX will contain 12, no matter what is passed a the 1st parameter. – HeartWare Jun 05 '14 at 16:16