cCmdLineArgs

Clase para desglosar (de forma práctica e inteligente) los argumentos pasados a nuestra aplicación de VB

 

Publicado el 07/Feb/2005
Revisión del 07/Feb/2005
Autor: Guillermo 'guille' Som

 

 


Introducción (te lo puedes saltar si no quieres leer batallitas)

En Septiembre del 97 (como pasa el tiempo), publiqué una utilidad para desglosar los argumentos indicados en nuestra aplicación. Y la cosa es que el código estaba bien y hacía su trabajo, es decir tomar la línea de comandos pasada a nuestra aplicación y crear un array con cada uno de los argumentos, algo parecido a lo que la función main de C hace, es más, en ese código llamé a las variables de la misma forma que en C: argv para el array y argc para el número de argumentos, (en esta nueva versión también he dejado esos nombres).

Realmente el código hacía lo mismo que en C (o ahora en C# y VB .NET), es decir, cada una de las "palabras" indicadas en la línea de comandos la incluía en un elemento del array. He dicho "palabras" porque realmente cada argumento se "supone" que debe estar separado del anterior con un espacio, aunque lo habitual también es que esos argumentos se indiquen usando los caracteres de la barra invertida (/) o el signo menos (-), y ese código comprobaba estos dos casos y si se los encontraba los guardaba en un elemento del array creado. También se tenían en cuenta lo que estuviera entre comillas dobles, que es lo que se suele hacer cuando queremos que en uno de los argumentos se puedan indicar espacios.

 

¿Qué hay de nuevo viejo?

Pero este nuevo código que te voy a mostrar no hace exactamente lo mismo que el código que publiqué hace casi 8 años, ya que no tendría demasiado sentido... y el cambio no es por el hecho de que ahora está incluido en una clase... sino porque ahora, (como dice el subtítulo), lo hace de forma más inteligente y, por lo tanto, más práctica.

Me explico.
Si antes teníamos esta línea de comandos (donde prueba.exe es el nombre del programa):

prueba.exe /f prueba.txt /c

El array contendría 3 elementos: /f, prueba.txt y /c

Si lo miramos bien, realmente /f prueba.txt debería ser un solo argumento y /c otro, por tanto nos podría ser de más utilidad tener la posibilidad de que en esos casos, se pudieran "agrupar" argumentos (teóricamente) relacionados.

Y esa es una de las cosas que el nuevo código que te muestro "sabe" hacer. Aunque también se puede seguir usando de la forma "clásica", es decir: cada argumento es un elemento del array.

Pero esta (que realmente es útil) no es la única novedad, ya que la clase cCmdLineArgs también hace otras cosas, como por ejemplo poder comprobar si un determinado "argumento" se ha indicado o saber el índice en el que está el argumento que nos interesa para posteriormente poder acceder a él usando un valor numérico, el cual podemos usar para eliminarlo o tomar el valor "asociado" a ese argumento.
También podemos indicarle que no permita argumentos repetidos o que distinga los nombres de los argumentos si se escriben en minúsculas o mayúsculas, e incluso poder decirle cuales son los argumentos permitidos, de forma que sólo guarde los indicados y el resto no los tenga en cuenta.

Como ves tiene "cosillas" que realmente le da un valor añadido y sin tener que pagar impuestos... chiste malo, lo se... je, je, je.

Esta clase puede procesar la línea de comandos pasada a la aplicación (Command$) o bien una cadena creada por nosotros, aunque lo normal es que procese los argumentos indicados a la aplicación.

 

Los miembros de la clase

A continuación te hago una lista con los métodos y propiedades que tiene esta clase junto con una pequeña descripción. Más adelante veremos el código para poder usarlos.
 

Nombre Descripción
Argc El número de argumentos.
Si se "asocian" argumentos, indica el total una vez asociados.
Argv Permite acceder a cada argumento mediante un índice numérico.
Aunque se utiliza como un array, solo es de lectura.
GetArgv Devuelve el array interno.
Realmente devuelve una copia, por tanto cualquier cambio al array devuelto no afecta al de la clase.
HayAlgunSeparador Indica si hay argumentos que incluya un separador (/ o -)
Clear Elimina todo lo que hubiera y reinicia los valores predeterminados.
Para cuando queremos volver a procesar otra línea de comandos.
CmdLine2Arg Esta es la función principal que se encarga de "desglosar" la línea de comandos.
Permite indicar una cadena creada por nosotros o, lo habitual, procesar el contenido de Command$, que es la que contiene los argumentos indicados al llamar a la aplicación.

En los argumentos de la línea de comandos se puede indicar como separador el signo / o el de la resta (-), pero cuando se procesa la línea de comandos, se guarda con el signo -, por tanto en posteriores "búsquedas" debemos indicar siempre el signo - (aunque originalmente hayamos usado /), esto es así, para evitar tener que hacer dobles comprobaciones por si el usuario ha usado uno u otro.
Desglosar Como la anterior, pero aquí se debe indicar la cadena a desglosar.
DiferenciarCase Para diferenciar mayúsculas de minúsculas.
El valor que puede tener es el usado por el propio VB para hacer comparaciones binarias (distingue mayúsculas de minúsculas) o comparaciones de texto (no distingue el "case").
Los valores que puede tener son los de la enumeración eTipoCompare.
El valor predeterminado es TextCompare (no diferenciar).
EntreSeparadores Para indicar si debemos asociar los argumentos dependiendo de que se usen los separadores / o -.
Los valores que puede tener son los de la enumeración: eOpSeparador.
El valor predeterminado es Ninguno.
GetArgument Devuelve el argumento asociado con el argumento con separador indicado.
Por ejemplo, si tenemos -f prueba.txt e indicamos -f, devolverá prueba.txt
También se puede indicar sin separador, pero realmente no tiene ninguna utilidad, ya que cuando un argumento no tiene separador, no hay "otro" argumento asociado.
GetArgumentByIndex Devuelve el valor asociado al argumento del índice numérico indicado.
No confundir este método con la posibilidad de acceder al argumento que estén en la posición indicada por el índice, para eso está el método Argv.
GetArgumentNumber Nos indica el índice dentro del array del argumento indicado.
Permitidos Una cadena con los argumentos permitidos.
Cada argumento se indicará sin el signo separador y se separarán usando punto y coma y sin ningún espacio extra.
Por ejemplo:
"c;f;x;help;h;?"
PermitirDuplicados Si se permiten argumentos con el mismo nombre.
Si no diferenciamos el "case" y PermitirDuplicados es False, no se aceptarán dos argumentos que se diferencien solo por mayúsculas y minúsculas.
El valor es True (permitir duplicados)
RemoveArgument Quita el argumento indicado.
Opcionalmente se le puede decir que también quite el argumento asociado, si es que el que hemos indicado tiene separador.
Por ejemplo, si tenemos -f prueba.txt
Usándolo con RemoveArgument "-f", quitaría solo el -f, dejando prueba.txt
Usándolo con RemoveArgument "-f", True, quitará los dos.
RemoveArgumentByIndex Como el anterior, pero en lugar de indicar el "nombre" del argumento, usamos un índice numérico.
Este índice deberíamos obtenerlo con GetArgumentByIndex.
eTipoCompare Enumeración para el tipo de comparación.
BinaryCompare, hace distinción entre mayúsculas y minúsculas.
TextCompare, no diferencia mayúsculas de minúsculas.

Estos son los mismos valores usados por VB, particularmente con la función StrComp.
eOpSeparador Enumeración para usar con la propiedad EntreSeparadores.
Ninguno, se toma cada argumento de forma independiente.
SeparadorArgumento, Cualquier separador o argumento al principio.
SoloSeparadores, Solo agrupar por separadores explícitos.

Tabla 1. Los miembros de la clase

 

Antes del código, ejemplos de cómo usarla

Para que lo veas todo más claro y comprendas mejor cómo funciona todo esto que te digo, he creado una pequeña aplicación en la que puedes probar algunas de las características de la clase.
En las siguientes capturas de la aplicación de prueba en plena ejecución, puedes ver cómo hace el trabajo, según las opciones indicadas:

En la figura 1 vemos un desglose "normal", es decir, cada argumento como un elemento del array.
 


Figura 1. Esta sería la forma "normal" de usarlo

 

En la figura 2 le decimos que NO permita duplicidad en los argumentos y como no hemos indicado que diferencie entre mayúsculas y minúsculas (la opción está oculta por el tip), ha quitado el argumento -F ya que existe otro anterior.
 


Figura 2.

 

En la figura 3 le decimos que "asocie" los argumentos, de forma que si encuentra uno que tenga cualquiera de los separadores (/ o -) y lo que sigue no tiene separador, pues lo une como un solo argumento.
 


Figura 3.

 

En la figura 4 es como la anterior, pero no permite duplicados.
 


Figura 4.

 

En la figura 5 le hemos indicado que solamente acepte los argumentos que contengan separadores.
 


Figura 5.

 

En la figura 6, le hemos indicado que solamente procese los argumentos permitidos, además de que los "asocie" y distinga mayúsculas de minúsculas.
 


Figura 6.

 

 

En todas estas figuras tienes las distintas combinaciones que podemos hacer mediante las propiedades de la clase. Pero también tenemos unos métodos que nos pueden ser de bastante utilidad para procesar de forma más "fácil" los argumentos indicados.

En la mayoría de aplicaciones que permiten argumentos en la línea de comandos, por ejemplo un compilador, suele permitirse que se indiquen de varias formas, lo habitual es que el mismo "comando" tenga una versión larga y otra corta, (con lo que se consigue hacer cierto eso que a muchos nos gustaría que fuese una "VERDAD INDISCUTIBLE" de que el tamaño NO importa, je, je), por ejemplo -help y -h.
Esas aplicaciones incluso permiten usar indistintamente los separadores - o /, por ejemplo /help o -help.
Por eso, esta clase, una vez procesados los argumentos, siempre usa - para indicar un argumento con separador, porque debemos tener en cuenta que también pueden existir argumentos que no tengan separadores, (aunque no es lo habitual), por ejemplo podríamos aceptar help sin necesidad de usar un separador.
A lo que iba, si queremos comprobar si el usuario ha indicado, por ejemplo, -buscar o -b, suponiendo que esas dos opciones realicen la misma operación y que se usen con el texto a buscar, por ejemplo:
-b "una frase con espacios" o -buscar elGuille, podríamos comprobarlo de esta forma:

n = cmd.GeArgumentNumber("-b")
If n = 0 Then
    n = cmd.GeArgumentNumber("-buscar")
End If
If n > 0 Then
    ' se ha indicado, ahora obtenemos lo que se ha indicado en ese argumento
    s = cmd.GetArgumentByIndex(n)
End If

Si después de tener lo que ha indicado el usuario queremos eliminar ese argumento (con el correspondiente valor asociado), podemos hacerlo de esta forma:

cmd.RemoveArgumentByIndex n

¿Que utilidad tiene quitar un argumento?
Imagínate que en tu programa se esperan ciertos valores de forma secuencial, por ejemplo, un path seguido de una especificación, pero también quieres que se puedan usar otras opciones, como incluir subdirectorios y que se pueda indicar un fichero en el que guardar los resultados, etc. Por ejemplo:
miprograma.exe C:\Pruebas *.txt -subdir -resultado fichero.log

Pero lo que no quieres es "obligar" al usuario a que lo indique "exactamente" así, (entre otras cosas, porque suele pasar de hacer las cosas bien o como se deben hacer... si lo sabré yo); en esos casos podrías ser permisivo y dejar que, salvo los dos parámetros obligatorios, los argumentos opcionales los ponga como le de la gana, por ejemplo:
miprograma.exe  -subdir C:\Pruebas *.txt -resultado fichero.log
E incluso rizando el rizo:
miprograma.exe C:\Pruebas -resultado fichero.log *.txt -subdir

En estos casos, comprobaríamos si existen los argumentos opcionales, guardamos los valores correspondientes, los quitamos y después tranquilamente podemos tomar los valores en el orden que deben ser indicados. De esta forma podríamos "aliviar" al usuario para que no tenga que indicar un argumento separador para cada uno de los parámetros (aunque es lo mejor y lo que queda más claro), por ejemplo:
miprograma.exe -dir C:\Pruebas -resultado fichero.log -ext *.txt -subdir
 

Para tu información, lo he hecho porque en un programilla que he "remodelado" hace poco he añadido cantidad de opciones y una de las formas de usarlo es como acabo de explicarte, además de la forma "larga" como en el último ejemplo.

Ahora, ya ¡por fin!

El código de la clase

Aquí tienes el código de la clase, el de la aplicación que utiliza este código, te lo puedes bajar del link que hay más abajo.

Realmente tienes que irte al final de la página para ver el código o bien pulsar el link.

 

Y esto ha sido todo, como siempre espero que te sea de utilidad y que si te sobra algo de calderilla (en tu tarjeta de crédito), te acuerdes de aportar algo mediante Paypal... je, je, por pedir que no quede.
Gracias.

 

Nos vemos
Guillermo
Nerja, 7 de Febrero de 2005

El link con el código fuente, tanto de la clase como del ejemplo: LineaComandos2.zip 26.9 KB
 


El código de cCmdLineArgs

El código está más o menos bien comentado, así que espero que tengas claro lo que hace cada uno de los "miembros" de la clase.

'------------------------------------------------------------------------------
' cCmdLineArgs                                                      (01/Feb/05)
' Clase para manejar las opciones de la línea de comandos (argumentos)
'
' Basado en: (Cmd2argv.bas)
'   Módulo para desglosar los parámetros de la línea de comandos
'   Primera versión:   30/Sep/97
'
' Esta clase tendrá estas características:
'   -De forma predeterminada cada parámetro será lo que esté separado por:
'       el guión (-)
'       la barra (/)
'       espacio
'       tabulador
'       entre comillas dobles
'   -Podemos indicar los nombres de los parámetros a tener en cuenta
'       En ese caso el resto de parámetros se ignorará
'   -Podemos indicar que los datos asociados a un parámetro
'    se comprueben hasta encontrar -, / o el final de línea
'
'   -Permitir (o no) parámetros duplicados
'
' ©Guillermo 'guille' Som, 1997, 2005
'------------------------------------------------------------------------------
Option Explicit

' Los valores deben corrsponderse con vbBinaryCompare y vbTextCompare
Public Enum eTipoCompare
    BinaryCompare   ' Se diferencia entre mayúsculas y minúsculas
    TextCompare     ' NO se diferencia entre mayúsculas y minúsculas
End Enum

' Para agrupar por separadores
Public Enum eOpSeparador
    Ninguno             ' No se tiene en cuenta
    SeparadorArgumento  ' Cualquier separador o argumento al principio
    SoloSeparadores     ' Solo agrupar por separadores explíctos
End Enum

Public HayAlgunSeparador        As Boolean      ' si alguno tiene separador

Private m_EntreSeparadores      As eOpSeparador ' para emparejar los parámetros
Private m_PermitirDuplicados    As Boolean      ' si se permiten duplicidades
Private m_DiferenciarCase       As eTipoCompare ' comparación binaria o de texto
Private nPerm                   As Long         ' número de parámetros permitidos
Private mPermitidos             As Boolean      ' si se comprueban los permitidos
Private aPermitidos()           As String       ' para los parámetros permitidos
Private m_Argv()                As String       ' Contenido de cada argumento

Const SEP_PERM                  As String = ";" ' el separador de parámetros
Const sepArg                    As String = "-/"

Public Argc             As Long         ' número de argumentos (de 1 a Argc)

'----------------------------------------------------------------------
' GetArgs
'
' Recupera una copia de los argumentos
'----------------------------------------------------------------------
Public Function GetArgs() As String()
    GetArgs = m_Argv
End Function

'----------------------------------------------------------------------
' Argv
'
' Para acceder a cada elemento del array de argumentos
'----------------------------------------------------------------------
Public Function Argv(ByVal index As Long) As String
    If index < 1 Or index > Argc Then
        Argv = ""
    Else
        Argv = m_Argv(index)
    End If
End Function

'----------------------------------------------------------------------
' Permitidos
'
' Indicar los parámetros permitidos
' Estarán en una cadena separados por ;
' (no indicar el separador, se supone - o /)
' Por ejemplo:
'   "x;imprimir;f"
'----------------------------------------------------------------------
Public Property Get Permitidos() As String
    ' devolver los parámetros permitidos
    If nPerm > 0 Then
        Permitidos = Join(aPermitidos, SEP_PERM)
    Else
        Permitidos = ""
    End If
End Property

Public Property Let Permitidos(ByVal value As String)
    If Len(Trim$(value)) > 0 Then
        ' desglosar en un array
        ' los parámetros estarán separados por ;
        If Right$(Trim$(value), 1) = SEP_PERM Then
            value = Left$(value, Len(value) - 1)
        End If
        value = Trim$(value)
        aPermitidos = Split(value, SEP_PERM)
        nPerm = UBound(aPermitidos)
        mPermitidos = True
    Else
        nPerm = 0
        ReDim aPermitidos(0)
        mPermitidos = False
    End If
End Property

'----------------------------------------------------------------------
' EntreSeparadores
'
' Si los parámetros se asignarán entre separadores,
' de esta forma podemos indicar espacios entre parámetros
' por ejemplo:
' -file C:\Prueba con espacios\t.txt -convertir si -imprimir no
' de esta forma se crearán estos elementos en argv:
'   -file C:\Prueba con espacios\t.txt
'   -convertir si
'   -imprimir no
'
' Si EntreSeparadores es eOpSeparador.Ninguno (False)
' y se indican argumentos a tener en cuenta
' sólo se procesarán los que coincidan,
' por ejemplo:
' Si tenemos en cuenta: "convertir;imprimir"
' se devolverá (sin - ni /):
'   convertir
'   imprimir
' El resto se ignora.
'
' Si EntreSeparadores es True y se indican argumentos a tener en cuenta
' teniendo estos separadores: "convertir;imprimir"
' Se devolverán estos parámetros:
'   convertir si
'   imprimir no
'----------------------------------------------------------------------
Public Property Get EntreSeparadores() As eOpSeparador
    EntreSeparadores = m_EntreSeparadores
End Property

Public Property Let EntreSeparadores(ByVal value As eOpSeparador)
    If value = SeparadorArgumento Or value = SoloSeparadores Then
        m_EntreSeparadores = value
    Else
        m_EntreSeparadores = eOpSeparador.Ninguno
    End If
End Property

'----------------------------------------------------------------------
' DiferenciarCase
'
' Diferenciar los parámetros entre mayúsculas y minúsculas
' Esto solo tiene utilidad si se indican parámetros permitidos
' o en el caso que se quiera evitr duplicidades de parámetros
'----------------------------------------------------------------------
Public Property Get DiferenciarCase() As eTipoCompare
    DiferenciarCase = m_DiferenciarCase
End Property

Public Property Let DiferenciarCase(ByVal value As eTipoCompare)
    If value = BinaryCompare Or value = TextCompare Then
        m_DiferenciarCase = value
    Else
        m_DiferenciarCase = TextCompare
    End If
End Property

'----------------------------------------------------------------------
' PermitirDuplicados
'
' Si se permiten parámetros duplicados
' (el mismo parámetro más de una vez)
'----------------------------------------------------------------------
Public Property Get PermitirDuplicados() As Boolean
    PermitirDuplicados = m_PermitirDuplicados
End Property

Public Property Let PermitirDuplicados(ByVal value As Boolean)
    m_PermitirDuplicados = value
End Property

'----------------------------------------------------------------------
' Clear
'
' Asigna los valores predeterminados
'----------------------------------------------------------------------
Public Sub Clear()
    ' valores predeterminados
    m_DiferenciarCase = TextCompare
    
    nPerm = 0
    ReDim aPermitidos(nPerm)
    mPermitidos = False
    
    Argc = 0
    ReDim m_Argv(Argc)
    
    m_EntreSeparadores = eOpSeparador.Ninguno '= SeparadorArgumento
    
    m_PermitirDuplicados = True
End Sub

'----------------------------------------------------------------------
' Desglosar
'
' Este método llama a Command2Arg pero no devuelve nada
' ni permite parámetros opcionales
'----------------------------------------------------------------------
Public Sub Desglosar(ByVal sCommand As String)
    'Call Command2Arg(sCommand)
    Call CmdLine2Arg(sCommand)
End Sub

Public Function CmdLine2Arg(Optional ByVal sCommand As String = "") As Long
    ' Devuelve lo que hay en command$ o en la variable de entrada
    ' en un array global Argv() y devuelve el número de parámetros
    ' o cero si no hay ninguno
    '-------------------------------------------------------------
    Dim c               As String
    Dim s               As String
    Dim i               As Long
    Dim j               As Long
    Dim k               As Long
    Dim b               As Boolean
    Dim separadores     As String
    
    separadores = "/- " & Chr$(34) & Chr$(9)
    
    ReDim m_Argv(0)
    Argc = 0
    
    ' Si no se especifica el parámetro se toma la línea de comandos
    If Len(sCommand) = 0 Then
        sCommand = Command$
    End If
    
    ' Si no tiene nada la variable devolver cero
    If Len(sCommand) = 0 Then
        CmdLine2Arg = 0
        Argc = 0
        Exit Function
    End If
    
    i = 0
    Do While i < Len(sCommand)
        i = i + 1
        c = Mid$(sCommand, i, 1)
        ' Si está entre comillas dobles
        ' asignar el contenido al argumento
        If c = Chr$(34) Then
            j = InStr(i + 1, sCommand, Chr$(34))
            If j = 0 Then j = Len(sCommand)
            s = Mid$(sCommand, i + 1, j - i - 1)
            i = j + 1
            
            Argc = Argc + 1
            ReDim Preserve m_Argv(Argc)
            m_Argv(Argc) = Trim$(s)
            
        ElseIf c = "/" Or c = "-" Or c <> " " Then
            s = c
            Do While i < Len(sCommand)
                i = i + 1
                c = Mid$(sCommand, i, 1)
                If InStr(separadores, c) Then
                    i = i - 1
                    Exit Do
                End If
                s = s & c
            Loop
            Argc = Argc + 1
            ReDim Preserve m_Argv(Argc)
            m_Argv(Argc) = Trim$(s)
            
        End If
        
    Loop
    
    If m_EntreSeparadores <> eOpSeparador.Ninguno Then
        testSep
    End If
    
    If m_PermitirDuplicados = False Then
        testDup
    End If
    
    If mPermitidos Then
        testPerm
    End If
    
    ' Devolver las opciones que tengan separador usando sólo -      (03/Feb/05)
    ' y que como mínimo tenga un espacio después del parámetro
    ' para que se pueda buscar usando If Left$(Argv(i),3) = "-x " Then
    '
    ' También se comprueba si hay algún separador
    ' Se cambiarán los caracteres especiales
    '   c34 comillas dobles
    HayAlgunSeparador = False
    For i = 1 To Argc
        
        If InStr(sepArg, Left$(m_Argv(i), 1)) > 0 Then
            HayAlgunSeparador = True
            m_Argv(i) = "-" & Mid$(m_Argv(i), 2) & " "
        Else
            m_Argv(i) = m_Argv(i) & " "
        End If
        
        m_Argv(i) = Replace(m_Argv(i), "c34", Chr$(34))
    Next
    
    CmdLine2Arg = Argc
End Function

Private Sub testSep()
    ' Este método comprueba si se desglosa entre separadores,
    ' (solo se tendrán en cuenta los que empiecen por - o /)
    ' si tenemos: -x -f prueba
    ' devolvería:
    '   -x
    '   -f prueba
    Dim t_argv()    As String
    Dim i           As Long
    Dim n           As Long
    Dim b           As Boolean
    
    If m_EntreSeparadores = eOpSeparador.Ninguno Then
        Exit Sub
    End If
    
    t_argv = m_Argv
    n = 0
    
    For i = 1 To Argc
        
        If InStr(sepArg, Left$(t_argv(i), 1)) > 0 Then
            n = n + 1
            m_Argv(n) = LTrim$(t_argv(i))
            b = True
            
        Else
            
            If m_EntreSeparadores = SoloSeparadores Then
                ' Si n = 0 no hay que tenerlo en cuenta,
                ' ya que es un parámetro no precedido por un separador,
                ' en otro caso es un valor del separador anterior.
                If n > 0 Then
                    m_Argv(n) = m_Argv(n) & " " & LTrim$(t_argv(i))
                End If
                
            Else
                ' Se puede indicar también entre separadores y
                ' los primeros que no estén entre separadores,
                ' en ese caso hacerlo así:
                If n = 0 Or b = False Then
                    n = n + 1
                    m_Argv(n) = LTrim$(t_argv(i))
                    
                Else
                    m_Argv(n) = m_Argv(n) & " " & LTrim$(t_argv(i))
                    
                End If
                
            End If
            
            b = False
            
        End If
    Next
    
    ReDim Preserve m_Argv(n)
    Argc = n
End Sub

Private Sub testDup()
    ' Comprobar si hay parámetros duplicados
    ' (sólo se tendrá en cuenta la primera palabra de cada argumento)
    ' Aquí cada parámetro puede estar precedido por un separador,
    ' pero no tiene porqué ser así.
    ' Si tenemos -x fichero -p -x Documento.txt fichero
    ' suponiendo que EntreSeparadores = False, tendríamos estos argumentos:
    '   -x
    '   fichero
    '   -p
    '   -x
    '   Documento.txt
    '   fichero
    ' por tanto -x y fichero estarían duplicados
    Dim t_argv()    As String
    Dim i           As Long
    Dim j           As Long
    Dim k           As Long
    Dim n           As Long
    Dim s           As String
    Dim s1          As String
    Dim b           As Boolean
    '
    If m_PermitirDuplicados = True Then
        Exit Sub
    End If
    
    t_argv = m_Argv
    n = 0
    
    For i = 1 To Argc
        ' solo se comprueba la primera palabra
        ' (o la línea completa si solo hay una palabra)
        k = InStr(t_argv(i), " ")
        If k = 0 Then
            k = Len(t_argv(i)) + 1
        End If
        
        If n = 0 Then
            n = n + 1
            m_Argv(n) = t_argv(i)
        Else
            s = Left$(t_argv(i), k - 1)
            b = False
            For j = 1 To n
                k = InStr(m_Argv(j), " ")
                If k > 0 Then
                    s1 = Left$(m_Argv(j), k - 1)
                Else
                    s1 = m_Argv(j)
                End If
                If StrComp(s, s1, m_DiferenciarCase) = 0 Then
                    b = True
                    Exit For
                End If
            Next
            If b = False Then
                n = n + 1
                m_Argv(n) = t_argv(i)
            End If
        End If
    Next
    
    ReDim Preserve m_Argv(n)
    Argc = n
End Sub

Private Sub testPerm()
    ' Comprobar los permitidos
    ' Se comprueban los parámetros permitidos
    ' de forma que sólo se acepten los indicados en Permitidos
    Dim t_argv()    As String
    Dim i           As Long
    Dim j           As Long
    Dim k           As Long
    Dim n           As Long
    Dim s           As String
    Dim b           As Boolean
    '
    If mPermitidos = False Then
        Exit Sub
    End If
    
    t_argv = m_Argv
    n = 0
    
    For i = 1 To Argc
        k = InStr(t_argv(i), " ")
        If k > 0 Then
            s = Left$(t_argv(i), k - 1)
        Else
            s = t_argv(i)
        End If
        If InStr(sepArg, Left$(s, 1)) > 0 Then
            s = Mid$(s, 2)
        End If
        
        b = False
        For j = 0 To nPerm
            If StrComp(s, aPermitidos(j), m_DiferenciarCase) = 0 Then
                b = True
                Exit For
            End If
        Next
        If b Then
            n = n + 1
            m_Argv(n) = t_argv(i)
        End If
    Next
    
    ReDim Preserve m_Argv(n)
    Argc = n
End Sub

Private Sub Class_Initialize()
    Clear
End Sub

'----------------------------------------------------------------------
' Funciones de apoyo después de desglosar la línea de comandos
'----------------------------------------------------------------------
Public Function GetArgument(ByVal sArg As String) As String
    ' Busca el argumento indicado y devuelve la cadena asociada     (03/Feb/05)
    ' se debe indicar el signo - si es un argumento que se usa de separador
    ' ya que pueden existir argumentos con nombre, pero sin separador
    Dim i As Long
    Dim k As Long
    Dim s As String
    
    s = ""
    For i = 1 To Me.Argc
        k = InStr(m_Argv(i), " ")
        If k > 0 Then
            s = Left$(m_Argv(i), k - 1)
            If StrComp(s, sArg, vbTextCompare) = 0 Then
                s = Mid$(m_Argv(i), k + 1)
                Exit For
            End If
        End If
    Next
    
    GetArgument = s
End Function

Public Function GetArgumentNumber(ByVal sArg As String) As Long
    ' Busca el argumento indicado y devuelve la posición            (03/Feb/05)
    ' Devuelve cero si no se ha encontrado
    ' Esta función se puede usar con GetArgumentByIndex(index)
    Dim i As Long
    Dim k As Long
    Dim s As String
    Dim n As Long
    
    n = 0
    For i = 1 To Argc
        k = InStr(m_Argv(i), " ")
        If k > 0 Then
            s = Left$(m_Argv(i), k - 1)
            If StrComp(s, sArg, vbTextCompare) = 0 Then
                n = i
                Exit For
            End If
        End If
    Next
    
    GetArgumentNumber = n
End Function

Public Function GetArgumentByIndex(ByVal index As Long) As String
    ' Devuelve lo que contiene el índice indicado                   (03/Feb/05)
    ' hay que buscarlo con GetArgumentNumber
    Dim k As Long
    Dim s As String
    
    s = ""
    If Not (index < 1 Or index > Argc) Then
        k = InStr(m_Argv(index), " ")
        If k > 0 Then
            s = Trim$(Mid$(m_Argv(index), k + 1))
        End If
    End If
    GetArgumentByIndex = s
End Function

Public Sub RemoveArgumentByIndex(ByVal index As Long, Optional ByVal quitarExtra As Boolean = False)
    ' Quita el argumento del índice indicado                        (05/Feb/05)
    Dim k As Long
    Dim s As String
    
    s = ""
    If Not (index < 1 Or index > Argc) Then
        k = InStr(m_Argv(index), " ")
        If k > 0 Then
            s = Trim$(Left$(m_Argv(index), k - 1))
        End If
    End If
    RemoveArgument s, quitarExtra
End Sub

Public Sub RemoveArgument(ByVal sArg As String, Optional ByVal quitarExtra As Boolean = False)
    ' Quitar el argumento indicado del array                        (04/Feb/05)
    ' Hay que indicarlo con el signo - delante                      (05/Feb/05)
    ' Si quitarExtra = True, se quitará lo que haya a continuación
    ' esto es válido para argumentos que tienen datos
    Dim i           As Long
    Dim k           As Long
    Dim s           As String
    Dim n           As Long
    Dim t_argv()    As String
    
    t_argv = m_Argv
    
    HayAlgunSeparador = False
    
    n = 0
    For i = 1 To Argc
        k = InStr(t_argv(i), " ")
        If k > 0 Then
            s = Left$(t_argv(i), k - 1)
            If StrComp(s, sArg, vbTextCompare) <> 0 Then
                If Left$(s, 1) = "-" Then
                    HayAlgunSeparador = True
                End If
                n = n + 1
                m_Argv(n) = t_argv(i)
            ElseIf quitarExtra = False Then
                ' comprobar si le sigue algo
                ' (por si se ha indicado otro parámetro sin separador)
                s = Trim$(Mid$(t_argv(i), k + 1))
                If Len(s) Then
                    n = n + 1
                    m_Argv(n) = s
                End If
            End If
        Else
            n = n + 1
            m_Argv(n) = t_argv(i)
        End If
    Next
    
    Argc = n
    ReDim Preserve m_Argv(n)
End Sub

 


Índice de Visual Basic -*- Índice de Mis Utilidades

ir al índice