This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
d766da37bc4cb6982c739b8de57509a58db308bf
[perl5.git] / os2 / suffix.c
1 /*
2  * Suffix appending for in-place editing under MS-DOS and OS/2.
3  *
4  * Here are the rules:
5  *
6  * Style 0:  Append the suffix exactly as standard perl would do it.
7  *           If the filesystem groks it, use it.  (HPFS will always
8  *           grok it.  FAT will rarely accept it.)
9  *
10  * Style 1:  The suffix begins with a '.'.  The extension is replaced.
11  *           If the name matches the original name, use the fallback method.
12  *
13  * Style 2:  The suffix is a single character, not a '.'.  Try to add the 
14  *           suffix to the following places, using the first one that works.
15  *               [1] Append to extension.  
16  *               [2] Append to filename, 
17  *               [3] Replace end of extension, 
18  *               [4] Replace end of filename.
19  *           If the name matches the original name, use the fallback method.
20  *
21  * Style 3:  Any other case:  Ignore the suffix completely and use the
22  *           fallback method.
23  *
24  * Fallback method:  Change the extension to ".$$$".  If that matches the
25  *           original name, then change the extension to ".~~~".
26  *
27  * If filename is more than 1000 characters long, we die a horrible
28  * death.  Sorry.
29  *
30  * The filename restriction is a cheat so that we can use buf[] to store
31  * assorted temporary goo.
32  *
33  * Examples, assuming style 0 failed.
34  *
35  * suffix = ".bak" (style 1)
36  *                foo.bar => foo.bak
37  *                foo.bak => foo.$$$    (fallback)
38  *                foo.$$$ => foo.~~~    (fallback)
39  *                makefile => makefile.bak
40  *
41  * suffix = "~" (style 2)
42  *                foo.c => foo.c~
43  *                foo.c~ => foo.c~~
44  *                foo.c~~ => foo~.c~~
45  *                foo~.c~~ => foo~~.c~~
46  *                foo~~~~~.c~~ => foo~~~~~.$$$ (fallback)
47  *
48  *                foo.pas => foo~.pas
49  *                makefile => makefile.~
50  *                longname.fil => longname.fi~
51  *                longname.fi~ => longnam~.fi~
52  *                longnam~.fi~ => longnam~.$$$
53  *                
54  */
55
56 #include "EXTERN.h"
57 #include "perl.h"
58 #ifdef OS2
59 #define INCL_DOSFILEMGR
60 #define INCL_DOSERRORS
61 #include <os2.h>
62 #endif /* OS2 */
63
64 static char suffix1[] = ".$$$";
65 static char suffix2[] = ".~~~";
66
67 #define ext (&buf[1000])
68
69 add_suffix(str,suffix)
70 register STR *str;
71 register char *suffix;
72 {
73     int baselen;
74     int extlen;
75     char *s, *t, *p;
76     STRLEN slen;
77
78     if (!(str->str_pok)) (void)str_2ptr(str);
79     if (str->str_cur > 1000)
80         fatal("Cannot do inplace edit on long filename (%d characters)", str->str_cur);
81
82 #ifdef OS2
83     /* Style 0 */
84     slen = str->str_cur;
85     str_cat(str, suffix);
86     if (valid_filename(str->str_ptr)) return;
87
88     /* Fooey, style 0 failed.  Fix str before continuing. */
89     str->str_ptr[str->str_cur = slen] = '\0';
90 #endif /* OS2 */
91
92     slen = strlen(suffix);
93     t = buf; baselen = 0; s = str->str_ptr;
94     while ( (*t = *s) && *s != '.') {
95         baselen++;
96         if (*s == '\\' || *s == '/') baselen = 0;
97         s++; t++;
98     }
99     p = t;
100
101     t = ext; extlen = 0;
102     while (*t++ = *s++) extlen++;
103     if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; }
104
105     if (*suffix == '.') {        /* Style 1 */
106         if (strEQ(ext, suffix)) goto fallback;
107         strcpy(p, suffix);
108     } else if (suffix[1] == '\0') {  /* Style 2 */
109         if (extlen < 4) { 
110             ext[extlen] = *suffix;
111             ext[++extlen] = '\0';
112         } else if (baselen < 8) {
113             *p++ = *suffix;
114         } else if (ext[3] != *suffix) {
115             ext[3] = *suffix;
116         } else if (buf[7] != *suffix) {
117             buf[7] = *suffix;
118         } else goto fallback;
119         strcpy(p, ext);
120     } else { /* Style 3:  Panic */
121 fallback:
122         (void)bcopy(strEQ(ext, suffix1) ? suffix2 : suffix1, p, 4+1);
123     }
124     str_set(str, buf);
125 }
126
127 #ifdef OS2
128 int 
129 valid_filename(s)
130 char *s;
131 {
132     HFILE hf;
133     USHORT usAction;
134
135     switch(DosOpen(s, &hf, &usAction, 0L, 0, FILE_OPEN,
136         OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0L)) {
137     case ERROR_INVALID_NAME:
138     case ERROR_FILENAME_EXCED_RANGE:
139         return 0;
140     case NO_ERROR:
141         DosClose(hf);
142         /*FALLTHROUGH*/
143     default:
144         return 1;
145     }
146 }
147 #endif /* OS2 */