- added instructions how to update the online documentation
[bochs-mirror.git] / misc / bximage.c
blob87aebcca63813b072b13293e08220ddee014d3b2
1 /*
2 * misc/bximage.c
3 * $Id: bximage.c,v 1.33 2008/02/05 22:57:42 sshwarts Exp $
5 * Create empty hard disk or floppy disk images for bochs.
7 */
9 #ifdef WIN32
10 # include <conio.h>
11 # include <windows.h>
12 # include <winioctl.h>
13 #ifdef _MSC_VER
14 # include <io.h>
15 #endif
16 #endif
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <assert.h>
22 #include "config.h"
24 #include <string.h>
26 #include "../osdep.h"
28 #define HDIMAGE_HEADERS_ONLY 1
29 #include "../iodev/hdimage.h"
31 int bx_hdimage;
32 int bx_fdsize_idx;
33 int bx_hdsize;
34 int bx_hdimagemode;
35 int bx_interactive;
36 char bx_filename[256];
38 typedef int (*WRITE_IMAGE)(FILE*, Bit64u);
39 #ifdef WIN32
40 typedef int (*WRITE_IMAGE_WIN32)(HANDLE, Bit64u);
41 #endif
43 char *EOF_ERR = "ERROR: End of input";
44 char *rcsid = "$Id: bximage.c,v 1.33 2008/02/05 22:57:42 sshwarts Exp $";
45 char *divider = "========================================================================";
47 /* menu data for choosing floppy/hard disk */
48 char *fdhd_menu = "\nDo you want to create a floppy disk image or a hard disk image?\nPlease type hd or fd. ";
49 char *fdhd_choices[] = { "fd", "hd" };
50 int fdhd_n_choices = 2;
52 /* menu data for choosing floppy size */
53 char *fdsize_menu = "\nChoose the size of floppy disk image to create, in megabytes.\nPlease type 0.16, 0.18, 0.32, 0.36, 0.72, 1.2, 1.44, 1.68, 1.72, or 2.88.\n ";
54 char *fdsize_choices[] = { "0.16","0.18","0.32","0.36","0.72","1.2","1.44","1.68","1.72","2.88" };
55 int fdsize_n_choices = 10;
57 /* menu data for choosing disk mode */
58 char *hdmode_menu = "\nWhat kind of image should I create?\nPlease type flat, sparse or growing. ";
59 char *hdmode_choices[] = {"flat", "sparse", "growing" };
60 int hdmode_n_choices = 3;
62 void myexit (int code)
64 #ifdef WIN32
65 printf ("\nPress any key to continue\n");
66 getch();
67 #endif
68 exit(code);
71 /* stolen from main.cc */
72 void bx_center_print (FILE *file, char *line, int maxwidth)
74 int imax;
75 int i;
76 imax = (maxwidth - strlen(line)) >> 1;
77 for (i=0; i<imax; i++) fputc (' ', file);
78 fputs (line, file);
81 void
82 print_banner ()
84 printf ("%s\n", divider);
85 bx_center_print (stdout, "bximage\n", 72);
86 bx_center_print (stdout, "Disk Image Creation Tool for Bochs\n", 72);
87 bx_center_print (stdout, rcsid, 72);
88 printf ("\n%s\n", divider);
91 /* this is how we crash */
92 void fatal (char *c)
94 printf ("%s\n", c);
95 myexit (1);
98 /* check if the argument string is present in the list -
99 returns index on success, -1 on failure. */
100 int get_menu_index(char *arg, int n_choices, char *choice[])
102 int i;
103 for (i=0; i<n_choices; i++) {
104 if (!strcmp (choice[i], arg)) {
105 // matched, return the choice number
106 return i;
109 return -1;
112 /* remove leading spaces, newline junk at end. returns pointer to
113 cleaned string, which is between s0 and the null */
114 char *
115 clean_string (char *s0)
117 char *s = s0;
118 char *ptr;
119 /* find first nonblank */
120 while (isspace (*s))
121 s++;
122 /* truncate string at first non-alphanumeric */
123 ptr = s;
124 while (isprint (*ptr))
125 ptr++;
126 *ptr = 0;
127 return s;
130 /* returns 0 on success, -1 on failure. The value goes into out. */
132 ask_int (char *prompt, int min, int max, int the_default, int *out)
134 int n = max + 1;
135 char buffer[1024];
136 char *clean;
137 int illegal;
138 while (1) {
139 printf ("%s", prompt);
140 printf ("[%d] ", the_default);
141 if (!fgets (buffer, sizeof(buffer), stdin))
142 return -1;
143 clean = clean_string (buffer);
144 if (strlen(clean) < 1) {
145 // empty line, use the default
146 *out = the_default;
147 return 0;
149 illegal = (1 != sscanf (buffer, "%d", &n));
150 if (illegal || n<min || n>max) {
151 printf ("Your choice (%s) was not an integer between %d and %d.\n\n",
152 clean, min, max);
153 } else {
154 // choice is okay
155 *out = n;
156 return 0;
162 ask_menu (char *prompt, int n_choices, char *choice[], int the_default, int *out)
164 char buffer[1024];
165 char *clean;
166 int i;
167 *out = -1;
168 while (1) {
169 printf ("%s", prompt);
170 printf ("[%s] ", choice[the_default]);
171 if (!fgets (buffer, sizeof(buffer), stdin))
172 return -1;
173 clean = clean_string (buffer);
174 if (strlen(clean) < 1) {
175 // empty line, use the default
176 *out = the_default;
177 return 0;
179 for (i=0; i<n_choices; i++) {
180 if (!strcmp (choice[i], clean)) {
181 // matched, return the choice number
182 *out = i;
183 return 0;
186 printf ("Your choice (%s) did not match any of the choices:\n", clean);
187 for (i=0; i<n_choices; i++) {
188 if (i>0) printf (", ");
189 printf ("%s", choice[i]);
191 printf ("\n");
196 ask_yn (char *prompt, int the_default, int *out)
198 char buffer[16];
199 char *clean;
200 *out = -1;
201 while (1) {
202 printf ("%s", prompt);
203 printf ("[%s] ", the_default?"yes":"no");
204 if (!fgets (buffer, sizeof(buffer), stdin))
205 return -1;
206 clean = clean_string (buffer);
207 if (strlen(clean) < 1) {
208 // empty line, use the default
209 *out = the_default;
210 return 0;
212 switch (tolower(clean[0])) {
213 case 'y': *out=1; return 0;
214 case 'n': *out=0; return 0;
216 printf ("Please type either yes or no.\n");
221 ask_string (char *prompt, char *the_default, char *out)
223 char buffer[1024];
224 char *clean;
225 out[0] = 0;
226 printf ("%s", prompt);
227 printf ("[%s] ", the_default);
228 if (!fgets (buffer, sizeof(buffer), stdin))
229 return -1;
230 clean = clean_string (buffer);
231 if (strlen(clean) < 1) {
232 // empty line, use the default
233 strcpy (out, the_default);
234 return 0;
236 strcpy (out, clean);
237 return 0;
240 // fileset is like memset but for a file handle
241 void fileset(FILE * fp, int c, size_t n)
243 #define BLOCK_SIZE (1024)
244 int block[BLOCK_SIZE];
245 size_t left_to_write = n;
247 memset(block, c, sizeof(block));
249 while (left_to_write > 0)
251 size_t write = sizeof(block);
252 if (write > left_to_write) write = left_to_write;
254 if (1 != fwrite(block, write, 1, fp))
256 fclose (fp);
257 fatal ("ERROR: The disk image is not complete - could not write data block!");
260 left_to_write -= write;
265 /* Create a suited redolog header */
266 void make_redolog_header(redolog_header_t *header, const char* type, Bit64u size)
268 Bit32u entries, extent_size, bitmap_size;
269 Bit64u maxsize;
271 // Set standard header values
272 strcpy((char*)header->standard.magic, STANDARD_HEADER_MAGIC);
273 strcpy((char*)header->standard.type, REDOLOG_TYPE);
274 strcpy((char*)header->standard.subtype, type);
275 header->standard.version = htod32(STANDARD_HEADER_VERSION);
276 header->standard.header = htod32(STANDARD_HEADER_SIZE);
278 entries = 512;
279 bitmap_size = 1;
281 // Compute #entries and extent size values
282 do {
283 static Bit32u flip=0;
285 extent_size = 8 * bitmap_size * 512;
287 header->specific.catalog = htod32(entries);
288 header->specific.bitmap = htod32(bitmap_size);
289 header->specific.extent = htod32(extent_size);
291 maxsize = (Bit64u)entries * (Bit64u)extent_size;
293 flip++;
295 if(flip&0x01) bitmap_size *= 2;
296 else entries *= 2;
297 } while (maxsize < size);
299 header->specific.disk = htod64(size);
302 /* produce a flat image file */
303 #ifdef WIN32
304 int make_flat_image_win32(HANDLE hFile, Bit64u sec)
306 LARGE_INTEGER pos;
307 DWORD dwCount, errCode;
308 USHORT mode;
309 char buffer[1024];
311 SetLastError(NO_ERROR);
312 mode = COMPRESSION_FORMAT_DEFAULT;
313 dwCount = 0;
314 memset(buffer, 0, 512);
315 WriteFile(hFile, buffer, 512, &dwCount, NULL); // set the first sector to 0, Win98 doesn't zero out the file
316 // if there is a write at/over the end
317 DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, &mode, sizeof(mode), NULL, 0, &dwCount, NULL);
318 pos.u.LowPart = (unsigned long)((sec - 1) << 9);
319 pos.u.HighPart = (unsigned long)((sec - 1) >> 23);
320 pos.u.LowPart = SetFilePointer(hFile, pos.u.LowPart, &pos.u.HighPart, FILE_BEGIN);
321 memset(buffer, 0, 512);
322 if ((pos.u.LowPart == 0xffffffff && GetLastError() != NO_ERROR) || !WriteFile(hFile, buffer, 512, &dwCount, NULL) || dwCount != 512)
324 errCode = GetLastError();
325 CloseHandle(hFile);
326 if (errCode == ERROR_DISK_FULL) {
327 fatal ("\nERROR: Not enough space on disk for image!");
328 } else {
329 sprintf(buffer, "\nERROR: Disk image creation failed with error code %i!", errCode);
330 fatal (buffer);
333 return 0;
335 #endif
337 int make_flat_image(FILE *fp, Bit64u sec)
340 * seek to sec*512-1 and write a single character.
341 * can't just do: fseek(fp, 512*sec-1, SEEK_SET)
342 * because 512*sec may be too large for signed int.
344 while (sec > 0)
346 /* temp <-- min(sec, 4194303)
347 * 4194303 is (int)(0x7FFFFFFF/512)
349 long temp = (long)((sec < 4194303) ? sec : 4194303);
350 fseek(fp, 512*temp, SEEK_CUR);
351 sec -= temp;
354 fseek(fp, -1, SEEK_CUR);
355 if (fputc('\0', fp) == EOF)
357 fclose (fp);
358 fatal ("\nERROR: The disk image is not complete! (image larger then free space?)");
360 return 0;
363 /* produce a sparse image file */
364 int make_sparse_image(FILE *fp, Bit64u sec)
366 Bit64u numpages;
367 sparse_header_t header;
368 size_t sizesofar;
369 size_t padtopagesize;
371 memset(&header, 0, sizeof(header));
372 header.magic = htod32(SPARSE_HEADER_MAGIC);
373 header.version = htod32(SPARSE_HEADER_VERSION);
375 header.pagesize = htod32((1 << 10) * 32); // Use 32 KB Pages - could be configurable
376 numpages = (sec / (dtoh32(header.pagesize) / 512)) + 1;
378 header.numpages = htod32((Bit32u)numpages);
379 header.disk = htod64(sec * 512);
381 if (numpages != dtoh32(header.numpages))
383 fclose (fp);
384 fatal ("ERROR: The disk image is too large for a sparse image!");
385 // Could increase page size here.
386 // But note this only happens at 128 Terabytes!
389 if (fwrite(&header, sizeof(header), 1, fp) != 1)
391 fclose (fp);
392 fatal ("ERROR: The disk image is not complete - could not write header!");
395 fileset(fp, 0xff, 4 * dtoh32(header.numpages));
397 sizesofar = SPARSE_HEADER_SIZE + (4 * dtoh32(header.numpages));
398 padtopagesize = dtoh32(header.pagesize) - (sizesofar & (dtoh32(header.pagesize) - 1));
400 fileset(fp, 0, padtopagesize);
402 return 0;
405 /* produce a growing image file */
406 int make_growing_image(FILE *fp, Bit64u sec)
408 redolog_header_t header;
409 Bit32u i, not_allocated = htod32(REDOLOG_PAGE_NOT_ALLOCATED);
411 memset(&header, 0, sizeof(header));
412 make_redolog_header(&header, REDOLOG_SUBTYPE_GROWING, sec * 512);
414 if (fwrite(&header, sizeof(header), 1, fp) != 1)
416 fclose (fp);
417 fatal ("ERROR: The disk image is not complete - could not write header!");
420 for (i=0; i<dtoh32(header.specific.catalog); i++)
422 if (fwrite(&not_allocated, sizeof(Bit32u), 1, fp) != 1)
424 fclose (fp);
425 fatal ("ERROR: The disk image is not complete - could not write catalog!");
429 return 0;
432 /* produce the image file */
433 #ifdef WIN32
434 int make_image_win32 (Bit64u sec, char *filename, WRITE_IMAGE_WIN32 write_image)
436 HANDLE hFile;
437 char buffer[1024];
439 // check if it exists before trashing someone's disk image
440 hFile = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL);
441 if (hFile != INVALID_HANDLE_VALUE) {
442 int confirm;
443 sprintf (buffer, "\nThe disk image '%s' already exists. Are you sure you want to replace it?\nPlease type yes or no. ", filename);
444 if (ask_yn (buffer, 0, &confirm) < 0)
445 fatal (EOF_ERR);
446 if (!confirm)
447 fatal ("ERROR: Aborted");
448 CloseHandle(hFile);
451 // okay, now open it for writing
452 hFile = CreateFile(filename, GENERIC_WRITE|GENERIC_READ, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
453 if (hFile == INVALID_HANDLE_VALUE) {
454 // attempt to print an error
455 #ifdef HAVE_PERROR
456 sprintf (buffer, "while opening '%s' for writing", filename);
457 perror (buffer);
458 #endif
459 fatal ("ERROR: Could not write disk image");
462 printf ("\nWriting: [");
464 if( (*write_image)(hFile, sec) != 0)
465 fatal ("ERROR: while writing disk image!");
467 printf ("] Done.\n");
468 CloseHandle(hFile);
469 return 0;
471 #endif
473 int make_image (Bit64u sec, char *filename, WRITE_IMAGE write_image)
475 FILE *fp;
476 char buffer[1024];
478 // check if it exists before trashing someone's disk image
479 fp = fopen (filename, "r");
480 if (fp) {
481 int confirm;
482 sprintf (buffer, "\nThe disk image '%s' already exists. Are you sure you want to replace it?\nPlease type yes or no. ", filename);
483 if (ask_yn (buffer, 0, &confirm) < 0)
484 fatal (EOF_ERR);
485 if (!confirm)
486 fatal ("ERROR: Aborted");
487 fclose (fp);
490 // okay, now open it for writing
491 fp = fopen (filename, "w");
492 if (fp == NULL) {
493 // attempt to print an error
494 #ifdef HAVE_PERROR
495 sprintf (buffer, "while opening '%s' for writing", filename);
496 perror (buffer);
497 #endif
498 fatal ("ERROR: Could not write disk image");
501 printf ("\nWriting: [");
503 if( (*write_image)(fp, sec) != 0)
504 fatal ("ERROR: while writing disk image!");
506 printf ("] Done.\n");
507 fclose (fp);
508 return 0;
511 void print_usage ()
513 fprintf(stderr,
514 "Usage: bximage [options] [filename]\n\n"
515 "Supported options:\n"
516 " -fd create floppy image\n"
517 " -hd create hard disk image\n"
518 " -mode=... image mode (hard disks only)\n"
519 " -size=... image size in megabytes\n"
520 " -q quiet mode (don't prompt for user input)\n"
521 " --help display this help and exit\n\n");
524 int parse_cmdline (int argc, char *argv[])
526 int arg = 1;
527 int ret = 1;
529 bx_hdimage = -1;
530 bx_fdsize_idx = -1;
531 bx_hdsize = -1;
532 bx_hdimagemode = -1;
533 bx_interactive = 1;
534 bx_filename[0] = 0;
535 while ((arg < argc) && (ret == 1)) {
536 // parse next arg
537 if (!strcmp ("--help", argv[arg]) || !strncmp ("/?", argv[arg], 2)) {
538 print_usage();
539 ret = 0;
541 else if (!strcmp ("-fd", argv[arg])) {
542 bx_hdimage = 0;
543 bx_hdimagemode = 0;
545 else if (!strcmp ("-hd", argv[arg])) {
546 bx_hdimage = 1;
547 bx_fdsize_idx = 0;
549 else if (!strncmp ("-mode=", argv[arg], 6)) {
550 if (bx_hdimage == 1) {
551 bx_hdimagemode = get_menu_index(&argv[arg][6], hdmode_n_choices, hdmode_choices);
552 if (bx_hdimagemode < 0) {
553 printf ("Unknown image mode: %s\n\n", &argv[arg][6]);
554 ret = 0;
556 } else {
557 printf ("Image mode option only supported for hard disks\n\n");
558 ret = 0;
561 else if (!strncmp ("-size=", argv[arg], 6)) {
562 if (bx_hdimage == 0) {
563 bx_fdsize_idx = get_menu_index(&argv[arg][6], fdsize_n_choices, fdsize_choices);
564 if (bx_fdsize_idx < 0) {
565 printf ("Unknown floppy image size: %s\n\n", &argv[arg][6]);
566 ret = 0;
568 } else if (bx_hdimage == 1) {
569 if (sscanf (&argv[arg][6], "%d", &bx_hdsize) != 1) {
570 printf ("Error in hard disk image size argument: %s\n\n", &argv[arg][6]);
571 ret = 0;
572 } else if ((bx_hdsize < 1) || (bx_hdsize > 32255)) {
573 printf ("Hard disk image size out of range\n\n");
574 ret = 0;
576 } else {
577 printf ("Image type (fd/hd) not specified\n\n");
580 else if (!strcmp ("-q", argv[arg])) {
581 bx_interactive = 0;
583 else if (argv[arg][0] == '-') {
584 printf ("Unknown option: %s\n\n", argv[arg]);
585 ret = 0;
586 } else {
587 strcpy(bx_filename, argv[arg]);
589 arg++;
591 if (bx_hdimage == -1) {
592 bx_hdimage = 1;
593 bx_fdsize_idx = 6;
594 bx_interactive = 1;
596 if (bx_hdimage == 1) {
597 if (bx_hdimagemode == -1) {
598 bx_hdimagemode = 0;
599 bx_interactive = 1;
601 if (bx_hdsize == -1) {
602 bx_hdsize = 10;
603 bx_interactive = 1;
605 } else {
606 if (bx_fdsize_idx == -1) {
607 bx_fdsize_idx = 6;
608 bx_interactive = 1;
611 if (!strlen(bx_filename)) {
612 bx_interactive = 1;
614 return ret;
617 int main (int argc, char *argv[])
619 Bit64s sectors = 0;
620 char filename[256];
621 char bochsrc_line[256];
623 WRITE_IMAGE write_function=NULL;
624 #ifdef WIN32
625 WRITE_IMAGE_WIN32 writefn_win32=NULL;
626 #endif
628 if (!parse_cmdline (argc, argv))
629 myexit(1);
631 print_banner ();
632 if (bx_interactive) {
633 if (ask_menu (fdhd_menu, fdhd_n_choices, fdhd_choices, bx_hdimage, &bx_hdimage) < 0)
634 fatal (EOF_ERR);
636 if (bx_hdimage) {
637 unsigned int cyl;
638 int hdsize, heads=16, spt=63;
639 int mode;
641 if (bx_interactive) {
642 if (ask_menu (hdmode_menu, hdmode_n_choices, hdmode_choices, bx_hdimagemode, &mode) < 0)
643 fatal (EOF_ERR);
644 if (ask_int ("\nEnter the hard disk size in megabytes, between 1 and 129023\n", 1, 129023, bx_hdsize, &hdsize) < 0)
645 fatal (EOF_ERR);
646 } else {
647 mode = bx_hdimagemode;
648 hdsize = bx_hdsize;
650 cyl = (unsigned int) (hdsize*1024.0*1024.0/16.0/63.0/512.0);
651 assert (cyl < 262144);
652 sectors = cyl*heads*spt;
653 printf ("\nI will create a '%s' hard disk image with\n", hdmode_choices[mode]);
654 printf (" cyl=%d\n", cyl);
655 printf (" heads=%d\n", heads);
656 printf (" sectors per track=%d\n", spt);
657 printf (" total sectors=" FMT_LL "d\n", sectors);
658 printf (" total size=%.2f megabytes\n", (float)(Bit64s)(sectors/2)/1024.0);
659 if (bx_interactive) {
660 if (!strlen(bx_filename)) strcpy(bx_filename, "c.img");
661 if (ask_string ("\nWhat should I name the image?\n", bx_filename, filename) < 0)
662 fatal (EOF_ERR);
663 } else {
664 strcpy(filename, bx_filename);
667 sprintf (bochsrc_line, "ata0-master: type=disk, path=\"%s\", mode=%s, cylinders=%d, heads=%d, spt=%d", filename, hdmode_choices[mode], cyl, heads, spt);
669 switch (mode) {
670 case 1:
671 write_function=make_sparse_image;
672 break;
673 case 2:
674 write_function=make_growing_image;
675 break;
676 default:
677 #ifdef WIN32
678 writefn_win32=make_flat_image_win32;
679 #else
680 write_function=make_flat_image;
681 #endif
683 } else {
684 int fdsize, cyl=0, heads=0, spt=0;
685 if (bx_interactive) {
686 if (ask_menu (fdsize_menu, fdsize_n_choices, fdsize_choices, bx_fdsize_idx, &fdsize) < 0)
687 fatal (EOF_ERR);
688 } else {
689 fdsize = bx_fdsize_idx;
691 switch (fdsize) {
692 case 0: cyl=40; heads=1; spt=8; break; /* 0.16 meg */
693 case 1: cyl=40; heads=1; spt=9; break; /* 0.18 meg */
694 case 2: cyl=40; heads=2; spt=8; break; /* 0.32 meg */
695 case 3: cyl=40; heads=2; spt=9; break; /* 0.36 meg */
696 case 4: cyl=80; heads=2; spt=9; break; /* 0.72 meg */
697 case 5: cyl=80; heads=2; spt=15; break; /* 1.2 meg */
698 case 6: cyl=80; heads=2; spt=18; break; /* 1.44 meg */
699 case 7: cyl=80; heads=2; spt=21; break; /* 1.68 meg */
700 case 8: cyl=82; heads=2; spt=21; break; /* 1.72 meg */
701 case 9: cyl=80; heads=2; spt=36; break; /* 2.88 meg */
702 default:
703 fatal ("ERROR: fdsize out of range");
705 sectors = cyl*heads*spt;
706 printf ("I will create a floppy image with\n");
707 printf (" cyl=%d\n", cyl);
708 printf (" heads=%d\n", heads);
709 printf (" sectors per track=%d\n", spt);
710 printf (" total sectors=" FMT_LL "d\n", sectors);
711 printf (" total bytes=" FMT_LL "d\n", sectors*512);
712 if (bx_interactive) {
713 if (!strlen(bx_filename)) strcpy(bx_filename, "a.img");
714 if (ask_string ("\nWhat should I name the image?\n", bx_filename, filename) < 0)
715 fatal (EOF_ERR);
716 } else {
717 strcpy(filename, bx_filename);
719 sprintf (bochsrc_line, "floppya: image=\"%s\", status=inserted", filename);
721 write_function=make_flat_image;
723 if (sectors < 1)
724 fatal ("ERROR: Illegal disk size!");
725 if (strlen (filename) < 1)
726 fatal ("ERROR: Illegal filename");
727 #ifdef WIN32
728 if (writefn_win32 != NULL) {
729 make_image_win32 (sectors, filename, writefn_win32);
731 else
732 #endif
734 make_image (sectors, filename, write_function);
736 printf ("\nI wrote " FMT_LL "u bytes to ", sectors*512);
737 printf ("%s.\n", filename);
738 printf ("\nThe following line should appear in your bochsrc:\n");
739 printf (" %s\n", bochsrc_line);
740 #ifdef WIN32
741 if (OpenClipboard(NULL)) {
742 HGLOBAL hgClip;
743 EmptyClipboard();
744 hgClip = GlobalAlloc(GMEM_DDESHARE, (strlen(bochsrc_line) + 1));
745 strcpy((char *)GlobalLock(hgClip), bochsrc_line);
746 GlobalUnlock(hgClip);
747 SetClipboardData(CF_TEXT, hgClip);
748 CloseClipboard();
749 printf("(The line is stored in your windows clipboard, use CTRL-V to paste)\n");
751 #endif
752 myexit(0);
754 // make picky compilers (c++, gcc) happy,
755 // even though we leave via 'myexit' just above
756 return 0;