Pregunta 1:
llamadas estaticas y dinamicas
Respuesta 1:
Las llamadas a módulos se realizan mediante la sentencia CALL. Estas llamadas pueden realizarse de dos formas:
Estática: lleva el nombre del módulo entre comillas.
CALL 'PROGRAMA' USING XXXXX
Después de la llamada el módulo queda residente en memoria, porque se integra en el programa objeto. Lo que quiere decir que el código de la rutina queda integrado dentro del objeto del programa llamante. Si se modificase la rutina, habría que recompilar todos los programas que la llaman para que integren el nuevo código y no se queden con el viejo.
Dinámica: utiliza una variable que contiene el nombre del programa.
CALL WX-PROGRAMA USING XXXX
donde
01 WX-PROGRAMA PIC X(8) VALUE 'PROGRAMA'.
Después de la llamada el módulo es descargado de la memoria. Son objetos independientes de los programas llamantes.
Pregunta 2
perform thru
Respuesta 2:
En los ejemplos del consultorio siempre utilizamos la sentencia PERFORM para llamar a un párrafo, sin utilizar el THRU. La razón es que en los clientes en los que hemos trabajado es la norma.
Un PERFORM/THRU se codificaría de este modo:
PERFORM 1000-INICIO
THRU 1000-INICIO-EXIT
Donde
1000-INICIO.
código cobol
1000-INICIO-EXIT.
EXIT.
El párrafo 1000-INICIO-EXIT sólo contiene la sentencia EXIT.
Otra opción sería:
PERFORM PARRAFO1
THRU PARRAFO3
Y ejecutaría todo el código que hubiese entre ambos párrafos, y PARRAFO3 contendría la sentencia EXIT.
Hoy día se podría decir que no se utilizan del mismo modo que no se utiliza el GO TO. Evitas riesgos. Para un cliente grande puede haber cientos de programadores codificando cada día, y seguro que no todos somos unos craks... Así que mejor no arriesgar! Sin olvidar que lo normal es que el párrafo del THRU vaya justo después del párrafo indicado en el PERFORM (como en el ejemplo 1), por lo que su utilidad sería dudosa cuando menos. Además, ahorramos líneas de código y tiempo si pasamos del THRU :P
Pregunta 3:
enviar sysout a archivo
Respuesta 3:
Cuando estamos probando un programa (ya sea batch u online), solemos ir a la cola SYSOUT a ver los DISPLAYs que hayamos puesto (o los mensajes de error, o lo que sea). Esta información a veces es útil guardarla en fichero para no perderla (y no tener que copiar pantalla a pantalla a un txt...).
Para ello:
Entramos con ? en nuestra ejecución (nombre del job para batch, cola del CICS/IMS para online).
Nos posicionamos en la cola SYSOUT que contiene los mensajes y escribimos SE.
Ahora en la línea de comandos escribimos CREATE y un nombre de fichero (el que sea) y copiamos todo el código (C9999).
Elegimos la opción 2 para indicar los atributos del fichero y rellenamos los campos necesarios (podemos abrir otro fichero que ya exista y ver sus atributos escribiendo una S delante del nombre del fichero).
Y listo, tenemos nuestra información guardada en fichero^^
Pregunta 4:
error b37 cobol
Respuesta 4:
El error B37 aparece en el artículo de Errores de sistema y nos indica que un fichero se ha quedado sin espacio.
Esto puede ocurrir porque hemos definido un fichero como TRK y necesitamos un CYL, o incluso un TAPE. Por ejemplo:
SPACE=(TRK,(100,50)) si aumentamos pistas: SPACE=(TRK,(500,50))
SPACE=(CYL,(100,50)) si aumentamos cilindros: SPACE=(CYL,(500,50))
Y sino habremos llegado al UNIT=TAPE^^
Pero si estamos probando algo nuevo, puede ser que haya un error en el programa y estemos escribiendo en el fichero indefinidamente (nos hemos embuclado y estamos llamando al párrafo que hace el WRITE indefinidamente). Por si acaso, antes de aumentar las pistas o los cilindros, revisad el código no vaya a ser!
jueves, 31 de mayo de 2012
viernes, 25 de mayo de 2012
2022...el fin

Lo que igual no sabe la gente de El Confidencial, es que hace 10 años ya hacía 10 años que otras personas auguraban lo mismo.
Según nos explican, los avances tecnológicos hacen que determinados puestos de trabajo queden obsoletos y acaben desapareciendo con el tiempo. Otros permanecen como una actividad residual, tal como ha ocurrido con los afiladores, curtidores o herreros, oficios artesanales que permanecen casi por cuestiones nostálgicas vinculadas con el turismo.
Dentro del sector de los técnicos informáticos y de telecomunicaciones algunos puestos se han quedado desfasados a su entender. Así es el caso de los programadores de COBOL, un lenguaje de programación que está en desuso, muy vinculado a los mainframe. (que por lo que dan a entender también desaparecerán)
La verdad es que sería una desgracia en estos tiempos que corren que se terminasen puestos de trabajo que dan una oportunidad a recién diplomados o licenciados en Informática, Matemáticas, Físicas, Químicas o Biología. Tal como están las cosas apostaría a que se terminan antes los puestos de políticos (por los sueldos se podría considerar un puesto, ¿no?) que de programadores COBOL.
¡Dentro de 10 años os lo contamos!
Artículo El Confidencial
lunes, 21 de mayo de 2012
Respuestas de la semana II
Recordad que podéis escribirnos con vuestras dudas concretas y os responderemos lo antes posible : )
Pregunta 1:
como saber si una fecha es valida o no en db2
Respuesta 1:
Una fecha DB2 es un campo definido como DATE, que a los efectos de un programa cobol es un campo alfanumérico con PIC X(10).
El formato de la fecha será AAAA-MM-DD, donde AAAA es el año, MM el mes y DD el día. Los guiones son guiones normales.
En el blog hay un artículo sobre los diferentes formatos de fechas que podéis consultar:
Fechas: Juliana, Gregoriana, DB2...
Pregunta 2:
como validar variables alfanumericas en cobol
Respuesta 2:
Así como existe una sentencia "IS NUMERIC" para comprobar que un campo sólo lleva números, para los campos alfanuméricos tendremos también la opción de preguntar por "IS ALPHABETIC" para comprobar que solo lleva caracteres de la A a la Z.
Para el resto de caracteres:
Nuestra variable.
01 WX-ALFANUM PIC X(10) VALUE 'ABCD;EFGH1'.
01 INDICE PIC S9(4) COMP.
Definimos un switch con los los caracteres que queramos detectar.
01 SW-VALIDAR PIC X.
88 CAMPO-SIMBOLOS VALUE ';', '@', '#', '$',
'%', '&', '/', '(',
')', '='.
01 SW-BUCLE PIC X.
88 SALIR-BUCLE VALUE 'S'.
Montamos un bucle para recorrer todas las posiciones de nuestra variable alfanumérica.
PERFORM VARYING INDICE FROM 1 BY 1 UNTIL INDICE > 10
OR SALIR-BUCLE
MOVE WX-ALFANUM(INDICE:1) TO SW-VALIDAR
IF NOT CAMPO-SIMBOLOS
CONTINUE
ELSE
SET SALIR-BUCLE TO TRUE
END-IF
END-PERFORM
De tal forma que si al salir del bucle el switch SALIR-BUCLE está activado significa que la variable contiene caracteres especiales (en el ejemplo al llegar al punto y coma ';' activará SALIR-BUCLE).
La validación podéis montarla al gusto, siempre que comprobéis cada una de las posiciones:
WX-ALFANUM(INDICE:1) donde INDICE va cambiando de 1 en 1 y solo cogemos una posición (:1).
Pregunta 3:
agregar consecutivos desde jcl
Respuesta 3:
Se me ocurre que lo que estaba buscando esta persona era la manera de añadir un número secuencial a un registro de un fichero por JCL (que lo mismo no, pero bueno, yo os lo cuento).
Hay una opción de OUTREC para generar un número secuencial que podremos colocar donde queramos.
//SYSIN DD *
SORT FIELDS=COPY
OUTREC FIELDS=(SEQNUM,10,ZD,START=0000000001,INCR=1,1,300)
Se trata de la opción SEQNUM. En el ejemplo vemos que indicamos lo siguiente:
SEQNUM: número secuencial
10: tendrá 10 posiciones
ZD: será de tipo numérico sin comprimir
START=0000000001: comenzará con el valor 0000000001
INCR=1: iremos incrementando de 1 en 1
1,300: son las demás posiciones del fichero de entrada que queremos incluir en salida (aquí podríamos poner lo que quisiéramos)
El SEQNUM podemos colocarlo en cualquier posición del registro, no hace falta que sea en la primera posición.
Pregunta 4:
declarar variables que no permite negativos en cobol
Respuesta 4:
Una variable definida sin signo nunca podrá ser negativa. Por ejemplo:
01 WX-CAMPO-POSITIVO PIC 9(8)V9(3).
No lleva el signo (la S delante del 9) por lo que nunca podrá ser menor que cero.
En las variables signadas podemos comprobar si son negativas preguntando si la variable es menor que cero:
IF WX-CAMPO-SIGNADO LESS THAN ZERO
Pregunta 5:
host utilidad comparar dos ficheros tso
Respuesta 5:
La utilidad para comparar ficheros está en la opción 3.13 del ISPF: SuperCE
En ella indicaremos los 2 ficheros a comparar y en el resultado veremos las filas que no coinciden (nos mostrará la fila de ambos ficheros). Lo malo es que si el fichero es muy largo, el final del registro no lo veremos (por mucho que demos F11 para que muestre más pantallas a la derecha).
Pregunta 1:
como saber si una fecha es valida o no en db2
Respuesta 1:
Una fecha DB2 es un campo definido como DATE, que a los efectos de un programa cobol es un campo alfanumérico con PIC X(10).
El formato de la fecha será AAAA-MM-DD, donde AAAA es el año, MM el mes y DD el día. Los guiones son guiones normales.
En el blog hay un artículo sobre los diferentes formatos de fechas que podéis consultar:
Fechas: Juliana, Gregoriana, DB2...
Pregunta 2:
como validar variables alfanumericas en cobol
Respuesta 2:
Así como existe una sentencia "IS NUMERIC" para comprobar que un campo sólo lleva números, para los campos alfanuméricos tendremos también la opción de preguntar por "IS ALPHABETIC" para comprobar que solo lleva caracteres de la A a la Z.
Para el resto de caracteres:
Nuestra variable.
01 WX-ALFANUM PIC X(10) VALUE 'ABCD;EFGH1'.
01 INDICE PIC S9(4) COMP.
Definimos un switch con los los caracteres que queramos detectar.
01 SW-VALIDAR PIC X.
88 CAMPO-SIMBOLOS VALUE ';', '@', '#', '$',
'%', '&', '/', '(',
')', '='.
01 SW-BUCLE PIC X.
88 SALIR-BUCLE VALUE 'S'.
Montamos un bucle para recorrer todas las posiciones de nuestra variable alfanumérica.
PERFORM VARYING INDICE FROM 1 BY 1 UNTIL INDICE > 10
OR SALIR-BUCLE
MOVE WX-ALFANUM(INDICE:1) TO SW-VALIDAR
IF NOT CAMPO-SIMBOLOS
CONTINUE
ELSE
SET SALIR-BUCLE TO TRUE
END-IF
END-PERFORM
De tal forma que si al salir del bucle el switch SALIR-BUCLE está activado significa que la variable contiene caracteres especiales (en el ejemplo al llegar al punto y coma ';' activará SALIR-BUCLE).
La validación podéis montarla al gusto, siempre que comprobéis cada una de las posiciones:
WX-ALFANUM(INDICE:1) donde INDICE va cambiando de 1 en 1 y solo cogemos una posición (:1).
Pregunta 3:
agregar consecutivos desde jcl
Respuesta 3:
Se me ocurre que lo que estaba buscando esta persona era la manera de añadir un número secuencial a un registro de un fichero por JCL (que lo mismo no, pero bueno, yo os lo cuento).
Hay una opción de OUTREC para generar un número secuencial que podremos colocar donde queramos.
//SYSIN DD *
SORT FIELDS=COPY
OUTREC FIELDS=(SEQNUM,10,ZD,START=0000000001,INCR=1,1,300)
Se trata de la opción SEQNUM. En el ejemplo vemos que indicamos lo siguiente:
SEQNUM: número secuencial
10: tendrá 10 posiciones
ZD: será de tipo numérico sin comprimir
START=0000000001: comenzará con el valor 0000000001
INCR=1: iremos incrementando de 1 en 1
1,300: son las demás posiciones del fichero de entrada que queremos incluir en salida (aquí podríamos poner lo que quisiéramos)
El SEQNUM podemos colocarlo en cualquier posición del registro, no hace falta que sea en la primera posición.
Pregunta 4:
declarar variables que no permite negativos en cobol
Respuesta 4:
Una variable definida sin signo nunca podrá ser negativa. Por ejemplo:
01 WX-CAMPO-POSITIVO PIC 9(8)V9(3).
No lleva el signo (la S delante del 9) por lo que nunca podrá ser menor que cero.
En las variables signadas podemos comprobar si son negativas preguntando si la variable es menor que cero:
IF WX-CAMPO-SIGNADO LESS THAN ZERO
Pregunta 5:
host utilidad comparar dos ficheros tso
Respuesta 5:
La utilidad para comparar ficheros está en la opción 3.13 del ISPF: SuperCE
En ella indicaremos los 2 ficheros a comparar y en el resultado veremos las filas que no coinciden (nos mostrará la fila de ambos ficheros). Lo malo es que si el fichero es muy largo, el final del registro no lo veremos (por mucho que demos F11 para que muestre más pantallas a la derecha).
Utilidades REXX II: editar fichero desde JCL.
ACTUALIZADO: corregido el error que daba cuando el fichero no existía.
En esta ocasión os traemos un programa REXX, pequeño, fácil y para toda la familia. Con él podremos entrar a "ver" o "editar" un fichero desde el JCL, sólo con posicionar el cursor encima del nombre del fichero.
Unos lo llamarán comodidad, otros vagancia^^
Veamos el código REXX:
/* REXX */
/*EDIT DE FICHERO SEGUN POSICION DEL CURSOR DSN= */
MENSA=MSG('OFF')
"PROFILE NOPREFIX"
TRACE OFF
ARG A_OPC .
ADDRESS ISPEXEC "ISREDIT MACRO"
ADDRESS ISPEXEC "ISREDIT (LIN,COL) = CURSOR "
ADDRESS ISPEXEC "ISREDIT (LINEA) = LINE " LIN
X=OPCION() /* IDENTIFICAR OPCIÓN */
X=BFILE() /* BUSCA NOMBRE */
X=VFILE() /* VALIDA FILE */
RETURN 0
OPCION: /* IDENTIFICA LA OPCIóN ELEGIDA, EDIT O VIEW */
IF A_OPC = '' THEN
DO
SAY 'SELECCIONE OPCIóN: E (EDITAR) ó V (VIEW)'
PARSE EXTERNAL A_OPC .
IF A_OPC = '' THEN
EXIT
UPPER A_OPC
END
RETURN 0
BFILE: /* BUSCA NOMBRE FICHERO EN LA LINEA */
F = INDEX(LINEA,'DSN=')
IF F=0 THEN
DO
FILE=STRIP(SUBWORD(SUBSTR(LINEA,COL),1,1),T,',')
FILE=STRIP(FILE,,"'")
F=INDEX(FILE,"')")
IF F=0 THEN
DO
FILE=SUBSTR(FILE,1,F-1)
END
END
ELSE
DO
FILE=SUBWORD(SUBSTR(LINEA,F+4),1,1)
F=INDEX(FILE,',')
IF F<>0 THEN
DO
FILE = SUBSTR(FILE,1,F-1)
END
F = INDEX(FILE,'(')
IF F <> 0 THEN
DO
/*-- EXTRAER VERSION DEL GDG --*/
GDGVERS = SUBSTR(FILE, F+1, INDEX(FILE,')')-F-1)
IF SUBSTR(GDGVERS, 1, 1) = '+' THEN
IN = 0
ELSE
DO
IF SUBSTR(GDGVERS, 1, 1) = '-' THEN
IN = SUBSTR(GDGVERS, 2, LENGTH(GDGVERS)-1)
ELSE
IN = 0
END
FILE = SUBSTR(FILE,1,F-1)
/*-- LISTA TODAS LAS VERSIONES DEL GDG. --*/
Q = OUTTRAP(DATA.)
"LISTC ENT('"||FILE||"')"
Q = OUTTRAP(OFF)
/*-- DETERMINA EL NOMBRE DE LA VERSION ACTUAL --*/
REC = DATA.0 -(2*IN+1)
PARSE VAR DATA.REC . . FILE
END
END
FILE=STRIP(FILE,,' ')
RETURN 0
VFILE: /* VALIDA FILE */
IF SYSDSN(FILE) <> 'OK' THEN
ADDRESS ISPEXEC "ISREDIT LINE_AFTER "LIN" = MSGLINE <1>"
ELSE
DO
IF A_OPC = 'E' THEN
ISPEXEC "EDIT DATASET('"FILE"')"
IF A_OPC = 'V' THEN
ISPEXEC "VIEW DATASET('"FILE"')"
END
RETURN 0
Donde:
ARG A_OPC:
Variable donde guardaremos la opción "E" o "V"
"ISREDIT MACRO":
Es una macro
"ISREDIT (LIN,COL) = CURSOR ":
Posición del cursor
"ISREDIT (LINEA) = LINE " LIN:
Línea
PARSE EXTERNAL A_OPC:
Guarda el valor introducido en la variable A_OPC
INDEX(LINEA,'DSN='):
El nombre del fichero estará después del 'DSN='.
FILE=STRIP(SUBWORD(SUBSTR(LINEA,COL),1,1),T,','):
Recupera la cadena de caracteres que contiene el nombre del fichero.
GDGVERS = SUBSTR(FILE, F+1, INDEX(FILE,')')-F-1):
Recupera la versión en la que estamos para el caso de que el fichero sea un GDG. Por ejemplo (-1).
SUBSTR(GDGVERS, 1, 1) = '+' THEN IN = 0:
Para las versiones positivas mostraremos la última versión del GDG.
SUBSTR(GDGVERS, 1, 1) = '-':
Si se trata de versiones negativas del GDG calculamos a cual corresponde.
"EDIT DATASET('"FILE"')":
Abre el fichero en modo EDIT.
"VIEW DATASET('"FILE"')":
Abre el fichero en modo VIEW.
Para ejecutar el programa tenemos dos opciones:
1. Escribir en la linea de comando el nombre del programa (por ejemplo REXEDI), colocar el cursor encima del nombre del fichero que queremos abrir y pulsar intro. Elegimos E o V y damos intro.
2. Guardar el nombre del programa REXX en una de nuestras KEYS. Colocamos el cursor encima del nombre del fichero y pulsar intro. Elegimos E o V y damos intro.
En el caso de que no os funcione, habrá que hacer esta comprobación:
En la línea de comandos escribimos "TSO ISRDDN". Nos saldrá algo de este estilo:
Volume Disposition Act DDname Data Set Name Actions: B E V
TSST50 NEW,DEL > ISPCTL0 LIBRERIA1
CXDR21 SHR,KEEP > ISPILIB LIBRERIA2
MVSC04 SHR,KEEP > ISPLLIB LIBRERIA3
CXDR21 SHR,KEEP > LIBRERIA4
MVSC04 SHR,KEEP > ISPMLIB LIBRERIA5
(...)
Buscaremos SYSEXEC escribiendo "O SYSEXEC". Nos mostrará algo de este estilo:
Volume Disposition Act DDname Data Set Name Actions: B E V
CXDS01 SHR,KEEP > SYSEXEC LIBRERIA6
MVSC09 SHR,KEEP > LIBRERIA7
PSTS01 SHR,KEEP > LIBRERIA8
MVSC09 SHR,KEEP > LIBRERIA9
Nuestro programilla REXX deberá estar en una de las librerías del SYSEXEC. La razón es que lo que estamos ejecutando es en realidad una macro.
Si se da el caso de que no tenemos acceso a ninguna de las librerías del SYSEXEC podemos añadir una nuestra. Para ello tenemos el siguiente código:
CONTROL NOFLUSH LIST
ALLOC F(SYSEXEC) SHR REUSE DA('LIBRERIA6' +
'LIBRERIA7' +
'LIBRERIA8' +
'LIBRERIA9' +
'MILIBRERIA')
que escribiremos en un fichero (es un CLIST).
Lo ejecutaremos con un TSO EX FICHERO.CON.CODIGO.ANTERIOR.
Ahora al consultar el ISRDDN veremos que ya aparece en el SYSEXEC nuestra librería.
Perfecto, ya podemos ejecutar macros!
Si preferís que no os pida elegir entre editar "E" o visualizar "V", podemos tener dos macros: una para edit y otra para view.
Guardando el nombre de la macro en una de las KEYS, o escribiéndolo en la línea de comandos, sólo tendremos que posicionarnos en el nombre del fichero que queremos ver y dar intro. Según estemos ejecutando la macro de edit o la de view nos abrirá el fichero en edición o visualización respectivamente.
ACTUALIZADO: corregido el error que daba cuando el fichero no existía.
Os dejo la última versión del código REXX para la opción de editar:
Descargar EDI-FILE
Si tenéis cualquier problema con esto nos contáis e intentamos solucionarlo : )
En esta ocasión os traemos un programa REXX, pequeño, fácil y para toda la familia. Con él podremos entrar a "ver" o "editar" un fichero desde el JCL, sólo con posicionar el cursor encima del nombre del fichero.
Unos lo llamarán comodidad, otros vagancia^^
Veamos el código REXX:
/* REXX */
/*EDIT DE FICHERO SEGUN POSICION DEL CURSOR DSN= */
MENSA=MSG('OFF')
"PROFILE NOPREFIX"
TRACE OFF
ARG A_OPC .
ADDRESS ISPEXEC "ISREDIT MACRO"
ADDRESS ISPEXEC "ISREDIT (LIN,COL) = CURSOR "
ADDRESS ISPEXEC "ISREDIT (LINEA) = LINE " LIN
X=OPCION() /* IDENTIFICAR OPCIÓN */
X=BFILE() /* BUSCA NOMBRE */
X=VFILE() /* VALIDA FILE */
RETURN 0
OPCION: /* IDENTIFICA LA OPCIóN ELEGIDA, EDIT O VIEW */
IF A_OPC = '' THEN
DO
SAY 'SELECCIONE OPCIóN: E (EDITAR) ó V (VIEW)'
PARSE EXTERNAL A_OPC .
IF A_OPC = '' THEN
EXIT
UPPER A_OPC
END
RETURN 0
BFILE: /* BUSCA NOMBRE FICHERO EN LA LINEA */
F = INDEX(LINEA,'DSN=')
IF F=0 THEN
DO
FILE=STRIP(SUBWORD(SUBSTR(LINEA,COL),1,1),T,',')
FILE=STRIP(FILE,,"'")
F=INDEX(FILE,"')")
IF F=0 THEN
DO
FILE=SUBSTR(FILE,1,F-1)
END
END
ELSE
DO
FILE=SUBWORD(SUBSTR(LINEA,F+4),1,1)
F=INDEX(FILE,',')
IF F<>0 THEN
DO
FILE = SUBSTR(FILE,1,F-1)
END
F = INDEX(FILE,'(')
IF F <> 0 THEN
DO
/*-- EXTRAER VERSION DEL GDG --*/
GDGVERS = SUBSTR(FILE, F+1, INDEX(FILE,')')-F-1)
IF SUBSTR(GDGVERS, 1, 1) = '+' THEN
IN = 0
ELSE
DO
IF SUBSTR(GDGVERS, 1, 1) = '-' THEN
IN = SUBSTR(GDGVERS, 2, LENGTH(GDGVERS)-1)
ELSE
IN = 0
END
FILE = SUBSTR(FILE,1,F-1)
/*-- LISTA TODAS LAS VERSIONES DEL GDG. --*/
Q = OUTTRAP(DATA.)
"LISTC ENT('"||FILE||"')"
Q = OUTTRAP(OFF)
/*-- DETERMINA EL NOMBRE DE LA VERSION ACTUAL --*/
REC = DATA.0 -(2*IN+1)
PARSE VAR DATA.REC . . FILE
END
END
FILE=STRIP(FILE,,' ')
RETURN 0
VFILE: /* VALIDA FILE */
IF SYSDSN(FILE) <> 'OK' THEN
ADDRESS ISPEXEC "ISREDIT LINE_AFTER "LIN" = MSGLINE <1>"
ELSE
DO
IF A_OPC = 'E' THEN
ISPEXEC "EDIT DATASET('"FILE"')"
IF A_OPC = 'V' THEN
ISPEXEC "VIEW DATASET('"FILE"')"
END
RETURN 0
Donde:
ARG A_OPC:
Variable donde guardaremos la opción "E" o "V"
"ISREDIT MACRO":
Es una macro
"ISREDIT (LIN,COL) = CURSOR ":
Posición del cursor
"ISREDIT (LINEA) = LINE " LIN:
Línea
PARSE EXTERNAL A_OPC:
Guarda el valor introducido en la variable A_OPC
INDEX(LINEA,'DSN='):
El nombre del fichero estará después del 'DSN='.
FILE=STRIP(SUBWORD(SUBSTR(LINEA,COL),1,1),T,','):
Recupera la cadena de caracteres que contiene el nombre del fichero.
GDGVERS = SUBSTR(FILE, F+1, INDEX(FILE,')')-F-1):
Recupera la versión en la que estamos para el caso de que el fichero sea un GDG. Por ejemplo (-1).
SUBSTR(GDGVERS, 1, 1) = '+' THEN IN = 0:
Para las versiones positivas mostraremos la última versión del GDG.
SUBSTR(GDGVERS, 1, 1) = '-':
Si se trata de versiones negativas del GDG calculamos a cual corresponde.
"EDIT DATASET('"FILE"')":
Abre el fichero en modo EDIT.
"VIEW DATASET('"FILE"')":
Abre el fichero en modo VIEW.
Para ejecutar el programa tenemos dos opciones:
1. Escribir en la linea de comando el nombre del programa (por ejemplo REXEDI), colocar el cursor encima del nombre del fichero que queremos abrir y pulsar intro. Elegimos E o V y damos intro.
2. Guardar el nombre del programa REXX en una de nuestras KEYS. Colocamos el cursor encima del nombre del fichero y pulsar intro. Elegimos E o V y damos intro.
En el caso de que no os funcione, habrá que hacer esta comprobación:
En la línea de comandos escribimos "TSO ISRDDN". Nos saldrá algo de este estilo:
Volume Disposition Act DDname Data Set Name Actions: B E V
TSST50 NEW,DEL > ISPCTL0 LIBRERIA1
CXDR21 SHR,KEEP > ISPILIB LIBRERIA2
MVSC04 SHR,KEEP > ISPLLIB LIBRERIA3
CXDR21 SHR,KEEP > LIBRERIA4
MVSC04 SHR,KEEP > ISPMLIB LIBRERIA5
(...)
Buscaremos SYSEXEC escribiendo "O SYSEXEC". Nos mostrará algo de este estilo:
Volume Disposition Act DDname Data Set Name Actions: B E V
CXDS01 SHR,KEEP > SYSEXEC LIBRERIA6
MVSC09 SHR,KEEP > LIBRERIA7
PSTS01 SHR,KEEP > LIBRERIA8
MVSC09 SHR,KEEP > LIBRERIA9
Nuestro programilla REXX deberá estar en una de las librerías del SYSEXEC. La razón es que lo que estamos ejecutando es en realidad una macro.
Si se da el caso de que no tenemos acceso a ninguna de las librerías del SYSEXEC podemos añadir una nuestra. Para ello tenemos el siguiente código:
CONTROL NOFLUSH LIST
ALLOC F(SYSEXEC) SHR REUSE DA('LIBRERIA6' +
'LIBRERIA7' +
'LIBRERIA8' +
'LIBRERIA9' +
'MILIBRERIA')
que escribiremos en un fichero (es un CLIST).
Lo ejecutaremos con un TSO EX FICHERO.CON.CODIGO.ANTERIOR.
Ahora al consultar el ISRDDN veremos que ya aparece en el SYSEXEC nuestra librería.
Perfecto, ya podemos ejecutar macros!
Si preferís que no os pida elegir entre editar "E" o visualizar "V", podemos tener dos macros: una para edit y otra para view.
Guardando el nombre de la macro en una de las KEYS, o escribiéndolo en la línea de comandos, sólo tendremos que posicionarnos en el nombre del fichero que queremos ver y dar intro. Según estemos ejecutando la macro de edit o la de view nos abrirá el fichero en edición o visualización respectivamente.
ACTUALIZADO: corregido el error que daba cuando el fichero no existía.
Os dejo la última versión del código REXX para la opción de editar:
Descargar EDI-FILE
Si tenéis cualquier problema con esto nos contáis e intentamos solucionarlo : )
miércoles, 9 de mayo de 2012
JCL Avanzado II. Operaciones aritméticas con OUTREC.
Este es un ejemplo de como podemos operar con la información de un fichero usando la opción OUTREC del programa SORT.
//SORT001 EXEC PGM=SORT
//SORTIN DD DSN=nombre.fichero.entrada1,DISP=SHR
//SORTOUT DD DSN=nombre.fichero.salida1,
// DISP=(,CATLG,DELETE),SPACE=(CYL,(500,100))
//SYSOUT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
SORT FIELDS=COPY
OUTREC FIELDS=(I,L,Ti,O,D,TO=Tf,LENGTH=L)
I – Inicio. Posición donde empieza el campo.
L – Longitud máxima del campo.
Ti - Tipo de dato inicial:
CH - Alfanumérico
ZD - Numérico
BI - Hexadecimal (campos COMP)
PD - Empaquetado con o sin signo(campos COMP-3)
O - Operador:
ADD - Suma
SUB - Resta
MUL - Multiplicación
DIV - División
D – Dato de la operación
Tf - Tipo de dato final
L - Longitud del campo convertido
La razón por la que incluimos el tipo de dato inicial y final es que, si no lo hacemos, perderemos el formato del campo.
En lugar de indicar SORT FIELDS=COPY podríamos indicar cualquier tipo de ordenación.
Ejemplo 1: Añadir uno al saldo del fichero de empresas.
----+----1----+----2----+----3----+----4----+
000000002EMPRESA CAFETERIA NOVELTY 00110000
000000001EMPRESA LANAS MARUJA 00220000
000000004EMPRESA ASESORIA ASOCIA 00100000
Fórmula:
SORT FIELDS=COPY
OUTREC FIELDS=(1,35,36,8,ZD,ADD,+1,TO=ZD,LENGTH=8)
Resultado 1:
----+----1----+----2----+----3----+----4----+
000000002EMPRESA CAFETERIA NOVELTY 00110001
000000001EMPRESA LANAS MARUJA 00220001
000000004EMPRESA ASESORIA ASOCIA 00100001
Como podéis ver en el último campo todas las cantidades se ven incrementadas en 1.
Si quisiésemos cambiar el formato hay que tener en cuenta que la longitud del fichero de salida cambiaría.
Ejemplo 2:Añadir 5 al saldo del fichero de empresas y convertirlo a COMP-3.
----+----1----+----2----+----3----+----4----+
000000002EMPRESA CAFETERIA NOVELTY 00110000
000000001EMPRESA LANAS MARUJA 00220000
000000004EMPRESA ASESORIA ASOCIA 00100000
Fórmula:
SORT FIELDS=COPY
OUTREC FIELDS=(1,35,36,8,ZD,ADD,+5,TO=PD,LENGTH=5)
Resultado 2:
----+----1----+----2----+----3----+----4----+
000000002EMPRESA CAFETERIA NOVELTY
FFFFFFFFFCDDDCEC4CCCCECDCC4DDECDEE40010544444
000000002547952103165359910565533800100C00000
---------------------------------------------
000000001EMPRESA LANAS MARUJA
FFFFFFFFFCDDDCEC4DCDCE4DCDEDC4444440020544444
000000001547952103151204194110000000200C00000
---------------------------------------------
000000004EMPRESA ASESORIA ASOCIA
FFFFFFFFFCDDDCEC4CECEDDCC4CEDCCC4440000544444
000000004547952101252699101263910000100C00000
La operación se aplica al campo inmediatamente anterior indicado en el OUTREC. En ambos ejemplos veis que por un lado hemos indicado que queremos sacar en salida la información de la posición 1 ocupando 35, y después de la 36 ocupando 8, para la cual se aplica la operación "sumar 1".
Podéis probar con todas las operaciones : )
Aportes de los lectores:
Se pueden sumar dos campos del mismo archivo asi:
OUTREC FIELDS=((01,10,ZD),ADD,(11,10,ZD),TO=ZD,LENGTH=10)
Convertir un campo 9(3)v9(6) comp-3 a un 99v999 comp-3:
OUTREC FIELDS=(57,5,PD,DIV,+1000,TO=PD,LENGTH=3)
//SORT001 EXEC PGM=SORT
//SORTIN DD DSN=nombre.fichero.entrada1,DISP=SHR
//SORTOUT DD DSN=nombre.fichero.salida1,
// DISP=(,CATLG,DELETE),SPACE=(CYL,(500,100))
//SYSOUT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
SORT FIELDS=COPY
OUTREC FIELDS=(I,L,Ti,O,D,TO=Tf,LENGTH=L)
I – Inicio. Posición donde empieza el campo.
L – Longitud máxima del campo.
Ti - Tipo de dato inicial:
CH - Alfanumérico
ZD - Numérico
BI - Hexadecimal (campos COMP)
PD - Empaquetado con o sin signo(campos COMP-3)
O - Operador:
ADD - Suma
SUB - Resta
MUL - Multiplicación
DIV - División
D – Dato de la operación
Tf - Tipo de dato final
L - Longitud del campo convertido
La razón por la que incluimos el tipo de dato inicial y final es que, si no lo hacemos, perderemos el formato del campo.
En lugar de indicar SORT FIELDS=COPY podríamos indicar cualquier tipo de ordenación.
Ejemplo 1: Añadir uno al saldo del fichero de empresas.
----+----1----+----2----+----3----+----4----+
000000002EMPRESA CAFETERIA NOVELTY 00110000
000000001EMPRESA LANAS MARUJA 00220000
000000004EMPRESA ASESORIA ASOCIA 00100000
Fórmula:
SORT FIELDS=COPY
OUTREC FIELDS=(1,35,36,8,ZD,ADD,+1,TO=ZD,LENGTH=8)
Resultado 1:
----+----1----+----2----+----3----+----4----+
000000002EMPRESA CAFETERIA NOVELTY 00110001
000000001EMPRESA LANAS MARUJA 00220001
000000004EMPRESA ASESORIA ASOCIA 00100001
Como podéis ver en el último campo todas las cantidades se ven incrementadas en 1.
Si quisiésemos cambiar el formato hay que tener en cuenta que la longitud del fichero de salida cambiaría.
Ejemplo 2:Añadir 5 al saldo del fichero de empresas y convertirlo a COMP-3.
----+----1----+----2----+----3----+----4----+
000000002EMPRESA CAFETERIA NOVELTY 00110000
000000001EMPRESA LANAS MARUJA 00220000
000000004EMPRESA ASESORIA ASOCIA 00100000
Fórmula:
SORT FIELDS=COPY
OUTREC FIELDS=(1,35,36,8,ZD,ADD,+5,TO=PD,LENGTH=5)
Resultado 2:
----+----1----+----2----+----3----+----4----+
000000002EMPRESA CAFETERIA NOVELTY
FFFFFFFFFCDDDCEC4CCCCECDCC4DDECDEE40010544444
000000002547952103165359910565533800100C00000
---------------------------------------------
000000001EMPRESA LANAS MARUJA
FFFFFFFFFCDDDCEC4DCDCE4DCDEDC4444440020544444
000000001547952103151204194110000000200C00000
---------------------------------------------
000000004EMPRESA ASESORIA ASOCIA
FFFFFFFFFCDDDCEC4CECEDDCC4CEDCCC4440000544444
000000004547952101252699101263910000100C00000
La operación se aplica al campo inmediatamente anterior indicado en el OUTREC. En ambos ejemplos veis que por un lado hemos indicado que queremos sacar en salida la información de la posición 1 ocupando 35, y después de la 36 ocupando 8, para la cual se aplica la operación "sumar 1".
Podéis probar con todas las operaciones : )
Aportes de los lectores:
Se pueden sumar dos campos del mismo archivo asi:
OUTREC FIELDS=((01,10,ZD),ADD,(11,10,ZD),TO=ZD,LENGTH=10)
Convertir un campo 9(3)v9(6) comp-3 a un 99v999 comp-3:
OUTREC FIELDS=(57,5,PD,DIV,+1000,TO=PD,LENGTH=3)
lunes, 7 de mayo de 2012
JCL Avanzado I. Incluir condiciones IF THEN
Actualizado: Paso para comprobar si un fichero existe y otro modo de incluir condiciones IF/ELSE.
Os dejo otra pequeña utilidad para que un jcl ejecute un paso o no en función de una condición.
Vamos a aplicar las condiciones para hacer que un jcl ejecute un paso u otro en función de si un fichero tiene datos o está vacío
Lo primero que hacemos es verificar que el fichero tiene datos o no:
//**=======================================================*
//** PASO01 - COMPRUEBA SI EL FICHERO TIENE DATOS O ESTÁ VACIO
//**=======================================================*
//PASO01 EXEC PGM=IDCAMS
//IN DD DSN=nombre.fichero.prueba1,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
PRINT INFILE(IN) COUNT(1)
IF MAXCC=12 THEN SET MAXCC=4
/*
Lo segundo es incluir la condición en el paso para que se ejecute en función de éste:
//**=======================================================*
//** PASO02 - REALIZA EL PASO SI SE CUMPLE LA CONDICIÓN
//**=======================================================*
//PASO02 EXEC SORTD,COND=(4,EQ,PASO01)
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=nombre.fichero.prueba1,DISP=SHR
//SORTOUT DD DSN=nombre.fichero.prueba2,
// DISP=(,CATLG),
// SPACE=(CYL,(100,100),RLSE)
//SYSIN DD *
SORT FIELDS=COPY
Posibles resultados:
- Si existe y tiene datos --> El primer paso dice que todo es correcto (MAXXCC=0) y se ejecuta el segundo paso.
- Si existe pero está vacío --> El primer paso da un MAXXCC=4 y no se ejecuta el siguiente paso
- Si no existe --> El jcl abenda dando un FLUSH
Si lo que quieres es lo contrario, es decir, que ejecute el paso solo cuando el fichero esté vacío, pon: COND=(0,EQ,PASO01) en vez de COND=(4,EQ,PASO01).
NOTAS:
- Si se quiere aplicar la condición a más pasos posteriores únicamente añadir el COND=(X,EQ,PASO01) en cada paso.
- Ojo con poner correctamente el nombre del paso en el COND=(0,EQ,PASO01). Puede ser cualquier nombre pero debe coincidir con el que hace la validación de fichero vacío.
Otra manera de incluir condiciones IF/ELSE:
Vamos a construir un paso de JOB que comprueba si un fichero existe.
OJO! No estamos comprobando si lleva datos, sólo si existe.
//**=======================================================*
//** PASO01 - COMPRUEBA SI EL FICHERO EXISTE
//**=======================================================*
//PASO01 EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT ENTRIES (nombre.fichero.prueba1) ALL
IF LASTCC NE 0 THEN DO
SET MAXCC=4
END
/*
//**********************************************************
//**CONDICION PARA EJECUTAR EL SIGUIENTE PASO
//**SOLO SI EL FICHERO EXISTE*
//**********************************************************
//CONDIC1 IF (PASO01.RC > 0) THEN
//* NO EJECUTA BLOQUE CONDIC1 PORQUE EL FICHERO NO EXISTE
//CONDIC1 ELSE
//*******************************************************
//** PASO 02 A EJECUTAR. POR EJEMPLO UN SORT:
//*******************************************************
//PASO02 EXEC SORTD
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=nombre.fichero.prueba1,DISP=SHR
//SORTOUT DD DSN=nombre.fichero.prueba2,
// DISP=(,CATLG),
// SPACE=(CYL,(100,100),RLSE)
//SYSIN DD *
SORT FIELDS=COPY
/*
//CONDIC1 ENDIF
En primer lugar utilizamos el programa IDCAMS para comprobar si el fichero existe con la instrucción LISTCAT. Si el fichero no existe, el Return Code (RC) será 4.
Lo siguiente que hacemos es crear un paso CONDIC1 con la sentencia IF, donde preguntamos si el RC del PASO01 es mayor que cero. Si es mayor que cero significa que el fichero no existe, por lo que no haremos nada. En otro caso, ejecutamos los siguientes pasos del JOB.
OJO! Todas las partes de un mismo IF deben ir precedidas del mismo nombre de paso. En nuestro ejemplo CONDIC1.
Todo IF debe terminar con un ENDIF.
La sentencia ELSE no es obligatoria.
Os dejo otra pequeña utilidad para que un jcl ejecute un paso o no en función de una condición.
Vamos a aplicar las condiciones para hacer que un jcl ejecute un paso u otro en función de si un fichero tiene datos o está vacío
Lo primero que hacemos es verificar que el fichero tiene datos o no:
//**=======================================================*
//** PASO01 - COMPRUEBA SI EL FICHERO TIENE DATOS O ESTÁ VACIO
//**=======================================================*
//PASO01 EXEC PGM=IDCAMS
//IN DD DSN=nombre.fichero.prueba1,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
PRINT INFILE(IN) COUNT(1)
IF MAXCC=12 THEN SET MAXCC=4
/*
Lo segundo es incluir la condición en el paso para que se ejecute en función de éste:
//**=======================================================*
//** PASO02 - REALIZA EL PASO SI SE CUMPLE LA CONDICIÓN
//**=======================================================*
//PASO02 EXEC SORTD,COND=(4,EQ,PASO01)
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=nombre.fichero.prueba1,DISP=SHR
//SORTOUT DD DSN=nombre.fichero.prueba2,
// DISP=(,CATLG),
// SPACE=(CYL,(100,100),RLSE)
//SYSIN DD *
SORT FIELDS=COPY
Posibles resultados:
- Si existe y tiene datos --> El primer paso dice que todo es correcto (MAXXCC=0) y se ejecuta el segundo paso.
- Si existe pero está vacío --> El primer paso da un MAXXCC=4 y no se ejecuta el siguiente paso
- Si no existe --> El jcl abenda dando un FLUSH
Si lo que quieres es lo contrario, es decir, que ejecute el paso solo cuando el fichero esté vacío, pon: COND=(0,EQ,PASO01) en vez de COND=(4,EQ,PASO01).
NOTAS:
- Si se quiere aplicar la condición a más pasos posteriores únicamente añadir el COND=(X,EQ,PASO01) en cada paso.
- Ojo con poner correctamente el nombre del paso en el COND=(0,EQ,PASO01). Puede ser cualquier nombre pero debe coincidir con el que hace la validación de fichero vacío.
Otra manera de incluir condiciones IF/ELSE:
Vamos a construir un paso de JOB que comprueba si un fichero existe.
OJO! No estamos comprobando si lleva datos, sólo si existe.
//**=======================================================*
//** PASO01 - COMPRUEBA SI EL FICHERO EXISTE
//**=======================================================*
//PASO01 EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
LISTCAT ENTRIES (nombre.fichero.prueba1) ALL
IF LASTCC NE 0 THEN DO
SET MAXCC=4
END
/*
//**********************************************************
//**CONDICION PARA EJECUTAR EL SIGUIENTE PASO
//**SOLO SI EL FICHERO EXISTE*
//**********************************************************
//CONDIC1 IF (PASO01.RC > 0) THEN
//* NO EJECUTA BLOQUE CONDIC1 PORQUE EL FICHERO NO EXISTE
//CONDIC1 ELSE
//*******************************************************
//** PASO 02 A EJECUTAR. POR EJEMPLO UN SORT:
//*******************************************************
//PASO02 EXEC SORTD
//SYSOUT DD SYSOUT=*
//SORTIN DD DSN=nombre.fichero.prueba1,DISP=SHR
//SORTOUT DD DSN=nombre.fichero.prueba2,
// DISP=(,CATLG),
// SPACE=(CYL,(100,100),RLSE)
//SYSIN DD *
SORT FIELDS=COPY
/*
//CONDIC1 ENDIF
En primer lugar utilizamos el programa IDCAMS para comprobar si el fichero existe con la instrucción LISTCAT. Si el fichero no existe, el Return Code (RC) será 4.
Lo siguiente que hacemos es crear un paso CONDIC1 con la sentencia IF, donde preguntamos si el RC del PASO01 es mayor que cero. Si es mayor que cero significa que el fichero no existe, por lo que no haremos nada. En otro caso, ejecutamos los siguientes pasos del JOB.
OJO! Todas las partes de un mismo IF deben ir precedidas del mismo nombre de paso. En nuestro ejemplo CONDIC1.
Todo IF debe terminar con un ENDIF.
La sentencia ELSE no es obligatoria.
viernes, 4 de mayo de 2012
Viaje al cerebro de un banco

Este CPD es el primer centro de Europa y el cuarto del mundo en recibir la doble certificación Tier IV (en diseño y construcción) que verifica que cuenta con los niveles máximos de fiabilidad y seguridad.
El nuevo CPD de BBVA está en Tres Cantos (Madrid), Tiene 20.000 metros cuadrados. Aloja equipos con hasta 10.000 procesadores de alta gama, frente a los 4800 del antiguo centro. Desde este centro se gestionan 44 millones de operaciones diarias.
Escuchar reportaje SER Reporteros
Suscribirse a:
Entradas (Atom)