Don't cast returns from malloc()
[openafs.git] / src / config / util_cr.c
1 /* crlf.c : Defines the entry point for the console application.*/
2
3 /* Copyright 2000, International Business Machines Corporation and others.
4         All Rights Reserved.
5
6         This software has been released under the terms of the IBM Public
7         License.  For details, see the LICENSE file in the top-level source
8         directory or online at http://www.openafs.org/dl/license10.html
9
10 */
11
12 #undef _CRTDBG_MAP_ALLOC
13 #include "stdio.h"
14 #include "io.h"
15 #include "string.h"
16 #include "process.h"
17 #include "windows.h"
18 #include "malloc.h"
19 #include "time.h"
20 #include "stdlib.h"
21
22 #ifndef  intptr_t
23 #define intptr_t INT_PTR
24 #endif
25
26 void
27 usage()
28 {
29     printf("util_cr file ;remove cr (from crlf)\n\
30         OR util_cr } ProductVersion in_filename out_filename ; substitute for %%1-%%5 in file\n\
31            %%1=Major version, %%2=Minor version, %%3=Patch(first digit) %%4=(last two digits) %%5=Version display string \n\
32            ProductVersion=maj.min.pat.pat2 ;maj=numeric, min=numeric pat,pat2 are not more than 3 digits or 1-2 digits and one alpha \n\
33            e.g 1.0.4.1, 1.0.4 a 1.0.401, 1.0.4a  all represent the same version\n\
34         OR util_cr + file ;add cr\n \
35         OR util_cr * \"+[register key value] x=y\" ; add register key value\n\
36         OR util_cr * \"-[register key value]\" ; aremove register key value\n\
37         OR util_cr @ file.ini \"[SectionKey]variable=value\" ; update ini-ipr-pwf file\n\
38         OR util_cr @ file.ini \"[SectionKey]variable=value*DatE*\" ; update ini-ipr-pwf file, insert date\n\
39         OR util_cr ~  ;force error\n\
40         OR util_cr _del  [/q=quiet /s=recurese] [*. *. *.] ;delete \n\
41         OR util_cr _cpy [/q=quiet ] [*. *. *.] destinationFolder;\n\
42         OR util_cr _isOS [nt xp 98 9x w2] ;test for OS, return 1 if match else 0\n\
43         OR util_cr _dir !build type!source!object! set current directory in file->home base is used for offset\n\
44         OR unil_cr _ver return compiler version\n");
45     exit(0xc000);
46 }
47
48 struct TRANSLATION {
49     WORD langID;                // language ID
50     WORD charset;               // character set (code page)
51 };
52
53 int
54 CheckVersion(int argc, char *argv[])
55 {
56     OSVERSIONINFO VersionInfo;
57     int i;
58     memset(&VersionInfo, 0, sizeof(VersionInfo));
59     VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
60     if (!GetVersionEx(&VersionInfo)) {
61         return 0XC000;
62     }
63     for (i = 2; i < argc; i++) {
64         if (stricmp(argv[i], "nt") == 0) {
65             if ((VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
66                 && (VersionInfo.dwMajorVersion == 4)
67                 && (VersionInfo.dwMinorVersion == 0))
68                 return 1;
69         }
70         if (stricmp(argv[i], "xp") == 0) {
71             if ((VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
72                 && (VersionInfo.dwMajorVersion == 5)
73                 && (VersionInfo.dwMinorVersion == 1))
74                 return 1;
75         }
76         if (stricmp(argv[i], "w2") == 0) {
77             if ((VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
78                 && (VersionInfo.dwMajorVersion == 5)
79                 && (VersionInfo.dwMinorVersion == 0))
80                 return 1;
81         }
82         if (stricmp(argv[i], "98") == 0) {
83             if ((VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
84                 && (VersionInfo.dwMinorVersion == 10))
85                 return 1;
86         }
87         if (stricmp(argv[i], "95") == 0) {
88             if ((VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
89                 && (VersionInfo.dwMinorVersion == 0))
90
91                 return 1;
92         }
93         if (stricmp(argv[i], "9x") == 0) {
94             if (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
95                 return 1;
96         }
97         if (stricmp(argv[i], "_") == 0)
98             return 0;
99     }
100     return 0;
101 }
102
103 void
104 Addkey(const char *hkey, const char *subkey, const char *stag,
105        const char *sval)
106 {
107     DWORD disposition, result;
108     HKEY kPkey, kHkey = 0;
109     if (strcmp(hkey, "HKEY_CLASSES_ROOT") == 0)
110         kHkey = HKEY_CLASSES_ROOT;
111     if (strcmp(hkey, "HKEY_CURRENT_USER") == 0)
112         kHkey = HKEY_CURRENT_USER;
113     if (strcmp(hkey, "HKEY_LOCAL_MACHINE") == 0)
114         kHkey = HKEY_LOCAL_MACHINE;
115     if (kHkey == 0)
116         usage();
117     result = (RegCreateKeyEx(kHkey      /*HKEY_LOCAL_MACHINE */
118                              , subkey, 0, NULL, REG_OPTION_NON_VOLATILE,
119                              KEY_ALL_ACCESS, NULL, &kPkey,
120                              &disposition) == ERROR_SUCCESS);
121     if (!result) {
122         printf("AFS Error - Could Not create a registration key\n");
123         exit(0xc000);
124     }
125     if (stag == NULL)
126         return;
127     if ((sval) && (strlen(sval))) {
128         if (*stag == '@')
129             result =
130                 RegSetValueEx(kPkey, "", 0, REG_SZ, (CONST BYTE *) sval,
131                               (DWORD)strlen(sval));
132         else
133             result =
134                 RegSetValueEx(kPkey, stag, 0, REG_SZ, (CONST BYTE *) sval,
135                               (DWORD)strlen(sval));
136     } else {
137
138         if (*stag == '@')
139             result =
140                 (RegSetValueEx(kPkey, "", 0, REG_SZ, (CONST BYTE *) "", 0));
141         else
142             result =
143                 (RegSetValueEx(kPkey, stag, 0, REG_SZ, (CONST BYTE *) "", 0));
144     }
145     if (result != ERROR_SUCCESS) {
146         printf("AFS Error - Could Not create a registration key\n");
147         exit(0xc000);
148     }
149 }
150
151 void
152 Subkey(const char *hkey, const char *subkey)
153 {
154     DWORD result;
155     HKEY kHkey = 0;
156     if (strcmp(hkey, "HKEY_CLASSES_ROOT") == 0)
157         kHkey = HKEY_CLASSES_ROOT;
158     if (strcmp(hkey, "HKEY_CURRENT_USER") == 0)
159         kHkey = HKEY_CURRENT_USER;
160     if (strcmp(hkey, "HKEY_LOCAL_MACHINE") == 0)
161         kHkey = HKEY_LOCAL_MACHINE;
162     if (kHkey == 0)
163         usage();
164     result = RegDeleteKey(kHkey, subkey);
165     if (result != ERROR_SUCCESS) {
166         printf("AFS Error - Could Not create a registration key\n");
167         exit(0xc000);
168     }
169 }
170
171 void
172 doremove(BOOL bRecurse, BOOL bQuiet, char *argv)
173 {
174     char *pParm;
175     char parm[MAX_PATH + 1];
176     char basdir[MAX_PATH + 1];
177     strcpy(parm, argv);
178     pParm = parm;
179     GetCurrentDirectory(sizeof(basdir), basdir);
180     if (strrchr(parm, '\\') != NULL) {  /*jump to base directory */
181         pParm = strrchr(parm, '\\');
182         *pParm = 0;
183         if (!SetCurrentDirectory(parm))
184             return;
185         pParm++;
186     }
187     if (!bRecurse) {
188         struct _finddata_t fileinfo;
189         intptr_t hfile;
190         BOOL bmore;
191         char basdir[MAX_PATH + 1];
192         GetCurrentDirectory(sizeof(basdir), basdir);
193         hfile = _findfirst(pParm, &fileinfo);
194         bmore = (hfile != -1);
195         while (bmore) {
196             if ((DeleteFile(fileinfo.name) == 1) && (!bQuiet))
197                 printf("Remove %s\\%s\n", basdir, fileinfo.name);
198             bmore = (_findnext(hfile, &fileinfo) == 0);
199         }
200         _findclose(hfile);
201     } else {
202         /*RECURSIVE LOOP - SCAN directories */
203         struct _finddata_t fileinfo;
204         intptr_t hfile;
205         BOOL bmore;
206         doremove(FALSE, bQuiet, pParm);
207         hfile = _findfirst("*.*", &fileinfo);
208         bmore = (hfile != -1);
209         while (bmore) {
210             if (fileinfo.attrib & _A_SUBDIR) {
211                 if ((strcmp(fileinfo.name, ".") != 0)
212                     && (strcmp(fileinfo.name, "..") != 0)) {
213                     if (SetCurrentDirectory(fileinfo.name))
214                         doremove(TRUE, bQuiet, pParm);
215                     SetCurrentDirectory(basdir);
216                 }
217             }
218             bmore = (_findnext(hfile, &fileinfo) == 0);
219         }
220         _findclose(hfile);
221     }
222     SetCurrentDirectory(basdir);
223 }
224
225 void
226 gencurdir(char *val)
227 {
228     char bld[MAX_PATH + 1], parm[MAX_PATH + 1], src[MAX_PATH + 1],
229         obj[MAX_PATH + 1], dir[MAX_PATH + 1], curdir[MAX_PATH + 1];
230     char *p, *po;
231     FILE *f;
232     BOOL isObjAbs, isSrcAbs;    /* two flags to determine if either string is not relative */
233     strcpy(bld, val + 1);       /*it better be checked or free */
234     strcpy(src, strchr(bld, '!') + 1);
235     strcpy(obj, strchr(src, '!') + 1);
236     *strchr(bld, '!') = 0;
237     *strchr(obj, '!') = 0;
238     *strchr(src, '!') = 0;
239     isObjAbs = ((*obj == '\\') || (strstr(obj, ":")));
240     isSrcAbs = ((*src == '\\') || (strstr(src, ":")));
241     GetCurrentDirectory(MAX_PATH, dir);
242     strlwr(bld);
243     strlwr(dir);
244     strlwr(src);
245     strlwr(obj);
246     strcpy(curdir, dir);
247     strcat(curdir, "\\ \n");
248     if (GetTempPath(MAX_PATH, parm) == 0)
249         exit(0xc000);
250     strcat(parm, "home");
251     if ((f = fopen(parm, "w")) == NULL)
252         exit(0xc000);
253     __try {
254         __try {
255             if (obj[strlen(obj) - 1] != '\\')
256                 strcat(obj, "\\");
257             if (src[strlen(src) - 1] != '\\')
258                 strcat(src, "\\");
259             do {                /* try to match src or obj */
260                 if ((p = strstr(dir, src)) && isSrcAbs) {
261                     po = p;
262                     p += strlen(src);
263                 } else if ((p = strstr(dir, src)) && !isSrcAbs
264                            && *(p - 1) == '\\') {
265                     po = p;
266                     p += strlen(src);
267                 } else if ((p = strstr(dir, obj)) && isObjAbs) {
268                     po = p;
269                     p += strlen(obj);
270                 } else if ((p = strstr(dir, obj)) && !isObjAbs
271                            && *(p - 1) == '\\') {
272                     po = p;
273                     p += strlen(obj);
274                 }
275             } while (strstr(p, src) || strstr(p, obj));
276             if (isObjAbs) {
277                 sprintf(parm, "OJT=%s%s\\%s \n", obj, bld, p);
278             } else {
279                 *po = 0;
280                 sprintf(parm, "OJT=%s%s%s\\%s \n", dir, obj, bld, p);
281             }
282             if (strcmp(curdir, parm + 4) == 0)  /* current directory is object */
283                 strcpy(parm, "OJT= \n");
284             fwrite(parm, strlen(parm), 1, f);
285             if (isSrcAbs) {
286                 sprintf(parm, "SRT=%s%s\\ \n", src, p);
287             } else {
288                 *(p - strlen(src)) = 0;
289                 sprintf(parm, "SRT=%s%s%s\\ \n", dir, src, p);
290             }
291             if (strcmp(curdir, parm + 4) == 0)  /* current directory is object */
292                 strcpy(parm, "SRT= \n");
293             fwrite(parm, strlen(parm), 1, f);
294             /* now lets set the AFS_LASTCMP environment variable */
295             sprintf(parm, "AFS_LASTCMP=%s\\%s", src, p);
296         }
297         __except(EXCEPTION_EXECUTE_HANDLER) {
298             exit(0xc000);
299         }
300     }
301     __finally {
302         fclose(f);
303     }
304 }
305
306 int
307 isequal(char *msg1, char *msg2, char *disp)
308 {
309     strlwr(msg1);
310     strlwr(msg2);
311     if (strcmp(msg1, msg2) != 0)
312         return 0;
313     printf("ERROR -- %s \n", disp);
314     exit(0xc000);
315 }
316
317 int
318 SetSysEnv(int argc, char *argv[])
319 {
320     DWORD_PTR dwResult;
321     printf("assignment %s %s\n", argv[2], argv[3]);
322     Addkey("HKEY_LOCAL_MACHINE",
323            "System\\CurrentControlSet\\Control\\Session Manager\\Environment",
324            argv[2]
325            , argv[3]
326         );
327     SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
328                        (LPARAM) "Environment", SMTO_NORMAL, 1, &dwResult);
329     return 0;
330 }
331
332 int
333 main(int argc, char *argv[])
334 {
335     char fname[128];
336     FILE *file;
337     int i;
338     char **pvar, *ch, *save;
339     size_t len;
340     BOOL bRecurse = FALSE;
341     BOOL bQuiet = FALSE;
342     if (argc < 2)
343         usage();
344
345    /* RSM4: Add an "ECHO" that doesn't append a new line... */
346    if (strcmp(argv[1], "_echo") == 0) {
347       if(argc<3)
348          usage();
349       printf("%s",argv[2]);
350       return 0;
351    }
352
353     if (strcmp(argv[1], "_sysvar") == 0) {
354         if (argc < 4)
355             usage();
356         return (SetSysEnv(argc, argv));
357
358     }
359     if (strnicmp(argv[1], "_dir", 4) == 0) {    /*get current directory routine */
360         gencurdir(argv[1]);
361         return 0;
362     }
363     if (strnicmp(argv[1], "_isequal", 4) == 0) {        /*get current directory routine */
364         return isequal(argv[2], argv[3], argv[4]);
365     }
366     if (stricmp(argv[1], "_del") == 0) {        /*DELETE routine */
367         int iargc = 2;
368         if ((argc > iargc) && (stricmp(argv[iargc], "/s") == 0)) {
369             iargc++;
370             bRecurse = TRUE;
371         }
372         if ((argc > iargc) && (stricmp(argv[iargc], "/q") == 0)) {
373             iargc++;
374             bQuiet = TRUE;
375         }
376         if ((argc > iargc) && (stricmp(argv[iargc], "/s") == 0)) {
377             iargc++;
378             bRecurse = TRUE;
379         }
380         while (iargc < argc) {
381             doremove(bRecurse, bQuiet, argv[iargc]);
382             iargc++;
383         }
384         return 0;
385     }
386     if (strcmp(argv[1], "_ver") == 0) {
387         return _MSC_VER;
388     }
389     if (argc < 3)
390         usage();
391     if (strcmp(argv[1], "_isOS") == 0)
392         return CheckVersion(argc, argv);
393     if (strcmp(argv[1], "}") == 0) {
394         char v1[4], v2[4], v3[4], v4[4];
395         char v5[132];
396         char *ptr = NULL;
397         char *buf;
398         int maj;
399         int min;
400         int pat, pat2;
401         strcpy(v5, argv[2]);
402         if (argc < 5)
403             usage();
404         if ((ptr = strtok(argv[2], ". \n")) == NULL)
405             return 0;
406         maj = atoi(ptr);
407         if ((ptr = strtok(NULL, ". \n")) == NULL)
408             return 0;
409         min = atoi(ptr);
410         if ((ptr = strtok(NULL, ". \n")) == NULL)
411             return 0;
412         pat2 = -1;
413         switch (strlen(ptr)) {
414         case 0:
415             usage();
416         case 1:
417             pat = atoi(ptr);
418             if (isdigit(*ptr) != 0)
419                 break;
420             usage();
421         case 2:         //ONLY 1.0.44 is interpreted as 1.0.4.4 or 1.0.4a as 1.0.4.a
422             if (isdigit(*ptr) == 0)
423                 usage();
424             pat = *ptr - '0';
425             ptr++;
426             if (isalpha(*ptr) == 0) {
427                 pat2 = atoi(ptr);
428             } else if (isalpha(*ptr) != 0) {
429                 pat2 = tolower(*ptr) - 'a' + 1;
430             } else
431                 usage();
432             break;
433         case 3:         //1.0.401 or 1.0.40a are the same;
434             if ((isdigit(*ptr) == 0)    // first 2 must be digit
435                 || (isdigit(*(ptr + 1)) == 0)
436                 || (*(ptr + 1) != '0' && isdigit(*(ptr + 2)) == 0)      // disallow 1.0.4b0  or 1.0.41a
437                 )
438                 usage();
439             pat = *ptr - '0';
440             ptr++;
441             pat2 = atoi(ptr);
442             ptr++;
443             if (isalpha(*ptr))
444                 pat2 = tolower(*ptr) - 'a' + 1;
445             break;
446         default:
447             usage();
448         }
449         // last can be 1-2 digits or one alpha (if pat2 hasn't been set)
450         if ((ptr = strtok(NULL, ". \n")) != NULL) {
451             if (pat2 >= 0)
452                 usage();
453             switch (strlen(ptr)) {
454             case 1:
455                 pat2 = (isdigit(*ptr)) ? atoi(ptr) : tolower(*ptr) - 'a' + 1;
456                 break;
457             case 2:
458                 if (isdigit(*ptr) == 0 || isdigit(*(ptr + 1)) == 0)
459                     usage();
460                 pat2 = atoi(ptr);
461                 break;
462             default:
463                 usage();
464             }
465         }
466         file = fopen(argv[3], "r");
467         if (file == NULL)
468             usage();
469         len = filelength(_fileno(file));
470         save = malloc(len + 1);
471         buf = save;
472         len = fread(buf, sizeof(char), len, file);
473         buf[len] = 0;           //set eof
474         fclose(file);
475         file = fopen(argv[4], "w");
476         if (file == NULL)
477             usage();
478         sprintf(v1, "%i", maj);
479         sprintf(v2, "%i", min);
480         sprintf(v3, "%i", pat);
481         sprintf(v4, "%02i", pat2);
482         while (1) {
483             ptr = strstr(buf, "%");
484             fwrite(buf, 1, (ptr) ? ptr - buf : strlen(buf), file);      //write file if no % found or up to %
485             if (ptr == NULL)
486                 break;
487             switch (*(ptr + 1)) //skip first scan if buf="1...."
488             {
489             case '1':
490                 fwrite(v1, 1, strlen(v1), file);
491                 ptr++;
492                 break;
493             case '2':
494                 fwrite(v2, 1, strlen(v2), file);
495                 ptr++;
496                 break;
497             case '3':
498                 fwrite(v3, 1, strlen(v3), file);
499                 ptr++;
500                 break;
501             case '4':
502                 fwrite(v4, 1, strlen(v4), file);
503                 ptr++;
504                 break;
505             case '5':
506                 fwrite(v5, 1, strlen(v5), file);
507                 ptr++;
508                 break;
509             default:
510                 fwrite("%", 1, 1, file);        //either % at end of file or no %1...
511                 break;
512             }
513             buf = ptr + 1;
514         }
515         fclose(file);
516         free(save);
517         return 0;
518     }
519     if (strcmp(argv[1], "~") == 0) {    //check for file presence
520         if (fopen(argv[2], "r"))
521             return (0);
522         if (argc < 4)
523             printf("ERROR --- File not present %s\n", argv[2]);
524         else
525             printf("Error---%s\n", argv[3]);
526         exit(0xc000);
527     }
528     if (strcmp(argv[1], "*") == 0) {    /* "[HKEY_CLASSES_ROOT\CLSID\{DC515C27-6CAC-11D1-BAE7-00C04FD140D2}]  @=AFS Client Shell Extension" */
529         if (argc < 3)
530             usage();
531         for (i = 2; argc >= 3; i++) {
532             char *ssub = strtok(argv[i], "[");
533             BOOL option;
534             char *skey = strtok(NULL, "]");
535             char *sval, *stag;
536             if ((ssub == NULL) || (skey == NULL)) {
537                 printf("format error parameter %s\n", argv[i]);
538                 exit(0xc000);
539             }
540             option = (*ssub == '-');
541             stag = strtok(NULL, "\0");
542             if (stag)
543                 while (*stag == ' ')
544                     stag++;
545             ssub = strtok(skey, "\\");
546             ssub = strtok(NULL, "\0");
547             sval = strtok(stag, "=");
548             sval = strtok(NULL, "\0");
549             switch (option) {
550             case 0:
551                 Addkey(skey, ssub, stag, sval);
552                 break;
553             default:
554                 if (stag)
555                     Addkey(skey, ssub, stag, "");
556                 else
557                     Subkey(skey, ssub);
558                 break;
559             }
560
561             argc -= 1;
562         }
563         return 0;
564     }
565     if (strcmp(argv[1], "@") == 0) {
566         char msg[256], msgt[256];
567         char *ptr;
568         if (argc < 4)
569             usage();
570         for (i = 3; argc >= 4; i++) {
571
572             char *ssect = strstr(argv[i], "[");
573             char *skey = strstr(ssect, "]");
574             char *sval;
575             if ((ssect == NULL) || (skey == NULL)) {
576                 printf("format error parameter %s\n", argv[i]);
577                 exit(0xc000);
578             }
579             ssect++;
580             *skey = 0;
581             if ((strlen(skey + 1) == 0) || (strlen(ssect) == 0)) {
582                 printf("format error parameter %s\n", argv[i]);
583                 exit(0xc000);
584             }
585             while (*++skey == ' ');
586             sval = strstr(skey, "=");
587             if (sval == NULL) {
588                 printf("format error parameter %s\n", argv[i]);
589                 exit(0xc000);
590             }
591             ptr = sval;
592             while (*--ptr == ' ');
593             *(ptr + 1) = 0;
594             while (*++sval == ' ');
595             if (ptr = strstr(sval, "*DatE*")) { // ok so lets substitute date in this string;
596                 char tmpbuf[32];
597                 *(ptr) = 0;
598                 strcpy(msg, sval);
599                 _tzset();
600                 _strdate(tmpbuf);
601                 strcat(msg, tmpbuf);
602                 strcat(msg, ptr + 6);
603                 sval = msg;
604             }
605             if (ptr = strstr(sval, "*TimE*")) {
606                 char tmpbuf[32];
607                 *(ptr) = 0;
608                 strcpy(msgt, sval);
609                 _strtime(tmpbuf);
610                 strncat(msgt, tmpbuf, 5);
611                 strcat(msgt, ptr + 6);
612                 sval = msgt;
613             }
614             if (WritePrivateProfileString(ssect, skey, sval, argv[2]) == 0) {
615                 LPVOID lpMsgBuf;
616                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
617                               FORMAT_MESSAGE_FROM_SYSTEM |
618                               FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
619                               GetLastError(), MAKELANGID(LANG_NEUTRAL,
620                                                          SUBLANG_DEFAULT),
621                               (LPTSTR) & lpMsgBuf, 0, NULL);
622                 printf("Error writing profile string - %s", lpMsgBuf);
623                 LocalFree(lpMsgBuf);
624                 exit(0xc000);
625             }
626             argc -= 1;
627         }
628         return 0;
629     }
630     strcpy(fname, argv[2]);
631     if (strcmp(argv[1], "+") == 0) {
632         file = fopen(fname, "rb");
633         if (file == NULL)
634             exit(0xc000);
635         len = filelength(_fileno(file));
636         save = malloc(len + 2);
637         ch = save;
638         *ch++ = 0;              /* a small hack to allow matching /r/n if /n is first character */
639         len = fread(ch, sizeof(char), len, file);
640         file = freopen(fname, "wb", file);
641         while (len-- > 0) {
642             if ((*ch == '\n') && (*(ch - 1) != '\r')) { /*line feed alone */
643                 fputc('\r', file);
644             }
645             fputc(*ch, file);
646             ch++;
647         }
648         fclose(file);
649         free(save);
650         return 0;
651     }
652     if (strcmp(argv[1], "-") == 0) {
653         strcpy(fname, argv[2]);
654         file = fopen(fname, "rb");
655         if (file == NULL)
656             exit(0xc000);
657         len = filelength(_fileno(file));
658         save = malloc(len + 1);
659         ch = save;
660         len = fread(ch, sizeof(char), len, file);
661         file = freopen(fname, "wb", file);
662         while (len-- > 0) {
663             if (*ch != '\r')
664                 fputc(*ch, file);
665             ch++;
666         }
667         fclose(file);
668         free(save);
669         return 0;
670     }
671     if (strstr(fname, ".et") == NULL)
672         strcat(fname, ".et");
673     file = fopen(fname, "rb");
674     if (file == NULL)
675         exit(0xc000);
676     len = filelength(_fileno(file));
677     save = malloc(len + 1);
678     ch = save;
679     len = fread(ch, sizeof(char), len, file);
680     file = freopen(fname, "wb", file);
681     while (len-- > 0) {
682         if (*ch != '\r')
683             fputc(*ch, file);
684         ch++;
685     }
686     fclose(file);
687     pvar = malloc(argc * sizeof(char *));
688     for (i = 1; i < argc - 1; i++)
689         pvar[i] = argv[i + 1];
690     pvar[argc - 1] = NULL;
691     pvar[0] = argv[1];
692     (void)_spawnvp(_P_WAIT, argv[1], pvar);
693     if (save)
694         free(save);
695     if (pvar)
696         free(pvar);
697     return 0;
698 }