ae6239e0c18d3fa17ecda09e02778f530c72d8f8
[platform/upstream/mtools.git] / file_name.c
1 /*  Copyright 1995 David C. Niemi
2  *  Copyright 1996-1998,2000-2002,2008,2009 Alain Knaff.
3  *  This file is part of mtools.
4  *
5  *  Mtools is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  Mtools is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "sysincludes.h"
20 #include "msdos.h"
21 #include "mtools.h"
22 #include "vfat.h"
23 #include "codepage.h"
24 #include "file_name.h"
25
26 /* Write a DOS name + extension into a legal unix-style name.  */
27 char *unix_normalize (doscp_t *cp, char *ans, dos_name_t *dn)
28 {
29         char buffer[13];
30         wchar_t wbuffer[13];
31         char *a;
32         int j;
33         
34         for (a=buffer,j=0; (j<8) && (dn->base[j] > ' '); ++j,++a)
35                 *a = dn->base[j];
36         if(dn->ext[0] > ' ') {
37                 *a++ = '.';
38                 for (j=0; j<3 && dn->ext[j] > ' '; ++j,++a)
39                         *a = dn->ext[j];
40         }
41         *a++ = '\0';
42         dos_to_wchar(cp, buffer, wbuffer, 13);
43         wchar_to_native(wbuffer, ans, 13);
44         return ans;
45 }
46
47 typedef enum Case_l {
48         NONE,
49         UPPER,
50         LOWER
51 } Case_t;
52
53 static void TranslateToDos(doscp_t *toDos, const char *in, char *out, int count,
54                            char *end, Case_t *Case, int *mangled)
55 {
56         wchar_t buffer[12];
57         wchar_t *s=buffer;
58         wchar_t *t=buffer;
59
60         /* first convert to wchar, so we get to use towupper etc. */
61         native_to_wchar(in, buffer, count, end, mangled);
62         buffer[count]='\0';
63
64         *Case = NONE;
65         for( ;  *s ; s++) {
66                 /* skip spaces & dots */
67                 if(*s == ' ' || *s == '.') {
68                         *mangled |= 3;
69                         continue;
70                 }
71
72                 if (iswcntrl(*s)) {
73                         /* "control" characters */
74                         *mangled |= 3;
75                         *t = '_';
76                 } else if (iswlower(*s)) {
77                         *t = towupper(*s);
78                         if(*Case == UPPER && !mtools_no_vfat)
79                                 *mangled |= 1;
80                         else
81                                 *Case = LOWER;
82                 } else if (iswupper(*s)) {
83                         *t = *s;
84                         if(*Case == LOWER && !mtools_no_vfat)
85                                 *mangled |= 1;
86                         else
87                                 *Case = UPPER;
88                 } else
89                         *t = *s;
90                 t++;
91         }
92         wchar_to_dos(toDos, buffer, out, t - buffer, mangled);
93 }
94
95 /* dos_name
96  *
97  * Convert a Unix-style filename to a legal MSDOS name and extension.
98  * Will truncate file and extension names, will substitute
99  * the character '~' for any illegal character(s) in the name.
100  */
101 void dos_name(doscp_t *toDos, const char *name, int verbose, int *mangled,
102               dos_name_t *dn)
103 {
104         char *s, *ext;
105         register int i;
106         Case_t BaseCase, ExtCase;
107
108         *mangled = 0;
109
110         /* skip drive letter */
111         if (name[0] && name[1] == ':')
112                 name = &name[2];
113
114         /* zap the leading path */
115         name = (char *) _basename(name);
116         if ((s = strrchr(name, '\\')))
117                 name = s + 1;
118         
119         memset(dn, ' ', 11);
120
121         /* skip leading dots and spaces */
122         i = strspn(name, ". ");
123         if(i) {
124                 name += i;
125                 *mangled = 3;
126         }
127
128         ext = strrchr(name, '.');
129
130         /* main name */
131         TranslateToDos(toDos, name, dn->base, 8, ext, &BaseCase, mangled);
132         if(ext)
133                 TranslateToDos(toDos, ext+1, dn->ext, 3, 0, &ExtCase,  mangled);
134
135         if(*mangled & 2)
136                 autorename_short(dn, 0);
137
138         if(!*mangled) {
139                 if(BaseCase == LOWER)
140                         *mangled |= BASECASE;
141                 if(ExtCase == LOWER)
142                         *mangled |= EXTCASE;
143         }
144 }
145
146
147 /*
148  * Get rid of spaces in an MSDOS 'raw' name (one that has come from the
149  * directory structure) so that it can be used for regular expression
150  * matching with a Unix filename.  Also used to 'unfix' a name that has
151  * been altered by dos_name().
152  */
153
154 wchar_t *unix_name(doscp_t *dosCp,
155                    const char *base, const char *ext, char Case, wchar_t *ret)
156 {
157         char *s, tname[9], text[4], ans[13];
158         int i;
159
160         strncpy(tname, base, 8);
161         tname[8] = '\0';
162         if ((s = strchr(tname, ' ')))
163                 *s = '\0';
164
165         if(!(Case & (BASECASE | EXTCASE)) && mtools_ignore_short_case)
166                 Case |= BASECASE | EXTCASE;
167
168         if(Case & BASECASE)
169                 for(i=0;i<8 && tname[i];i++)
170                         tname[i] = tolower(tname[i]);
171
172         strncpy(text, ext, 3);
173         text[3] = '\0';
174         if ((s = strchr(text, ' ')))
175                 *s = '\0';
176
177         if(Case & EXTCASE)
178                 for(i=0;i<3 && text[i];i++)
179                         text[i] = tolower(text[i]);
180
181         if (*text) {
182                 strcpy(ans, tname);
183                 strcat(ans, ".");
184                 strcat(ans, text);
185         } else
186                 strcpy(ans, tname);
187
188         /* fix special characters (above 0x80) */
189         dos_to_wchar(dosCp, ans, ret, 12);
190         return ret;
191 }
192
193 /* If null encountered, set *end to 0x40 and write nulls rest of way
194  * 950820: Win95 does not like this!  It complains about bad characters.
195  * So, instead: If null encountered, set *end to 0x40, write the null, and
196  * write 0xff the rest of the way (that is what Win95 seems to do; hopefully
197  * that will make it happy)
198  */
199 /* Always return num */
200 int unicode_write(wchar_t *in, struct unicode_char *out, int num, int *end_p)
201 {
202         int j;
203
204         for (j=0; j<num; ++j) {
205                 if (*end_p)
206                         /* Fill with 0xff */
207                         out->uchar = out->lchar = (char) 0xff;
208                 else {
209                         out->uchar = *in >> 8;
210                         out->lchar = *in;
211                         if (! *in) {
212                                 *end_p = VSE_LAST;
213                         }
214                 }
215
216                 ++out;
217                 ++in;
218         }
219         return num;
220 }