4-May-86 13:56:29-PDT,5916;000000000001 Return-Path: Received: FROM UNIX.MACC.WISC.EDU BY USC-ISIB.ARPA WITH TCP ; 4 May 86 13:51:39 PDT Received: by unix.macc.wisc.edu (4.12/6.0.GT) id AA09143; Sun, 4 May 86 15:49:46 cdt Date: Sun, 4 May 86 15:49:46 cdt From: Peter Wu Message-Id: <8605042049.AA09143@unix.macc.wisc.edu> To: info-ibmpc-request@mosis Subject: input.c /* INPUT version 1.0 by Peter Wu 5/86 ** Send comments to ** uucp: ..{ihnp4|seismo|ucbvax|harvard|allegra}!uwvax!uwmacc!pwu ** arpa: uwmacc!pwu@uwvax.ARPA ** ** compile with IBMC using "cc input /ze" ** link with "clink input /stack:4000" ** ** Usage: ** Read a string from console into a DOS environment variable ** e.g. In a batch file: ** ** echo off ** input "Who are you? " name ** if %name%.==God. goto greet ** . \ ** . \-- (Note: %name% is an undocumented feature in Dos 3.1) ** :greet ** echo Your honor, why am I teleported here? ** ** This program relies on a number of undocumented features in DOS 3.1 to work ** properly. If you are not using DOS 3.1 on a real IBMPC, this program ** might not work. It's been tested with DOS 3.1 on IBM PC AT and IBM PC XT. ** ** See external document for more examples. */ #include #include #include #include #include #define VLEN 80 #define BUFLEN 1000 #define argprompt argv[1] #define argname argv[2] unsigned int _psp; unsigned short peekw(); unsigned char peekb(); void pokeb(); main(argc,argv) int argc; char *argv[]; { unsigned short x, p, y, envsize, free; int found; char c, var[VLEN+BUFSIZ+1], buf[BUFLEN]; int i, varlen; if (argc != 3) { cputs("Usage: input \n\015"); cputs("Input string will always be converted to lower case\n\015"); cputs("E.g. INPUT \"How are you? \" answer\n\015"); cputs(" if %answer%.==fine. goto fine\n\015"); exit(0); }; varlen = strlen(argname); /* var. name */ if (varlen > VLEN) { cputs("Variable name too long\n"); exit(1); }; for (i=0; i <= varlen; i++) { /* convert to upper case */ var[i] = toupper(argname[i]); }; strcat(var,"="); varlen++; p = _psp; do { /* find DOS's segment */ x = p; p = peekw(x,0xc); /* terminate segment address */ } while (p != x); if (peekb(x-1,0) != 0x4d) { cputs("Oops! Wrong DOS segment - something is wrong\n\015"); exit(2); } /* found DOS segment at x */ p = peekw(x-1,3) + x + 1; /* DOS's env. space */ envsize = peekw(p-1, 3) << 4; /* size of env. space in bytes */ #ifdef DEBUG printf("Your env. size has total of %d bytes\n", envsize); #endif /* The following code looks for an environment variable with the same ** name supplied by the user. If such a variable is found, it will be ** deleted (by copying the next variables over it) */ x = 0; found = 0; do { /* find environment var with the same name */ if (mystrncmp(p,x,var,varlen) == 0) { /* found same name */ y = x; found = 1; }; while (c=peekb(p,x)) { #ifdef DEBUG putchar(c); #endif if (found == 2) { pokeb(p,y,c); y++; }; x++; }; switch (found) { case 1: found=2; break; case 2: pokeb(p,y,c); y++; break; }; #ifdef DEBUG putchar('\n'); #endif } while (peekb(p,++x)); if (found) { pokeb(p,y,'\0'); x = y; }; /* Ok. Now we have gotten rid of identical variable name. All that's ** left to be done is to make sure there's room to copy the new ** variable and input string into the environment space */ /* now p:x points to the 0 at the end of current environment */ /* calculate free env. space */ free = envsize - x - 1; #ifdef DEBUG printf("You have %d bytes left in your env.\n", free); #endif cputs(argprompt); /* prompt */ buf[0] = BUFLEN - 3; cgets(buf); cputs("\n\015"); /* line feed on console after user entered string */ /* now convert the input string to lower case */ for (i=2; i < strlen(buf+2) + 2; i++) { /* convert to lower case */ buf[i] = tolower(buf[i]); }; strcat(var,buf+2); /* first two bytes of buf is not the string */ /* check to see if things will fit */ y = strlen(var); if (y+1 > free) { /* Oops, won't fit! */ cputs("Sorry, your environment space is full, program abort.\n\015"); cputs("Try \"shell=c:\command.com /p /e:62\" in config.sys to\n\015"); cputs("increase your environment space to 992 bytes\n\015"); exit(3); }; /* now copy the NAME=string to the end of environment space */ for (i=0; i <= y; i++) { /* poke the '\0' also, that's why I use <= */ pokeb(p, x++, var[i]); }; pokeb(p, x, 0); /* terminate environment space */ } /* strncmp with one string in a different segment */ mystrncmp(seg,offset,source,n) short seg,offset; int n; char *source; { int i, dif; for (i=0; i < n; i++) { dif = peekb(seg,offset+i) - source[i]; if (dif) return dif; }; return 0; } unsigned char peekb(seg,offset) short seg,offset; { char far *fptr; /* far pointer (segment + offset) to character */ /* if you forgot to use /ze option when you compile you'll get an ** error here about the '*' */ FP_SEG(fptr) = seg; FP_OFF(fptr) = offset; return *fptr; } void pokeb(seg,offset,what) short seg,offset; char what; { char far *fptr; /* far pointer (segment + offset) to character */ FP_SEG(fptr) = seg; FP_OFF(fptr) = offset; *fptr = what; } unsigned short peekw(seg,offset) short seg,offset; { unsigned far *fptr; /* far pointer (segment + offset) to short */ FP_SEG(fptr) = seg; FP_OFF(fptr) = offset; return *fptr; }