diff --git a/src/john.c b/src/john.c
index a5dbd97..2570cf4 100644
--- a/src/john.c
+++ b/src/john.c
@@ -967,7 +967,7 @@ static void john_load(void)
 				ldr_show_pw_file(&database, current->data);
 			} while ((current = current->next));
 
-			if (john_main_process)
+			if (john_main_process && !options.loader.showtypes)
 			printf("%s%d password hash%s cracked, %d left\n",
 				database.guess_count ? "\n" : "",
 				database.guess_count,
diff --git a/src/loader.c b/src/loader.c
index 777cece..9e67026 100644
--- a/src/loader.c
+++ b/src/loader.c
@@ -446,6 +446,92 @@ static int ldr_split_line(char **login, char **ciphertext,
 	if (ldr_check_list(db_opts->groups, gid, gid)) return 0;
 	if (ldr_check_shells(db_opts->shells, shell)) return 0;
 
+        /* TODO: Should john_main_process be checked? */
+	if (db_opts->showtypes) {
+		int fs = db_opts->field_sep_char;
+		/* To suppress warnings,
+		 * particularly from generic crypt's valid() (c3_fmt.c)
+		 */
+		/* TODO: Shoud a separate var be made? */
+		ldr_in_pot = 1;
+		/* TODO: right about \0 and \n? */
+		/* \0 and \n are not possible in any field. */
+		/* TODO: right field_sep_char? What about prepare that insert username into the hash? */
+		/* field_sep_char is not possible in any field too. */
+		/* The format:
+		 * Once for each hash even if it can't be loaded (7 fields):
+		 *   login,
+		 *   original ciphertext,
+		 *   uid,
+		 *   gid,
+		 *   gecos,
+		 *   home,
+		 *   shell.
+		 * For each valid format (may be nothing):
+		 *   label,
+		 *   is format disabled? (1/0),
+		 *   canonical hash or hashes (if there are several parts)
+		 * All fields are separated by field_sep_char.
+		 * Formats are separated by empty field.
+		 * Additional field_sep_char occurs at the end of line:
+		 * it does not break numeration of fields but
+		 * it allows parser to get field_sep_char from the line.
+		 *
+		 * It should look like the following:
+		 * login:hash:u:g:g:h:shell:LM:0:h1:h2::someformat:0:h3:
+		 */
+		printf("%s%c%s%c%s%c%s%c%s%c%s%c%s",
+		       *login,
+		       fs, *ciphertext,
+		       fs, *uid,
+		       fs, gid,
+		       fs, *gecos,
+		       fs, *home,
+		       fs, shell);
+		/* TODO: Right about uid, gid and shell fields? */
+		/* Only uid, gid and shell fields may be empty. */
+		/* Empty fields are separators after this point. */
+		alt = fmt_list;
+		do {
+			char *prepared;
+			int disabled = 0;
+			int valid;
+			int part;
+			/* We don't skip generic crypt. */
+			/* Format disabled in john.conf */
+			if (cfg_get_bool(SECTION_DISABLED, SUBSECTION_FORMATS,
+			                 alt->params.label, 0)) {
+				/* TODO: should not I skip disabled formats? */
+				disabled = 1;
+			}
+			prepared = alt->methods.prepare(fields, alt);
+			if (!prepared)
+				continue;
+			valid = alt->methods.valid(prepared, alt);
+			if (!valid)
+				continue;
+			ldr_set_encoding(alt);
+			/* TODO: alt->params.label is the name of format? */
+			/* TODO: Is it guaranteed that format's label does not contain spaces? */
+			printf("%c%s%c%d",
+			       fs, alt->params.label,
+			       fs, disabled);
+			/* Canonical hash or hashes (like halfs of LM) */
+			for (part = 0; part < valid; part++) {
+				char *splitted = alt->methods.split(*ciphertext, part, alt);
+				/* TODO: handle splitted == 0; it should be a bug then */
+				int same = !strcmp(splitted, *ciphertext);
+				printf("%c%s", fs, splitted);
+			}
+			/* Format is surrounded by separaters.
+			 * They provide empty field between formats. */
+			printf("%c", fs);
+		} while ((alt = alt->next));
+		printf("\n");
+		return 0;
+	}
+
+
 	if (*format) {
 		char *prepared;
 		int valid;
diff --git a/src/loader.h b/src/loader.h
index c74e844..ef2463d 100644
--- a/src/loader.h
+++ b/src/loader.h
@@ -198,6 +198,9 @@ struct db_options {
 /* if --show=left is used, john dumps the non-cracked hashes */
 	int showuncracked;
 
+/* if --show=types is used, john shows all hashes in machine readable form */
+	int showtypes;
+
 /* Field separator (normally ':') */
 	char field_sep_char;
 
diff --git a/src/options.c b/src/options.c
index 03ee4bc..5fa0aad 100644
--- a/src/options.c
+++ b/src/options.c
@@ -905,8 +905,11 @@ void opt_init(char *name, int argc, char **argv, int show_usage)
 			// instead of normal loading if we are in 'normal' show mode)
 			options.flags &= ~FLG_SHOW_CHK;
 		}
+		else if (!strcasecmp(show_uncracked_str, "types")) {
+			options.loader.showtypes = 1;
+		}
 		else {
-			fprintf(stderr, "Invalid option in --show switch.\nOnly --show or --show=left are valid\n");
+			fprintf(stderr, "Invalid option in --show switch.\nOnly --show , --show=left or --show=types are valid\n");
 			error();
 		}
 	}