utiles.h
y
utiles.c
switch()
.
utiles.c
El objetivo que perseguimos es crear un código fuente que pueda compilarse tanto en un entorno Unix (Linux, Mac OS X) como en un entorno Windows. Esto exige hacer uso de directrices de compilación condicional adaptadas a los entornos de destino. En nuestro caso, utilizaremos el compilador GNU
gcc
en ambos entornos, lo cual facilita las cosas sin llegar a ofrecer una total compatibilidad. Véase el contenido del archivo
utiles.h
(la última versión está siempre disponible en la página de
Programación
):#include<stdio.h> #include <stdlib.h> #include <string.h> /* Latest change: 2009 09 04 */ /* Si se va a compilar el programa para Windows, eliminar el comentario (//) en la línea siguiente */ //#define __WINDOWS__ #ifndef __UTILES__ #define __UTILES__ typedef char * charRef; typedef double * doubleRef; typedef FILE * FILERef; typedef float * floatRef; typedef int * intRef; charRef pedir(charRef); charRef pedir_nv(charRef); charRef sgets(void); double pedirDouble(charRef,double,double); float pedirFloat(charRef,float,float); int pedirInt(charRef,int,int); int confirmar(const charRef indicacion); void spause(void); void leer_cadena(charRef, int); #ifdef __WINDOWS__ #define BORRAR "cls" #else #define BORRAR "clear" #include<termios.h> char getch(void); #endif #endifLa constante __WINDOWS__ se ha creado con objeto de identificar el entorno de desarrollo utilizado en Windows, y es preciso declararla ( q.v. ) o bien se puede indicar su definición al compilador empleando la directriz
-D__WINDOWS__
. Si se estudia el color de las compilacione condicionales, se observará que en color
verde
se tienen las definiciones comunes para todas las plataformas . En
rojo
están marcadas las definiciones que aporta
utiles.c
en el entorno Windows™, y en
azul
se muestran adiciones para el entorno Unix.
utiles.c
, tiene el aspecto siguiente:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<ctype.h> #include "utiles.h" /* Last modified: 2009 09 04 */ /* Si se va a compilar el programa para Windows, eliminar el comentario (//) en la línea siguiente. También se puede emplear la directriz _D__WINDOWS__ en en la compilación: gcc _D__WINDOWS__ ... */ //#define __WINDOWS__ /* sgets() has different implementations in Unix and elsewhere, hence our first step is to determine just what the underlying OS is */ #ifdef __WINDOWS__ /* This is not Unix, hence no fgetln() and sgets() is somewhat less safe. We hope the user will not input more than 1024 characteres at a time. */ charRef sgets(void) { int MAXCHARS = 1024; charRef temp = (charRef)malloc(MAXCHARS); charRef resultado; fgets(temp,MAXCHARS,stdin); resultado = (charRef)malloc(strlen(temp)); strcpy(resultado, temp); resultado[strlen(resultado)-1] = '\0'; free(temp); fflush(stdin); /* No leftovers */ return resultado; } #else /* This is Unix, hence fgetln() is available but getch() is not. We produce a reasonable implementation of sgets() and of getch() */ charRef sgets(void) { charRef puntero_linea; size_t longitud_linea; charRef resultado; puntero_linea = fgetln(stdin, &longitud_linea);/* No leftovers */ resultado = (charRef)malloc(longitud_linea+2); memcpy(resultado,puntero_linea,longitud_linea); resultado[longitud_linea-1] = '\0'; return resultado; } char getch(void) { struct termios conf_vieja, conf_nueva; char c; tcgetattr(0,&conf_vieja); conf_nueva = conf_vieja; conf_nueva.c_lflag &= (~ICANON); conf_nueva.c_cc[VTIME] = 0; conf_nueva.c_cc[VMIN] = 1; tcsetattr(0,TCSANOW,&conf_nueva); c = getchar(); tcsetattr(0,TCSANOW,&conf_vieja); return c; } #endif /* Once we have sgets() and getch() at our disposal, we build further useful functions like pedir (ask) and confirmar (confirm). All these functions are shared between platforms. */ charRef pedir(const charRef indicacion) { charRef resultado; printf("%s ", indicacion); resultado = sgets(); return resultado; } charRef pedir_nv(const charRef indicacion) { charRef resultado; int longitud; do { printf("%s ", indicacion); resultado = sgets(); longitud = strlen(resultado); if(0 == longitud) printf("\nPerdón, no se admite una respuesta en blanco.\n"); } while (0 == longitud); return resultado; } int pedirInt(charRef indicacion,int limInf,int limSup) { charRef linea = NULL; charRef temp = NULL; int numero; do { numero = limInf-1; printf("(%d <= x <= %d) ",limInf,limSup); linea = pedir(indicacion); numero = strtol(linea,&temp, 10); free(linea); } while(linea == temp || numero < limInf || numero > limSup); return numero; } float pedirFloat(charRef indicacion,float limInf,float limSup) { charRef linea = NULL; charRef temp = NULL; float numero; do { numero = limInf -1.0; printf("(%.2f <= x <= %.2f) ",limInf,limSup); linea = pedir(indicacion); numero = strtof(linea,&temp); free(linea); } while(linea == temp || numero < limInf || numero > limSup); return numero; } double pedirDouble(charRef indicacion,double limInf,double limSup) { charRef linea = NULL; charRef temp = NULL; double numero; do { numero = limInf -1.0; printf("(%.2f <= x <= %.2f) ",limInf,limSup); linea = pedir(indicacion); numero = strtof(linea,&temp); free(linea); } while(linea == temp || numero < limInf || numero > limSup); return numero; } void spause(void) { charRef temp; printf("\n\nPulse <INTRO> para continuar\n\n"); temp = sgets(); free(temp); /* No leaks! */ return; } int confirmar(charRef indicacion) { charRef respuesta; int resultado; printf("%s (s/n): ", indicacion); respuesta = sgets(); resultado = toupper(respuesta[0]) == 'S'; free(respuesta); /* No leaks! */ return resultado; }
sgets()
se ha construido de forma diferente para Unix y Windows, debido a que en Windows no existe la función
fgetln()
. Se observará también que en Unix se ha creado la función
getch()
, que no existía originalmente. Las funciones
pedir()
,
spause()
y
confirmar()
, comunes para todas las plataformas, se han creado basándose en
sgets()
, para todas las plataformas. El esquema de colores es el mismo que se ha empleado para describir
utiles.h
.