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