/************************************************************************* *** Install.cmm *** *** This is the installation program to set up CEnvi unregistered *** *** shareware on your computer. Before running this program, CEnvi *** *** must be copied to a hard disk directory. This Install.cmm *** *** program is identical for DOS, OS/2, and Windows version of CEnvi *** *** and this program is itself an example for how to use CEnvi *** *************************************************************************/ main(argc,argv) { // There should be no input args. If there are then the user needs help. ScreenClear(); if ( argc != 1 ) GiveInstructionsAndExit(); // Get the current directory. The GetInstallDirectory() function assures // that it is not a floppy. InstallDirectory = GetInstallDirectory(argv[0]); if defined( _DOS_ ) DosOrOS2Install(InstallDirectory,"C:\\AUTOEXEC.BAT","C:\\AUTOEXEC.BAK"); else if defined( _OS2_) DosOrOS2Install(InstallDirectory,"C:\\CONFIG.SYS","C:\\CONFIG.BAK"); else { assert( defined(_WINDOWS_) ); WindowsInstall(InstallDirectory); printf("\nPress any key to exit..."); getch(); } return(EXIT_SUCCESS); } GiveInstructionsAndExit() // Show some info about using this program { // and then exit this program. Do not return. printf("Install.cmm - CEnvi installation procedure. Execute with no parameters\n"); printf(" from the directory that contains CEnvi.exe and also contains\n"); printf(" the *.cmm and other sample CEnvi files, including Install.cmm\n"); if defined( _WINDOWS_ ) { printf("\nPress any key to exit..."); getch(); } exit(EXIT_FAILURE); } GetInstallDirectory(Executable) // return current dir that is not on a floppy { // current source directory from the name of the executable CurDir = SplitFileName(FullPath(Executable)).dir; assert( CurDir != NULL && CurDir[0] != 0 ); // check that current directory is not floppy A: or B: if ( CurDir[0] == 'A' || CurDir[0] == 'B' ) { printf("\nCannot install CEnvi from a floppy.\n\a\n"); GiveInstructionsAndExit(); } // Have found the directory Install.cmm is in, and so check that // CEnvi.exe is also in the same directory. if ( NULL == Directory(strcat(strcpy(temp,CurDir),"CEnvi.exe")) ) { printf("\nThis installation assumes that CEnvi.exe is in the same directory as\n"); printf("Install.cmm. Could not find CEnvi.exe in the Install.cmm directory.\n\a\n"); GiveInstructionsAndExit(); } // remove extra backslash if at end of name (i.e., not root directory) if ( strcmp(CurDir+1,":\\") ) CurDir[strlen(CurDir)-1] = 0; // return the result return(CurDir); } Fatal(Format) // like printf() but also beeps and exits program { va_start(parameters,Format); printf("\a\n"); // beep vprintf(Format,parameters); exit(EXIT_FAILURE); } GetYesOrNo() // prompt for Yes or No, and return entered boolean TRUE { // if YES else FALSE if NO. printf(" (Y/N) "); while( TRUE ) { // forever key = toupper(getch()); if ( key != 'Y' && key != 'N' ) printf("\a"); // beep else break; } printf("%c\n",key); return( key == 'Y' ); } CopyFile(Source,Destination) // copy file from source to destination { // open source and destination files src = fopen(Source,"rb"); if ( src == NULL ) Fatal("Could not open source file \"%s\" for reading.",Source); dest = fopen(Destination,"wb"); if ( dest == NULL ) Fatal("Could not open file \"%s\" for writing.",Destination); // read chunks from source, and copy to destination #define COPY_CHUNK_SIZE 500 while ( 0 != (size = fread(buf,COPY_CHUNK_SIZE,src)) ) { fwrite(buf,size,dest); } // close the files fclose(dest); fclose(src); } SkipWhitespace(str) { while( isspace(str[0]) ) str++; } AlreadyInPath(Dir,Path) // search through path for this Dir, return True if found, else False { len = strlen(Dir) p = Path; do { if ( 0 == strnicmp(p,Dir,len) && (p[len]==0 || p[len]==';') ) return(True) p = strchr(p,';') } while( p++ != NULL ) return(False) } AlterEVarLine(text,EVar,Dir) // If this text is a line setting the EVar environment variable, and if // Dir is not already in it, then add Dir. Return TRUE if this is // a line for EVar, and False if it is not. { FoundEVar = FALSE; // assume this is not the line // determine if text is of the type "EVAR=" or "set EVAR=" SkipWhitespace(c = text); // if the next statement is "SET" then skip it if ( !strncmpi(c,"SET",3) ) { // Skip beyond the SET statement c += 3; SkipWhitespace(c); } // test if this next part is the variable name EVarLen = strlen(EVar); if ( !strncmpi(c,EVar,EVarLen) ) { c += EVarLen; if ( isspace(c[0]) || c[0] == '=' ) { // THIS IS IT. This line describes the EVar. SkipWhitespace(c); if ( c[0] == '=' ) { c++; SkipWhitespace(c); } FoundEVar = TRUE; // If Dir is not already in this line then add Dir at the end. // Check each dir as value between semicolons (;) SkipWhitespace(c); if ( !AlreadyInPath(Dir,c) ) { // add this to the end of the existing path if ( c[strlen(c)-1] != ';' ) strcat(c,";"); strcat(c,Dir); } } } return(FoundEVar); } DosOrOS2Install(Dir,FileName,BackupFileName) { // append the PATH statement so that it contains this directory, and // also add the CMMPATH environment variable. But give user a choice // of whether to do this first; if they choose not to then tell them // what they must do by hand. printf("\nIf you choose, install will add the directory:\n\n"); printf(" \"%s\"\n\n",Dir); printf("to the PATH environment variable in your %s file. Install will\n",FileName); printf("also add this directory to the CMMPATH environment variable in that\n"); printf("file. If you select to make these changes to %s, then\n",FileName); printf("install will backup the current version of %s to %s.\n",FileName,BackupFileName); printf("\n\nShould these changes be made to %s?",FileName); if ( GetYesOrNo() ) { printf("Making changes to %s...",FileName); // user chose to make automatic changes. Do so now CopyFile(FileName,BackupFileName); // will now read the backup file, and if any PATH or CMMPATH line is // encountered then will alter it, else just copy line exactly. src = fopen(BackupFileName,"rt"); if ( src == NULL ) Fatal("Could not open source file \"%s\" for reading.",BackupFileName); dest = fopen(FileName,"wt"); if ( dest == NULL ) Fatal("Could not open source file \"%s\" for reading.",BackupFileName); SetPath = SetCmmPath = False; while ( NULL != (line = fgets(src)) ) { // remove the pesky newline if there is one if ( PeskyNewLine = (line[strlen(line)-1] == '\n') ) line[strlen(line)-1] = 0; if ( AlterEVarLine(line,"PATH",Dir) ) SetPath = True; if ( AlterEVarLine(line,"CMMPATH",Dir) ) SetCmmPath = True; fputs(line,dest); if ( PeskyNewLine ) fputs("\n",dest); } fclose(src); // if haven't already written PATH or CMMPATH, then do so now if ( !SetPath ) fprintf(dest,"\nSET PATH=%s\n",Dir); if ( !SetCmmPath ) fprintf(dest,"\nSET CMMPATH=%s\n",Dir); fclose(dest); printf("\n%s has been altered.\n",FileName); printf("Changes will take effect after you reboot.\n"); } else { // user choose not to automatically install, so describe what the user // needs to do by hand to make it work. ScreenClear(); printf("\nThe PATH environment variable is used to find executable files, such as\n"); printf("CEnvi.exe, and batch files, such as those included in this CEnvi\n"); printf("unregistered shareware release. The CMMPATH environment variable is\n"); printf("used by CEnvi to find common source code that may be included\n"); printf("in other CEnvi source files.\n\n"); printf("You chose not to have Install automatically alter %s.\n\n",FileName); printf("You may wish to try Install.cmm again, or to make these modifications\n"); printf("to %s by hand.\n",FileName); } } WindowsInstall(Dir) { // If the user chooses, then add CMM Extensions and also add // CMMPATH setting to WIN.INI. printf("\nIf you choose, install will add the directory:\n\n"); printf(" \"%s\"\n\n",Dir); printf("as a CMMPATH profile string in you WIN.INI file. Install will also\n"); printf("also add the .CMM extension to WIN.INI so that you can execute any\n"); printf("*.CMM file simply by double-clicking on it.\n"); printf("\n\nShould these changes be made to WIN.INI?"); if ( GetYesOrNo() ) { printf("Making changes to WIN.INI..."); // add extensions sprintf(extension,"%s\\CENVI.EXE ^.CMM",Dir); WriteProfileString("Extensions","CMM",extension); // add CMMPATH WriteProfileString("CEnvi","CMMPATH",Dir); TellEveryoneThatWinIniHasChanged(); printf("\n"); } else { // user choose not to automatically install, so describe what the user // needs to do by hand to make it work. ScreenClear(); printf("The .CMM extension in WIN.INI would allow you to execute CMM code simply by\n"); printf("double-clicking the file name. The CMMPATH profile string allows CEnvi to\n"); printf("find Cmm source code or code library that may be in a different directory.\n"); printf("\n"); printf("You chose not to have Install automatically alter WIN.INI\n"); printf("\n"); printf("You may wish to make these changes by hand; if so, then add the line:\n"); printf(" CMM=%s\\CENVI.EXE ^.CMM\n",Dir); printf("to the [Extensions] section of WIN.INI. At the end of WIN.INI you may also\n"); printf("want to add these lines:\n"); printf(" [CEnvi]\n"); printf(" CMMPATH=%s\n",Dir); } } WriteProfileString(ApplicationName,KeyName,KeyValue) // This is a wrapper for the WriteProfileString in the Windows Kernel. { DynamicLink("KERNEL","WRITEPROFILESTRING",SWORD16,PASCAL, ApplicationName,KeyName,KeyValue); } TellEveryoneThatWinIniHasChanged() { #define HWND_BROADCAST 0xFFFF #define WM_WININICHANGE 0x001A DynamicLink("USER","SENDMESSAGE",SWORD16,PASCAL, HWND_BROADCAST,WM_WININICHANGE,0,0,0); }