-------------------------------------- TODO SOBRE... K-dos, ficheros y programacion modulada (overlay) ---------------------------------------------------------------------------------- Ya he tratado antes sobre ficheros con 128k, OPUS, DiscIple y +D con Betados o Unidos, Beta128, Timex FDD y +3e o +3 con la libreria de funciones de Microhobby. Hoy toca el turno al Kempston-dos y vamos a tratar tres cosas a la vez. El primero precisamente sobre los ficheros, el segundo sobre la tecnica "overlay" o equivalente CHAIN MERGE en el K-dos y por ultimo convertir o crear desde cero un programa en varias partes. I - Traducido del manual del K-dos I.A - Ficheros 3.0 FICHEROS DE ACCESO SECUENCIAL Un fichero de acceso secuencial es un fichero que consiste en un numero de registros individuales de datos. Un registro de datos puede ser una cadena de datos ya sea numerica o alfanumerica, cuyo final es marcado por un signo o caracter que lo termina (coma, apostrofe, CR, etc). El comienzo del registro es usualmente definido como el caracter que sigue al que marca el final del registro. Asi que un fichero de acceso secuencial puede ser considerado como una coleccion de 'n' registros que solo pueden ser leidos empezando con el primer registro, e incrementando el puntero de a 1 por cada operacion de lectura hasta que el registro 'n' ha sido accedido. Cualquier intento de leer un registro inexistente (n+1) genera un error de 'fin de fichero" reportado. El tama~o de un fichero de acceso secuencial depende del espacio disponible en el disco y asi que la demanda en memoria RAM es muy modesta. El K-DOS posee un numero de comandos para el manejo de ficheros de acceso secuencial que son OPEN #n, CLOSE #n, INPUT #, INKEY$# y PRINT #. Vease la referencia en el manual con la descripcion de cada comando para tener una indicacion de la aplicacion de cada uno de ellos. I.B - Programacion modular 4.0 BASIC OVERLAYS Las versiones K-DOS de MERGE y CLEAR ofrecen al programador de BASIC un inmenso poder de programacion al permitir la construccion de 'BASIC OVERLAYS' (literalmente 'superposicionado del Basic') mejor traducido como la programacion modular para reducir el uso de la RAM con programas de mayor tama~o. Si un programa BASIC, salvado con un numero de linea, es cargado con MERGE, auto ejecutara desde ese numero de linea tras haberse fusionado primero con el programa principal. Un programa muy largo en BASIC puede ser escrito en forma modular (es decir dividir un programa muy largo en varias partes llamadas modulos) con los modulos hechos para ocupar el mismo bloque de numeros de linea y ser SALVAdos como programas que se auto ejecutan separadamente. Un menu principal puede conformar el cuerpo central del programa y las respuestas del usuario a dicho menu muy simplemente cargarian el modulo requerido {overlay}, ejecutarlo para luego regresar al menu. Los modulos necesitan ser auto ejecutables para que de ese modo esten protegidos y puedan operar desde cualquier linea especificada. Si el modulo cargado con MERGE no tiene exactamente el mismo numero de lineas que el modulo anterior, uno solo puede esperar errores debido a la ejecucion de lineas que no deberian estar alli. Precisamente para eso esta CLEAR el cual simplemente borra bloques de lineas con el fin de prevenir tales errores. II - Creando el fichero mediante overlays Retomo el Programa: Fichero Biblioteca para mi ejemplo practico. La estructura del listado Basic original es la sigte.: 1-90 : el programa principal y menu. 99-190 : rutina de creacion 199-290 : insercion de datos 299-385 : busqueda 399-490 : eliminacion 499-530 : impresion de todo el fichero 599-690 : grabacion del fichero 699-790 : carga 899-1160: ordenacion de los datos Como se puede ver el listado esta dividido en varias partes, 9 en total. Vamos a dividirlo en varios modulos: el modulo principal que contiene el menu y la inicializacion de los datos, los demas modulos serian los de creacion, insercion, busqueda, eliminacion, impresion, grabacion y carga, mientras la ultima parte ordenacion se queda en el modulo principal con lo que tenemos el programa dividido en solo 8 partes. MODULO 1 crea.bas conformado por el bloque de lineas 99-190, lo renumeramos para que empiece a partir de 100 hasta el 300 y a~adimos las lineas 80 y 90 para su invocacion y borrado automaticos. 80 GOSUB 100: PRINT#4: CLEAR: PRINT 100,280 90 GOTO 5 100 REM MODULO 1 crea.bas 110 REM creacion del fichero 120 IF C=7 THEN GOTO 280 130 PRINT "Estas seguro de querer crear... s/n " 140 INPUT N$ 150 IF N$<>"s" THEN GOTO 280 160 RESTORE 170 LET C=7: GOSUB 1220 180 INPUT "Numero maximo de titulos a guardar ";NUMERO 190 DIM A$(NUMERO,160) 200 FOR J=1 TO NUMERO: PRINT ' "PARA TERMINAR: zzz" 210 FOR I=1 TO C:PRINT V$(I):INPUT A$(J,X(I)+1 TO X(I+1)) 220 IF A$(J, TO 3)="zzz" THEN GOTO 280 230 NEXT I:CLS:NEXT J 240 LET INDICE=NUMERO 250 GOTO 280 260 LET INDICE=J-1 270 GOSUB 900 280 RETURN Una vez hechas las modificaciones pertinentes, salvamos todo este modulo mediante PRINT#4:SAVE"crea/bas"LINE80 MODULO 2 inser.bas conformado por el bloque de lineas 199-290, lo renumeramos igualmente para que empiece desde la linea 100 y procedemos igual que antes. 80 GOSUB 100: PRINT#4: CLEAR: PRINT 100,230 90 GOTO 5 100 REM MODULO 2 inser.bas 110 REM insercion de 1 elemento 120 IF INDICE=NUMERO THEN GOTO 220 130 PRINT "INSERCION" 140 FOR I=1 TO C 150 PRINT V$(I):INPUT A$(INDICE+1,X(I)+1 TO X(I+1)) 160 NEXT I 170 PRINT:INPUT "CORRECTO? s/n ";N$ 180 IF N$<>"s" THEN GOTO 230 190 LET INDICE=INDICE+1 200 GOSUB 900 210 GOTO 230 220 PRINT "FICHERO COMPLETO": INPUT LINE J$ 230 RETURN Salvamos con PRINT#4:SAVE"inser/bas"LINE80 MODULO 3 busq.bas este es el conformado por el bloque de lineas 299-385, renumeramos igual. 80 GOSUB 100: PRINT#4: CLEAR: PRINT 100,250 90 GOTO 5 100 REM MODULO 3 busq.bas 110 REM rutina de busqueda de 1 elemento 120 IF INDICE=NUMERO THEN RETURN 130 GOSUB 900 140 PRINT "Introduce ";V$(S);" a buscar" 150 INPUT N$ 160 FOR I=1 TO INDICE 170 IF A$(I,X(S)+1 TO X(S)+LEN N$)=N$ THEN GOTO 230 180 IF A$(I,X(S)+1 TO X(S)+LEN N$)>N$ THEN GOTO 200 190 NEXT I 200 CLS:PRINT "NO ESTA ";N$: INPUT LINE J$ 210 LET RN=0 220 RETURN 230 LET RN=I 240 FOR I=1 TO C: PRINT V$(I);": ";A$(RN,X(I)+1 TO X(I+1)):NEXT I:INPUT LINE J$ 250 GOTO 220 Salvamos con PRINT#4:SAVE"busq/bas"LINE80 MODULO 4 elim.bas conformado por el bloque de lineas 399-490, hacemos lo mismo. 80 GOSUB 100: PRINT#4: CLEAR: PRINT 100,385 90 GOTO 5 100 REM MODULO 4 elim.bas 110 REM eliminacion de 1 elemento 120 IF INDICE=NUMERO THEN GOTO 190 130 GOSUB 300 140 IF RN=0 THEN GOTO 190 150 INPUT "Seguro de querer borrarlo? s/n ";T$: IF T$<>"s" THEN GOTO 490 160 LET A$(RN)="zzzzzz" 170 GO SUB 1000 180 LET INDICE=INDICE-1 190 RETURN 299 REM rutina de busqueda de 1 elemento 300 IF INDICE=NUMERO THEN GOTO 340 301 GOSUB 900 302 PRINT "Introduce ";V$(S);" a buscar" 303 INPUT N$ 305 FOR I=1 TO INDICE 310 IF A$(I,X(S)+1 TO X(S)+LEN N$)=N$ THEN GOTO 375 315 IF A$(I,X(S)+1 TO X(S)+LEN N$)>N$ THEN GOTO 330 320 NEXT I 330 CLS:PRINT "NO ESTA ";N$: INPUT LINE J$ 332 RN=0 340 RETURN 375 RN=I 380 FOR I=1 TO C: PRINT V$(I);": ";A$(RN,X(I)+1 TO X(I+1)):NEXT I:INPUT LINE J$ 385 GOTO 340 Este modulo requiere de la subrutina de busqueda por lo que he decidido repetirla con su numeracion original aqui para mantener la independencia del modulo. Salvamos con PRINT#4:SAVE"elim/bas"LINE80 MODULO 5 list.bas conformado por el bloque de lineas 499-530, mismo procedimiento. 80 GOSUB 100: PRINT#4: CLEAR: PRINT 100,160 90 GOTO 5 100 REM MODULO 5 list.bas 110 REM impresion de todo el fichero 120 FOR I=1 TO INDICE:FOR J=1 TO C 130 PRINT V$(J);": ";A$(I,X(J)+1 TO X(J+1)) 140 NEXT J: PAUSE 50:PRINT:PRINT:NEXT I 150 INPUT LINE J$ 160 RETURN Salvamos con PRINT#4:SAVE"list/bas"LINE80 MODULO 6 grab.bas conformado por el bloque de lineas 599-690 80 GOSUB 100: PRINT#4: CLEAR: PRINT 100,190 90 GOTO 5 100 REM MODULO 6 grab.bas 110 REM RUTINA DE GRABACION 120 IF INDICE=NUMERO THEN GOTO 190 130 PRINT#4: OPEN #1;"fichas/t":PRINT NN 140 PRINT#1;INDICE ' C 150 FOR I=1 TO INDICE 160 PRINT#1;A$(I) 170 NEXT I 180 PRINT#4:CLOSE #1 190 RETURN Salvamos con PRINT#4:SAVE"grab/bas"LINE80 MODULO 7 carga.bas conformado por el bloque de lineas 699-790, carece de saltos por condicion, osea que es plenamnete secuencial. 80 GOSUB 100: PRINT#4: CLEAR: PRINT 100,190 90 GOTO 5 100 REM MODULO 7 carga.bas 110 REM rutina de carga 120 PRINT#4:OPEN #1;"fichas/t":PRINT NN 130 INPUT #1;INDICE;C:DIM A$(INDICE+10,160) 140 FOR I=1 TO INDICE 150 INPUT #1;A$(I) 160 NEXT I 170 PRINT#4:CLOSE #1 180 GOSUB 1220 190 RETURN Salvamos con PRINT#4:SAVE"carga/bas"LINE80 y por ultimo el... MODULO principal del Programa el cual estaria conformado por los bloques de lineas 1-90 y 899-1160. 1 REM PROGRAMA FICHERO BIBLIOTECA VERSION KEMPSTONDOS 2 REM MODULO 0 Programa principal 3 LET C=0:LET NN=1 4 DEFFN W$(N)="crea/bas inser/bas busq/bas elim/bas list/bas grab/bas carga/bas "(N*10-9 TO N*10) 5 CLS 7 PRINT" Fichero Biblioteca" 10 PRINT' ' "MENU",''' "0-selecciona unidad" ' "1-creacion" ' "2-insercion" ' "3-busqueda" ' "4-eliminacion" ' "5-listado" ' "6-grabacion" ' "7-carga" 15 PRINT "8-catalogo del disco" ' "9-fin del programa" 20 INPUT " opcion ?";N 25 CLS 30 IF N=8 THEN PRINT#4:CAT:PRINT NN:: PRINT#0;"PULSE " :PAUSE 0 32 IF N=9 THEN GOTO 20000 34 IF N=0 THEN INPUT "Unidad de disco #";NN: IF NN<1 OR NN>4 THEN GOTO 34 36 IF N<0 OR N>9 THEN GOTO 5 40 PRINT#4: MERGE FN W$(N):PRINT NN 90 GOTO 5 899 REM rutina de ordenacion (no visible) 900 CLS:PRINT "Por que numero de campo desea la busqueda/ordenacion": FOR K=1 TO C:PRINT K;"-";V$(K):NEXT K:INPUT "numero ";S 1005 LET J=0 1010 FOR I=1 TO INDICE-1 1020 IF A$(I,X(S)+1 TO X(S+1))>A$(I+1,X(S)+1 TO X(S+1)) THEN GOSUB 1100 1030 NEXT I 1040 IF J<>0 THEN GOTO 1005 1050 RETURN 1100 LET J=1 1120 LET N$=A$(I) 1130 LET A$(I)=A$(I+1) 1140 LET A$(I+1)=N$ 1160 RETURN 1220 REM creacion de campos 1230 DIM V$(C,9): FOR I=1 TO C: READ V$(I): NEXT I 1240 DIM x(c+1):FOR i=1 TO c+1: READ x(i): NEXT i 1250 RETURN 1260 DATA "titulo","autor","editorial","idioma","edicion","paginas","notas", 0,32,64,74,84,88,92,160 Salvamos todo el programa principal como "FICHERO" mediante el comando PRINT#4:SAVE"FICHERO"LINE1 Ahora bastara con hacer PRINT#4:LOAD"FICHERO" para ejecutarlo todo. Para cerrar... MERGE en cada sistema MERGE como ya es sabido solo permite cargar y mezclar o fusionar los programas siempre que sean de BASIC. Hay versiones de Basic que no lo tienen como es el caso del Basic de Commodore. Mientras que en la mayoria de versiones de Basic Microsoft, MERGE carga sin ejecutar por lo que con ese fin existe CHAIN MERGE. Ahora en el Basic de casete del Spectrum, MERGE puede cargar programas sin importar que hayan sido salvados o no con la opcion SAVE LINE, ya que simplemente no ejecuta solamente fusiona el programa cargado con el que esta en curso. Sin embargo ese no es el caso con los Microdrives, MERGE solamente puede cargar archivos sin auto arranque, dando error si se intenta cargar un archivo previamente salvado con SAVE LINE. MERGE actua en OPUS, Wafadrive, Speccydos, Timex FDD y Didaktik 80 del mismo modo que su contraparte de cinta. La adaptacion de los modulos para este ultimo caso seria la sigte.: - eliminar todas las lineas 80 y 90 de cada modulo - poner dichas lineas solo en el modulo principal - Wafadrive, Timex y Didaktik usan letras para designar los discos - si no se desea se deja disco por defecto y se elimina la opcion 0 y derivados - usar la sintaxis correspondiente: 40 MERGE *FN W$(N) Sin embargo el comportamiento de MERGE en K-dos tambien es compartido por FloppyOne y Swift disk. Por lo que la tecnica ofrecida para el K-dos es valida tambien para estos ultimos, con la salvedad de que estos carecen de un comando DELETE para borrar lineas por lo que o se prescinde de esto o se a~ade al programa alguna utilidad que lo haga. De lo contrario tambien se puede usar algun Basic extendido como BetaBasic. (c)2023 zx_if1@hotmail.com