1 /***************************************************************************
2  *                                                                         *
3  *    LIBDSK: General floppy and diskimage access library                  *
4  *    Copyright (C) 2001-2, 2005  John Elliott <seasip.webmaster@gmail.com>    *
5  *                                                                         *
6  *    This library is free software; you can redistribute it and/or        *
7  *    modify it under the terms of the GNU Library General Public          *
8  *    License as published by the Free Software Foundation; either         *
9  *    version 2 of the License, or (at your option) any later version.     *
10  *                                                                         *
11  *    This library is distributed in the hope that it will be useful,      *
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of       *
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    *
14  *    Library General Public License for more details.                     *
15  *                                                                         *
16  *    You should have received a copy of the GNU Library General Public    *
17  *    License along with this library; if not, write to the Free           *
18  *    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,      *
19  *    MA 02111-1307, USA                                                   *
20  *                                                                         *
21  ***************************************************************************/
22 
23 #include "drvi.h"
24 
25 /* Standard disc geometries. These are used
26  * (i)  when logging in a disc, if the superblock is recognised
27  * (ii) when formatting */
28 
29 typedef struct dsk_namedgeom
30 {
31     dsk_cchar_t name;
32     DSK_GEOMETRY dg;
33     dsk_cchar_t desc;
34     struct dsk_namedgeom *next;
35 } DSK_NAMEDGEOM;
36 
37 /* These must match the order of the entries in dsk_format_t in libdsk.h */
38 
39 static DSK_NAMEDGEOM stdg[] =
40 {
41         /*    sidedness cyl hd sec  psn  sz   rate    rwgap  fmtgap  fm  nomulti*/
42 {"pcw180",  { SIDES_ALT,     40, 1, 9,    1, 512, RATE_SD, 0x2A, 0x52,   0,  0 }, "PCW / IBM 180k" }, /* 180k */
43 {"cpcsys",  { SIDES_ALT,     40, 1, 9, 0x41, 512, RATE_SD, 0x2A, 0x52,   0,  0 }, "CPC System" }, /* CPC system */
44 {"cpcdata", { SIDES_ALT,     40, 1, 9, 0xC1, 512, RATE_SD, 0x2A, 0x52,   0,  0 }, "CPC Data" }, /* CPC data */
45 {"pcw720",  { SIDES_ALT,     80, 2, 9,    1, 512, RATE_SD, 0x2A, 0x52,   0,  0 }, "PCW / IBM 720k" }, /* 720k */
46 {"pcw1440", { SIDES_ALT,     80, 2,18,    1, 512, RATE_HD, 0x1B, 0x54,   0,  0 }, "PcW16 / IBM 1440k "}, /* 1.4M */
47 {"ibm160",  { SIDES_ALT,     40, 1, 8,    1, 512, RATE_SD, 0x2A, 0x50,   0,  0 }, "IBM 160k (CP/M-86 / DOSPLUS)" }, /* 160k */
48 {"ibm320",  { SIDES_ALT,     40, 2, 8,    1, 512, RATE_SD, 0x2A, 0x50,   0,  0 }, "IBM 320k (CP/M-86 / DOSPLUS)" }, /* 320k */
49 {"ibm360",  { SIDES_ALT,     40, 2, 9,    1, 512, RATE_SD, 0x2A, 0x52,   0,  0 }, "IBM 360k (CP/M-86 / DOSPLUS)" }, /* 360k */
50 {"ibm720",  { SIDES_OUTBACK, 80, 2, 9,    1, 512, RATE_SD, 0x2A, 0x52,   0,  0 }, "IBM 720k (144FEAT)", }, /* 720k 144FEAT */
51 {"ibm1200", { SIDES_OUTBACK, 80, 2,15,    1, 512, RATE_HD, 0x1B, 0x54,   0,  0 }, "IBM 1.2M (144FEAT)", }, /* 1.2M 144FEAT */
52 {"ibm1440", { SIDES_OUTBACK, 80, 2,18,    1, 512, RATE_HD, 0x1B, 0x54,   0,  0 }, "IBM 1.4M (144FEAT)", }, /* 1.4M 144FEAT */
53 {"acorn160",    { SIDES_OUTOUT,  40, 1,16,    0, 256, RATE_SD, 0x12, 0x60,   0,  0 }, "Acorn 160k" }, /* Acorn 160k */
54 {"acorn320",    { SIDES_OUTOUT,  80, 1,16,    0, 256, RATE_SD, 0x12, 0x60,   0,  0 }, "Acorn 320k" }, /* Acorn 320k */
55 {"acorn640",    { SIDES_OUTOUT,  80, 2,16,    0, 256, RATE_SD, 0x12, 0x60,   0,  0 }, "Acorn 640k" }, /* Acorn 640k */
56 {"acorn800",    { SIDES_ALT,     80, 2, 5,    0,1024, RATE_SD, 0x04, 0x05,   0,  0 }, "Acorn 800k" }, /* Acorn 800k */
57 {"acorn1600",   { SIDES_ALT,     80, 2,10,    0,1024, RATE_HD, 0x04, 0x05,   0,  0 }, "Acorn 1600k" }, /* Acorn 1600k */
58 {"pcw800",  { SIDES_ALT,     80, 2,10,    1, 512, RATE_SD, 0x0C, 0x17,   0,  0 }, "PCW 800k" }, /* 800k */
59 {"pcw200",  { SIDES_ALT,     40, 1,10,    1, 512, RATE_SD, 0x0C, 0x17,   0,  0 }, "PCW 200k" }, /* 200k */
60 {"bbc100",  { SIDES_ALT,     40, 1,10,    0, 256, RATE_SD, 0x2A, 0x50,   1,  0 }, "BBC 100k" }, /* 100k */
61 {"bbc200",  { SIDES_ALT,     80, 1,10,    0, 256, RATE_SD, 0x2A, 0x50,   1,  0 }, "BBC 200k" }, /* 200k */
62 {"mbee400", { SIDES_ALT,     40, 1,10,    0, 512, RATE_SD, 0x0C, 0x17,   0,  0 }, "Microbee 400k" }, /* 400k */
63 {"mgt800",  { SIDES_OUTOUT,  80, 2,10,    1, 512, RATE_SD, 0x0C, 0x17,   0,  0 }, "MGT 800k" }, /* MGT 800k */
64 {"trdos640",{ SIDES_ALT,     80, 2,16,    1, 256, RATE_SD, 0x12, 0x60,   0,  0 }, "TR-DOS 640k" }, /* TR-DOS 640k */
65 {"ampro200",{ SIDES_ALT,     40, 1,10,   1, 512, RATE_SD, 0x0C, 0x17,   0,  0 }, "Ampro 40 track single-sided" }, /* Ampro 200k (22DISK AMP1) */
66 {"ampro400d",{ SIDES_ALT,     40, 2,10,   17, 512, RATE_SD, 0x0C, 0x17,   0,  0 }, "Ampro 40 track double-sided" }, /* Ampro 400k (22DISK AMP2) */
67 {"ampro400s",{ SIDES_ALT,     80, 1, 5,   1,1024, RATE_SD, 0x04, 0x05,   0,  0 }, "Ampro 80 track single-sided" }, /* Ampro 400k (22DISK AMP3) */
68 {"ampro800",{ SIDES_ALT,     80, 2, 5,   17,1024, RATE_SD, 0x04, 0x05,   0,  0 }, "Ampro 80 track double-sided" }, /* Ampro 800k (22DISK AMP4) */
69 /* Geometries below this line don't appear in dsk_format_t and can be accessed
70  * only by name. */
71 
72 {"myz80",   { SIDES_ALT,     64, 1,128,   0,1024, RATE_ED, 0x2A, 0x52,   0,  0 }, "MYZ80 8Mb" }, /* MYZ80 8Mb */
73 
74 /* re this comment ('This was commented out in libdsk-1.1.3, but I can't
75  * remember why. Bring it back.') -- I think I now remember why. The
76  * numeric format IDs were out of sync with the actual definitions, and I
77  * think this may be part of the reason. Move it down to the bottom, beyond
78  * the last numeric ID. */
79 {"pcpm320", { SIDES_OUTBACK, 40, 2, 8,    1, 512, RATE_SD, 0x2A, 0x50,   0,  0 }, "IBM 320k (CP/M-86 / DOSPLUS)" }, /* 320k */
80 };
81 
82 
83 #ifdef HAVE_SHLOBJ_H
84 #include <shlobj.h>
85 #include <io.h>
86 #include <objidl.h>
87 
dg_shell_folder(int csidl,char * buf)88 static void dg_shell_folder(int csidl, char *buf)
89 {
90     LPMALLOC pMalloc;
91     LPITEMIDLIST pidl;
92     char *cwd;
93         char result[PATH_MAX];
94 
95     cwd = getcwd(result, PATH_MAX);
96     if (cwd == NULL) strcpy(result, ".");
97     strcpy(buf, result);
98 
99     /* Get the shell's allocator */
100     if (!SUCCEEDED(SHGetMalloc(&pMalloc))) return;
101     /* Get the PIDL for the folder in question */
102     if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidl, &pidl)))
103     {
104         if (SHGetPathFromIDList(pidl, result))
105             strcpy(buf, result);
106         (pMalloc->lpVtbl->Free)(pMalloc, pidl);
107     }
108     /* Release the shell's allocator */
109     (pMalloc->lpVtbl->Release)(pMalloc);
110 }
111 
dg_homedir(void)112 const char *dg_homedir(void)
113 {
114     HKEY hk;
115     DWORD dws;
116     static char buf[PATH_MAX];
117     char *t;
118     long l;
119 
120     l = RegOpenKeyEx(HKEY_CURRENT_USER,
121         "Software\\jce@seasip\\LibDsk", 0, KEY_READ, &hk);
122     if (l == ERROR_SUCCESS)
123     {
124         dws = PATH_MAX;
125         l = RegQueryValueEx(hk, "HomeDir", NULL, NULL,
126                 (BYTE *)buf, &dws);
127         RegCloseKey(hk);
128         if (l == ERROR_SUCCESS) return buf;
129     }
130     dg_shell_folder(CSIDL_PERSONAL, buf);
131 
132     while ((t = strchr(buf, '\\'))) *t = '/';
133 
134     /* Ensure path ends with a slash */
135     if (buf[strlen(buf)-1] != '/') strcat(buf, "/");
136 
137     return buf;
138 }
139 #elif defined(HAVE_PWD_H) && defined(HAVE_UNISTD_H)
140 
141 #include <unistd.h>
142 #include <pwd.h>
143 
dg_homedir(void)144 const char *dg_homedir(void)
145 {
146     char *s;
147     static char buf[PATH_MAX];
148     struct passwd *pw;
149     int uid = getuid();
150 
151     s = getenv("HOME");
152     if (s)
153     {
154         strcpy(buf, s);
155         /* Ensure path ends with a slash */
156 
157         if (buf[strlen(buf)-1] != '/') strcat(buf, "/");
158         return buf;
159     }
160     else
161     {
162         setpwent();
163         while ((pw = getpwent()))
164         {
165             if (pw->pw_uid == uid)
166             {
167                 strcpy(buf, pw->pw_dir);
168                 if ( buf[strlen(buf)-1] != '/') strcat(buf, "/");
169                 endpwent();
170                 return buf;
171             }
172         }
173         endpwent();
174     }
175     return NULL;
176 }
177 #else
178 
dg_homedir(void)179 const char *dg_homedir(void)
180 {
181     static char buf[PATH_MAX];
182     char *s = getenv("HOME");
183 
184     if (!s) return NULL;
185     strcpy(buf, s);
186     /* Ensure path ends with a slash */
187     if (s && buf[strlen(buf)-1] != '/') strcat(buf, "/");
188 
189     return buf;
190 }
191 #endif
192 
193 
194 
195 #ifdef HAVE_WINDOWS_H
196 
dg_sharedir(void)197 const char *dg_sharedir(void)
198 {
199     static char buf[PATH_MAX + 8];
200     char *t;
201 #ifdef _WIN32   /* Win16 doesn't have HKLM */
202     long l;
203     HKEY hk;
204     DWORD dws = sizeof(buf)-1;
205 
206     l = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
207         "Software\\jce@seasip\\LibDsk", 0, KEY_READ, &hk);
208     if (l == ERROR_SUCCESS)
209     {
210         dws = PATH_MAX;
211         l = RegQueryValueEx(hk, "ShareDir", NULL, NULL,
212                 (BYTE *)buf, &dws);
213         RegCloseKey(hk);
214         if (l == ERROR_SUCCESS) return buf;
215     }
216 #endif
217     GetModuleFileName((HINSTANCE)NULL, buf, PATH_MAX);
218     while ((t = strchr(buf, '\\'))) *t = '/';
219     for (t = buf + strlen(buf); t >= buf; t--)
220     {
221         if (t[0] == ':' || t[0] == '/')
222         {
223             t[1] = 0;
224             break;
225         }
226     }
227     strcat(buf, "share/");
228     return buf;
229 }
230 
231 #else /* def HAVE_WINDOWS_H */
232 
dg_sharedir()233 const char *dg_sharedir()
234 {
235     static char buf[PATH_MAX];
236     char *s = getenv("LIBDSK");
237 
238 #ifdef AUTOSHARE
239     if (SHAREDIR)
240     {
241         return SHAREDIR "/";
242     }
243 #endif
244 
245     if (!s) return NULL;
246     strcpy(buf, s);
247     /* Ensure path ends with a slash */
248     if (s && buf[strlen(buf)-1] != '/') strcat(buf, "/");
249     return buf;
250 }
251 
252 #endif /* def HAVE_WINDOWS_H */
253 
254 static DSK_NAMEDGEOM *customgeom = NULL;
255 
256 
dg_parse(FILE * fp,DSK_GEOMETRY * dg,char * description)257 dsk_err_t dg_parse(FILE *fp, DSK_GEOMETRY *dg, char *description)
258 {
259     char linebuf[160];
260     dsk_err_t err;
261 
262     /* Init geometry to default values */
263     memcpy(dg, &stdg[0].dg, sizeof(*dg));
264 
265     while (fgets(linebuf, sizeof(linebuf), fp))
266     {
267         /* Start of next section */
268         if (linebuf[0] == '[') return DSK_ERR_OK;
269         err = dg_parseline(linebuf, dg, description);
270         if (err) return err;
271     }
272     return DSK_ERR_OK;
273 }
274 
dg_parseline(char * linebuf,DSK_GEOMETRY * dg,char * description)275 dsk_err_t dg_parseline(char *linebuf, DSK_GEOMETRY *dg, char *description)
276 {
277     char *s;
278     char *value;
279 /* Drop comments and newlines */
280 
281     s = strchr(linebuf, ';'); if (s) *s = 0;
282     s = strchr(linebuf, '#'); if (s) *s = 0;
283     s = strchr(linebuf, '\n'); if (s) *s = 0;
284 
285     value = strchr(linebuf, '=');
286     if (!value) return DSK_ERR_OK;
287     *value = 0;
288     ++value;
289 
290     /* Chop variable name at first space */
291     s = strchr(linebuf, ' ');
292     if (s) *s = 0;
293     /* Skip leading spaces in the value */
294     while (*value == ' ') ++value;
295 
296 /* Make the variable name case-insensitive */
297     for (s = linebuf; s[0]; s++)
298     {
299         *s = tolower(*s);
300     }
301     if (!strcmp(linebuf, "description"))
302     {
303         if (description)
304             strcpy(description, value);
305     }
306     if (!strcmp(linebuf, "sidedness") || !strcmp(linebuf, "sides"))
307     {
308         for (s = value; s[0]; s++) *s = tolower(*s);
309         if (!strcmp(value, "alt"))
310             dg->dg_sidedness = SIDES_ALT;
311         if (!strcmp(value, "outback"))
312             dg->dg_sidedness = SIDES_OUTBACK;
313         if (!strcmp(value, "outout"))
314             dg->dg_sidedness = SIDES_OUTOUT;
315         if (!strcmp(value, "extsurface"))	/* [1.3.7] */
316             dg->dg_sidedness = SIDES_EXTSURFACE;
317     }
318     if (!strcmp(linebuf, "cylinders") && atoi(value))
319         dg->dg_cylinders = atoi(value);
320     if (!strcmp(linebuf, "heads") && atoi(value))
321         dg->dg_heads     = atoi(value);
322     if (!strcmp(linebuf, "sectors") && atoi(value))
323         dg->dg_sectors   = atoi(value);
324     if (!strcmp(linebuf, "secbase"))
325         dg->dg_secbase   = atoi(value);
326     if (!strcmp(linebuf, "secsize") && atoi(value))
327         dg->dg_secsize   = atoi(value);
328     if (!strcmp(linebuf, "datarate"))
329     {
330         for (s = value; s[0]; s++) *s = tolower(*s);
331         if (!strcmp(value, "hd")) dg->dg_datarate = RATE_HD;
332         if (!strcmp(value, "dd")) dg->dg_datarate = RATE_DD;
333         if (!strcmp(value, "sd")) dg->dg_datarate = RATE_SD;
334         if (!strcmp(value, "ed")) dg->dg_datarate = RATE_ED;
335     }
336     if (!strcmp(linebuf, "rwgap") && atoi(value))
337         dg->dg_rwgap  = atoi(value);
338     if (!strcmp(linebuf, "fmtgap") && atoi(value))
339         dg->dg_fmtgap  = atoi(value);
340     if (!strcmp(linebuf, "fm"))
341     {
342         for (s = value; s[0]; s++) *s = tolower(*s);
343         if (!strcmp(value, "y"))
344 	    dg->dg_fm = (dg->dg_fm & RECMODE_FLAGMASK) | RECMODE_FM;
345         if (!strcmp(value, "n"))
346 	    dg->dg_fm = (dg->dg_fm & RECMODE_FLAGMASK) | RECMODE_MFM;
347     }
348     /* [1.4.1] Allow 'recmode=mfm' / 'recmode=fm' as a synonym for 'fm=y / fm=n'
349      *         Obviously this syntax would allow additional recording modes in
350      *         future. */
351     if (!strcmp(linebuf, "recmode"))
352     {
353         for (s = value; s[0]; s++) *s = tolower(*s);
354         if (!strcmp(value, "fm"))
355 	    dg->dg_fm = (dg->dg_fm & RECMODE_FLAGMASK) | RECMODE_FM;
356         if (!strcmp(value, "mfm"))
357 	    dg->dg_fm = (dg->dg_fm & RECMODE_FLAGMASK) | RECMODE_MFM;
358     }
359     /* [1.4.1] 'Complement' flag */
360     if (!strcmp(linebuf, "complement"))
361     {
362         for (s = value; s[0]; s++) *s = tolower(*s);
363         if (!strcmp(value, "y"))
364 	    dg->dg_fm |= RECMODE_COMPLEMENT;
365         if (!strcmp(value, "n"))
366 	    dg->dg_fm &= ~RECMODE_COMPLEMENT;
367     }
368     if (!strcmp(linebuf, "multitrack"))
369     {
370         for (s = value; s[0]; s++) *s = tolower(*s);
371         if (!strcmp(value, "y")) dg->dg_nomulti = 0;
372         if (!strcmp(value, "n")) dg->dg_nomulti = 1;
373     }
374     if (!strcmp(linebuf, "skipdeleted"))
375     {
376         for (s = value; s[0]; s++) *s = tolower(*s);
377         if (!strcmp(value, "y")) dg->dg_noskip = 0;
378         if (!strcmp(value, "n")) dg->dg_noskip = 1;
379     }
380     return DSK_ERR_OK;
381 }
382 
383 
384 
dg_store(FILE * fp,DSK_GEOMETRY * dg,char * description)385 dsk_err_t dg_store(FILE *fp, DSK_GEOMETRY *dg, char *description)
386 {
387     if (description) fprintf(fp, "description=%s\n", description);
388     switch(dg->dg_sidedness)
389     {
390         case SIDES_ALT:        fprintf(fp, "sides=alt\n");     break;
391         case SIDES_OUTOUT:     fprintf(fp, "sides=outback\n"); break;
392         case SIDES_OUTBACK:    fprintf(fp, "sides=outout\n");  break;
393         case SIDES_EXTSURFACE: fprintf(fp, "sides=extsurface\n");  break;
394     }
395     fprintf(fp, "cylinders=%d\n", dg->dg_cylinders);
396     fprintf(fp, "heads=%d\n",     dg->dg_heads);
397     fprintf(fp, "sectors=%d\n",   dg->dg_sectors);
398     fprintf(fp, "secbase=%d\n",   dg->dg_secbase);
399     fprintf(fp, "secsize=%ld\n",  (long)dg->dg_secsize);
400     switch(dg->dg_datarate)
401     {
402         case RATE_HD: fprintf(fp, "datarate=HD\n"); break;
403         case RATE_DD: fprintf(fp, "datarate=DD\n"); break;
404         case RATE_SD: fprintf(fp, "datarate=SD\n"); break;
405         case RATE_ED: fprintf(fp, "datarate=ED\n"); break;
406     }
407     fprintf(fp, "rwgap=%d\n", dg->dg_rwgap);
408     fprintf(fp, "fmtgap=%d\n", dg->dg_fmtgap);
409 
410     switch (dg->dg_fm & RECMODE_MASK)
411     {
412         case RECMODE_MFM: fprintf(fp, "recmode=MFM\n"); break;
413         case RECMODE_FM:  fprintf(fp, "recmode=FM\n"); break;
414     }
415     fprintf(fp, "complement=%c\n", (dg->dg_fm & RECMODE_COMPLEMENT) ? 'Y' : 'N');
416     fprintf(fp, "multitrack=%c\n", dg->dg_nomulti ? 'N' : 'Y');
417     fprintf(fp, "skipdeleted=%c\n", dg->dg_noskip ? 'N' : 'Y');
418     return DSK_ERR_OK;
419 }
420 
421 
dg_parse_file(FILE * fp)422 static dsk_err_t dg_parse_file(FILE *fp)
423 {
424     DSK_NAMEDGEOM ng, *pg;
425     char linebuf[160];
426     char formname[160];
427     char formdesc[160];
428     char *s;
429     long pos;
430     dsk_err_t err;
431 
432     while (fgets(linebuf, sizeof(linebuf), fp))
433     {
434         formdesc[0] = 0;
435 /* Drop comments and newlines */
436         s = strchr(linebuf, ';'); if (s) *s = 0;
437         s = strchr(linebuf, '#'); if (s) *s = 0;
438         s = strchr(linebuf, '\n'); if (s) *s = 0;
439 
440         if (linebuf[0] != '[') continue;
441 /* Format names cannot start with "-", so any section beginning "[-" is
442  * going to be something other than a format. */
443 	if (linebuf[1] == '-') continue;
444         strcpy(formname, linebuf+1);
445         s = strchr(formname, ']');
446         if (s) *s = 0;
447         pos = ftell(fp);
448         err = dg_parse(fp, &ng.dg, formdesc);
449         if (err) return err;
450         fseek(fp, pos, SEEK_SET);
451 
452         pg = dsk_malloc(sizeof(ng) + 2 +
453                 strlen(formdesc) + strlen(formname));
454         if (!pg) return DSK_ERR_NOMEM;
455         memcpy(pg, &ng, sizeof(ng));
456 
457         pg->name = ((char *)pg) + sizeof(ng);
458         pg->desc = ((char *)pg) + sizeof(ng) + 1 + strlen(formname);
459         strcpy((char *)pg->name, formname);
460         strcpy((char *)pg->desc, formdesc);
461         pg->next = customgeom;
462         customgeom = pg;
463     }
464     return DSK_ERR_OK;
465 }
466 
dg_custom_init(void)467 dsk_err_t dg_custom_init(void)
468 {
469     const char *path;
470     char buf[2 * PATH_MAX];
471     FILE *fp;
472     dsk_err_t err;
473 
474     static int custom_inited = 0;
475 
476 /* Assert that the format names and numeric IDs are in sync. */
477 
478 #ifdef HAVE_ASSERT_H
479     assert(!strcmp(stdg[FMT_180K].name, "pcw180"));
480     assert(!strcmp(stdg[FMT_320K].name, "ibm320"));
481     assert(!strcmp(stdg[FMT_720F].name, "ibm720"));
482     assert(!strcmp(stdg[FMT_1440F].name, "ibm1440"));
483     assert(!strcmp(stdg[FMT_ACORN160].name, "acorn160"));
484     assert(!strcmp(stdg[FMT_AMPRO800].name, "ampro800"));
485 #endif
486     if (custom_inited < 1)
487     {
488         path = dg_sharedir();
489         if (path)
490         {
491             sprintf(buf, "%s%s", path, "libdskrc");
492             fp = fopen(buf, "r");
493             if (fp)
494             {
495                 err = dg_parse_file(fp);
496                 fclose(fp);
497                 if (err) return err;
498             }
499         }
500         custom_inited = 1;
501     }
502     if (custom_inited < 2)
503     {
504         path = dg_homedir();
505         if (path)
506         {
507             sprintf(buf, "%s%s", path, ".libdskrc");
508             fp = fopen(buf, "r");
509             if (fp)
510             {
511                 err = dg_parse_file(fp);
512                 fclose(fp);
513                 if (err) return err;
514             }
515         }
516         custom_inited = 2;
517     }
518     return DSK_ERR_OK;
519 }
520 
521 
522 
523 /* Initialise a DSK_GEOMETRY with a standard format */
dg_stdformat(DSK_GEOMETRY * self,dsk_format_t formatid,dsk_cchar_t * fname,dsk_cchar_t * fdesc)524 LDPUBLIC32 dsk_err_t LDPUBLIC16 dg_stdformat(DSK_GEOMETRY *self, dsk_format_t formatid,
525             dsk_cchar_t *fname, dsk_cchar_t *fdesc)
526 {
527     int idx = (formatid - FMT_180K);
528 
529     dg_custom_init();
530 
531 /* If index is out of range in the standard set, search the custom set */
532     if ((unsigned)idx >= (sizeof(stdg)/sizeof(stdg[0]))  )
533     {
534         DSK_NAMEDGEOM *cg = customgeom;
535         idx -= (sizeof(stdg) / sizeof(stdg[0]));
536 
537         while (idx)
538         {
539             if (!cg) return DSK_ERR_BADFMT;
540             cg = cg->next;
541             --idx;
542         }
543         if (!cg) return DSK_ERR_BADFMT;
544 
545         if (self) memcpy(self, &cg->dg, sizeof(*self));
546         if (fname) *fname = cg->name;
547         if (fdesc) *fdesc = cg->desc;
548         return DSK_ERR_OK;
549     }
550 /* Search the standard set */
551     if (self) memcpy(self, &stdg[idx].dg, sizeof(*self));
552     if (fname) *fname = stdg[idx].name;
553     if (fdesc) *fdesc = stdg[idx].desc;
554     return DSK_ERR_OK;
555 }
556 
557 
558 
559