La unidad DOS nos permite acceder a muchos de los servicios que el sistema operativo pone a nuestra disposición, como son:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Espacio libre en la }
{ unid. de disco actual }
{ ESPACIO.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program Espacio; { Mira el espacio libre en la unidad de disco actual }
uses Dos;
begin
write(' Hay disponibles: ');
write( DiskFree(0) div 1024 ); { Muestra el espacio libre }
write(' K de ');
write( DiskSize(0) div 1024 ); { y el espacio total }
writeln(' K totales.');
end.
El 0 de DiskFree y DiskSize indica que se trata de la unidad actual. Un 1 se referiría a la A, un 2 a la B, un 3 a la C, y así sucesivamente. Si una unidad no existe, DiskSize devuelve -1.
Un segundo ejemplo, que muestre la fecha del sistema, sería:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Muestra la fecha }
{ actual }
{ FECHA.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program Fecha;
uses Dos;
const
nombre : array [0..6] of String[15] =
('Domingo','Lunes','Martes','Miércoles',
'Jueves','Viernes','Sábado');
var
anyo, mes, dia, diaSem : Word;
begin
GetDate( anyo, mes, dia, diaSem );
writeln('Hoy es ', nombre[diaSem], ' ',
dia, '/', mes, '/', anyo);
end.
Esto mismo lo podemos hacer usando interrupciones del DOS (os aconsejo no experimentar con esto si no sabeis lo que estais haciendo; una buena fuente de información es la lista de interrupciones recopilada por Ralf Brown). Eso sí, esta forma no funcionará en compiladores de Pascal no basados en MsDos, como FreePascal:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Lee la fecha usando }
{ interrupciones }
{ FECHA2.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program Fecha2;
uses Dos;
var
anyo, mes, dia: string; { Aquí guardaremos cada dato }
regs: Registers; { Necesaria para Intr }
{ El tipo Registers está definido en la unidad Dos }
begin
regs.ah := $2a; { Llamamos a la funcion 2Ah }
with regs do
intr($21,regs); { De la interrupción 21h }
with regs do
begin
str(cx, anyo); { El año está en regs.CX, el mes en DH }
str(dh, mes); { y el día en DL. Pasamos todo a cadena }
str(dl, dia); { con Str }
end;
writeln('Hoy es ', dia+'/'+mes+'/'+anyo);
end.
Podemos ver la lista de los ficheros que hay en un directorio mediante FindFirst y FindNext. Por ejemplo, para ver los que tienen extensión .PAS:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Lista de ficheros en }
{ un directorio }
{ LISTADIR.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{--------------------------}
program ListaDir;
uses Dos;
var
Hallado: SearchRec; { Información sobre el directorio }
{ El tipo SearchRec está definido en la unidad Dos }
begin
FindFirst( '*.PAS', AnyFile, Hallado ); { Los busca }
while DosError = 0 do { Mientras existan }
begin
Writeln( Hallado.Name ); { Escribe el nombre hallado }
FindNext( Hallado ); { y busca el siguiente }
end;
end.
("AnyFile" es una constante, definida también en la unidad DOS y se refiere a que tome cualquier fichero, tenga los atributos que tenga).
Finalmente, vamos a ver un ejemplo de cómo ejecutar otros programas desde uno nuestro:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejecuta otro prog. }
{ desde el nuestro }
{ EJECUTA.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
{$M 2000,0,0 } { 2000 bytes pila, sin heap }
{ Habrá que suprimir la línea anterior si se usa Tmt Pascal }
program EjecutaOrden;
uses dos;
begin
SwapVectors;
Exec('C:\WP51\WP.EXE', 'MITEXTO.TXT');
SwapVectors;
end.
Lo del principio es una "directiva de compilación" (se tratan con más detalle en una de las ampliaciones del curso), que indica al compilador cuanta memoria queremos reservar. En este caso, 2000 bytes para la pila (donde se guardarán las llamadas recursivas, por ejemplo) y nada (0 como mínimo y 0 como máximo) para el Heap o "montón", donde se guardan las variables dinámicas, que no tiene este programa.
Después guardamos los vectores de interrupción
con SwapVectors, y ejecutamos el programa, indicando su nombre (camino
completo) y los parámetros. Finalmente, restauramos los vectores
de interrupciones.
Podemos ejecutar ordenes del DOS como DIR y otros programas cuyo nombre completo (incluyendo directorios) no conozcamos, pero para eso hemos de llamar a COMMAND.COM con la opción /C:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejecuta una orden }
{ interna de MsDos }
{ EJECUTA2.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
{$M 2000,0,0 } { 2000 bytes pila, sin heap }
{ Habrá que suprimir la línea anterior si se usa Tmt Pascal }
program EjecutaOrden2;
uses dos;
begin
SwapVectors;
Exec('C:\COMMAND.COM', '/C DIR *.PAS');
SwapVectors;
end.
¿Y qué ocurre si nuestro intérprete de comandos no es el COMMAND.COM? Esto puede ocurrir, por ejemplo, a quienes usen 4DOS o NDOS, o versiones recientes de Windos, que usen CMD.EXE. Pues entonces podemos recurrir a la variable de entorno COMSPEC, que nos dice cual es el intérprete de comandos que estamos usando. Así, nuestra orden Exec quedaría:
Exec( GetEnv('COMSPEC'), '/C DIR *.PAS');
Como se ve en el ejemplo, GetEnv es la función que nos devuelve el valor de una variable de entorno. El fuente completo quedaría:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Ejecuta una orden }
{ interna de MsDos/Win }
{ EJECUTA3.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
{$M 2000,0,0 } { 2000 bytes pila, sin heap }
{ Habrá que suprimir la línea anterior si se usa Tmt Pascal }
program EjecutaOrden3;
uses dos;
begin
SwapVectors;
Exec( GetEnv('COMSPEC'), '/C DIR *.PAS');
SwapVectors;
end.
Pues se acabó por hoy. Como siempre, os recuerdo que queda mucho jugo por sacar a esta unidad, así que experimentad. Recordad que la ayuda on-line os puede sacar de más de un apuro y os puede descubrir más de una cosa.
Os propongo un par de ejercicios:
(Puedes ver una propuesta de solución
-todavía no disponible-,
así como un ejemplo -todavía no disponible- que muestra
el espacio libre en todas las unidades de disco).
En el apartado anterior hemos visto algunas de las posibilidades de la unidad DOS. Ahora vamos a ver una lista de lo que nos permite (en el caso de Turbo Pascal 7.0), para que tengais más base para investigar y experimentar, sin tener que pelearos demasiado con la ayuda... :-)
Indicaré el nombre de cada procedimiento (proc) o función (func), su cometido y el formato de uso... a veces... :-)
Nombre
Cometido
----------------------- ----------------------------------------------
GetDate (proc)
Devuelve la fecha del sistema operativo.
Formato: GetDate(anyo, mes, dia, diaSemana)
donde anyo, mes, dia, diaSemana son de tipo
"word".
SetDate (proc)
Fija la fecha del sistema operativo.
Formato: SetDate(anyo, mes, dia)
GetTime (proc)
Devuelve la hora del sistema operativo.
Formato: GetTime(hora, min, seg, seg100)
con hora, mis, seg, seg100 de tipo "word".
SetTime (proc)
Fija la hora del sistema operativo.
Formato: SetTime(hora, min, seg, seg100)
GetFTime (proc)
Fecha y hora de la última modificación de un
fichero. El fichero debe estar asignado y
abierto. La fecha y hora están en formato
empaquetado, que se puede descomprimir con
UnpackTime.
UnpackTime (proc)
Convierte la fecha y hora del formato que
devuelven GetFTime, FindFirst y FindNext en
un "record" de formato "DateTime":
type
TDateTime = record
Year,Month,Day,Hour,Min,Sec: Word;
end;
SetFTime (proc)
Fija la fecha y hora de un fichero. La fecha
y la hora se pasan como un valor comprimido
(longint), que se crea con PackTime.
PackTime (proc)
Convierte un registro DateTime a un valor
empaquetado para poder usar SetFTime.
Funciones de estado del disco.
Nombre
Cometido
-------------------- -------------------------------------------------
DiskFree (func) Devuelve
el número de bytes libres en una unidad
de disco.
DiskSize (func) Devuelve
el tamaño total (bytes) de una unidad de
disco.
GetVerify (proc) Devuelve el
estado del flag de verificación
(verify) del DOS: si es TRUE, las escrituras
en disco son verificadas posteriormente; si es
FALSE, no se comprueban.
SetVerify (proc) Fija el flag
de verificación a TRUE o FALSE.
Funciones de manejo de ficheros.
Nombre
Cometido
----------------------- ---------------------------------------------
FindFirst (proc)
Busca en el directorio que se indique el primer
fichero que tenga unos ciertos atributos y un
cierto nombre (se permiten comodines * y ?).
(Ver un ejemplo en el apartado anterior).
FindNext (proc)
Busca el siguiente fichero que cumpla las
condiciones fijadas con FindFirst. Se
comprueba si aún quedan ficheros mirando el
valor de la variable DosError.
GetFAttr (proc)
Devuelve los atributos de un fichero. Estos
se encuentran en forma de un "word", en el
que cada bit tiene un significado:
ReadOnly $01
Hidden $02
SysFile $04
VolumeID $08
Directory $10
Archive $20
AnyFile $3F
Por tratarse de bits, lo habitual será
comprobar su valor utilizando el producto
lógico "and":
if atributos and Hidden <> 0 then ...
SetFAttr (proc)
Fija los atributos de un fichero.
FSearch (func)
Busca un fichero en una lista de directorios.
FExpand (func)
Expande un nombre de fichero a
unidad+directorio+nombre+extensión.
FSplit (func)
Parte un nombre de fichero completo en
(directorio, nombre y extensión).
Nombre
Cometido
-------------------- ----------------------------------------------
MsDos (proc)
Ejecuta una llamada a una función del DOS.
Para indicar los parámetros de la llamada
(valores de los registros del 80x86), se
debe usar una variable de tipo "Registers"
(ver ejemplo en el apartado anterior).
Intr (proc)
Llama a una cierta interrupción software.
GetIntVec (proc) Devuelve la
dirección a la que apunta un
cierto vector de interrupción. Junto con
SetIntVec nos permite modificar las interrup-
ciones. El uso de estas dos ordenes es
avanzado, y muy peligroso si no se domina lo
que se está haciendo.
SetIntVec (proc) Fija la dirección
a la que apuntará un
cierto vector de interrupción.
Nombre
Cometido
----------------------- ----------------------------------------------
Exec (proc)
Ejecuta un cierto programa externo, pasándole
una serie de parámetros.
SwapVectors (proc) Intercambia
los vectores de interrupción
salvados con los actuales. Será necesario
hacerlo antes y después de Exec, especialmente
si hemos redirigido alguna interrupción.
Keep (proc)
Hace que el programa termine y se quede
residente (TSR). El problema está en cómo
acceder a él después... :-)
(Se puede conseguir usando GetIntVec y
SetIntVec, pero esto cae muyyyy por encima
del nivel del curso).
DosExitCode (func) Devuelve
el código de salida de un subproceso,
el "errorlevel" que usan los ficheros BAT,
y que nosotros podemos fijar haciendo halt(n).
Nombre
Cometido
----------------------- ----------------------------------------------
DosVersion (func)
Devuelve el número de versión del DOS. Es
un valor de tipo "word", cuyo byte bajo nos
indica el número principal de versión (6 en
MsDos 6.22, p.ej. ) y cuyo byte alto nos dice
el número secundario de versión (22 en el
ejemplo anterior).
GetCBreak (proc)
Dice si el DOS comprobará la pulsación de
Ctrl-Break (Ctrl+Inter en los teclados
españoles).
SetCBreak (proc)
Hace que el DOS compruebe o no la pulsación
de Ctrl-Break.