Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 14:29 16 May 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Auto Backup

Author Message
elk1984

Senior Member

Joined: 11/07/2020
Location: United Kingdom
Posts: 227
Posted: 05:32pm 22 Oct 2020
Copy link to clipboard 
Print this post

After breaking my program (the dreaded line too long followed by a corrupted file), I've created an include that can be embedded in any program that will automatically create a copy every time it is run, and retain a set number of versions.

Comments welcome - I hope people find it useful.

OPTION BASE 0
OPTION EXPLICIT
OPTION DEFAULT NONE

'******************************************************************************************
' Filename: sub-backup-program.inc
' Author  : elk1984
' Version : 1.0
' Date    : 22 October 2020
'
' Description:
' Automatic Backup Routine to prevent file loss, the dreaded "line too long" error or
' to protect against bad edits.
'
' Usage:  
' Add into your main program
' #Include "sub-backup-program.inc"
' DoBackup(<NumVersion>, <ShowDetail>)
'
' Where <NumVersion> is an integer of the number of versions to keep
' And <ShowDetail> is an integer; 0 = silent, 1+ = show increasing levels of debug information
'
'******************************************************************************************

SUB DoBackup(versions As Integer, showDetail As Integer)
 LOCAL thisDate As String = IsoDate(date$)
 LOCAL thisTime As String = ReplaceText(time$,":","-")
 LOCAL fullPath As String = MM.INFO$(CURRENT)
 LOCAL directory As String = LEFT$(fullPath,LastIndexOf(fullPath,"/"))
 LOCAL fileName As String = RIGHT$(fullPath,LEN(fullPath)-LEN(directory))
 LOCAL extension As String = RIGHT$(fileName,LEN(fileName)-LastIndexOf(fileName,"."))
 LOCAL fileOnly As String = LEFT$(fileName,LEN(fileName)-LEN(extension)-1)
 LOCAL backupFileName As String = fileOnly+"."+thisDate+"."+thisTime+"."+extension
 LOCAL cleanupSpec As String = directory + fileOnly+".*.*."+extension

 LOCAL currentWorking As String = CWD$

 CHDIR directory

 IF ShowDetail>=1 THEN  
   PRINT "Backing Up Program "
   PRINT "Full Path        : " + fullPath
   PRINT "Directory        : " + directory
   PRINT "File Name        : " + fileName
   PRINT "File Only        : " + fileOnly
   PRINT "Extension        : " + extension
   PRINT "Backup Name      : " + backupFileName
   PRINT "Date             : " + thisDate
   PRINT "Time             : " + thisTime
   PRINT "Versions To Keep : " + STR$(Versions)
   PRINT "Cleanup Spec     : " + cleanupSpec
 END IF

 IF showDetail>=2 THEN PRINT "Creating backup of " + fileName + " called " + backupFileName

 IF versions > 0 THEN
   COPY fileName TO backupFileName
 END IF
 
 IF showDetail>=2 THEN PRINT "Clearing Up Old Versions.  Retaining " + str$(versions) + " of files matching " + cleanupSpec
 ManageVersions(cleanupSpec, versions, showDetail)

 CHDIR currentWorking
END SUB

'******************************************************************************************

SUB ManageVersions(fileSpec As String, versionCount As Integer, showDetail as Integer)
 LOCAL backupFile As String = DIR$(fileSpec,FILE)
 LOCAL backupFilesFound As Integer = 0
 LOCAL i As Integer = 0
 LOCAL currentWorking As String = CWD$

 'Find the number of matching files to generate a correctly sized array
 DO WHILE backupFile <> ""
   backupFilesFound = backupFilesFound + 1
   backupFile = DIR$()
 LOOP

 IF backupFilesFound > versionCount THEN

   'Create and fill array of filenames
   LOCAL backupFiles(backupFilesFound) As String  
 
   'Change into the directory of the fileSpec
   CHDIR LEFT$(fileSpec,LastIndexOf(fileSpec,"/"))
   
   backupFile = DIR$(fileSpec,FILE)
   
   IF backupFile <> "" THEN
     DO
       backupFiles(i) = backupFile
       backupFile = DIR$()
       i = i + 1
     LOOP UNTIL backupFile = ""
   END IF
   
   'Sort array ascending
   SORT backupFiles()
   
   'Loop backwards through the file collection to remove versions > version count
   i = backupFilesFound-1
   DO
     IF backupFilesFound-i > versionCount-1 THEN
       IF showDetail>=2 THEN PRINT "Removing File " + backupFiles(i)
       IF backupFiles(i) <> "" THEN
         KILL backupFiles(i)
       END IF
     END IF
 
     IF showDetail>=3 THEN
       PRINT backupFilesFound-i,versionCount,backupFiles(i)
     END IF
     i=i-1
   LOOP UNTIL i < 0
 
   'Cleanup    
   CHDIR currentWorking
   ERASE backupFiles
 END IF

 'Cleanup
 ERASE backupFile
 ERASE backupFilesFound
 ERASE i
END SUB

'******************************************************************************************

FUNCTION IsoDate(inputDate As String) As String
 IsoDate = RIGHT$(inputDate,4) + "-" + MID$(inputDate,4,2) + "-" + LEFT$(inputDate,2)
END FUNCTION

'******************************************************************************************

FUNCTION ReplaceText(inputString As String, textToReplace As String, replacementString As String) As String
 LOCAL foundPosition As Integer = 1
 LOCAL lastFoundPosition As Integer = 1
 LOCAL newString As String = ""
 LOCAL preFindString As String = ""
 LOCAL postFindString As String = ""

 lastFoundPosition=foundPosition
 foundPosition=INSTR(inputString, textToReplace)
 
 IF foundPosition > 0 THEN
   'Replace The Found Text
   preFindString=MID$(inputString,lastFoundPosition,foundPosition-1)
   postFindString = MID$(inputString,foundPosition+LEN(textToReplace),LEN(inputString)-foundPosition+LEN(textToReplace))
   newString=preFindString + replacementString + postFindString

   'Search for the next instance by recursing the string
   newString=ReplaceText(newString, textToReplace, replacementString)
 ELSE
   newString=inputString
 END IF

 ReplaceText=newString
END FUNCTION

'******************************************************************************************

FUNCTION LastIndexOf(inputString As String, textToFind As String) As Integer
 LOCAL foundPosition As Integer = 1
 LOCAL lastFoundPosition As Integer = 1

 DO
   lastFoundPosition=foundPosition
   foundPosition=INSTR(foundPosition+1,inputString, textToFind)
 LOOP UNTIL foundPosition=0
 
 LastIndexOf=lastFoundPosition
END FUNCTION

'******************************************************************************************

 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3861
Posted: 06:00pm 22 Oct 2020
Copy link to clipboard 
Print this post

Hi "elk1984",

That does look like a useful set of functionality.

The editor does create a single backup now though anyway which I would have thought
was sufficient protection against the dreaded line too long / file corruption ?

Why are you bothering with those ERASE statements though? those LOCALs will be cleaned up automatically when the SUB ends.

Tom.
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
elk1984

Senior Member

Joined: 11/07/2020
Location: United Kingdom
Posts: 227
Posted: 07:08pm 22 Oct 2020
Copy link to clipboard 
Print this post

  thwill said  The editor does create a single backup now though anyway which I would have thought was sufficient protection against the dreaded line too long / file corruption ?


Yes, the editor creating a backup does cover line too long.  I noticed editor has that feature in the newer versions of the Firmware than I'm running, but sometimes it's useful to have previous versions of the file in case of "user error" like messing up code when refactoring.

  thwill said  Why are you bothering with those ERASE statements though? those LOCALs will be cleaned up automatically when the SUB ends.


Thanks - I didn't realise I got that for free  
Edited 2020-10-23 05:08 by elk1984
 
thwill

Guru

Joined: 16/09/2019
Location: United Kingdom
Posts: 3861
Posted: 07:26pm 22 Oct 2020
Copy link to clipboard 
Print this post

  elk1984 said  ...sometimes it's useful to have previous versions of the file in case of "user error" like messing up code when refactoring.


Hmmm ... might be better if we could write a wrapper around EDIT that compared the current state of the file with the last "versioned" state and if they were different created a new version.

Unfortunately even using EXECUTE we cannot run EDIT from within a program:
Error in line X: Invalid in a program


@matherp, if you see this, is there a good reason for this limitation or did you just think it was a nuts thing for us to want to do ?

Best wishes

Tom
Game*Mite, CMM2 Welcome Tape, Creaky old text adventures
 
elk1984

Senior Member

Joined: 11/07/2020
Location: United Kingdom
Posts: 227
Posted: 07:30pm 22 Oct 2020
Copy link to clipboard 
Print this post

  thwill said  
  elk1984 said  ...sometimes it's useful to have previous versions of the file in case of "user error" like messing up code when refactoring.


Hmmm ... might be better if we could write a wrapper around EDIT that compared the current state of the file with the last "versioned" state and if they were different created a new version.

Unfortunately even using EXECUTE we cannot run EDIT from within a program:
Error in line X: Invalid in a program


@matherp, if you see this, is there a good reason for this limitation or did you just think it was a nuts thing for us to want to do ?

Best wishes

Tom


That's a good idea.  I'll incorporate a hash check into the next version  

I'm currently wrestling (without much success) with MMEdit, but I'll start a different thread for that....
 
elk1984

Senior Member

Joined: 11/07/2020
Location: United Kingdom
Posts: 227
Posted: 05:12pm 27 Oct 2020
Copy link to clipboard 
Print this post

New version created - backups are now only created if the source file has been modified and no backup exists.

sub-backup-program.zip
 
elk1984

Senior Member

Joined: 11/07/2020
Location: United Kingdom
Posts: 227
Posted: 05:45pm 27 Oct 2020
Copy link to clipboard 
Print this post

And another quick update

sub-backup-program.zip
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024