Desde 2017 con UPTIME 2 para DOS que no había vuelto a estos frikismos de retro-programación. En el ejemplo de hoy, una tontería bastante grande, pero bastante interesante.
FreeDOS distribuye con su software base VERIFY.COM, una herramienta que reproduce el comando interno VERIFY de DOS, y que aunque muchos no conoceréis, sigue implementado incluso en las consolas de comandos de Windows 11.
El caso es que ese VERIFY.COM creado por Peter Mikalajunas en 1995 estaba escrito en C, algo que no tiene mucho sentido debido a la simplicidad de su función, esencialmente invocar a los servicios de DOS. No es de extrañar, que incluyendo dependencias variadas (librerías y runtimes), el ejecutable resultante fuera 5.444 bytes.
Como entretenimiento decidí reimplementarlo en ensamblador, como es mi costumbre últimamente usando el macro-ensamblador UASM. Mientras que el original eran unas 70 líneas de código sin contar comentarios, no es de extrañar que mi implementación en ensamblador requiriera algunas más, unas 110. Sin embargo, el tamaño del ejecutable .COM resultante pasó a solamente 653 bytes, es decir, casi 10 veces menos.
A destacar que el original no era 100% compatible con el comando interno de DOS, que espera como argumentos ON u OFF, mientras que el código de esa versión entendía solamente /ON y /OFF. El mío es fiel al VERIFY de siempre, aceptando ON u OFF, sino también 0 o 1.
Por lo demás, no tiene mucho misterio a comentar, así que sin más te dejo aquí el enlace para descargar el código fuente y compilado (2 KB. en formato ZIP) (también disponible en Sourceforge), y como referencia, pego el código original de VERIFY.C, así como mi implementación de VERIFY.ASM.
/* VERIFY Copyright (c) 1995 Peter Mikalajunas * * VERIFY: command that tells DOS to verify if files are written * correctly to disk. * * Author: Peter Mikalajunas * kd9fb@xnet.com * * Date: 01/30/95 * * Version: 1.0 * * NOTE: This implementation relies on the intdos() function in dos.h. * As such, it is not strictly ANSI C. intdos() is available * in Borland and Microsoft C. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include/* for intdos() */ #include /* for puts */ #include /* for strcmp */ /* * 0 = Verify off * 1 = Verify on */ int get_verify_state (void) { union REGS regs; regs.h.ah = 0x54; intdos (®s, ®s); return regs.h.al; } void set_verify_state (int flag) { union REGS regs; regs.h.ah = 0x2e; regs.h.al = flag; regs.h.dl = 0; intdos (®s, ®s); } int main (int argc, char *argv[]) { int vflag; if (argc < 2) /* no command line arguments */ { if (get_verify_state () == 0) { puts ("VERIFICATION IS CURRENTLY OFF"); } else if (get_verify_state () == 1) { puts ("VERIFICATION IS CURRENTLY ON"); } } if (argc > 1) /* handle on/off command line arguments */ { if (strcmp (argv[1], "/on") == 0 || strcmp (argv[1], "/ON") == 0) { vflag=1; set_verify_state (vflag); puts ("VERIFICATION IS NOW SET ON"); } if (strcmp (argv[1], "/off") == 0 || strcmp (argv[1], "/OFF") == 0) { vflag=0; set_verify_state (vflag); puts ("VERIFICATION IS NOW SET OFF"); } if (strcmp (argv[1], "/?") == 0) { puts ("USAGE: VERIFY sets file copy verification ON or OFF."); puts(" "); puts (" VERIFY used alone returns the current setting."); puts (" VERIFY /on to turn verification on."); puts (" VERIFY /off to turn verification off."); } } return 0; }
;-------------------------------------------------------------------------------------------------------------------------------------------------------------- .model tiny .stack 64 .code org 100h ;-------------------------------------------------------------------------------------------------------------------------------------------------------------- .startup ;Parse command-line options mov al, byte ptr ds:[80h] ;We have arguments .if al > 0 mov ax, word ptr ds:[82h] ;One digit 0/1 .if al == '1' mov al, 1 call Doit .elseif al == '0' xor al, al call Doit .else ;Two digits on/off .switch ax .case 'no', 'NO', 'No', 'nO' mov al, 1 call Doit .endc .case 'fo', 'FO', 'Fo', 'fO' xor al, al call Doit .endc .default call ShowHelp .endc .endsw .endif .else call ShowStatus .endif .exit ;-------------------------------------------------------------------------------------------------------------------------------------------------------------- ;Enable/Disable in AL DoIt proc mov ah, 2eh xor dl, dl int 21h call ShowStatus ret DoIt endp ;-------------------------------------------------------------------------------------------------------------------------------------------------------------- ;Show status ShowStatus proc mov dx, offset acStatus call PrintText mov ah, 54h xor dl, dl int 21h .if (al == 0) mov dx, offset acOff .else mov dx, offset acOn .endif call PrintText ret ShowStatus endp ;-------------------------------------------------------------------------------------------------------------------------------------------------------------- ShowHelp proc mov dx, offset acCopyright call PrintText mov dx, offset acCrLf call PrintText ;Return mov al, -1 ret ShowHelp endp ;-------------------------------------------------------------------------------------------------------------------------------------------------------------- ;Text in DX PrintText proc uses ax mov ah, 9 int 21h ret PrintText endp ;-------------------------------------------------------------------------------------------------------------------------------------------------------------- .data acCopyright db 13, 10 db "VERIFY R1.00 (c) 2022 by Javier Gutierrez Chamorro (Guti)", 13, 10 db "Controls whether to verify files are written correctly to a disk.", 13, 10, 10 acHelp db "Syntax is: VERIFY [-h|on|1|off|0]", 13, 10, 10 db "Examples:", 13, 10, 10 db " VERIFY -h", 13, 10 db " Shows this help screen.", 13, 10 db " VERIFY ON", 13, 10 db " Enable verification flag", 13, 10 db " VERIFY", 13, 10 db " Display verification flag", 13, 10, 10 db "Type VERIFY without a parameter to display the current VERIFY setting.", 13, 10, 10 db "More information at:", 13, 10 db " http://nikkhokkho.sourceforge.net/static.php?page=VERIFY", 13, 10 acCrLf db 13, 10, ' acStatus db 'VERIFY is acOn db "ON$" acOff db "OFF$" end
Muy interesante, deberían incorporarlo por defecto en FreeDOS en lugar de la versión en C, la verdad es que entre una y otra no hay color, buen trabajo Guti.
En mi caso utilizo mucho Verify para la copia de archivos, porque me funciona mejor que la copia «en alto nivel» mediante la GUI de Windows y no te da tanto error. Lo que hecho en falta es una animación de estado, pero claro, viniendo de tiempos en los que la multitarea era una rareza, no me extraña que no se la pusieran.
FreeDOS lo publicó en su sección de noticias (https://sourceforge.net/p/freedos/news/2022/09/verify-and-cls-re-implementation-in-assembly/), así que entiendo que pronto estará incorporado a las distribuciones Droiddrika.
Me ha gustado el artículo, como curiosidad, el VERIFY lo uso cuando trasteo con el emulador del C64 vice, para ver si se ha escrito correctamente el programita basic en el «diskette», (VERIFY «program»,8).
Interesante el código ensamblador y que manera de tenerlo «fresco». Un buen reto intelectual, retro; valga el juego de palabras. Tiene mérito.
Gracias Torsan. Son de esas cosas que tienen una utilidad muy reducida, casi como hacer un crucigrama o un sudoku, pero lo disfruté.