Back to index

plt-scheme  4.2.1
start.c
Go to the documentation of this file.
00001 /* Launcher program for Windows. */
00002 /* Builds a MzScheme starter if MZSTART is defined. */
00003 /* Builds a MrEd starter if MRSTART is defined. */
00004 /* If neither is defined, MZSTART is auto-defined. */
00005 
00006 #include <windows.h>
00007 #include <stdlib.h>
00008 #include <stdio.h>
00009 #include <sys/types.h>
00010 #include <sys/stat.h>
00011 #include <process.h>
00012 #include <ctype.h>
00013 
00014 #ifndef MRSTART
00015 # ifndef MZSTART
00016 #  define MZSTART
00017 # endif
00018 #endif
00019 
00020 #ifdef MRSTART
00021 # define GOSUBDIR L"\\"
00022 # define GOEXE L"mred"
00023 # define sGOEXE "mred"
00024 # define WAITTILDONE 0
00025 #endif
00026 
00027 #ifdef MZSTART
00028 # define GOSUBDIR L"\\"
00029 # define GOEXE L"mzscheme"
00030 # define sGOEXE "mzscheme"
00031 # define WAITTILDONE 1
00032 #endif
00033 
00034 #define MAXCOMMANDLEN 1024
00035 #define MAX_ARGS 100
00036 
00037 #if defined(_MSC_VER)
00038 # define MSC_IZE(x) _ ## x
00039 #else
00040 # define MSC_IZE(x) x
00041 #endif
00042 #define DUPLICATE_INPUT
00043 
00044 /* Win command lines limited to 1024 chars, so 1024 chars for
00045    command tail is ample */
00046 
00047 static wchar_t *input = 
00048   L"<Command Line: Replace This ************************************"
00049   L"****************************************************************"
00050   L"****************************************************************"
00051   L"****************************************************************"
00052   L"****************************************************************"
00053   L"****************************************************************"
00054   L"****************************************************************"
00055   L"****************************************************************"
00056   L"****************************************************************"
00057   L"****************************************************************"
00058   L"****************************************************************"
00059   L"****************************************************************"
00060   L"****************************************************************"
00061   L"****************************************************************"
00062   L"****************************************************************"
00063   L"****************************************************************"
00064   L"****************************************************************"
00065   L"****************************************************************"
00066   L"****************************************************************"
00067   L"****************************************************************"
00068   L"****************************************************************"
00069   L"****************************************************************"
00070   L"****************************************************************"
00071   L"****************************************************************"
00072   L"****************************************************************"
00073   L"****************************************************************"
00074   L"****************************************************************"
00075   L"****************************************************************"
00076   L"****************************************************************"
00077   L"***************************************************************>";
00078 
00079 /* Win long filenames limited to 255 chars, so 254 chars for
00080    directory is ample */
00081 
00082 static wchar_t *exedir = L"<Executable Directory: Replace This ********"
00083                       L"********************************************"
00084                       L"********************************************"
00085                       L"********************************************"
00086                       L"********************************************"
00087                       L"********************************************>";
00088 
00089 static wchar_t *variant = L"<Executable Variant: Replace This>";
00090 
00091 static int wc_strlen(const wchar_t *ws)
00092 {
00093   int l;
00094   for (l = 0; ws[l]; l++) { }
00095   return l;
00096 }
00097 
00098 static void wc_strcpy(wchar_t *dest, const wchar_t *src)
00099 {
00100   while (*src) {
00101     *dest = *src;
00102     dest++;
00103     src++;
00104   }
00105   *dest = 0;
00106 }
00107 
00108 static void wc_strcat(wchar_t *dest, const wchar_t *src)
00109 {
00110   while (*dest)
00111     dest++;
00112   wc_strcpy(dest, src);
00113 }
00114 
00115 static wchar_t *protect(wchar_t *s)
00116 {
00117   wchar_t *naya;
00118   int has_space = 0, has_quote = 0, was_slash = 0;
00119 
00120   for (naya = s; *naya; naya++) {
00121     if (((*naya < 128) && isspace(*naya)) || (*naya == '\'')) {
00122       has_space = 1;
00123       was_slash = 0;
00124     } else if (*naya == '"') {
00125       has_quote += 1 + (2 * was_slash);
00126       was_slash = 0;
00127     } else if (*naya == '\\') {
00128       was_slash++;
00129     } else
00130       was_slash = 0;
00131   }
00132 
00133   if (has_space || has_quote) {
00134     wchar_t *p;
00135     int wrote_slash = 0;
00136 
00137     naya = (wchar_t *)malloc((wc_strlen(s) + 3 + 3*has_quote) * sizeof(wchar_t));
00138     naya[0] = '"';
00139     for (p = naya + 1; *s; s++) {
00140       if (*s == '"') {
00141        while (wrote_slash--)
00142          *(p++) = '\\';
00143        *(p++) = '"'; /* endquote */
00144        *(p++) = '\\';
00145        *(p++) = '"'; /* protected */
00146        *(p++) = '"'; /* start quote again */
00147        wrote_slash = 0;
00148       } else if (*s == '\\') {
00149        *(p++) = '\\';
00150        wrote_slash++;
00151       } else {
00152        *(p++) = *s;
00153        wrote_slash = 0;
00154       }
00155     }
00156     *(p++) = '"';
00157     *p = 0;
00158 
00159     return naya;
00160   }
00161 
00162   return s;
00163 }
00164 
00165 static int parse_command_line(int count, wchar_t **command, 
00166                            wchar_t *buf, int maxargs)
00167 
00168 {
00169   wchar_t *parse, *created, *write;
00170   int findquote = 0;
00171     
00172   parse = created = write = buf;
00173   while (*parse) {
00174     while (*parse && (*parse < 128) && isspace(*parse)) parse++;
00175     while (*parse && ((*parse > 128) || !isspace(*parse) || findquote))      {
00176       if (*parse== '"') {
00177        findquote = !findquote;
00178       } else if (*parse== '\\') {
00179        wchar_t *next;
00180        for (next = parse; *next == '\\'; next++);
00181        if (*next == '"') {
00182          /* Special handling: */
00183          int count = (next - parse), i;
00184          for (i = 1; i < count; i += 2)
00185            *(write++) = '\\';
00186          parse += (count - 1);
00187          if (count & 0x1) {
00188            *(write++) = '\"';
00189            parse++;
00190          }
00191        }      else
00192          *(write++) = *parse;
00193       } else
00194        *(write++) = *parse;
00195       parse++;
00196     }
00197     if (*parse)
00198       parse++;
00199     *(write++) = 0;
00200          
00201     if (*created) {
00202       command[count++] = created;
00203       if (count == maxargs)
00204        return count;
00205     }
00206     created = write;
00207   }
00208 
00209   return count;
00210 }
00211 
00212 static wchar_t *make_command_line(int argc, wchar_t **argv)
00213 {
00214   int i, len = 0;
00215   wchar_t *r;
00216 
00217   for (i = 0; i < argc; i++) {
00218     len += wc_strlen(argv[i]) + 1;
00219   }
00220   r = (wchar_t *)malloc(len * sizeof(wchar_t));
00221   len = 0;
00222   for (i = 0; i < argc; i++) {
00223     int l = wc_strlen(argv[i]);
00224     if (len) r[len++] = ' ';
00225     memcpy(r + len, argv[i], l * sizeof(wchar_t));
00226     len += l;
00227   }
00228 
00229   r[len] = 0;
00230   return r;
00231 }
00232 
00233 #ifdef MZSTART
00234 void WriteStr(HANDLE h, const char *s) {
00235   DWORD done;
00236   WriteFile(h, s, strlen(s), &done, NULL);
00237 }
00238 #endif
00239 
00240 #ifdef DUPLICATE_INPUT
00241 static wchar_t *copy_string(wchar_t *s)
00242 {
00243   int l = wc_strlen(s);
00244   wchar_t *d = (wchar_t *)malloc((l + 1) * sizeof(wchar_t));
00245   memcpy(d, s, (l + 1) * sizeof(wchar_t));
00246   return d;
00247 }
00248 #endif
00249 
00250 #ifdef MRSTART
00251 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
00252                    LPWSTR m_lpCmdLine, int nCmdShow)
00253 #else
00254 int wmain(int argc_in, wchar_t **argv_in)
00255 #endif
00256 {
00257   wchar_t go[MAXCOMMANDLEN * 2];
00258   wchar_t *args[MAX_ARGS + 1];
00259   wchar_t *command_line; 
00260   int count, i, cl_len;
00261   struct MSC_IZE(stat) st;
00262   STARTUPINFOW si;
00263   PROCESS_INFORMATION pi;
00264 #ifdef MZSTART
00265   HANDLE out;
00266 
00267   out = GetStdHandle(STD_OUTPUT_HANDLE);
00268 #endif
00269  
00270 #ifdef DUPLICATE_INPUT
00271   /* gcc: input is read-only */
00272   input = copy_string(input);
00273   exedir = copy_string(exedir);
00274 #endif
00275 
00276   count = 1;
00277   count = parse_command_line(count, args, input, MAX_ARGS);
00278   
00279   /* exedir can be relative to the current executable */
00280   if ((exedir[0] == '\\')
00281       || ((((exedir[0] >= 'a') && (exedir[0] <= 'z'))
00282           ||  ((exedir[0] >= 'A') && (exedir[0] <= 'Z')))
00283          && (exedir[1] == ':'))) {
00284     /* Absolute path */
00285   } else {
00286     /* Make it absolute, relative to this executable */
00287     int plen;
00288     int mlen;
00289     wchar_t *s2, *path;
00290 
00291     path = (wchar_t *)malloc(1024 * sizeof(wchar_t));
00292     GetModuleFileNameW(NULL, path, 1024);
00293 
00294     plen = wc_strlen(exedir);
00295     mlen = wc_strlen(path);
00296 
00297     while (mlen && (path[mlen - 1] != '\\')) {
00298       mlen--;
00299     }
00300     s2 = (wchar_t *)malloc((mlen + plen + 1) * sizeof(wchar_t));
00301     memcpy(s2, path, mlen * sizeof(wchar_t));
00302     memcpy(s2 + mlen, exedir, (plen + 1) * sizeof(wchar_t));
00303     exedir = s2;
00304   }
00305 
00306   wc_strcpy(go, exedir);
00307   wc_strcat(go, GOSUBDIR);
00308   wc_strcat(go, GOEXE);
00309   wc_strcat(go, variant);
00310   wc_strcat(go, L".exe");
00311 
00312   if (_wstat(go, &st)) {
00313 #ifdef MRSTART
00314     wchar_t errbuff[MAXCOMMANDLEN * 2];
00315     swprintf(errbuff,L"Can't find %s",go);
00316     MessageBoxW(NULL,errbuff,L"Error",MB_OK);
00317 #else
00318     char errbuff[MAXCOMMANDLEN * 2];
00319     sprintf(errbuff,"Can't find %S\n",go);
00320     WriteStr(out,errbuff);
00321 #endif
00322     exit(-1);
00323   }
00324 
00325   args[0] = go;
00326 
00327 #ifdef MRSTART
00328   {
00329     wchar_t *buf;
00330     
00331     m_lpCmdLine = GetCommandLineW();
00332 
00333     buf = (wchar_t *)malloc((wc_strlen(m_lpCmdLine) + 1) * sizeof(wchar_t));
00334     memcpy(buf, m_lpCmdLine, (wc_strlen(m_lpCmdLine) + 1) * sizeof(wchar_t));
00335     count = parse_command_line(count, args, buf, MAX_ARGS);
00336   }
00337 #else
00338   {
00339     int i;
00340     for (i = 1; i < argc_in; i++)
00341       args[count++] = argv_in[i];
00342   }
00343 #endif
00344   
00345   args[count] = NULL;
00346   
00347   for (i = 0; i < count; i++) {
00348     args[i] = protect(args[i]);
00349     /* MessageBox(NULL, args[i], "Argument", MB_OK); */
00350   }
00351   
00352   memset(&si, 0, sizeof(si));
00353   si.cb = sizeof(si);
00354   
00355   command_line = make_command_line(count, args);
00356 
00357   cl_len = wc_strlen(command_line);
00358   if (cl_len > MAXCOMMANDLEN) {
00359 #ifdef MRSTART
00360     wchar_t errbuff[MAXCOMMANDLEN * 2];
00361     swprintf(errbuff,L"Command line of %d characters exceeds %d characters: %.1024s",
00362             cl_len, MAXCOMMANDLEN,command_line);
00363     MessageBoxW(NULL,errbuff,L"Error",MB_OK);
00364 #else
00365     char errbuff[MAXCOMMANDLEN * 2];
00366     sprintf(errbuff,"Command line of %d characters exceeds %d characters: %.1024S\n",
00367            cl_len, MAXCOMMANDLEN,command_line);
00368     WriteStr(out,errbuff);
00369 #endif
00370     exit(-1);
00371   } 
00372 
00373   if (!CreateProcessW(go,
00374                     command_line,
00375                     NULL, NULL, TRUE,
00376                     0, NULL, NULL, &si, &pi)) {
00377     
00378 #ifdef MRSTART
00379     MessageBoxW(NULL, L"Can't start " GOEXE, L"Error", MB_OK);
00380 #else
00381     WriteStr(out, "Can't start " sGOEXE "\n");
00382 #endif
00383     return -1;
00384   } else {
00385 #if WAITTILDONE
00386     DWORD result;
00387     WaitForSingleObject(pi.hProcess, INFINITE);
00388     GetExitCodeProcess(pi.hProcess, &result);
00389     return result;
00390 #else
00391     return 0;
00392 #endif
00393   }
00394 }