File "linkbatch.bas"

Path: /linkbatch/linkbatch.bas
File size: 14.57 KB
MIME-type:
Charset: utf-8

' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'     After compilation, drag & drop this executable onto "setdos.exe"    !
' !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#COMPILE EXE "linkbatch.exe"
#RESOURCE "linkbatch.pbr"
#DIM ALL

'------------------------------------------------------------------------------
' Usage: linkbatch "c:\path\to\*.lnk" -Opt1:Field1 "arg 1" "arg 2" -Opt2:Field2...
'------------------------------------------------------------------------------
' List of '-Opt' options:
'   -p = print (display)    ; no argument
'   -w = write (overwrite)  ; 1 argument  = "any string"
'   -r = string replacement ; 2 arguments = "source string" "target string"
'------------------------------------------------------------------------------
' List of Fields:
'   exe = the target .exe path and name
'   arg = the .exe arguments
'   dir = working directory
'   rem = remark or comment
'   ico = icon path (can be .dll, .exe, .ico)
'   idx = icon index, zero based
'------------------------------------------------------------------------------
' Notes:
'   You can operate on a single .lnk, or on all shortcuts in a folder (*.lnk)
'   You can chain as many operations as wanted
'   Options and Fields are case insensitive: you can write -r:exe or -R:EXE
'   Arguments need double quotes only if they contain spaces
'   linkbatch does not make any backup! Make manual backups or be extra careful
'------------------------------------------------------------------------------

'------------------------------------------------------------------------------
'   ** Includes **
'------------------------------------------------------------------------------
#INCLUDE ONCE "WIN32API.INC"
#INCLUDE ONCE "DOSPRINT.INC"
#INCLUDE ONCE "SHORTCUT.INC"
'------------------------------------------------------------------------------

'------------------------------------------------------------------------------
'   ** Main Application Entry Point **
'------------------------------------------------------------------------------
FUNCTION PBMAIN()
    LOCAL lnk   AS LINKTYPE
    LOCAL tgt   AS STRING    ' linkbatch tgt -optn:field arg1 arg2 -optn:field arg1 ...
    LOCAL tgt() AS STRING      ' tgt = tgt() in case of multiple files
    LOCAL ope   AS STRING      ' ope = -optn:feild
    LOCAL optn  AS STRING
    LOCAL feild AS STRING
    LOCAL arg1  AS STRING
    LOCAL arg2  AS STRING
    LOCAL e     AS STRING
    LOCAL i, j  AS LONG
    LOCAL n     AS LONG

    IF COMMAND$ = "" THEN
        CALL FreeConsole() ' Win32 mode -> hide console
        ?"This utility is to be called from the command line."+$CR+$CR _
        +"Please execute Win+R > ""cmd"" and type:"+$CR+"linkbatch /?" _
        , %MB_ICONINFORMATION, "linkbatch"
    END IF

    ' Any argument: parse!
    tgt = TRIM$(COMMAND$(1), ANY $SPC+$TAB+$DQ)

    ' No valid shortcut as first argument > show full usage
    IF RIGHT$(LCASE$(tgt), 4) <> ".lnk" THEN
        ShowFullUsage()
        EXIT FUNCTION
    END IF

    '**************************************************************************
    ' Test existence of target file(s) to operate
    '**************************************************************************
    ' Special case: when called without path, add current path:
    IF INSTR(tgt, "\") = 0 THEN tgt = RTRIM$(CURDIR$, "\") + "\" + tgt
    IF INSTR(tgt, "*") = 0 AND INSTR(tgt, "?") = 0 THEN
        ' Treating a single file
        REDIM tgt(0)
        IF NOT EXISTS(tgt) THEN GOTO ErrFile
        tgt(0) = tgt
    ELSE
        ' Treating multiple files
        n = -1
        e = DIR$(tgt)
        WHILE e <> ""
            INCR n
            REDIM PRESERVE tgt(n)
            tgt(n) = PATHNAME$(PATH, tgt) + e
            e = DIR$(NEXT)
        WEND
        DIR$ CLOSE
        IF n < 0 THEN GOTO ErrFile
    END IF

    n = 2
    '**************************************************************************
    DO  ' Analyze all arguments for errors
    '**************************************************************************

        ' Check valid "-Optn:Field" operation syntax
        ope = TRIM$(LCASE$(COMMAND$(n)), ANY $SPC+$TAB+$DQ)
        IF LEFT$(ope,1) <> "-" OR MID$(ope,3,1) <> ":" THEN GOTO ErrOpe

        ' Get Optn from "-Optn:Field" and test against available options: -p -w -r
        optn = MID$(ope,2,1)
        IF INSTR("pwr", optn) = 0 THEN GOTO ErrOpe

        ' Get Field from "-Optn:Field" and test against allowed fields
        feild = MID$(ope,4)
        IF  feild <> "exe" AND feild <> "arg" AND feild <> "dir" _
        AND feild <> "rem" AND feild <> "ico" AND feild <> "idx" THEN GOTO ErrOpe

        ' All good > analyze arguments
        IF optn = "w" THEN
            ' -w = write = 1 non-empty argument needed
            INCR n
            arg1 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ)
            IF arg1 = "" OR LEFT$(arg1, 1) = "-" THEN GOTO ErrArg

        ELSEIF optn = "r" THEN
            ' -r = replace = 2 non-empty arguments needed
            INCR n
            arg1 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ)
            IF arg1 = "" OR LEFT$(arg1, 1) = "-" THEN GOTO ErrArg
            INCR n
            arg2 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ)
            ' arg2 can actually be an empty string, if we want to
            ' remove something, e.g. linkbatch shortcut.lnk -r:exe " (x86)" ""
            ' to replace "C:\Program Files (x86)\myprog.exe"
            ' with       "C:\Program Files\myprog.exe"  ...
            IF LEFT$(arg2, 1) = "-" THEN GOTO ErrArg

        ELSEIF optn = "p" THEN
            ' -p = print = no argument needed
        END IF

        INCR n
    LOOP UNTIL COMMAND$(n) = ""

    '**************************************************************************
    ' We completed the analysis without meeting any error :)
    ' --> for each target file, run the parsing again
    '     and this time execute the operations!
    '**************************************************************************

    '**************************************************************************
    FOR i = 0 TO UBOUND(tgt) ' For each target file
        DosPrint "File: " + tgt(i)
        ' Parse path and filename
        lnk.zLinkFolder = PATHNAME$(PATH , tgt(i))
        lnk.zLinkName   = PATHNAME$(NAMEX, tgt(i))
        ' And read shortcut information
        ReadShortcut(lnk)

        n = 2
        DO  ' Treat all operations

            ' Get Optn and Field from "-Optn:Field"
            ope   = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ)
            optn  = LCASE$(MID$(ope,2,1))
            feild = LCASE$(MID$(ope,4))

            ' Execute operation!
            SELECT CASE optn
            CASE "p"            ' -p = print (no argument)
                SELECT CASE feild
                CASE "exe" : DosPrint "- " + feild + " = " + lnk.zExeName
                CASE "arg" : DosPrint "- " + feild + " = " + lnk.zArguments
                CASE "dir" : DosPrint "- " + feild + " = " + lnk.zWorkDir
                CASE "rem" : DosPrint "- " + feild + " = " + lnk.zComment
                CASE "ico" : DosPrint "- " + feild + " = " + lnk.zIconFile
                CASE "idx" : DosPrint "- " + feild + " = " + FORMAT$(lnk.IconIndex)
                END SELECT

            CASE "w"            ' -w = write (1 argument)
                INCR n
                arg1 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ)
                SELECT CASE feild
                CASE "exe" : e = $DQ + lnk.zExeName   + $DQ : lnk.zExeName   = arg1
                CASE "arg" : e = $DQ + lnk.zArguments + $DQ : lnk.zArguments = arg1
                CASE "dir" : e = $DQ + lnk.zWorkDir   + $DQ : lnk.zWorkDir   = arg1
                CASE "rem" : e = $DQ + lnk.zComment   + $DQ : lnk.zComment   = arg1
                CASE "ico" : e = $DQ + lnk.zIconFile  + $DQ : lnk.zIconFile  = arg1
                CASE "idx" : e = FORMAT$(lnk.IconIndex)     : lnk.IconIndex = VAL(arg1)
                END SELECT
                DosPrint  "- " + feild + ": " + e + " <<< " + IIF$(LEFT$(e,1)=$DQ,$DQ,"") + arg1 + IIF$(LEFT$(e,1)=$DQ,$DQ,"")

            CASE "r"            ' -r = replace (2 arguments)
                INCR n
                arg1 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ)
                INCR n
                arg2 = TRIM$(COMMAND$(n), ANY $SPC+$TAB+$DQ)
                SELECT CASE feild

                CASE "exe"
                    j = INSTR(LCASE$(lnk.zExeName), LCASE$(arg1))
                    IF j = 0 THEN
                        DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace"
                    ELSE
                        e = lnk.zExeName
                        lnk.zExeName = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1))
                        DosPrint  "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zExeName + $DQ
                    END IF

                CASE "arg"
                    j = INSTR(LCASE$(lnk.zArguments), LCASE$(arg1))
                    IF j = 0 THEN
                        DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace"
                    ELSE
                        e = lnk.zArguments
                        lnk.zArguments = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1))
                        DosPrint  "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zArguments + $DQ
                    END IF

                CASE "dir"
                    j = INSTR(LCASE$(lnk.zWorkDir), LCASE$(arg1))
                    IF j = 0 THEN
                        DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace"
                    ELSE
                        e = lnk.zWorkDir
                        lnk.zWorkDir = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1))
                        DosPrint  "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zWorkDir + $DQ
                    END IF

                CASE "rem"
                    j = INSTR(LCASE$(lnk.zComment), LCASE$(arg1))
                    IF j = 0 THEN
                        DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace"
                    ELSE
                        e = lnk.zComment
                        lnk.zComment = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1))
                        DosPrint  "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zComment + $DQ
                    END IF

                CASE "ico"
                    j = INSTR(LCASE$(lnk.zIconFile), LCASE$(arg1))
                    IF j = 0 THEN
                        DosPrint "- " + feild + ": did not find any " + $DQ + arg1 + $DQ + " to replace"
                    ELSE
                        e = lnk.zIconFile
                        lnk.zIconFile = LEFT$(e, j-1) + arg2 + MID$(e, j+LEN(arg1))
                        DosPrint  "- " + feild + ": " + $DQ + e + $DQ + " <<< " + $DQ + lnk.zIconFile + $DQ
                    END IF

                CASE "idx"
                    IF lnk.IconIndex <> VAL(arg1) THEN
                        DosPrint "- " + feild + ": skipping icon index not equal to " + FORMAT$(VAL(arg1))
                    ELSE
                        e = FORMAT$(lnk.IconIndex)
                        lnk.IconIndex = VAL(arg2)
                        DosPrint  "- " + feild + ": " + e + " <<< " + FORMAT$(VAL(arg2))
                    END IF
                END SELECT

            END SELECT

            INCR n
        LOOP UNTIL COMMAND$(n) = ""

        ' Save modified shortcut
        WriteShortcut(lnk)
        DosPrint ""

    NEXT i

    ' Normal termination
    FUNCTION = 0
    EXIT FUNCTION
    '**************************************************************************


'******
ErrFile:
'******
    DosPrint "Error: no matching file " + $DQ + tgt + $DQ
    FUNCTION = 1
    EXIT FUNCTION

'******
ErrOpe:
'******
    DosPrint "Error: invalid ""-Opt:Field"" operation " + $DQ + ope + $DQ
    DosPrint ""
    ShowShortUsage()
    FUNCTION = 2
    EXIT FUNCTION

'******
ErrArg:
'******
    DosPrint "Error: invalid argument, or number of arguments, for " + $DQ + ope + $DQ
    DosPrint ""
    ShowShortUsage()
    FUNCTION = 3
    EXIT FUNCTION

END FUNCTION
'------------------------------------------------------------------------------

'------------------------------------------------------------------------------
SUB ShowShortUsage()
    DosCol 10, 0
    DosPrint "Usage: linkbatch ""c:\path\to\*.lnk"" -Opt1:Field1 ""arg 1"" ""arg 2"" -Opt2:Field2..."
    DosPrint "  -Opt   = -p (print, 0 arg), -w (write, 1 arg), -r (replace, 2 args)"
    DosPrint "  Fields = exe, arg, dir, rem, ico, idx
    DosPrint "  You can type ""linkbatch /?"" for more details"
    DosCol 7, 0
END SUB
'------------------------------------------------------------------------------

'------------------------------------------------------------------------------
SUB ShowFullUsage()
    DosCol 10, 0
    DosPrint "Usage: linkbatch ""c:\path\to\*.lnk"" -Opt1:Field1 ""arg 1"" ""arg 2"" -Opt2:Field2..."
    DosPrint ""
    DosPrint "List of '-Opt' options:"
    DosPrint "  -p = print (display)    ; no argument"
    DosPrint "  -w = write (overwrite)  ; 1 argument  = ""any string"""
    DosPrint "  -r = string replacement ; 2 arguments = ""source string"" ""target string"""
    DosPrint ""
    DosPrint "List of shortcut ':Fields':"
    DosPrint "  :exe = target .exe path and name"
    DosPrint "  :arg = executable arguments"
    DosPrint "  :dir = working directory"
    DosPrint "  :rem = remark or comment"
    DosPrint "  :ico = icon path (.dll, .exe, .ico)"
    DosPrint "  :idx = icon index, zero based"
    DosPrint ""
    DosPrint "Notes:"
    DosPrint "  You can operate on a single .lnk, or on all shortcuts in a folder (*.lnk)"
    DosPrint "  You can chain as many operations as wanted"
    DosPrint "  Options and Fields are case insensitive: you can write -r:exe or -R:EXE"
    DosPrint "  Target .lnk and arguments need double quotes only if they contain spaces"
    DosPrint "  linkbatch does not make any backup! Please backup your shortcuts manually"
    DosCol 7, 0
END SUB
'------------------------------------------------------------------------------

'------------------------------------------------------------------------------
FUNCTION EXISTS(BYVAL fileOrFolder AS STRING) AS LONG
    LOCAL Dummy&
    Dummy& = GETATTR(fileOrFolder)
    FUNCTION = (ERRCLEAR = 0)
END FUNCTION
'------------------------------------------------------------------------------