/*                  AFDISK  -  Amiga RDB Fdisk for Linux
 *              fdisk.c part  -  generic input output stuff
 *                   written in 1996 by Stefan Reinauer
 *
 *    Copyright (C) 1996-1998 Stefan Reinauer
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2, or (at your option)
 *    any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
 */

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <getopt.h>

#include <readline/readline.h>
#include <readline/history.h>     

#include <asm/byteorder.h>

#include <amiga/types.h>
#include <amigastuff.h>
#include <implemented.h>

#define VERSION "0.04"
#define RELDATE "98/11/03"

char *testdevs[] = { "/dev/hda", "/dev/hdb", "/dev/hdc", "/dev/hdd",
                     "/dev/sda", "/dev/sdb", "/dev/sdc", "/dev/sdd",
                     "/dev/sde", "/dev/sdf", "/dev/sdg", "/dev/sdh",
                     NULL };

char disk_device[256]="/dev/sda";
int  list_only=0, get_dev=0;

int atonum(char *s)
{
	char *d=s;
	int n;

	while (*s == ' ') /* Eat spaces */
		s++;

	/* 0x is hex, 0 is octal, everything else is decimal. */
	if (strncmp(s, "0x", 2) == 0 || strncmp(s, "0X", 2) == 0)
		sscanf(s + 2, "%x", &n);
	else if (s[0] == '0' && s[1])
		sscanf(s + 1, "%o", &n);
	else {
		d=s;
		while (d[0]!=0) {
			if (!isdigit( ((int)(d[0])) ))
				return 0;
			d++;
		}
		sscanf(s, "%d", &n);
	}
	return n;
}

int partition(void)
{
	char *partnum;
	int i;

	partition_show();

	partnum=readline("Partition number: ");
	if (partnum==NULL) exit(0);
	i=atonum(partnum);
	free(partnum);

	return i;
}

int override(void)
{
	char *ovr;
	int i=0;
	if (!list_only) {
		ovr=readline("Do you want to override this error? [y/N] ");
		if (ovr==NULL) exit(0);
		if (ovr[0]=='y' || ovr[0]=='Y') i=1;
		free(ovr);
	} else {
		fprintf (stderr,"Overriding last error.\n");
		i=1;
	}

	return i;
}

int listknown(void)
{
	printf("Known Partition Types\n---------------------\n
 1.  DOS\\0	Old Filesystem
 2.  DOS\\1	Original FastFileSystem (FFS)
 3.  DOS\\2	Old International Filesystem
 4.  DOS\\3	International FastFileSystem
 5.  DOS\\4	Old Filesystem with directory cache
 6.  DOS\\6	FastFileSystem with directory cache
 7.  UNI\\0	classic AT&T System-V filesystem
 8.  UNI\\1	UNIX boot \"filesystem\" (dummy entry for Amiga OS's boot menu)
 9.  UNI\\2	Berkeley filesystem for System V
10.  RESV	Reserved (e.g. swap space)
11.  LNX\\0	Linux native
12.  SWP\\0	Linux swap\n\n");

	return 0;
}

int menu(void)
{
	printf ("Command action
   a   toggle bootable flag
   b   change number of bootblocks
   c   change boot priority
   d   delete a partition
   e   toggle nomount flag
   l   list known partition types
   m   print this menu
   n   add a new partition
   p   print the partition table
   q   quit without saving changes
   t   change a partition's DosType
   r   reorganize/move RDB
   w   write table to disk and exit\n\n");
	return 0;
}

int version(void)
{
	printf ("amiga-fdisk %s (%s) by Stefan Reinauer, <stepan@linux.de>\n\n",VERSION,RELDATE);
	return 0;
}

ULONG gettype(void)
{
	char *dtype;
	ULONG hexval,ascii;

	listknown();

	printf ("\n  Choose a number of the upper list or\n  enter a DosType of the format 0x444f5302\n\n");
	dtype=readline("Enter DosType: ");
	if (dtype==NULL) exit (0);
	hexval=atonum(dtype);
        ascii=ntohl(*(ULONG *)dtype);
	free(dtype);

	switch (hexval) {
		case 0:  return ascii;
		case 1:  return 0x444f5300;
		case 2:  return 0x444f5301;
		case 3:  return 0x444f5302;
		case 4:  return 0x444f5303;
		case 5:  return 0x444f5304;
		case 6:  return 0x444f5305;
		case 7:  return 0x554e4900;
		case 8:  return 0x554e4901;
		case 9:  return 0x554e4902;
		case 10: return 0x52455356;
		case 11: return 0x4C4E5800;
		case 12: return 0x53575000;
		default: return (hexval);
	}
	return 0;
}

 
int main(int argc, char **argv)
{
	int  c, count;
	char *entry, *optinput;

	/* Parsing all command line parameters */

	while(((c = getopt(argc, argv, "-dvls:TViN:A:u:xC:H:S:fqLnRO:I:?")) != EOF))
	switch(c) {
	case 1:
		get_dev=1;
		strcpy(disk_device, optarg);
		break;
	case 'v':
		version();
		return 0;
	case '?':
		printf ("\nUsage: %s [-l] [-v] [-d] [-s /dev/hdxn] [/dev/hdx]\n",argv[0]);
		return 0;
	case 'l':
		list_only = 1;
		break;
	case 'T':
		version();
		listknown();
		return 0;
	default:
		count=0;
		while (functions[count].key!='!') {
			if (functions[count].key==c) {
				printf ("Option \"%c\" - \"%s\" - not yet implemented.\n",c, functions[count].desc);
				break;
			}
			count++;
		}
		return 0;
	}


	/* switch to selected mode and look for valid device */

	if (list_only) {
		if (get_dev) {
			if (get_rdb()!=-1) {
				rigiddisk_show();
				partition_show();
				printf ("\n");
			}
		} else {
			count=0;
			while (testdevs[count] != NULL) {
				strcpy(disk_device, testdevs[count++]);

				if (get_rdb()!=-1) {
					rigiddisk_show();
					partition_show();
					printf ("\n");
				}
			}
		}
		return 0;

	} else {
		if (!get_dev)
			printf ("Using %s as default device!\n",disk_device);
		if (get_rdb()==-1)
			 return -1;
	}

	printf ("\n");  

	/* Entering interactive mode */

	for (;;) {

#ifdef DEBUG
		pt();
#endif

		entry=readline(  "Command (m for help): ");
		if (entry==NULL) {
			quitall();
			return 0;
		}
		switch ((*entry)) {
		case 'q':
		case 'Q':
			quitall();
			free(entry);
			return 0;
		case 'l':
		case 'L':
			listknown();
			break;
		case 'p':
		case 'P':
			printf ("\n");
			rigiddisk_show();
			partition_show();
			printf ("\n");
			break;
		case 'a':
		case 'A':
			partition_togglebootable(partition());
			break;
		case 'b':
		case 'B':
			count=partition();
			optinput=readline("Number of bootblocks: ");
			if (optinput==NULL) return 0;
			partition_bootblk(count,atonum(optinput));
			free(optinput);
			break;
		case 'c':
		case 'C':
			count=partition();
			optinput=readline("New Boot Priority: ");
			if (optinput==NULL) return 0;
			partition_bootpri(count,atonum(optinput));
			free(optinput);
			break;
		case 'd':
		case 'D':
			partition_delete(partition());
			break;
		case 'e':
		case 'E':
			partition_togglenomount(partition());
			break;
		case 'n':
		case 'N':
			if (room_for_partition()!=-1) {
				count=partition();
				if (partition_new(count)!=-1) {
					optinput=readline("Low Cylinder: ");
					if (optinput==NULL) return 0;
					partition_locyl(count,atonum(optinput));
					free(optinput);

					optinput=readline("High Cylinder: ");
					if (optinput==NULL) return 0;
					partition_hicyl(count,atonum(optinput));
					free(optinput);
				}
			}
			break;
		case 't':
		case 'T':
			count=partition();
			partition_dostype(count,gettype());
			break;

		case 'w':
		case 'W':
			free(entry);
			rigiddisk_reorg(firstblock);
			rigiddisk_save();
			return 0;
		case 'r':
		case 'R':
			printf ("\n");
			rigiddisk_show();
			printf ("\n");
			optinput=readline(" RDB start at: ");
			if (optinput==NULL) return 0;
			rigiddisk_reorg(atonum(optinput));
			free(optinput);
			break;
		case '\0':
			break;
		case 'm':
		case 'M':
		default:
			menu();
			break;
		}

		free(entry);

	}
}

