! fntempfile.bsi [103]  - functions related to temporary files
!------------------------------------------------------------------------
!EDIT HISTORY
!Version 1.0:-
! [103] 24-Jan-24 / jdm / fix syntax error 
! [102] 06-Sep-23 / jdm / add keywords for funcidx, ifdef; minor cleanup
! [101] 23-Nov-18 / jdm / Add Fn'Temp'Dir$
! [100] 30-Jul-17 / jdm / created
!----------------------------------------------------------------------
!REQUIREMENTS
!
!NOTES
!KEYWORDS: file path directory temp
!------------------------------------------------------------------------
!FUNCTIONS:
! Fn'Temp'File'Spec$(flags, fspec$) - generate temp file name
! Fn'Temp'File'Unique$(flags, fspec$) - makes fspec$ unique
! Function Fn'Temp'Dir$() - return just temp dir (with trailing sep) [101] 
!------------------------------------------------------------------------

++ifnlbl Fn'Temp'File'Spec$()

++include'once ashinc:ashell.def
++include'once ashinc:types.def
++include'once ashinc:csidl.def
++include'once sosfunc:fnameext.bsi
++include'once sosfunc:fnbase36.bsi

define TMPF_UNQEXT    = &h0001  ! force unique extension (name.###)
define TMPF_UNQSUFFIX = &h0002  ! force unique suffix (name-###.ext)
define TMPF_UNIQUE    = &h0003  ! union of above flags

define TMPF_SEQ       = &h0004  ! (with unique) qualifier is sequential (else random)
define TMPF_TMPEXT    = &h0010  ! force .tmp extension (default if no fspec$ specified)
define TMPF_CURDIR    = &h0020  ! use current directory
define TMPF_JOBNAME   = &h0040  ! use jobname as filename base (if no fspec$ specified)
define TMPF_USERNAME  = &h0080  ! use username as filename base (if no fspec$ specified)
                                
!define TMPF_APEX      = &h0008  ! use APEX dir (if defined)
!define TMPF_ATECLI    = &h0010  ! generate name relative to ATE client

!---------------------------------------------------------------------
!Function:
!   Generate a temporary file name
!Params:
!   flags  (b,4) [in] - (optional) misc flags - see TMPF_xxx
!   fspec$ (str) [in] - (optional) fspec$ to use as basis
!Returns:
!   temp file spec
!Globals:
!Notes:
!   default location depends on environment:
!       ATE client-side calls use %ATECACHE%
!       UNIX server-side calls use %ASHTMP%
!   default is to just create file ash-yymmddhhmmss#.tmp in the
!   system temp directory.
!
!Examples:
!   Fn'Temp'File'Spec$() ...
!           /tmp/170731091423.tmp  (UNIX)
!           c:\users\jack\AppData\Local\Temp\170731091423.tmp  (Win)

!   Fn'Temp'File'Spec$(fspec$="c:\vm\miame\dsk0\100100\test.prt")  ...
!           /tmp/test.prt (UNIX)
!           c:\users\jack\AppData\Local\Temp\test.prt   (Win)
!
!   Fn'Temp'File'Spec$(TMPF_UNIQUE+TMPF_SEQ+TMPF_CURDIR,"c:\vm\miame\dsk0\100100\test.prt")  ...
!           ./test-1.prt (UNIX)
!           .\test-1.prt (Win)
!
!   Fn'Temp'File'Spec$(TMPF_UNIQUE+TMPF_CURDIR+TMPF_JOBNAME) ...
!           ./tskaab-17073109142357.tmp  (UNIX)
!           .\tskaab-17073109142357.tmp  (Win)
!
!   Fn'Temp'File'Spec$(TMPF_CURDIR+TMPF_JOBNAME) ...
!           ./tskaab.tmp  (UNIX)
!           .\tskaab.tmp  (Win)
!
!---------------------------------------------------------------------
Function Fn'Temp'File'Spec$(flags as b4:inputonly, fspec$ as T_NATIVEPATH:inputonly) as T_NATIVEPATH        

    map1 locals
        map2 dirsep$,s,1
        map2 datetime$,s,12         ! yymmddhhmmss
        map2 dir$,T_NATIVEPATH
        map2 base$,s,200
        map2 x,i,2
        map2 suffix,b,4
        map2 ext$,s,4

    if flags and TMPF_CURDIR then     ! [101] handle current dir option locally [103] 
        xcall MIAMEX, MX_DIRSEP, dirsep$        
        dir$ = "." + dirsep$
                                    ! [101] else use separate routine to get temp dir
    else
        dir$ = Fn'Temp'Dir$()
    endif
 
    ! now dir$ should contain the directory with trailing separator
    ! next decide on base filename
    
    if fspec$ # "" then             ! if fspec passed, use it's base filename
        base$ = Fn'Name'Ext$(fspec$)
        x = instr(1,base$,".")
        if x then
            ext$ = base$[x,-1]
            base$ = base$[1,x-1]
        endif
    elseif flags and TMPF_USERNAME then
        base$ = .USERNAME
    elseif flags and TMPF_JOBNAME then
        base$ = .JOBNAME
    endif

    if ext$ = "" or (flags and TMPF_TMPEXT) # 0 then
        ext$ = ".tmp"
    endif

    if base$ = "" then
        datetime$ = .YYMMDD + odtim(0, 0, &h21001)   ! yymmdd hhmmss
        base$ = datetime$
    endif

    ! assemble the parts
    .fn = dir$ + base$ + ext$
    
    ! and check for unique
    if flags and TMPF_UNIQUE then
        .fn = Fn'Temp'File'Unique$(flags, dir$ + base$ + ext$)
    endif
    
    debug.print (99,"tempfile") "Fn'Temp'File'Spec$", flags, fspec$, .fn
EndFunction


!---------------------------------------------------------------------
!Function:
!   adjust a file spec to make it unique (i.e. doesn't exist on disk)
!Params:
!   flags (num) [in] - just the TMPF_UNIQUE and TMPF_SEQ flags from Fn'Temp'File'Spec$()
!   fspec$ (str) [in] - fspec to adjust so as to be unique
!Returns:
!   unique version of fspec$ 
!Globals:
!Notes:
!   Two methods are used:
!       adding a suffix, i.e. name-###.ext
!       changing the extension, i.e. name.###
!   For each method, we can either generate random (default)
!   or sequential versions.  The random version uses 3 base36 digits
!   (46656 possibilities); the sequential version uses 1-999. 
!Examples:
!   name.001, name.002, ...     (TMPF_UNQEXT+TMPF_SEQ)
!   name-1.ext, name-2.ext, ... (TMPF_UNQSUFFIX+TMPF_SEQ)
!---------------------------------------------------------------------
Function Fn'Temp'File'Unique$(flags as b4:inputonly, fspec$ as T_NATIVEPATH:inputonly) as T_NATIVEPATH

    map1 locals
        map2 dirsep$,s,1
        map2 datetime$,s,12         ! yymmddhhmmss
        map2 dir$,T_NATIVEPATH
        map2 base$,T_NATIVEPATH
        map2 x,i,2
        map2 qualifier,b,4
        map2 qualifier$,s,3
        map2 ext$,s,4
        map2 tries,b,4

    ! if no unique flags set, or no fspec$, just exit
    if fspec$ = "" or (flags and TMPF_UNIQUE) = 0 then
        exitfunction
    endif
    
    ! deconstruct fspec$ into its parts
    x = instr(1,fspec$,".")
    if x then
        ext$ = fspec$[x+1,-1]
    elseif not flags and TMPF_UNQEXT
        ext$ = "tmp"
    endif
    base$ = fspec$[1,x-1]       ! dir + fname (without ext)    
    
    do 
        tries += 1
        if flags and TMPF_SEQ            ! sequential qualifiers 1, 2, ...
            qualifier += 1
            if flags and TMPF_UNQEXT
                qualifier$ = qualifier using "##Z"      ! .001, .002, ...
            else
                qualifier$ = str(qualifier)              ! -1.ext, -2.ext, ...
            endif
        else                                ! random
            xcall TIMES, 2, qualifier       ! # msecs since midnight (reasonable random proxy)
            qualifier$ = Fn'DecToBase36$(qualifier mod 46655,3)    ! XXX
        endif

        if flags and TMPF_UNQEXT     !   unique qualifier is ext (name.###)
            .fn = base$ + "." + qualifier$
        else                            ! else suffix (name-###.ext)
            .fn = base$ + "-" + qualifier$ + "." + ext$
        endif
        debug.print (99,"tempfile") "lookup", .fn
        if lookup(.fn) = 0 exit
    loop
    
    debug.print (99,"tempfile") "Fn'Temp'File'Unique$",flags,fspec$,.fn,tries
EndFunction


!---------------------------------------------------------------------
!Function:
!   Return temp dir spec
!Params:
!Returns:
!   temp dir with trailing separator
!Globals:
!Notes:
!   Use %ASHTMP% if avail, else %TEMP% for Windows and /tmp for UNIX
!   (Carved out of Fn'Temp'File'Spec$()
!---------------------------------------------------------------------
Function Fn'Temp'Dir$() as T_NATIVEPATH

    map1 locals
        map2 dirsep$,s,1
        
    ! decide on directory    
    xcall MIAMEX, MX_DIRSEP, dirsep$        
    
    ! first preference is %ASHTMP%
    xcall MIAMEX, MX_GETENV, "ASHTMP", .fn, 1
    
    ! if not defined then proceed to defaults based on OS
    if .fn = "" then
        if dirsep$ = "/" then           ! UNIX temp dir
            .fn = "/tmp" 
        else                            ! Windows temp dir
            xcall MIAMEX, MX_GETENV, "TEMP", .fn, 1
            if .fn = "" then
                xcall MIAMEX, MX_GETENV, "TMP", .fn, 1
                if .fn = "" then
                    xcall MIAMEX, MX_GETSHELLPATH, CSIDL_LOCAL_APPDATA, .fn, "L"
                endif
            endif
        endif
    endif
    if .fn # "" and .fn[-1,-1] # dirsep$ then
        .fn += dirsep$         ! add trailing sep
    endif

EndFunction

++endif
