// QuickSortExternal_4+GB r.2+, copyleft 2011 May 08, Kaze. A pseudo-problem exists in r.1++ and r.2, namely the sorted file is smaller than the incoming one (for example for graffith_L.log), bug?!

/*
[kaze@gea ~]$ cd /home/kaze/r2
[kaze@gea r2]$ ls -l
-rwxrwxrwx 1 kaze kaze 7773570191 2011-05-11 05:46 GRAFFITH_T.log
-rwxrwxrwx 1 kaze kaze        129 2011-05-13 00:18 Linux_QuickSortExternal_4+GB_Complile_Line.script
-rwxrwxrwx 1 kaze kaze     103015 2011-05-13 01:01 QuickSortExternal_4+GB.c
[kaze@gea r2]$ ./Linux_QuickSortExternal_4+GB_Complile_Line.script
QuickSortExternal_4+GB.c: In function ‘CompareStringsEndingWith13’:
QuickSortExternal_4+GB.c:757: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c:770: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c: In function ‘CompareStringsEndingWith13_EXTERNAL’:
QuickSortExternal_4+GB.c:823: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c:836: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c: In function ‘main’:
QuickSortExternal_4+GB.c:2022: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c:2041: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c:2502: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c:2554: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c:2581: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
QuickSortExternal_4+GB.c:2602: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
/usr/include/stdio.h:783: note: expected ‘const struct fpos_t *’ but argument is of type ‘long long unsigned int *’
[kaze@gea r2]$ ./QuickSortExternal_4+GB_r2+_generic_64bits.elf 
QuickSortExternal_4+GB r.2+, written by Kaze.
Usage: QuickSortExternal_4+GB wordlistfile {/fast|/slow}
Note1: The lines in wordlistfile must be up to 2048 chars/bytes and end with CRLF i.e. maximum 2050bytes long.
Note2: The goal is to sort a file unfittable in physical memory, and with 32bit code.
Note3: When /fast is specified wordlistfile is uploaded into internal memory if it is possible.
Note4: When /slow is specified wordlistfile is NOT uploaded into internal memory even if it is possible.
[kaze@gea r2]$ ./Corpus_script_T.txt
QuickSortExternal_4+GB r.2+, written by Kaze.
Size of input file: 7,773,570,191
Counting lines ...
Allocated memory for pointers-to-words in MB: 2602
Assigning pointers ...
Trying to allocate memory for the file itself in MB: 7414 ... UNSUCCESSFUL! Get on with slow external accesses.
Sorting 340,981,845 Pointers ...
Pass #1: Quicksort started ...
| RightEnd-LeftEnd: 000,000,000,019; NumberOfSplittings: 0,029,549,542 ...
Pass #2: Insertionsort started ...
| i: 000,340,981,845 ...
NumberOfComparisons: 11,329,560,863
The time to sort 340,981,845 items via Quicksort+Insertionsort was 38,001,370,000 clocks.
Dumping the sorted data ...
Dumped 340,981,845 lines.
OK! Incoming and resultant file's sizes match.
Dumping the sorted data [deduplicated] ...
Dumped 115,672,221 distinct lines.
Total time: 41,224,560,000 clocks.
Performance: 184 KB/s.
Done successfully.
[kaze@gea r2]$ 

[kaze@gea ~]$ cd r2/
[kaze@gea r2]$ ls -l
-rwxrwxrwx 1 kaze kaze 5641065963 2011-05-13 01:20 GRAFFITH_A.log
-rwxrwxr-x 1 kaze kaze     719059 2011-05-13 00:34 QuickSortExternal_4+GB_r2+_generic_64bits.elf
[kaze@gea r2]$ ./Corpus_script_A.txt
QuickSortExternal_4+GB r.2+, written by Kaze.
Size of input file: 5,641,065,963
Counting lines ...
Allocated memory for pointers-to-words in MB: 1898
Assigning pointers ...
UNSUCCESSFUL! Get on with slow external accesses.
Sorting 248,673,965 Pointers ...
Pass #1: Quicksort started ...
/ RightEnd-LeftEnd: 000,000,000,025; NumberOfSplittings: 0,021,635,123 ...
Pass #2: Insertionsort started ...
\ i: 000,248,673,965 ...
NumberOfComparisons: 7,999,804,609
The time to sort 248,673,965 items via Quicksort+Insertionsort was 25,793,490,000 clocks.
Dumping the sorted data ...
Dumped 248,673,965 lines.
OK! Incoming and resultant file's sizes match.
Dumping the sorted data [deduplicated] ...
Dumped 92,148,559 distinct lines.
Total time: 28,007,460,000 clocks.
Performance: 196 KB/s.
Done successfully.
[kaze@gea r2]$ 
*/

/*
Following data is taken during execution i.e. before going to prompt:

     1,141,536,585 GRAFFITH_N.log
     1,141,534,720 QuickSortExternal_4+GB.txt

D:\_KAZE_new-stuff\_BUG_HIDDEN>sort GRAFFITH_N.log /o GRAFFITH_N.log.WIN
     1,141,536,585 GRAFFITH_N.log.WIN

D:\_KAZE_new-stuff\_BUG_HIDDEN>fc GRAFFITH_N.log.WIN QuickSortExternal_4+GB.txt
Comparing files GRAFFITH_N.log.WIN and QUICKSORTEXTERNAL_4+GB.TXT
Resync Failed.  Files are too different.
***** GRAFFITH_N.log.WIN
nzxd_xxtm_nxt_x
nzxd_xxtnsz_ze_kn
nzxdvx_t_k_p
nzxdvx_t_kj_p
nzxdvx_t_u_u
nzxdvx_tk_k_xzbt
nzxdvx_tm_nxtpxnrn_bt
nzxdvx_tm_nxtpxnrn_btk
nzxdvx_tpnb_k_s
nzxdvx_tq_k_x
nzxdvxxt_kj_z_mnk
nzxdvxxtkj_z_m_kxmn
nzxf_nz_u_nxyo
nzxf_nzucnxhor_morx_u
nzxfs_zt_x_zt
nzxir_nq_ahi_ocow
nzxt_can_do_a
nzxt_case_with_w
nzxt_has_the_answer
nzxt_khaos_case_with
nzxt_khaos_corsair_hx
nzxt_lexa_blackline_case
nzxt_s_tempest_out
nzxt_sentry_we_ve
nzxt_tempest_how_the
nzxt_tempest_if_you
nzxt_x_nemesis_tower
nzxt_x_nemesis_tower
nzxt_zero_full_tower
nzxt_zero_ii_a
nzxt_zero_ii_is
nzxt_zero_ii_maximumpc
nzxt_zero_ii_s
nzxt_zero_watt_full
nzxtw_mod_see_through
nzxyz_ztsh_x_c
nzy_dx_dy_dz
nzy_dx_dy_dz
nzy_loefj_jmioy_lkp
nzy_loefj_jmioy_lkpa
nzy_nn_nno_njz
nzy_ntcwnw_wah_hbxlzdgf
nzy_nze_oz_input
nzy_nzx_nxz_nxy
nzy_on_hjwaoogbojy_ejy
nzy_ywny_i_n
nzybq_jmnzo_wxy_wljmp
nzycm_supplemented_with_a
nzycm_without_casamino_acids
nzyd_lbny_hnby_ym
nzyd_vyb_jsv_mn
nzym_nzycm_without_casamino
nzym_without_yeast_extract
nzymatic_background_reaction_to
nzymatic_filling_of_a
nzymatic_filling_of_a
nzymatic_reaction_to_form
nzyme_called_a_required
nzyme_called_a_required
nzyme_dna_from_any
nzyme_dna_from_any
nzyme_l_inked_i
nzyme_l_inked_i
nzyme_of_a_novice
nzyme_of_a_novice
nzyme_responsible_for_transport
nzyme_responsible_for_transport
nzyme_that_breaks_internal
nzyme_that_breaks_internal
nzyme_that_breaks_phos
nzyme_that_breaks_phos
nzyme_that_catalyze_sspe
nzyme_that_catalyze_sspe
nzyme_that_introduces_or
nzyme_that_introduces_or
nzyme_that_is_needed
nzyme_that_is_needed
nzymes_in_the_b
nzyr_lhym_ny_mb
nzyr_lhym_yhyh_hnjr
nzyrk_l_tb_r
nzyryh_mslg_xv_mxlb
nzythologie_et_d_archiologie
nzz_bck_qymcq_swr
nzz_came_after_nz
nzz_i_s_fhenf
nzz_nx_sh_psh
nzz_tzzvfu_l_del
nzz_zt_xxf_x
nzzmp_eskd_writing_the
***** QUICKSORTEXTERNAL_4+GB.TXT
nzxd_xxtm_nxt_x
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
nts_the
*****

204-106+1=99 'nts_the' lines

D:\_KAZE_new-stuff\_BUG_HIDDEN>dir GRAFFITH_N.log.WIN/b>q

D:\_KAZE_new-stuff\_BUG_HIDDEN>Linereporter.exe q
Linereporter, revision 1+, written by Kaze.
Purpose: Reports number of lines(LFs) in files from a given filelist.
Example:
D:\>Linereporter.exe LQ2048.lst
Note: Files can exceed 4GB limit.
Counting ...
Linereporter: Encountered lines in all files: 50,360,855
Linereporter: Longest line: 32

D:\_KAZE_new-stuff\_BUG_HIDDEN>dir "QuickSortExternal_4+GB.txt"/b>q

D:\_KAZE_new-stuff\_BUG_HIDDEN>Linereporter.exe q
Linereporter, revision 1+, written by Kaze.
Purpose: Reports number of lines(LFs) in files from a given filelist.
Example:
D:\>Linereporter.exe LQ2048.lst
Note: Files can exceed 4GB limit.
Counting ...
Linereporter: Encountered lines in all files: 50,360,766
Linereporter: Longest line: 32

50,360,855-50,360,766=89 lines shorter than original

D:\_KAZE_new-stuff\_BUG_HIDDEN>type "QuickSortExternal_4+GB.txt"
...
nzx_o_modulus_kcodb
nzx_o_modulus_kcode
nzx_produced_by_the
nzx_sin_nkq_dx
nzx_there_are_jtsoil
nzx_x_x_rotations
nzxd_xxt_k_k
nzxd_xxt_k_ua
nzxd_xxt_u_upu
nzxd_xxtm_nxt_x
n
D:\_KAZE_new-stuff\_BUG_HIDDEN>

!!! Why sometimes the cache is not flushed ??? !!! With immediate fclose maybe this pseudo-bug will vanish?!?!?!

*/

// To-do #1: remove Insertionsort as pass 2, it is so stupid/slow - sort the groups inside QuickSort instead.
// To-do #2: make my own cache - something like look-ahead and look-arear buffers of size 4KB i.e. 4KB ahead of LeftEnd and  4KB arear of RightEnd, of course constantly updating them/buffers with the moving of LeftPtr and RightPtr. The goal: to reduce/replace freads with a single fread of size 4KB.
// To-do #3: make also 'QuickSortExternal_4+GB.distinct.txt' with removed duplicates with a compression-friendly (higly compressable) number-of-occurrences stats:
//           were_most_sought_after\t100,000+
//           were_most_sought_after\t010,000+
//           were_most_sought_after\t001,000+
//           were_most_sought_after\t000,100+
//           were_most_sought_after\t000,010+
//           were_most_sought_after\t000,010-

/*
D:\QuickSortExternal_4+GB_r1+>copy con test.txt
aa
aa
aa
aa
bb
aa
dd
zz
aa
zz
qq
make good
made good
make good
^Z
        1 file(s) copied.

D:\QuickSortExternal_4+GB_r1+>"QuickSortExternal_4+GB.exe" test.txt
QuickSortExternal_4+GB r.1++, written by Kaze.
Size of input file: 77
Allocated memory for pointers-to-words in MB: 1
Sorting 14 Pointers ...
Pass #1: Quicksort started ...
/ RightEnd-LeftEnd: 000,000,000,013; NumberOfSplittings: 0,000,000,001 ...
Pass #2: Insertionsort started ...
- i: 000,000,000,015 ...
The time to sort 14 items via Quicksort was 0 clocks.
Dumping the sorted data ...
Dumped 14 lines.
Dumped 7 distinct lines.
Done.

D:\QuickSortExternal_4+GB_r1+>type "QuickSortExternal_4+GB.txt"
aa
aa
aa
aa
aa
aa
bb
dd
made good
make good
make good
qq
zz
zz

D:\QuickSortExternal_4+GB_r1+>type "QuickSortExternal_4+GB.distinct.txt"
0,000,006       aa
0,000,001       bb
0,000,001       dd
0,000,001       made good
0,000,002       make good
0,000,001       qq
0,000,002       zz

D:\QuickSortExternal_4+GB_r1+>
*/

/*
Linux Fedora 10 64bit log:

[kaze@saturn QuickSortExternal_4+GB_r1+]$ sh ./Linux_QuickSortExternal_4+GB_Complile_Line.script
QuickSortExternal_4+GB.c: In function ‘CompareStringsEndingWith13’:
QuickSortExternal_4+GB.c:363: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
QuickSortExternal_4+GB.c:376: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
QuickSortExternal_4+GB.c: In function ‘main’:
QuickSortExternal_4+GB.c:1937: warning: passing argument 2 of ‘fsetpos’ from incompatible pointer type
[kaze@saturn QuickSortExternal_4+GB_r1+]$ cat ./Linux_QuickSortExternal_4+GB_Complile_Line.script
gcc -D_FILE_OFFSET_BITS=64 -m64 -static -O3 -mtune=generic QuickSortExternal_4+GB.c -o QuickSortExternal_4+GB_generic_64bits.elf
[kaze@saturn QuickSortExternal_4+GB_r1+]$ ls -l *.elf
-rwxrwxr-x 1 kaze kaze 703669 2011-04-29 04:41 QuickSortExternal_4+GB_generic_64bits.elf
[kaze@saturn QuickSortExternal_4+GB_r1+]$ ./QuickSortExternal_4+GB_generic_64bits.elf Poirot_plus_Holmes.txt
QuickSortExternal_4+GB r.1+, written by Kaze.
Size of input file: 84,413,747
Allocated memory for pointers-to-words in MB: 30
Sorting 3,848,740 Pointers ...
Pass #1: Quicksort started ...
- RightEnd-LeftEnd: 000,000,000,019; NumberOfSplittings: 0,000,439,697 ...
Pass #2: Insertionsort started ...
/ i: 000,003,848,741 ...
The time to sort 3,848,740 items via Quicksort was 389,070,000 clocks.
Dumping the sorted data ...
Done.
[kaze@saturn QuickSortExternal_4+GB_r1+]$ ls -l Qu*.txt
-rw-rw-r-- 1 kaze kaze 84413747 2011-04-29 05:25 QuickSortExternal_4+GB.txt
[kaze@saturn QuickSortExternal_4+GB_r1+]$ 

Windows XP 32bit log:

D:\QuickSortExternal_4+GB_r1+>QuickSortExternal_4+GB.exe Poirot_plus_Holmes.txt
QuickSortExternal_4+GB r.1+, written by Kaze.
Size of input file: 84,413,747
Allocated memory for pointers-to-words in MB: 30
Sorting 3,848,740 Pointers ...
Pass #1: Quicksort started ...
- RightEnd-LeftEnd: 000,000,000,019; NumberOfSplittings: 0,000,439,697 ...
Pass #2: Insertionsort started ...
/ i: 000,003,848,741 ...
The time to sort 3,848,740 items via Quicksort was 523,531 clocks.
Dumping the sorted data ...
Done.
*/

//For everyone interested in slow external sorting ...

//Time results for sorting a file (84,413,747 bytes) with 3,848,740 words of length up to 31 bytes:
//- QuickSortExternal_4+GB_Microsoft.exe needs 743 seconds
//- sort (the Windows XP command utility) needs 16 seconds

//What to say: an unexpected far-cry. I had had some big illusions about OS (Windows XP) caching performance.
//I am still confused why the speed is so zombie-like: after all there are only I/O read accesses, not a single write?!
//The test machine is Notebook Satellite Merom 2.16GHz, 4GB RAM, Windows XP 32 bit, 7200rpm HDD.
//It is interesting a comparison to be made on HDD and SSD on a same machine: I expect 50microseconds vs 10milliseconds seek-time to make the difference I had expected initially, 200 times faster... hardly but who knows - must be tested.
//As far as I understand the bottlenecks are:
//- seek-time i.e. latency of external memory, not transfer rates;
//- freads by byte accesses - not buffered as I thought [obviously].

//A few words about limitations: revision 1+ compiled as 32bit can sort some 250,000,000 pseudo-pointers(8bytes offsets to 64bit external pool/file) to the CRLF ending strings in a file regarless of its size (it can exceed 4GB limit) due to maximum ~1950MB malloc with 32bit Windows.
//I am afraid to think how ultra-slow will crawl the code if these pseudo-pointers are put into their own pool/file in order to be fully independent from systen ram allocations.

//To run the test yourself here is the package: QuickSortExternal_4+GB_r1.zip (22,865,439 bytes).

//I ran it with 5,641,065,963 bytes 4-gram wordlist consisted of 248,673,965 lines:
//D:\QuickSortExternal_4+GB_r1>"QuickSortExternal_4+GB_Microsoft.exe" "Corpus_'Gamera'_r14_all_quadruplets_A_GRAFFITH.log"
//QuickSortExternal_4+GB r.1, written by Kaze.
//Size of input file: 5,641,065,963
//Allocated memory for pointers-to-words in MB: 1898
//Sorting 248673965 Pointers ...
//...
//78,486,203clocks = 78,486seconds = 21.8hours

//Any ideas how to boost this particular brute-force approach!?
//For any improvement/idea my e-mail: sanmayce@sanmayce.com

// Intel(R) C++ Compiler Professional for applications running on IA-32, Version 11.1:
// QuickSortExternal_4+GB_Intel.exe, Mingroup = 12:
//The current time is:  9:53:57.57
//- MidPtr: 000,001,068,662; NumberOfSplittings: 0,000,439,697 ...
//The time to sort 3848740 items via Quicksort was 1320953 clocks.
//The current time is: 10:16:59.89

// Open Visual C++ Toolkit 2003:
// QuickSortExternal_4+GB_Microsoft.exe, Mingroup = 12:
//The current time is: 10:26:13.34
//- MidPtr: 000,001,068,662; NumberOfSplittings: 0,000,439,697 ...
//The time to sort 3848740 items via Quicksort was 743297 clocks.
//The current time is: 10:38:58.31

// Open Visual C++ Toolkit 2003:
// QuickSort+Insertionsort follows with Mingroup = 16:
//The current time is:  8:22:58.70
//The time to sort 3848740 items via Quicksort was 756297 clocks.
//The current time is:  8:35:55.75

// Open Visual C++ Toolkit 2003:
// QuickSort+Insertionsort follows with Mingroup = 3:
//The current time is:  5:35:08.46
//The time to sort 3848740 items via Quicksort was 838516 clocks.
//The current time is:  5:49:27.45

// Open Visual C++ Toolkit 2003:
// QuickSort+Insertionsort follows with MinGroup = 64:
//The current time is:  5:54:38.84
//The time to sort 3848740 items via Quicksort was 857656 clocks.
//The current time is:  6:09:17.06

// Open Visual C++ Toolkit 2003:
// QuickSort+Insertionsort follows with Mingroup = 16384/32:
//The current time is:  4:34:04.51
//The time to sort 3848740 items via Quicksort was 2750641 clocks.
//The current time is:  5:20:17.20

/*
D:\QuickSortExternal_4+GB_r1>dir
 Volume in drive D is H320_Vol5
 Volume Serial Number is 0CB3-C881

 Directory of D:\QuickSortExternal_4+GB_r1

04/27/2011  10:25 AM    <DIR>          .
04/27/2011  10:25 AM    <DIR>          ..
04/27/2011  10:25 AM                 0 Empty
04/27/2011  10:25 AM                 2 ENTER
04/27/2011  10:25 AM            41,511 LBL2048.zip
04/27/2011  10:25 AM            41,844 Linereporter.zip
04/27/2011  10:25 AM            39,670 Overlapper-Blender_r1+1300MB_BUG-FIXED-WITH-FREE.rar
04/27/2011  10:25 AM             3,396 qsort.c.zip
04/27/2011  10:25 AM            74,248 QuickSortExternal_4+GB.c
04/27/2011  10:25 AM           182,058 QuickSortExternal_4+GB.cod
04/27/2011  10:25 AM                84 QuickSortExternal_4+GB_COMPILE_Intel.bat
04/27/2011  10:25 AM                97 QuickSortExternal_4+GB_COMPILE_Microsoft.bat
04/27/2011  10:25 AM           466,944 QuickSortExternal_4+GB_Intel.exe
04/27/2011  10:25 AM            49,152 QuickSortExternal_4+GB_Microsoft.exe
04/27/2011  10:25 AM               280 RUNME.BAT
04/27/2011  10:25 AM        57,389,250 _Agatha Christie_Texts.txt
04/27/2011  10:25 AM        27,024,497 _Sherlock Holmes_Texts.txt
              15 File(s)     85,313,033 bytes
               2 Dir(s)  33,349,967,872 bytes free

D:\QuickSortExternal_4+GB_r1>"QuickSortExternal_4+GB_Microsoft.exe"
QuickSortExternal_4+GB r.1, written by Kaze.
Usage: QuickSortExternal_4+GB wordlistfile
Note1: wordlistfile's lines must be up to 31 chars/bytes and end with CRLF i.e. maximum 33bytes long.
Note2: The goal is to sort a file unfittable in physical memory, and with 32bit code.

D:\QuickSortExternal_4+GB_r1>type RUNME.BAT
copy "_Agatha Christie_Texts.txt"+"_Sherlock Holmes_Texts.txt" Poirot_plus_Holmes.txt /b
time<ENTER
QuickSortExternal_4+GB_Microsoft.exe Poirot_plus_Holmes.txt
time<ENTER
sort Poirot_plus_Holmes.txt>SystemSort.txt
time<ENTER
fc QuickSortExternal_4+GB.txt SystemSort.txt /b

D:\QuickSortExternal_4+GB_r1>RUNME.BAT

D:\QuickSortExternal_4+GB_r1>copy "_Agatha Christie_Texts.txt"+"_Sherlock Holmes_Texts.txt" Poirot_plus_Holmes.txt /b
_Agatha Christie_Texts.txt
_Sherlock Holmes_Texts.txt
        1 file(s) copied.

D:\QuickSortExternal_4+GB_r1>time0<ENTER
The current time is: 10:26:13.34
Enter the new time:

D:\QuickSortExternal_4+GB_r1>QuickSortExternal_4+GB_Microsoft.exe Poirot_plus_Holmes.txt
QuickSortExternal_4+GB r.1, written by Kaze.
Size of input file: 84413747
Allocated memory for pointers-to-words in MB: 30
Sorting 3848740 Pointers ...
Pass #1: Quicksort started ...
- MidPtr: 000,001,068,662; NumberOfSplittings: 0,000,439,697 ...
Pass #2: Insertionsort started ...
| i: 000,003,833,857 ...
The time to sort 3848740 items via Quicksort was 743297 clocks.
Dumping the sorted data ...
Done.

D:\QuickSortExternal_4+GB_r1>time0<ENTER
The current time is: 10:38:58.31
Enter the new time:

D:\QuickSortExternal_4+GB_r1>sort Poirot_plus_Holmes.txt 1>SystemSort.txt

D:\QuickSortExternal_4+GB_r1>time0<ENTER
The current time is: 10:39:14.56
Enter the new time:

D:\QuickSortExternal_4+GB_r1>fc QuickSortExternal_4+GB.txt SystemSort.txt /b
Comparing files QuickSortExternal_4+GB.txt and SYSTEMSORT.TXT
FC: no differences encountered
*/

// Overlapper-Blender r.1+_SWAP, blend of Compare_Two_Wordlists, revision 1+ and Building-Blocks_DUMPER rev.1, written by Kaze.

//#define DumboDumpLOG
#define _WIN32_ENVIRONMENT_
//#define _POSIX_ENVIRONMENT_

#if defined(_WIN32_ENVIRONMENT_)
#include <io.h> // needed for Windows' 'lseeki64' and 'telli64'
//Above line must be commented in order to compile with Intel C compiler: an error "can't find io.h" occurs.
#else
#endif /* defined(_WIN32_ENVIRONMENT_)  */


/*
C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>type osho.txt
bxr bxr boban dodo
C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>dir osho.txt
18 osho.txt

C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>cl /Ox Building-Blocks_DUMPER.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.

Building-Blocks_DUMPER.c
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:Building-Blocks_DUMPER.exe
Building-Blocks_DUMPER.obj

C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>Building-Blocks_DUMPER.exe
Building-Blocks_DUMPER rev.1, written by Kaze.
Sorting 16 Pointers to Building-Blocks 3 chars in size ...
Allocated memory for pointers-to-words in MB: 1
Writing Sorted Building-Blocks to BB003.txt ...

In %c:
C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>type BB003.txt
 bo
 bx
 do
an
ban
bob
bxr
bxr
dod
n d
oba
odo
r b
r b
xr
xr

In HEX:
C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>type BB003.txt
20626f
206278
20646f
616e20
62616e
626f62
627872
627872
646f64
6e2064
6f6261
6f646f
722062
722062
787220
787220

C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>Building-Blocks_DUMPER.exe
Building-Blocks_DUMPER rev.1, written by Kaze.
Sorting 16 Pointers to Building-Blocks 3 chars in size ...
Allocated memory for pointers-to-words in MB: 1
Writing Sorted Building-Blocks to BB003.txt ...
3|18-3+1|13|3

C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>type BB003.txt
 bo
 bx
 do
an
ban
bob
bxr
dod
n d
oba
odo
r b
xr

C:\WorkTemp\LEPREC~1\VISUAL~1\LEA56D~1>type osho.txt
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifndef NULL
#define NULL ((void*)0)
#endif

typedef unsigned char char_t;
typedef char_t *string;

int Patternlen;      
unsigned long long NumberOfComparisons=0;
FILE *fp_in; // Global - not to burden the extract/compare function with one more parameter
#define LongestLineInclusive 2048 //31 former

//clock_t clocks1, clocks2;
//clock_t clocks3, clocks4;
double TotalRoughSearchTime = 0;

// SINHA fragment[

#define swapKAZE(a, b) { t = *(a); *(a) = *(b); *(b) = t; }

static void InsertSortKAZE(string *a, int n, int d) //void inssort(unsigned char **a, int n, int d)
{   string *pi, *pj, s, t;                          //unsigned char **pi, **pj, *s, *t;
    for (pi = a + 1; --n > 0; pi++)
        for (pj = pi; pj > a; pj--) {
            /* Inline strcmp: break if *(pj-1) <= *pj */
            for (s=*(pj-1)+d, t=*pj+d; *s==*t && *s!=0; s++, t++)
                ;
            if (*s <= *t)
                break;
            swapKAZE(pj, pj-1);
    }
}

//int cmpit(unsigned char **h1, unsigned char **h2)
//{
//    return( scmp(*h1, *h2) );
//}

int scmp( unsigned char *s1, unsigned char *s2 )
{
    while( *s1 != '\0' && *s1 == *s2 )
    {
        s1++;
        s2++;
    }
    return( *s1-*s2 );
}

static void simplesort(string a[], int n, int b)
{
   int i, j;
   string tmp;

   for (i = 1; i < n; i++)
      for (j = i; j > 0 && scmp(a[j-1]+b, a[j]+b) > 0; j--)
         { tmp = a[j]; a[j] = a[j-1]; a[j-1] = tmp; }
}

int strcmpKAZE13 (
        const char * src,
        const char * dst
        )
{
        int ret = 0 ;

        while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && (*dst!=13))
                ++src, ++dst;

        if ( ret < 0 )
                ret = -1 ;
        else if ( ret > 0 )
                ret = 1 ;

        return( ret );
}

int CompareStringsEndingWith13(unsigned long long AtPosition64L, unsigned long long AtPosition64R, char *POOLinternal) {

int i;
char FourGramL[LongestLineInclusive+2]; // 31 longest 4-gram + CR + LF
char FourGramR[LongestLineInclusive+2]; // 31 longest 4-gram + CR + LF
unsigned long long *AtPosition64Lpointer=&AtPosition64L;
unsigned long long *AtPosition64Rpointer=&AtPosition64R;

if (POOLinternal == NULL) { // INTERNAL [

// Caramba: seek and tell report OK but in fact they lie, only setpos works?!?!?!

//#if defined(_WIN32_ENVIRONMENT_)
//_lseeki64( fileno(fp_in), AtPosition64L, 0 );
//#else
//fseeko( fp_in, AtPosition64L, SEEK_SET );
//#endif /* defined(_WIN32_ENVIRONMENT_)  */

//  _CRTIMP __int64 __cdecl _telli64(int);
//  off64_t ftello64 (FILE *stream)  


fsetpos(fp_in, AtPosition64Lpointer);
#if defined(DumboDumpLOG)
printf("Tell %llu:\n",_telli64(fileno(fp_in)));
printf("L:\n");
#endif
	for (i=0; i<(LongestLineInclusive+1); i++) {fread(&FourGramL[i], 1, 1, fp_in); if (FourGramL[i]==13) break;}
	//Commented line below is slower than the one above: 778156 clocks vs 756297 clocks.
	//fread(&FourGramL[0], 31+1, 1, fp_in);
#if defined(DumboDumpLOG)
for (i=0; i<(LongestLineInclusive+1); i++) {printf("%c",FourGramL[i]); if (FourGramL[i]==13) break;}
printf("\n");
#endif

fsetpos(fp_in, AtPosition64Rpointer);
#if defined(DumboDumpLOG)
printf("Tell %llu:\n",_telli64(fileno(fp_in)));
printf("R:\n");
#endif
	for (i=0; i<(LongestLineInclusive+1); i++) {fread(&FourGramR[i], 1, 1, fp_in); if (FourGramR[i]==13) break;}
	//Commented line below is slower than the one above: 778156 clocks vs 756297 clocks.
	//fread(&FourGramR[0], 31+1, 1, fp_in);
#if defined(DumboDumpLOG)
for (i=0; i<(LongestLineInclusive+1); i++) {printf("%c",FourGramR[i]); if (FourGramR[i]==13) break;}
printf("\n");
#endif

} else { // INTERNAL

for (i=0; i<(LongestLineInclusive+1); i++) {
	//fread(&FourGramL[i], 1, 1, fp_in);
	FourGramL[i] = *(char *)(POOLinternal + AtPosition64L + i);
	if (FourGramL[i]==13) break;
}

for (i=0; i<(LongestLineInclusive+1); i++) {
	//fread(&FourGramR[i], 1, 1, fp_in);
	FourGramR[i] = *(char *)(POOLinternal + AtPosition64R + i);
	if (FourGramR[i]==13) break;
}

} // INTERNAL ]

NumberOfComparisons++;
return(strcmpKAZE13(FourGramL, FourGramR));
}

int CompareStringsEndingWith13_EXTERNAL(unsigned long long AtPosition64L, unsigned long long AtPosition64R) {

int i;
char FourGramL[LongestLineInclusive+2]; // 31 longest 4-gram + CR + LF
char FourGramR[LongestLineInclusive+2]; // 31 longest 4-gram + CR + LF
unsigned long long *AtPosition64Lpointer=&AtPosition64L;
unsigned long long *AtPosition64Rpointer=&AtPosition64R;

// Caramba: seek and tell report OK but in fact they lie, only setpos works?!?!?!

//#if defined(_WIN32_ENVIRONMENT_)
//_lseeki64( fileno(fp_in), AtPosition64L, 0 );
//#else
//fseeko( fp_in, AtPosition64L, SEEK_SET );
//#endif /* defined(_WIN32_ENVIRONMENT_)  */

//  _CRTIMP __int64 __cdecl _telli64(int);
//  off64_t ftello64 (FILE *stream)  


fsetpos(fp_in, AtPosition64Lpointer);
#if defined(DumboDumpLOG)
printf("Tell %llu:\n",_telli64(fileno(fp_in)));
printf("L:\n");
#endif
	for (i=0; i<(LongestLineInclusive+1); i++) {fread(&FourGramL[i], 1, 1, fp_in); if (FourGramL[i]==13) break;}
	//Commented line below is slower than the one above: 778156 clocks vs 756297 clocks.
	//fread(&FourGramL[0], 31+1, 1, fp_in);
#if defined(DumboDumpLOG)
for (i=0; i<(LongestLineInclusive+1); i++) {printf("%c",FourGramL[i]); if (FourGramL[i]==13) break;}
printf("\n");
#endif

fsetpos(fp_in, AtPosition64Rpointer);
#if defined(DumboDumpLOG)
printf("Tell %llu:\n",_telli64(fileno(fp_in)));
printf("R:\n");
#endif
	for (i=0; i<(LongestLineInclusive+1); i++) {fread(&FourGramR[i], 1, 1, fp_in); if (FourGramR[i]==13) break;}
	//Commented line below is slower than the one above: 778156 clocks vs 756297 clocks.
	//fread(&FourGramR[0], 31+1, 1, fp_in);
#if defined(DumboDumpLOG)
for (i=0; i<(LongestLineInclusive+1); i++) {printf("%c",FourGramR[i]); if (FourGramR[i]==13) break;}
printf("\n");
#endif

return(strcmpKAZE13(FourGramL, FourGramR));
}

int CompareStringsEndingWith13_INTERNAL(unsigned long long AtPosition64L, unsigned long long AtPosition64R, char *POOLinternal) {

int i;
char FourGramL[LongestLineInclusive+2]; // 31 longest 4-gram + CR + LF
char FourGramR[LongestLineInclusive+2]; // 31 longest 4-gram + CR + LF

for (i=0; i<(LongestLineInclusive+1); i++) {
	//fread(&FourGramL[i], 1, 1, fp_in);
	FourGramL[i] = *(char *)(POOLinternal + AtPosition64L);
	if (FourGramL[i]==13) break;
}

for (i=0; i<(LongestLineInclusive+1); i++) {
	//fread(&FourGramR[i], 1, 1, fp_in);
	FourGramR[i] = *(char *)(POOLinternal + AtPosition64R);
	if (FourGramR[i]==13) break;
}

return(strcmpKAZE13(FourGramL, FourGramR));
}

int memcmpKAZE (
        const void * buf1,
        const void * buf2,
        size_t count
        )
{
        if (!count)
                return(0);

        while ( --count && *(char *)buf1 == *(char *)buf2 ) {
                buf1 = (char *)buf1 + 1;
                buf2 = (char *)buf2 + 1;
        }

        return( *((unsigned char *)buf1) - *((unsigned char *)buf2) );
}

void * memcpyKAZE (
        void * dst,
        const void * src,
        size_t count
        )
{
        void * ret = dst;

        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
        }
        return(ret);
}

static void simplesortFIXEDLength(string a[], int n, int b, int FIXEDLength)
{
   int i, j;
   string tmp;

   for (i = 1; i < n; i++)
      for (j = i; j > 0 && memcmpKAZE(a[j-1]+b, a[j]+b,FIXEDLength) > 0; j--)
         { tmp = a[j]; a[j] = a[j-1]; a[j-1] = tmp; }
}


// SINHA fragment]

// mkqsort.c BEGIN **********************************************************
/*
   Multikey quicksort, a radix sort algorithm for arrays of character
   strings by Bentley and Sedgewick.

   J. Bentley and R. Sedgewick. Fast algorithms for sorting and
   searching strings. In Proceedings of 8th Annual ACM-SIAM Symposium
   on Discrete Algorithms, 1997.

   http://www.CS.Princeton.EDU/~rs/strings/index.html

   The code presented in this file has been tested with care but is
   not guaranteed for any purpose. The writer does not offer any
   warranties nor does he accept any liabilities with respect to
   the code.

   Ranjan Sinha, 1 jan 2003.

   School of Computer Science and Information Technology,
   RMIT University, Melbourne, Australia
   rsinha@cs.rmit.edu.au

*/

//#include "sortstring.h"

/* MULTIKEY QUICKSORT */

#ifndef min
#define min(a, b) ((a)<=(b) ? (a) : (b))
#endif


/* ssort2 -- Faster Version of Multikey Quicksort */

void vecswap2(unsigned char **a, unsigned char **b, int n)
{   while (n-- > 0) {
        unsigned char *t = *a;
        *a++ = *b;
        *b++ = t;
    }
}

#define swap2(a, b) { t = *(a); *(a) = *(b); *(b) = t; }
#define ptr2char(i) (*(*(i) + depth))

unsigned char **med3func(unsigned char **a, unsigned char **b, unsigned char **c, int depth)
{   int va, vb, vc;
    if ((va=ptr2char(a)) == (vb=ptr2char(b)))
        return a;
    if ((vc=ptr2char(c)) == va || vc == vb)
        return c;       
    return va < vb ?
          (vb < vc ? b : (va < vc ? c : a ) )
        : (vb > vc ? b : (va < vc ? a : c ) );
}
#define med3(a, b, c) med3func(a, b, c, depth)

void inssort_NON_Physical(unsigned char **a, int n, int d)
{   unsigned char **pi, **pj, *s, *t;
    for (pi = a + 1; --n > 0; pi++)
        for (pj = pi; pj > a; pj--) {
            /* Inline strcmp: break if *(pj-1) <= *pj */
            for (s=*(pj-1)+d, t=*pj+d; *s==*t && *s!=0; s++, t++)
                ;
            if (*s <= *t)
                break;
            swap2(pj, pj-1);
    }
}


void inssort(unsigned char **a, int n, int d)
{   unsigned char **pi, **pj, *s, *t;
    for (pi = a + 1; --n > 0; pi++)
        for (pj = pi; pj > a; pj--) {
            /* Inline strcmp: break if *(pj-1) <= *pj */
            for (s=*(pj-1)+d, t=*pj+d; *s==*t && *s!=0; s++, t++)
                ;
            if (*s <= *t)
                break;
            swap2(pj, pj-1);
    }
}

void mkqsort(unsigned char **a, int n, int depth)
{   int d, r, partval;
    unsigned char **pa, **pb, **pc, **pd, **pl, **pm, **pn, *t;
    if (n < 20) {
        inssort(a, n, depth);
          //simplesortFIXEDLength(a, n, depth, Patternlen);
        return;
    }
    pl = a;
    pm = a + (n/2);
    pn = a + (n-1);
    if (n > 30) { /* On big arrays, pseudomedian of 9 */
        d = (n/8);
        pl = med3(pl, pl+d, pl+2*d);
        pm = med3(pm-d, pm, pm+d);
        pn = med3(pn-2*d, pn-d, pn);
    }
    pm = med3(pl, pm, pn);
    swap2(a, pm);
    partval = ptr2char(a);
    pa = pb = a + 1;
    pc = pd = a + n-1;
    for (;;) {
        while (pb <= pc && (r = ptr2char(pb)-partval) <= 0) {
            if (r == 0) { swap2(pa, pb); pa++; }
            pb++;
        }
        while (pb <= pc && (r = ptr2char(pc)-partval) >= 0) {
            if (r == 0) { swap2(pc, pd); pd--; }
            pc--;
       }
        if (pb > pc) break;
        swap2(pb, pc);
        pb++;
        pc--;
    }
    pn = a + n;
    r = min(pa-a, pb-pa);    vecswap2(a,  pb-r, r);
    r = min(pd-pc, pn-pd-1); vecswap2(pb, pn-r, r);
    if ((r = pb-pa) > 1)
        mkqsort(a, r, depth);
    if (ptr2char(a + r) != 0)
        mkqsort(a + r, pa-a + pn-pd-1, depth+1);
    if ((r = pd-pc) > 1)
        mkqsort(a + n-r, r, depth);
}

void mkqsort_main(unsigned char **a, int n) { mkqsort(a, n, 0); }
// mkqsort.c END ************************************************************

// Why Sinha uses int instead of long??!!
static int readlines(char *file_name, string **lines)
{
   int nlines = 0;
   size_t size;
   FILE *in_file;
   string basep, cur, next;
   string *ASbackup;

   if (!(in_file = fopen(file_name, "rb"))) {
      printf( "Leprechaun: Can't open file %s \n", file_name ); 
      exit(-1);
   }
   fseek(in_file, 0, SEEK_END);
   size = ftell(in_file);
   fseek(in_file, 0, SEEK_SET);
   if (!(basep = (string) malloc(size*sizeof(char_t)))) return -1;
   printf( "Allocated memory for words in MB: %lu\n", ((size*sizeof(char_t))>>20)+1 );
   if (fread(basep, 1, size, in_file) < size) {
      printf( "Leprechaun: Can't read file %s \n", file_name ); 
      exit(-1);
   }
   fclose(in_file);

// GET nlines:
   cur = basep;
   while (cur < basep + size) {
      next = cur;
      while ((next < basep + size) && (*next != '\n')) {next++;}
      *--next = '\0';          // This is ala DOS i.e. Windows
                               // 1310 not 10(\n=10)
      cur = next + 2;
      nlines++;
   }

// printf("%lu\n",(unsigned long)*lines); -> backup = *lines = 0
ASbackup = (string *)malloc( nlines*sizeof(string) ); // sizeof(string) is 4
if( ASbackup == NULL )
{ puts( "Leprechaun: Needed memory allocation denied!\n" ); return( 1 ); }
printf( "Allocated memory for pointers-to-words in MB: %lu\n", ((nlines*sizeof(string))>>20)+1 );
*lines = ASbackup;
//printf("%lu\n",(unsigned long)*lines); -> backup = *lines = ASbackup = 6946888

// Upload nlines times:
   nlines = 0;
   cur = basep;
   while (cur < basep + size) {
      next = cur;
      while ((next < basep + size) && (*next != '\n')) {next++;}
      *--next = '\0';          // This is ala DOS i.e. Windows
                               // 1310 not 10(\n=10)
      ASbackup[nlines] = cur;
      cur = next + 2;
      nlines++;
   }
   return nlines;
}

void x64toaKAZE (      /* stdcall is faster and smaller... Might as well use it for the helper. */
        unsigned long long val,
        char *buf,
        unsigned radix,
        int is_neg
        )
{
        char *p;                /* pointer to traverse string */
        char *firstdig;         /* pointer to first digit */
        char temp;              /* temp char */
        unsigned digval;        /* value of digit */

        p = buf;

        if ( is_neg )
        {
            *p++ = '-';         /* negative, so output '-' and negate */
            val = (unsigned long long)(-(long long)val);
        }

        firstdig = p;           /* save pointer to first digit */

        do {
            digval = (unsigned) (val % radix);
            val /= radix;       /* get next digit */

            /* convert to ascii and store */
            if (digval > 9)
                *p++ = (char) (digval - 10 + 'a');  /* a letter */
            else
                *p++ = (char) (digval + '0');       /* a digit */
        } while (val > 0);

        /* We now have the digit of the number in the buffer, but in reverse
           order.  Thus we reverse them now. */

        *p-- = '\0';            /* terminate string; p points to last digit */

        do {
            temp = *p;
            *p = *firstdig;
            *firstdig = temp;   /* swap *p and *firstdig */
            --p;
            ++firstdig;         /* advance to next two digits */
        } while (firstdig < p); /* repeat until halfway */
}

/* Actual functions just call conversion helper with neg flag set correctly,
   and return pointer to buffer. */

char * _i64toaKAZE (
        long long val,
        char *buf,
        int radix
        )
{
        x64toaKAZE((unsigned long long)val, buf, radix, (radix == 10 && val < 0));
        return buf;
}

char * _ui64toaKAZE (
        unsigned long long val,
        char *buf,
        int radix
        )
{
        x64toaKAZE(val, buf, radix, 0);
        return buf;
}

char * _ui64toaKAZEzerocomma (
        unsigned long long val,
        char *buf,
        int radix
        )
{
                        char *p;
                        char temp;
                        int txpman;
                        int pxnman;
        x64toaKAZE(val, buf, radix, 0);
                        p = buf;
                        do {
                        } while (*++p != '\0');
                        p--; // p points to last digit
                             // buf points to first digit
                        buf[26] = 0;
                        txpman = 1;
                        pxnman = 0;
                        do
                        { if (buf <= p)
                          { temp = *p;
                            buf[26-txpman] = temp; pxnman++;
                            p--;
                            if (pxnman % 3 == 0)
                            { txpman++;
                              buf[26-txpman] = (char) (',');
                            }
                          }
                          else
                          { buf[26-txpman] = (char) ('0'); pxnman++;
                            if (pxnman % 3 == 0)
                            { txpman++;
                              buf[26-txpman] = (char) (',');
                            }
                          }
                          txpman++;
                        } while (txpman <= 26);
        return buf;
}

char * _ui64toaKAZEcomma (
        unsigned long long val,
        char *buf,
        int radix
        )
{
                        char *p;
                        char temp;
                        int txpman;
                        int pxnman;
        x64toaKAZE(val, buf, radix, 0);
                        p = buf;
                        do {
                        } while (*++p != '\0');
                        p--; // p points to last digit
                             // buf points to first digit
                        buf[26] = 0;
                        txpman = 1;
                        pxnman = 0;
                        while (buf <= p)
                        { temp = *p;
                          buf[26-txpman] = temp; pxnman++;
                          p--;
                          if (pxnman % 3 == 0 && buf <= p)
                          { txpman++;
                            buf[26-txpman] = (char) (',');
                          }
                          txpman++;
                        } 
        return buf+26-(txpman-1);
}

long Railgunhits=0;

#define ASIZE 256

// ### Boyer-Moore-Horspool algorithm [
long HORSPOOL(y, x, n, m)
    char *y, *x;
    long n;
    int m;
   {
    long i;
    int a, j, bm_bc[ASIZE];
    unsigned char ch, lastch;
   
    /* Preprocessing */
    for (a=0; a < ASIZE; a++) bm_bc[a]=m;
    for (j=0; j < m-1; j++) bm_bc[x[j]]=m-j-1;
   
    /* Searching */
    lastch=x[m-1];
    i=0;
    while (i <= n-m) {
       ch=y[i+m-1];
       if (ch ==lastch)
          //if (memcmp(&y[i],x,m-1) == 0) OUTPUT(i);
          if (memcmp(&y[i],x,m-1) == 0) return(i);
       i+=bm_bc[ch];
    }
    return(-1);
   }
long Boyer_Moore_Horspool_Kaze(y, x, n, m)
    char *y, *x;
    long n;
    int m;
   {
    long i;
    int a, j, bm_bc[ASIZE];
    unsigned char ch;
    //unsigned char ch, lastch;
    //unsigned char firstch;
   
    /* Preprocessing */
    for (a=0; a < ASIZE; a++) bm_bc[a]=m;
    for (j=0; j < m-1; j++) bm_bc[x[j]]=m-j-1;
   
    /* Searching */
    //lastch=x[m-1];
    //firstch=x[0];
    i=0;
    while (i <= n-m) {
       ch=y[i+m-1];
       //if (ch ==lastch)
          //if (memcmp(&y[i],x,m-1) == 0) OUTPUT(i);
// Below line gives: 315KB/clock
          //if (ch ==lastch && y[i] == firstch && memcmp(&y[i],x,m-1) == 0) return(i);  // Kaze: The idea(to prevent execution of slower 'memcmp') is borrowed from Karp-Rabin i.e. to perform a slower check only when the target "looks like".
// Below line gives: 328KB/clock
          if (ch ==x[m-1] && y[i] == x[0] && memcmp(&y[i],x,m-1) == 0) return(i);  // Kaze: The idea(to prevent execution of slower 'memcmp') is borrowed from Karp-Rabin i.e. to perform a slower check only when the target "looks like".
       i+=bm_bc[ch];
    }
    return(-1);
   }
// ### Boyer-Moore-Horspool algorithm ]


// ### Brute force 'Dummy' algorithm [
   long Brute_Force_Dummy(char *y, char *x, long n, int m) {
    long i, j;
  
    /* Searching */
    for (i=0; i <= n-m; i++) {
       j=0;
       while (j < m && y[i+j] == x[j]) j++;
       if (j >= m) return(i);
    }
    return(-1);
   }
// ### Brute force 'Dummy' algorithm ]


// ### Karp-Rabin algorithm [
   #define REHASH(a, b, h) ((((h) - (a)*d) << 1) + (b))
   long Karp_Rabin(char *y, char *x, long n, int m) {
   int d, hx, hy, i, j;

   /* Preprocessing */
   /* computes d = 2^(m-1) with
      the left-shift operator */
   for (d = i = 1; i < m; ++i)
      d = (d<<1);

   for (hy = hx = i = 0; i < m; ++i) {
      hx = ((hx<<1) + x[i]);
      hy = ((hy<<1) + y[i]);
   }

   /* Searching */
   j = 0;
   while (j <= n-m) {
      if (hx == hy && memcmp(x, y + j, m) == 0) return(j);
      hy = REHASH(y[j], y[j + m], hy);
      ++j;
   }
    return(-1);
   }
// ### Karp-Rabin algorithm ]


// ### Karp-Rabin-Kaze algorithm [
char * KarpRabinKaze (char * pbTarget,
     char * pbPattern,
     unsigned long cbTarget,
     unsigned long cbPattern)
{
    unsigned int    i;
    char *  pbTargetMax = pbTarget + cbTarget;
    char *  pbPatternMax = pbPattern + cbPattern;
    unsigned long  ulBaseToPowerMod = 1;
    register unsigned long  ulHashPattern = 0;
    unsigned long  ulHashTarget = 0;
long hits = 0;
//unsigned long count;
    //char *  buf1;
    //char *  buf2;

    if (cbPattern > cbTarget)
        return(NULL);

    // Compute the power of the left most character in base ulBase
    //for (i = 1; i < cbPattern; i++) ulBaseToPowerMod = (ulBase * ulBaseToPowerMod);

    // Calculate the hash function for the src (and the first dst)
    while (pbPattern < pbPatternMax)
    {
        // Below lines give 366KB/clock for 'underdog':
        //ulHashPattern = (ulHashPattern*ulBase + *pbPattern);
        //ulHashTarget = (ulHashTarget*ulBase + *pbTarget);
        pbPattern++;
        pbTarget++;
    }
        // Below lines give 436KB/clock for 'underdog' + requirement pattern to be 4 chars min.:
        //ulHashPattern = ( (*(long *)(pbPattern-cbPattern)) & 0xffffff00 ) + *(pbPattern-1);
        //ulHashTarget = ( (*(long *)(pbTarget-cbPattern)) & 0xffffff00 ) + *(pbTarget-1);
        // Below lines give 482KB/clock for 'underdog' + requirement pattern to be 2 chars min.:
        //ulHashPattern = ( (*(unsigned short *)(pbPattern-cbPattern)) | *(pbPattern-1) );
        //ulHashTarget = ( (*(unsigned short *)(pbTarget-cbPattern)) | *(pbTarget-1) );
        // Below lines give 482KB/clock for 'underdog' + requirement pattern to be 2 chars min.:
        //ulHashPattern = ( (*(unsigned short *)(pbPattern-cbPattern)) & 0xff00 ) + *(pbPattern-1);
        //ulHashTarget = ( (*(unsigned short *)(pbTarget-cbPattern)) & 0xff00 ) + *(pbTarget-1);
        // Below lines give 605KB/clock for 'underdog' + requirement pattern to be 2 chars min.:
        //ulHashPattern = ( (*(unsigned short *)(pbPattern-cbPattern))<<8 ) + *(pbPattern-1);
        //ulHashTarget = ( (*(unsigned short *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1);
        // Below lines give 668KB/clock for 'underdog':
        ulHashPattern = ( (*(char *)(pbPattern-cbPattern))<<8 ) + *(pbPattern-1);
        ulHashTarget = ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1);

    // Dynamically produce hash values for the string as we go
    for ( ;; )
    {
        if ( (ulHashPattern == ulHashTarget) && !memcmp(pbPattern-cbPattern, pbTarget-cbPattern, (unsigned int)cbPattern) )
       // if ( ulHashPattern == ulHashTarget ) {
       // 
       //  count = cbPattern;
       //  buf1 = pbPattern-cbPattern;
       //  buf2 = pbTarget-cbPattern;
       //  while ( --count && *(char *)buf1 == *(char *)buf2 ) {
       //          buf1 = (char *)buf1 + 1;
       //          buf2 = (char *)buf2 + 1;
       //  }
       //                 
       //  if ( *((unsigned char *)buf1) - *((unsigned char *)buf2) == 0) hits++;
       //  }
            return((pbTarget-cbPattern));
            //hits++;
                                                             
        if (pbTarget == pbTargetMax)
            return(NULL);

        // Below line gives 482KB/clock for 'underdog' + requirement pattern to be 2 chars min.:
        //ulHashTarget = ( (*(unsigned short *)(pbTarget+1-cbPattern)) | *pbTarget );
        // Below line gives 436KB/clock for 'underdog' + requirement pattern to be 4 chars min.:
        //ulHashTarget = ( (*(long *)(pbTarget+1-cbPattern)) & 0xffffff00 ) + *pbTarget;
//; Line 696
//        movsx   esi, BYTE PTR [ebx]
//        mov     ecx, DWORD PTR [edx+1]
//        and     ecx, -256                               ; ffffff00H
//        add     ecx, esi
        // Below line gives 482KB/clock for 'underdog' + requirement pattern to be 2 chars min.:
        //ulHashTarget = ( (*(unsigned short *)(pbTarget+1-cbPattern)) & 0xff00 ) + *pbTarget;
//; Line 691
//        movsx   esi, BYTE PTR [ebx]
//        xor     ecx, ecx
//        mov     cx, WORD PTR [edx+1]
//        and     ecx, 65280                              ; 0000ff00H
//        add     ecx, esi
        // Below line gives 605KB/clock for 'underdog' + requirement pattern to be 2 chars min.:
        //ulHashTarget = ( (*(unsigned short *)(pbTarget+1-cbPattern))<<8 ) + *pbTarget;
        // Below line gives 668KB/clock for 'underdog':
        ulHashTarget = ( (*(char *)(pbTarget+1-cbPattern))<<8 ) + *pbTarget;
//; Line 718
//        movsx   ecx, BYTE PTR [eax+1]
//        movsx   edx, BYTE PTR [ebp]
//        shl     ecx, 8
//        add     ecx, edx
        // Below line gives 366KB/clock for 'underdog':
        //ulHashTarget = (ulHashTarget - *(pbTarget-cbPattern)*ulBaseToPowerMod)*ulBase + *pbTarget;
        pbTarget++;
    }
}
// ### Karp-Rabin-Kaze algorithm ]


// ### Mix(2in1) of Karp-Rabin & Boyer-Moore-Horspool algorithm [
// Caution: For better speed the case 'if (cbPattern==1)' was removed, so Pattern must be longer than 1 char.
char * Railgun (char * pbTarget,
     char * pbPattern,
     unsigned long cbTarget,
     unsigned long cbPattern)
{
    char *  pbTargetMax = pbTarget + cbTarget;
    register unsigned long  ulHashPattern;
    unsigned long  ulHashTarget;
    unsigned long  count;
    unsigned long  countSTATIC, countRemainder;

    long i; //BMH needed
    int a, j, bm_bc[ASIZE]; //BMH needed
    unsigned char ch; //BMH needed
//    unsigned char lastch, firstch; //BMH needed

    if (cbPattern > cbTarget)
        return(NULL);

        countSTATIC = cbPattern-2;

// Doesn't work when cbPattern = 1
if (cbTarget<961) // This value is arbitrary(don't know how exactly), it ensures(at least must) better performance than 'Boyer_Moore_Horspool'.
{
        pbTarget = pbTarget+cbPattern;
        ulHashPattern = ( (*(char *)(pbPattern))<<8 ) + *(pbPattern+(cbPattern-1));

    for ( ;; )
    {
        // The line below gives for 'cbPattern'>=1:
        // Karp_Rabin_Kaze_4_OCTETS_hits/Karp_Rabin_Kaze_4_OCTETS_clocks: 4/543
        // Karp_Rabin_Kaze_4_OCTETS performance: 372KB/clock
/*
        if ( (ulHashPattern == ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1)) && !memcmp(pbPattern, pbTarget-cbPattern, (unsigned int)cbPattern) )
            return((long)(pbTarget-cbPattern));
*/

        // The fragment below gives for 'cbPattern'>=2:
        // Karp_Rabin_Kaze_4_OCTETS_hits/Karp_Rabin_Kaze_4_OCTETS_clocks: 4/546
        // Karp_Rabin_Kaze_4_OCTETS performance: 370KB/clock

        if ( ulHashPattern == ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1) ) {
         count = countSTATIC;
         while ( count && *(char *)(pbPattern+1+(countSTATIC-count)) == *(char *)(pbTarget-cbPattern+1+(countSTATIC-count)) ) {
               count--;
         }
         if ( count == 0) return((pbTarget-cbPattern));
        }

        // The fragment below gives for 'cbPattern'>=2:
	// Karp_Rabin_Kaze_4_OCTETS_hits/Karp_Rabin_Kaze_4_OCTETS_clocks: 4/554
	// Karp_Rabin_Kaze_4_OCTETS performance: 364KB/clock
/*
        if ( ulHashPattern == ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1) ) {
         count = countSTATIC>>2;
         countRemainder = countSTATIC % 4;

         while ( count && *(unsigned long *)(pbPattern+1+((count-1)<<2)) == *(unsigned long *)(pbTarget-cbPattern+1+((count-1)<<2)) ) {
               count--;
         }
	 //if (count == 0) {  // Disastrous degradation only from this line(317KB/clock when 1+2x4+2+1 bytes pattern: 'skillessness'; 312KB/clock when 1+1x4+2+1 bytes pattern: 'underdog'), otherwise 368KB/clock.
         while ( countRemainder && *(char *)(pbPattern+1+(countSTATIC-countRemainder)) == *(char *)(pbTarget-cbPattern+1+(countSTATIC-countRemainder)) ) {
               countRemainder--;
         }
         //if ( countRemainder == 0) return((long)(pbTarget-cbPattern));
         if ( count+countRemainder == 0) return((long)(pbTarget-cbPattern));
         //}
        }
*/

        pbTarget++;
        if (pbTarget > pbTargetMax)
            return(NULL);
    }
}
else
{
    /* Preprocessing */
    for (a=0; a < ASIZE; a++) bm_bc[a]=cbPattern;
    for (j=0; j < cbPattern-1; j++) bm_bc[pbPattern[j]]=cbPattern-j-1;

    /* Searching */
    //lastch=pbPattern[cbPattern-1];
    //firstch=pbPattern[0];
    i=0;
    while (i <= cbTarget-cbPattern) {
       ch=pbTarget[i+cbPattern-1];
       //if (ch ==lastch)
          //if (memcmp(&pbTarget[i],pbPattern,cbPattern-1) == 0) OUTPUT(i);
          //if (ch == lastch && pbTarget[i] == firstch && memcmp(&pbTarget[i],pbPattern,cbPattern-1) == 0) return(i);  // Kaze: The idea(to prevent execution of slower 'memcmp') is borrowed from Karp-Rabin i.e. to perform a slower check only when the target "looks like".
          if (ch == pbPattern[cbPattern-1] && pbTarget[i] == pbPattern[0])
             {
         count = countSTATIC;
         while ( count && *(char *)(pbPattern+1+(countSTATIC-count)) == *(char *)(&pbTarget[i]+1+(countSTATIC-count)) ) {
               count--;
         }
         if ( count == 0) return(pbTarget+i);
	     }
       i+=bm_bc[ch];
    }
    return(NULL);
}
}
// ### Mix(2in1) of Karp-Rabin & Boyer-Moore-Horspool algorithm ]


// ### Railgun_totalhits [
char * Railgun_totalhits (char * pbTarget,
     char * pbPattern,
     unsigned long cbTarget,
     unsigned long cbPattern)
{
    char *  pbTargetMax = pbTarget + cbTarget;
    register unsigned long  ulHashPattern;
    unsigned long  ulHashTarget;
    unsigned long  count;
    unsigned long  countSTATIC, countRemainder;

    long i; //BMH needed
    int a, j, bm_bc[ASIZE]; //BMH needed
    unsigned char ch; //BMH needed
//    unsigned char lastch, firstch; //BMH needed

    if (cbPattern > cbTarget)
        return(NULL);

        countSTATIC = cbPattern-2;

// Doesn't work when cbPattern = 1
if (cbTarget<961) // This value is arbitrary(don't know how exactly), it ensures(at least must) better performance than 'Boyer_Moore_Horspool'.
{
        pbTarget = pbTarget+cbPattern;
        ulHashPattern = ( (*(char *)(pbPattern))<<8 ) + *(pbPattern+(cbPattern-1));

    for ( ;; )
    {
        // The line below gives for 'cbPattern'>=1:
        // Karp_Rabin_Kaze_4_OCTETS_hits/Karp_Rabin_Kaze_4_OCTETS_clocks: 4/543
        // Karp_Rabin_Kaze_4_OCTETS performance: 372KB/clock
/*
        if ( (ulHashPattern == ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1)) && !memcmp(pbPattern, pbTarget-cbPattern, (unsigned int)cbPattern) )
            return((long)(pbTarget-cbPattern));
*/

        // The fragment below gives for 'cbPattern'>=2:
        // Karp_Rabin_Kaze_4_OCTETS_hits/Karp_Rabin_Kaze_4_OCTETS_clocks: 4/546
        // Karp_Rabin_Kaze_4_OCTETS performance: 370KB/clock

        if ( ulHashPattern == ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1) ) {
         count = countSTATIC;
         while ( count && *(char *)(pbPattern+1+(countSTATIC-count)) == *(char *)(pbTarget-cbPattern+1+(countSTATIC-count)) ) {
               count--;
         }
         if ( count == 0) Railgunhits++; //return((pbTarget-cbPattern));
        }

        // The fragment below gives for 'cbPattern'>=2:
	// Karp_Rabin_Kaze_4_OCTETS_hits/Karp_Rabin_Kaze_4_OCTETS_clocks: 4/554
	// Karp_Rabin_Kaze_4_OCTETS performance: 364KB/clock
/*
        if ( ulHashPattern == ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1) ) {
         count = countSTATIC>>2;
         countRemainder = countSTATIC % 4;

         while ( count && *(unsigned long *)(pbPattern+1+((count-1)<<2)) == *(unsigned long *)(pbTarget-cbPattern+1+((count-1)<<2)) ) {
               count--;
         }
	 //if (count == 0) {  // Disastrous degradation only from this line(317KB/clock when 1+2x4+2+1 bytes pattern: 'skillessness'; 312KB/clock when 1+1x4+2+1 bytes pattern: 'underdog'), otherwise 368KB/clock.
         while ( countRemainder && *(char *)(pbPattern+1+(countSTATIC-countRemainder)) == *(char *)(pbTarget-cbPattern+1+(countSTATIC-countRemainder)) ) {
               countRemainder--;
         }
         //if ( countRemainder == 0) return((long)(pbTarget-cbPattern));
         if ( count+countRemainder == 0) return((long)(pbTarget-cbPattern));
         //}
        }
*/

        pbTarget++;
        if (pbTarget > pbTargetMax)
            return(NULL);
    }
}
else
{
    /* Preprocessing */
    for (a=0; a < ASIZE; a++) bm_bc[a]=cbPattern;
    for (j=0; j < cbPattern-1; j++) bm_bc[pbPattern[j]]=cbPattern-j-1;

    /* Searching */
    //lastch=pbPattern[cbPattern-1];
    //firstch=pbPattern[0];
    i=0;
    while (i <= cbTarget-cbPattern) {
       ch=pbTarget[i+cbPattern-1];
       //if (ch ==lastch)
          //if (memcmp(&pbTarget[i],pbPattern,cbPattern-1) == 0) OUTPUT(i);
          //if (ch == lastch && pbTarget[i] == firstch && memcmp(&pbTarget[i],pbPattern,cbPattern-1) == 0) return(i);  // Kaze: The idea(to prevent execution of slower 'memcmp') is borrowed from Karp-Rabin i.e. to perform a slower check only when the target "looks like".
          if (ch == pbPattern[cbPattern-1] && pbTarget[i] == pbPattern[0])
             {
         count = countSTATIC;
         while ( count && *(char *)(pbPattern+1+(countSTATIC-count)) == *(char *)(&pbTarget[i]+1+(countSTATIC-count)) ) {
               count--;
         }
         if ( count == 0) Railgunhits++; //return(pbTarget+i);
	     }
       i+=bm_bc[ch];
    }
    return(NULL);
}
}
// ### Railgun_totalhits ]


// ### Karp-Rabin-Kaze_BOOSTED algorithm [
char * KarpRabinKaze_BOOSTED (char * pbTarget,
     char * pbPattern,
     unsigned long cbTarget,
     unsigned long cbPattern)
{
    char *  pbTargetMax = pbTarget + cbTarget;
    register unsigned long  ulHashPattern;
    unsigned long  ulHashTarget;

    if (cbPattern > cbTarget)
        return(NULL);

        pbTarget = pbTarget+cbPattern;
        ulHashPattern = ( (*(char *)(pbPattern))<<8 ) + *(pbPattern+(cbPattern-1));

    for ( ;; )
    {
        // Kaze: The idea(FAILED) here is to add an additional(second) layer in order to prevent execution of slower hash calculation(i.e. first layer) which(hash) prevents execution of even slower 'memcmp'.
        // The line below gives: 314KB/clock
        //if ( *pbPattern == *(char *)(pbTarget-cbPattern) && (ulHashPattern == ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1)) && !memcmp(pbPattern, pbTarget-cbPattern, (unsigned int)cbPattern) )
        // The line below gives: 370KB/clock
        if ( (ulHashPattern == ( (*(char *)(pbTarget-cbPattern))<<8 ) + *(pbTarget-1)) && !memcmp(pbPattern, pbTarget-cbPattern, (unsigned int)cbPattern) )
            return((pbTarget-cbPattern));

        pbTarget++;
        if (pbTarget > pbTargetMax)
            return(NULL);
    }
}
// ### Karp-Rabin-Kaze_BOOSTED algorithm ]

char * strstr_Microsoft (
        const char * str1,
        const char * str2
        )
{
        char *cp = (char *) str1;
        char *s1, *s2;

        if ( !*str2 )
            return((char *)str1);

        while (*cp)
        {
                s1 = cp;
                s2 = (char *) str2;

                while ( *s1 && *s2 && !(*s1-*s2) )
                        s1++, s2++;

                if (!*s2)
                        return(cp);

                cp++;
        }
        return(NULL);
}

char *
strstr_GNU_C_Library (phaystack, pneedle)
     const char *phaystack;
     const char *pneedle;
{
  const unsigned char *haystack, *needle;
  char b;
  const unsigned char *rneedle;

  haystack = (const unsigned char *) phaystack;

  if ((b = *(needle = (const unsigned char *) pneedle)))
    {
      char c;
      haystack--;		/* possible ANSI violation */

      {
	char a;
	do
	  if (!(a = *++haystack))
	    goto ret0;
	while (a != b);
      }

      if (!(c = *++needle))
	goto foundneedle;
      ++needle;
      goto jin;

      for (;;)
	{
	  {
	    char a;
	    if (0)
	    jin:{
		if ((a = *++haystack) == c)
		  goto crest;
	      }
	    else
	      a = *++haystack;
	    do
	      {
		for (; a != b; a = *++haystack)
		  {
		    if (!a)
		      goto ret0;
		    if ((a = *++haystack) == b)
		      break;
		    if (!a)
		      goto ret0;
		  }
	      }
	    while ((a = *++haystack) != c);
	  }
	crest:
	  {
	    char a;
	    {
	      const unsigned char *rhaystack;
	      if (*(rhaystack = haystack-- + 1) == (a = *(rneedle = needle)))
		do
		  {
		    if (!a)
		      goto foundneedle;
		    if (*++rhaystack != (a = *++needle))
		      break;
		    if (!a)
		      goto foundneedle;
		  }
		while (*++rhaystack == (a = *++needle));
	      needle = rneedle;	/* took the register-poor aproach */
	    }
	    if (!a)
	      break;
	  }
	}
    }
foundneedle:
  return (char *) haystack;
ret0:
  return 0;
}


int main(argc, argv)
int argc; char *argv[];
  {
FILE *fp_inLINE;
//FILE *fp_in;
FILE *fp_in2;
FILE *fp_out;
FILE *fp_out2;
FILE *fp_out3;
FILE *fp_outRG;
int Bozan;
long ThunderwithL, ThunderwithR;
long ThunderwithL2, ThunderwithR2;
char *Strng;
char *Strng2;
char *StrngDUMMY;
long Strnglen;
long Strnglen2;
long Hits;
int HitsFound=0, HitsUnfamiliar=0;
long OVERLAPPEDlines=0;
long Unfamiliarlines=0;
long nlines_A=0;
long nlines_B=0;

long StrnglenTRAVERSED;
char Pattern[20+2000]; // skillessness=12 human consciousness=19 I should have known=19
// In the East, enlightenment is described as a state of ultimate=62
//int Patternlen;      // Make it global in sake of QSORT
long LinesEncountered=0;
long BruteForceDummyhits=0;
long KarpRabinKazehits=0;
long KarpRabinKaze_BOOSTEDhits=0;
long Karp_Rabin_Kaze_4_OCTETShits=0;
long KarpRabinhits=0;
long HORSPOOLhits=0;
long HORSPOOL_Kazehits=0;
long strstrMicrosofthits=0;
long strstrGNUCLibraryhits=0;

//int i,j;
char *DumboBox[8][2] = { "an\0", "to\0",
                         "TDK\0", "the\0",
                         "fast\0", "easy\0",
                         "grmbl\0", "email\0",
                         "pasting\0", "amazing\0",
                         "underdog\0", "superdog\0",
                         "participants\0", "skillessness\0",
                         "I should have known\0", "human consciousness\0"
};

long FoundIn;
char *FoundInPTR;
//char llTOaDigits[27]; // 9,223,372,036,854,775,807: 1(sign or carry)+19(digits)+1('\0')+6(,)
char BuildingBlocksBox[10] = "BB---.txt\0";


//SWAP [

unsigned long long ThunderwithL64;
unsigned long long Strnglen64;
unsigned long long size_in64, size_in2;
unsigned long long Over4billionLines, j_Over4billion;
char OneChar_ieByte;
unsigned long long SeekPosition;
unsigned long long *PointerToSeekPosition;

char FourGram[LongestLineInclusive+2]; // 31 longest 4-gram + CR + LF
char *Auberge[4] = {"|\0","/\0","-\0","\\\0"};
int Melnitchka;
char llTOaDigits[27]; // 9,223,372,036,854,775,807: 1(sign or carry)+19(digits)+1('\0')+6(,)

char *PoolPhysical;
char *ARG_CLf = "/fast\0";
char *ARG_CLs = "/slow\0";
unsigned long long fsetpos_ZERO=0;

//QuickSort:
unsigned long long Nbr2Sort;
unsigned long long QSleft[512];                    //  Stack arrays for the left/right
unsigned long long QSright[512];                   //  ends of subgroups within QuickSort()
unsigned long long    i, j, k, StackPtr;
unsigned long long     LeftEnd, RightEnd, LeftPtr, RightPtr, MidPtr, MinGroup;
unsigned long long    Pvalue, temp;
long clocks1, clocks2;
long clocks0, clocks3;
unsigned long long NumberOfSplittings=0;

//RG:
unsigned long long jFirst, jPrevLine, j_RG;
unsigned long long linecounterNotRL, linecounterRL, nlines1;
unsigned long long TimesOverItem;

//SWAP ]

   int nlines = 0;
   string basep, cur, next;
   string *ASbackup;
   string *ASbackup2;

   //unsigned long nlines1, linecounterNotRL, linecounterRL, jPrevLine, jFirst;

printf("QuickSortExternal_4+GB r.2+, written by Kaze.\n");
if (argc != 3) {
printf("Usage: QuickSortExternal_4+GB wordlistfile {/fast|/slow}\n");
printf("Note1: The lines in wordlistfile must be up to 2048 chars/bytes and end with CRLF i.e. maximum 2050bytes long.\n");
printf("Note2: The goal is to sort a file unfittable in physical memory, and with 32bit code.\n");
printf("Note3: When /fast is specified wordlistfile is uploaded into internal memory if it is possible.\n");
printf("Note4: When /slow is specified wordlistfile is NOT uploaded into internal memory even if it is possible.\n");

//printf("Note1: wordlistfile1's lines encountered in wordlistfile2's lines go to 'Overlapped.txt' file.\n");
//printf("Note2: wordlistfile1's lines blended (no repetitions allowed) with wordlistfile2's lines go to 'Blended.txt' file.\n");
//printf("Note3: wordlistfile1's lines not encountered in wordlistfile2 go to 'Unfamiliar.txt' file.\n");
//printf("Note1a: (wordlistfile1 logical_AND wordlistfile2) = 'Overlapped.txt' file.\n");
//printf("Note2a: (wordlistfile1 logical_OR wordlistfile2) = 'Blended.txt' file.\n");
//printf("Note3a: wordlistfile1 - (wordlistfile1 logical_AND wordlistfile2) = 'Unfamiliar.txt' file.\n");
//printf("Note4: If you need only one file to be sorted-and-deduplicated then use this:\n");
//printf("D:\\_KAZE_new-stuff\\Overlapper-Blender_r1+>copy con Empty\n");
//printf("^Z\n");
//printf("        1 file(s) copied.\n");
//printf("\n");
//printf("D:\\_KAZE_new-stuff\\Overlapper-Blender_r1+>dir Empty\n");
//printf("03/02/2011  08:59 PM                 0 Empty\n");
//printf("\n");
//printf("D:\\_KAZE_new-stuff\\Overlapper-Blender_r1+>Overlapper-Blender wordlistfile1 Empty\n");
//printf("Note5: Current pool(due to 32bit address limitation) for incoming strings is 1GB.\n");
exit (1);
}

if( strcmp(argv[2], ARG_CLs) != 0 && strcmp(argv[2], ARG_CLf) != 0 ) exit (1);

  clocks0 = clock();

if( ( fp_in = fopen( argv[1], "rb" ) ) == NULL )
{ printf( "QuickSortExternal_4+GB: Can't open file %s \n", argv[1] ); return( 1 ); }

#if defined(_WIN32_ENVIRONMENT_)
   // 64bit:
_lseeki64( fileno(fp_in), 0L, SEEK_END );
size_in64 = _telli64( fileno(fp_in) );
_lseeki64( fileno(fp_in), 0L, SEEK_SET );
#else
   // 64bit:
fseeko( fp_in, 0L, SEEK_END );
size_in64 = ftello( fp_in );
fseeko( fp_in, 0L, SEEK_SET );
#endif /* defined(_WIN32_ENVIRONMENT_)  */

//fseek( fp_in, 0L, SEEK_END );
//size_in64 = ftell( fp_in );
//fseek( fp_in, 0L, SEEK_SET );
//printf( "Size of 1st input file: %llu\n", size_in64 );
//printf( "Size of input file: %llu\n", size_in64 ); // ?! doesn't report the correct size whne 4+GB ?!
printf( "Size of input file: %s\n",  _ui64toaKAZEcomma(size_in64, llTOaDigits, 10));

// if( ( fp_in2 = fopen( argv[2], "rb" ) ) == NULL )
// { printf( "Overlapper-Blender: Can't open file %s \n", argv[2] ); return( 1 ); }
// 
// #if defined(_WIN32_ENVIRONMENT_)
//    // 64bit:
// _lseeki64( fileno(fp_in2), 0L, SEEK_END );
// size_in2 = _telli64( fileno(fp_in2) );
// _lseeki64( fileno(fp_in2), 0L, SEEK_SET );
// #else
//    // 64bit:
// fseeko( fp_in2, 0L, SEEK_END );
// size_in2 = ftello( fp_in2 );
// fseeko( fp_in2, 0L, SEEK_SET );
// #endif /* defined(_WIN32_ENVIRONMENT_)  */
// 
// //fseek( fp_in2, 0L, SEEK_END );
// //size_in2 = ftell( fp_in2 );
// //fseek( fp_in2, 0L, SEEK_SET );
// printf( "Size of 2nd input file: %llu\n", size_in2 );
// 
// if( ( fp_out2 = fopen( "Overlapped.txt", "wb+" ) ) == NULL )
// { printf( "Overlapper-Blender: Can't create file 'Overlapped.txt'.\n" ); return( 1 ); }
// if( ( fp_out = fopen( "Blended.txt", "wb+" ) ) == NULL )
// { printf( "Overlapper-Blender: Can't create file 'Blended.txt'.\n" ); return( 1 ); }
// if( ( fp_out3 = fopen( "Unfamiliar.txt", "wb+" ) ) == NULL )
// { printf( "Overlapper-Blender: Can't create file 'Unfamiliar.txt'.\n" ); return( 1 ); }

if( ( fp_out = fopen( "QuickSortExternal_4+GB.txt", "wb+" ) ) == NULL )
{ printf( "QuickSortExternal_4+GB: Can't create file 'QuickSortExternal_4+GB.txt'.\n" ); return( 1 ); }

if( ( fp_outRG = fopen( "QuickSortExternal_4+GB.distinct.txt", "wb+" ) ) == NULL )
{ printf( "QuickSortExternal_4+GB: Can't create file 'QuickSortExternal_4+GB.distinct.txt'.\n" ); return( 1 ); }

//if( ( fp_out = fopen( "Left-File_Lines_Found_In_Right-File.txt", "wb+" ) ) == NULL )
//{ printf( "Compare_Two_Wordlists: Can't create file 'Left-File_Lines_Found_In_Right-File.txt' \n" ); return( 1 ); }
//if( ( fp_out2 = fopen( "Left-File_Lines_Not-Found_In_Right-File.txt", "wb+" ) ) == NULL )
//{ printf( "Compare_Two_Wordlists: Can't create file 'Left-File_Lines_Not-Found_In_Right-File.txt' \n" ); return( 1 ); }


  printf( "Counting lines ...\n" );
fsetpos(fp_in, &fsetpos_ZERO); // SOMETHING ROTTEN with lseeki64/fseeko and fsetpos ??!! So DO-IT-OVER.
// 1++_NON_Physical: [ ================================================================================================
   Strnglen64 = size_in64;

   Over4billionLines = 0;
	for (ThunderwithL64=0; ThunderwithL64<Strnglen64; ThunderwithL64++)
            { fread(&OneChar_ieByte, 1, 1, fp_in);
		if (OneChar_ieByte == 13) {Over4billionLines++;}
            }

   //fseek(fp_in, 0, SEEK_SET);
   //  _CRTIMP __int64 __cdecl _lseeki64(int, __int64, int);
   //  int fseeko64 (FILE *stream, off64_t offset, int whence)  

#if defined(_WIN32_ENVIRONMENT_)
_lseeki64( fileno(fp_in), 0L, SEEK_SET );
#else
fseeko( fp_in, 0L, SEEK_SET );
#endif /* defined(_WIN32_ENVIRONMENT_)  */
fsetpos(fp_in, &fsetpos_ZERO); // SOMETHING ROTTEN with lseeki64/fseeko and fsetpos ??!! So DO-IT-OVER.

PointerToSeekPosition = (unsigned long long *)malloc( (Over4billionLines + 1)*sizeof(unsigned long long) ); // sizeof(string) is 4 ; +1 for QS sentinel
if( PointerToSeekPosition == NULL )
{ puts( "QuickSortExternal_4+GB: Needed memory allocation denied!\n" ); return( 1 ); }
printf( "Allocated memory for pointers-to-words in MB: %lu\n", (((Over4billionLines + 1)*sizeof(unsigned long long))>>20)+1 ); // 8bytes per element

  printf( "Assigning pointers ...\n" );
// ASSIGNING POINTERS ... [
   SeekPosition = 0;
      for( j_Over4billion = 1; j_Over4billion <= Over4billionLines; j_Over4billion++ )
   {
      PointerToSeekPosition[j_Over4billion] = SeekPosition;
//printf("%llu\n",PointerToSeekPosition[j_Over4billion]);
//printf("%llu\n",SeekPosition);
      for (;;) {
          fread(&OneChar_ieByte, 1, 1, fp_in);
          if (OneChar_ieByte == 10) break;
          SeekPosition++;
      }
      SeekPosition++;
   }
// ASSIGNING POINTERS ... ]

#if defined(_WIN32_ENVIRONMENT_)
_lseeki64( fileno(fp_in), 0L, SEEK_SET );
#else
fseeko( fp_in, 0L, SEEK_SET );
#endif /* defined(_WIN32_ENVIRONMENT_)  */

if( strcmp(argv[2], ARG_CLf) == 0 ) 
printf( "Trying to allocate memory for the file itself in MB: %lu ... ", (((size_in64 + 1))>>20)+1 ); // 8bytes per element
if( strcmp(argv[2], ARG_CLs) == 0 ) 
  PoolPhysical = NULL;
else
  PoolPhysical = (char *)malloc( (size_in64 + 1) ); // sizeof(string) is 4 ; +1 for QS sentinel
if( PoolPhysical == NULL )
{ printf( "UNSUCCESSFUL! Get on with slow external accesses.\n" ); }
else
{ printf( "OK! Get on with fast internal accesses.\n" );
  printf( "Uploading ...\n" );
  fread(PoolPhysical, size_in64, 1, fp_in);
}

//printf( "Sorting %llu Pointers ...\n", Over4billionLines); // %llu %lu %d where is the law?
printf( "Sorting %s Pointers ...\n",  _ui64toaKAZEcomma(Over4billionLines, llTOaDigits, 10));

// SORTING POINTERS ... [
//void mkqsort_main(unsigned char **a, int n) { mkqsort(a, n, 0); }
//mkqsort_main(ASbackup, nlines);
//inssort_NON_Physical(ASbackup, nlines,0);
// SORTING POINTERS ... ]

//printf ("%d\n",CompareStringsEndingWith13(PointerToSeekPosition[1],PointerToSeekPosition[2])); // Returns 1  if 1>2
//printf ("%d\n",CompareStringsEndingWith13(PointerToSeekPosition[2],PointerToSeekPosition[1])); // Returns -1 if 1<2
//printf ("%d\n",CompareStringsEndingWith13(PointerToSeekPosition[1],PointerToSeekPosition[1])); // Returns 0  if 1==2

//exit(1);


// QuickSort Standalone [ -----------------------------------------------------------------------------
//unsigned long Nbr2Sort = 100000000;           //  Number of items to sort.
//unsigned char RandNbrs[100000001];            //  Must be + 1 because of using [0] as a sentinel.
Nbr2Sort = Over4billionLines;

//*****************************************************************************
//
//                                    QuickSort
//
//  QuickSort has long had a reputation for being the fastest general purpose
//  sort algorithm. It is also perhaps the most difficult to code, and is
//  subject to sharply adverse execution time if the "pivot values" are picked
//  poorly - which can happen if the data to be sorted is already partially
//  sorted.
//
//  The algorithm works by picking one of the elements to be sorted as a "pivot
//  value". The list of items to be sorted is then partitioned so that all
//  elements that have a value less than the pivot end up in the front portion
//  of the array while all elements that are greater than the pivot value end
//  up in the other end. (Elements that are equal to the pivot could end up in
//  either section.) After the first pass, the array of items to be sorted
//  looks like:
//
//                                     Pivot
//             Low elements are here   Item     Higher elements are here
//            -----------------------------------------------------------
//  RandNbrs |    |    |    |    |    |    |    |    |    |    |    |    |
//            -----------------------------------------------------------
//              1    2    3    4                                  Nbr2Sort
//
//  After round 1, the QuickSort process is applied to both of the 2 subgroups.
//  Whichever subgroup was smaller is processed immediately while the location
//  of the left and right ends of the larger subgroup are placed on a stack
//  for later processing. This processing order will guarantee that the stack
//  will never exceed Log2(Nbr2Sort) items.
//
//  The repetitive processing of subgroups continues until the size of a
//  subgroup falls below a size defined by "MinGroup". Once a subgroup is
//  smaller than this, it is not sorted further by QuickSort. Small groups can
//  be processed faster by Insertion Sort. When Quicksort has reduced all
//  subgroups to < "MinGroup" size, control passes to "Insertion Sort" for a
//  final pass through the entire array.
//
//  In the "old days", the optimal size for "MinGroup" was about 18. The cache
//  memory on current processor chips reduces the time to access anything in
//  the cache - which includes the part of the array that is currently residing
//  in the cache. This greatly increases the efficiency of the final "Insertion
//  Sort" relative to the quicksort portion. Thus, significantly larger values
//  for "MinGroup" work better when a cache is being used. (You can experiment
//  with the value that is assigned to "MinGroup".)
//
//  Selection of the "pivot value" is crucial to the efficiency of Quicksort.
//  If the pivot value is selected so that it evenly partitions a subgroup,
//  then Quicksort is very efficient. On the other hand, if the value of the
//  "Pivot item" is near either the lowest or highest values that are going to
//  be partitioned within any subgroup, that particular round of Quicksort will
//  not do its job of quickly spliting the subgroups into ever smaller sizes.
//
//  The "median of three" portion of the routine is an effort to pick a good
//  "pivot value". If a "pivot value" can be picked so that it exactly splits a
//  subgroup into 2 equal portions, then Quicksort will be as efficient as
//  possible. An effort is made to do this by trying to find a value which is
//  close to the median of the subgroup. This is done by checking the values at
//  the second, last, and middle positions within a subgroup. The middle value
//  of these three is used as the "pivot value" while the two extremes are
//  placed at the two ends of the subgroup.
//
//  The code given here is based on a flyer that Robert Sedgewick (author of
//  "Algorithms") handed out "a few years ago" during a 2-semester sequence of
//  "Analysis of Algorithms". (Professor Sedgewick is 2nd from the left in the
//  center photo at http://groups.yahoo.com/group/CSAtrium/)
//
//*****************************************************************************

//void QuickSort(void) {

//unsigned long long QSleft[512];                    //  Stack arrays for the left/right
//unsigned long long QSright[512];                   //  ends of subgroups within QuickSort()

//  unsigned long long    i, j, k, StackPtr;
//  unsigned longlong     LeftEnd, RightEnd, LeftPtr, RightPtr, MidPtr, MinGroup;
//  unsigned long long    Pvalue, temp;
//  long clocks1, clocks2;

printf( "Pass #1: Quicksort started ...\n");

  clocks1 = clock();

//  RandNbrs[0] = 0;                            //  Sentinel for sort - used
                                              //  by the Insertion Sort
                                              //  portion.
PointerToSeekPosition[0] = 0; // In fact not needed: look the comment below at insertionsort.

    //  Initialize left end, right end, stack pointer,
    //  and minimum size for subgroups.

  LeftEnd = 1;                                //  For the first round, the 2
  RightEnd = Nbr2Sort;                        //  ends will be the whole array
  MinGroup = 16384/32; 		              //  Years ago this would be ~18
  MinGroup = 16; //12 gives NumberOfComparisons: 1,585,788,132
                 // 3 gives NumberOfComparisons: 1,613,651,713

  //printf("Name:                 AMD Athlon XP\n");
  //printf("Code Name:            Barton\n");
  //printf("Specification:        AMD Athlon(tm) XP 2600+\n");
  //printf("Technology:           0.13 microns\n");
  //printf("CPU Clock Speed:      1919.6 MHz\n");
  //printf("L1 Data Cache:        64 KBytes, 2-way set associative, 64 Bytes line size\n");
  //printf("L1 Instruction Cache: 64 KBytes, 2-way set associative, 64 Bytes line size\n");
  //printf("L2 Cache:             512 KBytes, 16-way set associative, 64 Bytes line size\n");
  //printf("L2 Speed:             1919.6 MHz (Full)\n");
  //printf("MinGroup =      16*1byte, gives 8984 clocks.\n");
  //printf("MinGroup =      64*1byte, gives 8469 clocks.\n");
  //printf("MinGroup =     256*1byte, gives 7954 clocks.\n");
  //printf("MinGroup =    1024*1byte, gives 7390 clocks.\n");
  //printf("MinGroup =    4096*1byte, gives 6937 clocks.\n");
  //printf("MinGroup =   16384*1byte, gives 6719 clocks.\n");
  //printf("MinGroup =   65536*1byte, gives 11500 clocks.\n");
  //printf("MinGroup =  262144*1byte, gives 73781 clocks.\n");
  //printf("MinGroup = 1048576*1byte, gives 1249734 clocks.\n");


  if (Nbr2Sort > MinGroup)                    //  Run quicksort until no
    StackPtr = 1;                             //  subgroup remains larger
  else StackPtr = 0;                          //  than "MinGroup" elements.


    //  Start quicksort. First, set the pivot value equal to the median of the
    //  array values at RandNbrs[LeftEnd+1], RandNbrs[(LeftEnd+RightEnd)/2],
    //  and RandNbrs[RightEnd]. The minimum of these 3 is placed at
    //  RandNbrs[LeftEnd+1] while the maximum is placed at RandNbrs[RightEnd].
    //  The value at RandNbrs[LeftEnd] is moved to
    //  RandNbrs[(LeftEnd+RightEnd)/2].

  while (StackPtr) {                          //  Loop until all subgroups
                                              //  are partitioned down to
                                              //  <= "MinGroup" size.
    LeftPtr = LeftEnd + 1;                    //  Ptr to left end.
    RightPtr = RightEnd;                      //  Ptr to right end.
    MidPtr = (LeftEnd + RightEnd)/2;          //  Point to middle

NumberOfSplittings++;

if (NumberOfSplittings % (1*256) == 1) {
Melnitchka = Melnitchka & 3; // 0 1 2 3: 00 01 10 11
printf( "%s RightEnd-LeftEnd: %s; ", Auberge[Melnitchka++], _ui64toaKAZEzerocomma(RightEnd-LeftEnd, llTOaDigits, 10)+(26-15));
printf( "NumberOfSplittings: %s ...\r", _ui64toaKAZEzerocomma(NumberOfSplittings, llTOaDigits, 10)+(26-13));
}

                                              //  Start sort of these 3
//    if (RandNbrs[LeftPtr] > RandNbrs[RightPtr]) {
    if (CompareStringsEndingWith13(PointerToSeekPosition[LeftPtr],PointerToSeekPosition[RightPtr], PoolPhysical) == 1) {
//      temp = RandNbrs[LeftPtr];               //  elements
      temp = PointerToSeekPosition[LeftPtr];
//      RandNbrs[LeftPtr] = RandNbrs[RightPtr];
      PointerToSeekPosition[LeftPtr] = PointerToSeekPosition[RightPtr];
//      RandNbrs[RightPtr] = temp;
      PointerToSeekPosition[RightPtr] = temp;
    }

//    if (RandNbrs[MidPtr] > RandNbrs[RightPtr]) {
    if (CompareStringsEndingWith13(PointerToSeekPosition[MidPtr],PointerToSeekPosition[RightPtr], PoolPhysical) == 1) {
//      Pvalue = RandNbrs[RightPtr];
      Pvalue = PointerToSeekPosition[RightPtr];
//      RandNbrs[RightPtr] = RandNbrs[MidPtr];
      PointerToSeekPosition[RightPtr] = PointerToSeekPosition[MidPtr];
    }
//    else if (RandNbrs[MidPtr] < RandNbrs[LeftPtr]) {
    else if (CompareStringsEndingWith13(PointerToSeekPosition[MidPtr],PointerToSeekPosition[LeftPtr], PoolPhysical) == -1) {
//      Pvalue = RandNbrs[LeftPtr];
      Pvalue = PointerToSeekPosition[LeftPtr];
//      RandNbrs[LeftPtr] = RandNbrs[MidPtr];
      PointerToSeekPosition[LeftPtr] = PointerToSeekPosition[MidPtr];
    }
//    else Pvalue = RandNbrs[MidPtr];
    else Pvalue = PointerToSeekPosition[MidPtr];
                                              //  The 3 values are sorted and
                                              //  and the median is in Pvalue
//    RandNbrs[MidPtr] = RandNbrs[LeftEnd];     //  Fill in hole with LeftEnd
    PointerToSeekPosition[MidPtr] = PointerToSeekPosition[LeftEnd];

    //  Start the main loop. Move pointers inward until
    //  we find 2 elements that have to be exchanged.

//    while (RandNbrs[++LeftPtr] < Pvalue);     //  Set up pointers
    while (CompareStringsEndingWith13(PointerToSeekPosition[++LeftPtr],Pvalue, PoolPhysical) == -1);
//    while (RandNbrs[--RightPtr] > Pvalue);    //  for 1st exchange
    while (CompareStringsEndingWith13(PointerToSeekPosition[--RightPtr],Pvalue, PoolPhysical) == 1);
    while (LeftPtr < RightPtr) {              //  Make these
//      temp = RandNbrs[LeftPtr];               //  statements as
      temp = PointerToSeekPosition[LeftPtr];
//      RandNbrs[LeftPtr] = RandNbrs[RightPtr]; //  efficient as
      PointerToSeekPosition[LeftPtr] = PointerToSeekPosition[RightPtr];
//      RandNbrs[RightPtr] = temp;              //  possible.
      PointerToSeekPosition[RightPtr] = temp;
//      while (RandNbrs[++LeftPtr] < Pvalue);   //  Continue this loop until
      while (CompareStringsEndingWith13(PointerToSeekPosition[++LeftPtr],Pvalue, PoolPhysical) == -1);
//      while (RandNbrs[--RightPtr] > Pvalue);  //  the pointers cross.
      while (CompareStringsEndingWith13(PointerToSeekPosition[--RightPtr],Pvalue, PoolPhysical) == 1);
    }

//    RandNbrs[LeftEnd] = RandNbrs[RightPtr];   //  After pointers cross, fill
    PointerToSeekPosition[LeftEnd] = PointerToSeekPosition[RightPtr];
//    RandNbrs[RightPtr] = Pvalue;              //  left end and middle hole.
    PointerToSeekPosition[RightPtr] = Pvalue;

    //  All values to the left of RandNbrs[RightPtr] are <= Pvalue while all to
    //  the right are >= Pvalue. Next, test the 2 subgroups on either side to
    //  see if they are still larger than the minimum efficient size. If both
    //  are still too large, then place the larger one on the stack and
    //  partition the smaller. If only one needs partitioning, then partition
    //  it, otherwise get the left and right ends of a subgroup stored on the
    //  stack in an earlier operation.

                                              //  Move RightPtr into
    RightPtr--;                               //  unsorted left subgroup

    if (RightPtr < MidPtr) {                  //  If left SubGroup is smaller
      if (RightPtr - LeftEnd > MinGroup) {    //  If both are large then put
        QSleft[StackPtr] = LeftPtr;           //  right side on the stack
        QSright[StackPtr] = RightEnd;         //  and sort the left side.
        RightEnd = RightPtr;
        ++StackPtr;                           //  Ready for next subgroup
      }
      else if (RightEnd - LeftPtr > MinGroup) //  Else if just have to
        LeftEnd = LeftPtr;                    //  sort the right side
      else {                                  //  Else neither gets sorted. Get a
        if (--StackPtr!=0) { 
        LeftEnd = QSleft[StackPtr];           //  prior subgroup from the stack.
        RightEnd = QSright[StackPtr];         //  (Will be garbage if all
        }
      }                                       //  subgroups are sorted)
    }                                         //  End of "if left is smaller"

    else {                                    //  Else left side is larger
      if (RightEnd - LeftPtr > MinGroup) {    //  If both sides are large
        QSleft[StackPtr] = LeftEnd;           //  then put left side on
        QSright[StackPtr] = RightPtr;         //  the stack
        LeftEnd = LeftPtr;                    //  and sort the right side
        ++StackPtr;                           //  Ready for next subgroup
      }
      else if (RightPtr - LeftEnd > MinGroup) //  else if left side is
        RightEnd = RightPtr;                  //  too large, then sort it.
      else {                                  //  Else neither gets sorted. Get a
        if (--StackPtr!=0) { 
        LeftEnd = QSleft[StackPtr];           //  prior subgroup from the stack
        RightEnd = QSright[StackPtr];         //  (Will be garbage if all
        }
      }                                       //  subgroups are sorted).
    }                                         //  End of "if left is larger"

  if (StackPtr==0) 
     {
Melnitchka = Melnitchka & 3; // 0 1 2 3: 00 01 10 11
printf( "%s RightEnd-LeftEnd: %s; ", Auberge[Melnitchka++], _ui64toaKAZEzerocomma(RightEnd-LeftEnd, llTOaDigits, 10)+(26-15));
printf( "NumberOfSplittings: %s ...\n", _ui64toaKAZEzerocomma(NumberOfSplittings, llTOaDigits, 10)+(26-13));
     }

  }                                           //  Repeat until all subgroups are
                                              //  small.

                                              //  Finish up with "Insertion Sort"

//goto SkipInsertion;
printf( "Pass #2: Insertionsort started ...\n");

//void inssort_NON_Physical(unsigned char **a, int n, int d)
//{   unsigned char **pi, **pj, *s, *t;
//    for (pi = a + 1; --n > 0; pi++)
//        for (pj = pi; pj > a; pj--) {
//            /* Inline strcmp: break if *(pj-1) <= *pj */
//            for (s=*(pj-1)+d, t=*pj+d; *s==*t && *s!=0; s++, t++)
//                ;
//            if (*s <= *t)
//                break;
//            swap2(pj, pj-1);
//    }
//}

//void StraightInsertion(TElem M[], int N)
//  {
//    for (int i = 2; i <= N; i++)
//      {
//        TElem X = M[i]; int j = i-1; M[0] = X;
//        while (X.Key < M[j].Key) M[j+1] = M[j--];
//        M[j+1] = X;
//      }
//  }

//void BinaryInsertion(TElem M[], int N)
//  {
//    for (int i = 2; i <= N; i++)
//      { TElem X = M[i];
//        int L = 1,
//            R = i-1;
//        while (L <= R)
//          { int Med = (L+R) / 2;
//            if (X.Key < M[Med].Key) R = Med-1; else L = Med+1; }
//        for (int j = i-1; j >= L; j--) M[j+1] = M[j];
//        M[L] = X;
//      }
//  }

  for (i = 2; i <= Nbr2Sort; i++) {
if (i % (16*1024) == 1) {
Melnitchka = Melnitchka & 3; // 0 1 2 3: 00 01 10 11
printf( "%s i: %s ...\r", Auberge[Melnitchka++], _ui64toaKAZEzerocomma(i, llTOaDigits, 10)+(26-15));
}

    j = i - 1;
//    temp = RandNbrs[k];
    temp = PointerToSeekPosition[i];
    PointerToSeekPosition[0] = temp;
//    while (RandNbrs[j] > temp) {
    while (CompareStringsEndingWith13(PointerToSeekPosition[j],temp, PoolPhysical) == 1) {
//      RandNbrs[k] = RandNbrs[j];
      PointerToSeekPosition[j+1] = PointerToSeekPosition[j];
      j--;
    }
//    RandNbrs[k] = temp;
    PointerToSeekPosition[j+1] = temp;
  }

Melnitchka = Melnitchka & 3; // 0 1 2 3: 00 01 10 11
printf( "%s i: %s ...\n", Auberge[Melnitchka++], _ui64toaKAZEzerocomma(i-1, llTOaDigits, 10)+(26-15));

//SkipInsertion:

// Insertionsort(above fragment) follows:
/*
	mov	eax, DWORD PTR _Nbr2Sort
$L1481:
; Line 431
	cmp	eax, 2
	jb	SHORT $L1514
	mov	ecx, OFFSET FLAT:_RandNbrs+1
	mov	ebp, 2
	sub	ebp, ecx
$L1512:
; Line 434
	mov	dl, BYTE PTR [ecx+1]
; Line 435
	cmp	BYTE PTR [ecx], dl
	lea	edi, DWORD PTR [ecx+ebp]
	jbe	SHORT $L1517
	mov	esi, ecx
	mov	eax, ecx
$L1516:
; Line 436
	mov	bl, BYTE PTR [esi]
	mov	BYTE PTR [eax+1], bl
	mov	bl, BYTE PTR [eax-1]
; Line 438
	dec	edi
	dec	eax
	cmp	bl, dl
	mov	esi, eax
	ja	SHORT $L1516
; Line 435
	mov	eax, DWORD PTR _Nbr2Sort
$L1517:
; Line 434
	inc	ecx
; Line 440
	mov	BYTE PTR _RandNbrs[edi], dl
	lea	edx, DWORD PTR [ecx+ebp]
	cmp	edx, eax
	jbe	SHORT $L1512
$L1514:
*/

/*
  // Bubblesort
        for(i=1;i<((Nbr2Sort+1)-1);i++)           
              for(j=1;j<((Nbr2Sort+1)-(i+1));j++) 
                           if(RandNbrs[j] > RandNbrs[j+1])
                                    {   temp = RandNbrs[j+1];
                                        RandNbrs[j+1] = RandNbrs[j];
                                        RandNbrs[j] = temp;
                                    }
*/

  clocks2 = clock();
  //printf("The time to sort %llu items via Quicksort was %d clocks.\n", Nbr2Sort, clocks2 - clocks1);
  //Caramba again: Why above line doesn't print the second argument?!?!
  //printf("The time to sort %llu items via Quicksort was ", Nbr2Sort);

  printf( "NumberOfComparisons: %s\n",  _ui64toaKAZEcomma(NumberOfComparisons, llTOaDigits, 10));

  printf( "The time to sort %s items via Quicksort+Insertionsort was ",  _ui64toaKAZEcomma(Nbr2Sort, llTOaDigits, 10));
  //printf("%d clocks.\n", clocks2 - clocks1);
  printf( "%s clocks.\n",  _ui64toaKAZEcomma(clocks2 - clocks1, llTOaDigits, 10));

//}

// QuickSort Standalone ] -----------------------------------------------------------------------------

printf( "Dumping the sorted data ...\n");
      for( j_Over4billion = 1; j_Over4billion <= Over4billionLines; j_Over4billion++ )
   {
if( PoolPhysical == NULL ) {
fsetpos(fp_in, &PointerToSeekPosition[j_Over4billion]);
for (i=0; i<(LongestLineInclusive+1)+1; i++) {fread(&FourGram[i], 1, 1, fp_in); fwrite(&FourGram[i], 1, 1, fp_out); if (FourGram[i]==10) break;}
} else {
 for (i=0; i<(LongestLineInclusive+1)+1; i++) {
	FourGram[i] = *(char *)(PoolPhysical + PointerToSeekPosition[j_Over4billion] + i);
        fwrite(&FourGram[i], 1, 1, fp_out);
	if (FourGram[i]==10) break;
 }
}

//for (i=0; i<32+1; i++) {printf("%c",FourGram[i]); if (FourGram[i]==10) break;}
//printf("\n");
   }
  printf( "Dumped %s lines.\n",  _ui64toaKAZEcomma(j_Over4billion-1, llTOaDigits, 10));

fclose(fp_out); 
if( ( fp_out = fopen( "QuickSortExternal_4+GB.txt", "rb" ) ) == NULL )
{ printf( "QuickSortExternal_4+GB: Can't open file 'QuickSortExternal_4+GB.txt'.\n" ); return( 1 ); }

#if defined(_WIN32_ENVIRONMENT_)
   // 64bit:
_lseeki64( fileno(fp_out), 0L, SEEK_END );
size_in2 = _telli64( fileno(fp_out) );
_lseeki64( fileno(fp_out), 0L, SEEK_SET );
#else
   // 64bit:
fseeko( fp_out, 0L, SEEK_END );
size_in2 = ftello( fp_out );
fseeko( fp_out, 0L, SEEK_SET );
#endif /* defined(_WIN32_ENVIRONMENT_)  */

fclose(fp_out); 
if (size_in2 == size_in64)
printf( "OK! Incoming and resultant file's sizes match.\n");
else
{ printf( "Failure! Incoming and resultant file's sizes mismatch?!.\n"); exit(13);}

printf( "Dumping the sorted data [deduplicated] ...\n");

// Caution: the difference from above fragment is the first array element: 1 above 0 below!
nlines1 = Over4billionLines;
linecounterNotRL = Over4billionLines;
linecounterRL = 0;
      // Railgunning ... [
      //jFirst = 0;
      jFirst = 0+1;
                                      if (linecounterNotRL == 1) {
                                          //fprintf(fp_outRG, "%s", backupPAT1[jFirst]);
                                          //fwrite(CRdLFa, 2, 1, fp_outRG );
                                          //  fprintf(fp_outRG, "%lu\n", 1);
                                          fprintf( fp_outRG, "%s\t", _ui64toaKAZEzerocomma(1, llTOaDigits, 10)+(26-9) );
if( PoolPhysical == NULL ) {
                                          fsetpos(fp_in, &PointerToSeekPosition[jFirst]);
                                          for (i=0; i<(LongestLineInclusive+1)+1; i++) {fread(&FourGram[i], 1, 1, fp_in); fwrite(&FourGram[i], 1, 1, fp_outRG); if (FourGram[i]==10) break;}
} else {
 for (i=0; i<(LongestLineInclusive+1)+1; i++) {
	FourGram[i] = *(char *)(PoolPhysical + PointerToSeekPosition[jFirst] + i);
        fwrite(&FourGram[i], 1, 1, fp_outRG);
	if (FourGram[i]==10) break;
 }
}
                                          linecounterRL++;
                                      }
      jPrevLine = jFirst;
                linecounterNotRL--;
      TimesOverItem = 1;
      for( j_RG = jFirst + 1; j_RG < nlines1+1; j_RG++ )
      {
                if (linecounterNotRL != 0) {
                linecounterNotRL--;


                //if ( strcmpKAZE(backupPAT1[jPrevLine], backupPAT1[j_RG]) != 0 ) {
                if ( CompareStringsEndingWith13(PointerToSeekPosition[jPrevLine],PointerToSeekPosition[j_RG], PoolPhysical) != 0 ) {
                     //fprintf(fp_outRG, "%s", backupPAT1[jPrevLine]);
                     //fwrite(CRdLFa, 2, 1, fp_outRG );
                     //  fprintf(fp_outRG, "%lu\n", TimesOverItem);
                                          fprintf( fp_outRG, "%s\t", _ui64toaKAZEzerocomma(TimesOverItem, llTOaDigits, 10)+(26-9) );
if( PoolPhysical == NULL ) {
                                          fsetpos(fp_in, &PointerToSeekPosition[jPrevLine]);
                                          for (i=0; i<(LongestLineInclusive+1)+1; i++) {fread(&FourGram[i], 1, 1, fp_in); fwrite(&FourGram[i], 1, 1, fp_outRG); if (FourGram[i]==10) break;}
} else {
 for (i=0; i<(LongestLineInclusive+1)+1; i++) {
	FourGram[i] = *(char *)(PoolPhysical + PointerToSeekPosition[jPrevLine] + i);
        fwrite(&FourGram[i], 1, 1, fp_outRG);
	if (FourGram[i]==10) break;
 }
}

                       TimesOverItem = 0;
                     linecounterRL++;
                }
                TimesOverItem++;

                if (linecounterNotRL == 0) {
                                          //fprintf(fp_outRG, "%s", backupPAT1[j_RG]);
                                          //fwrite(CRdLFa, 2, 1, fp_outRG );
                                          //  fprintf(fp_outRG, "%lu\n", TimesOverItem);
                                          fprintf( fp_outRG, "%s\t", _ui64toaKAZEzerocomma(TimesOverItem, llTOaDigits, 10)+(26-9) );
if( PoolPhysical == NULL ) {
                                          fsetpos(fp_in, &PointerToSeekPosition[j_RG]);
                                          for (i=0; i<(LongestLineInclusive+1)+1; i++) {fread(&FourGram[i], 1, 1, fp_in); fwrite(&FourGram[i], 1, 1, fp_outRG); if (FourGram[i]==10) break;}
} else {
 for (i=0; i<(LongestLineInclusive+1)+1; i++) {
	FourGram[i] = *(char *)(PoolPhysical + PointerToSeekPosition[j_RG] + i);
        fwrite(&FourGram[i], 1, 1, fp_outRG);
	if (FourGram[i]==10) break;
 }
}

                                          linecounterRL++;
                }
                jPrevLine = j_RG;
                }
      }
      // Railgunning ... ]

  printf( "Dumped %s distinct lines.\n",  _ui64toaKAZEcomma(linecounterRL, llTOaDigits, 10));

free(PointerToSeekPosition); free(PoolPhysical);
fclose(fp_outRG);

  clocks3 = clock();

  printf( "Total time: %s clocks.\n",  _ui64toaKAZEcomma(clocks3 - clocks0, llTOaDigits, 10));

#if defined(_WIN32_ENVIRONMENT_)
  printf( "Performance: %s KB/s.\n",  _ui64toaKAZEcomma((size_in64>>10)/((clocks3 - clocks0 + 1)/1000 + 1), llTOaDigits, 10));
#else
  printf( "Performance: %s KB/s.\n",  _ui64toaKAZEcomma((size_in64>>10)/((clocks3 - clocks0 + 1)/1000000 + 1), llTOaDigits, 10));
#endif /* defined(_WIN32_ENVIRONMENT_)  */

printf( "Done successfully.\n");
exit(0);

// 1++_NON_Physical: ] ================================================================================================

  }

/*
;DEFLNG A-Z
;SUB FoxQuickSort (Quantity&, HIMEMhandle%, EMBoffsetOfDATA&, MotherStringL%, StringS%, StringL%, EMBoffsetForStack&)
;SHARED VideoBuffer%, ZeroIfT5100%, c0%, c3%, c4%
;DIM XMS AS EMMsructure
;        Left = 1: Right = Quantity&: StackPtr = 0
;        ' PUSH Left
;                StackPtr = StackPtr + 1
;                XMS.SourceHandle = 0
;                CALL ToLong(XMS.SourceOffset, VARPTR(Left), VARSEG(Left))
;                XMS.NumberOfBytes = 4
;                XMS.TargetHandle = HIMEMhandle%
;                XMS.TargetOffset = EMBoffsetForStack& + (StackPtr - 1) * 4
;                CALL HIMEMMove(ErrorBL%, VARSEG(XMS), VARPTR(XMS), ErrorStatus%)
;        ' PUSH Right
;                StackPtr = StackPtr + 1
;                XMS.SourceHandle = 0
;                CALL ToLong(XMS.SourceOffset, VARPTR(Right), VARSEG(Right))
;                XMS.NumberOfBytes = 4
;                XMS.TargetHandle = HIMEMhandle%
;                XMS.TargetOffset = EMBoffsetForStack& + (StackPtr - 1) * 4
;                CALL HIMEMMove(ErrorBL%, VARSEG(XMS), VARPTR(XMS), ErrorStatus%)
;DO
;        ' POP Right
;                XMS.SourceHandle = HIMEMhandle%
;                XMS.SourceOffset = EMBoffsetForStack& + (StackPtr - 1) * 4
;                XMS.NumberOfBytes = 4
;                XMS.TargetHandle = 0
;                CALL ToLong(XMS.TargetOffset, VARPTR(Right), VARSEG(Right))
;                CALL HIMEMMove(ErrorBL%, VARSEG(XMS), VARPTR(XMS), ErrorStatus%)
;                StackPtr = StackPtr - 1
;        ' POP Left
;                XMS.SourceHandle = HIMEMhandle%
;                XMS.SourceOffset = EMBoffsetForStack& + (StackPtr - 1) * 4
;                XMS.NumberOfBytes = 4
;                XMS.TargetHandle = 0
;                CALL ToLong(XMS.TargetOffset, VARPTR(Left), VARSEG(Left))
;                CALL HIMEMMove(ErrorBL%, VARSEG(XMS), VARPTR(XMS), ErrorStatus%)
;                StackPtr = StackPtr - 1
;DO
;                Pivot$ = MID$(FoxDATA$((Left + Right) \ 2, HIMEMhandle%, EMBoffsetOfDATA&, MotherStringL%), StringS%, StringL%)
;        Indx = Left
;        Jndx = Right
;DO
;DO WHILE MID$(FoxDATA$(Indx, HIMEMhandle%, EMBoffsetOfDATA&, MotherStringL%), StringS%, StringL%) < Pivot$
;        Indx = Indx + 1
;LOOP
;DO WHILE MID$(FoxDATA$(Jndx, HIMEMhandle%, EMBoffsetOfDATA&, MotherStringL%), StringS%, StringL%) > Pivot$
;        Jndx = Jndx - 1
;LOOP
;        IF Indx <= Jndx THEN
;        IF Indx < Jndx THEN
;                ' Jndx -> Temp
;                Temp$ = FoxDATA$(Jndx, HIMEMhandle%, EMBoffsetOfDATA&, MotherStringL%)
;                ' Indx -> Jndx
;                XMS.SourceHandle = HIMEMhandle%
;                XMS.SourceOffset = EMBoffsetOfDATA& + (Indx - 1) * MotherStringL%
;                XMS.NumberOfBytes = MotherStringL%
;                XMS.TargetHandle = HIMEMhandle%
;                XMS.TargetOffset = EMBoffsetOfDATA& + (Jndx - 1) * MotherStringL%
;                CALL HIMEMMove(ErrorBL%, VARSEG(XMS), VARPTR(XMS), ErrorStatus%)
;                ' Temp -> Indx
;                XMS.SourceHandle = 0
;                CALL ToLong(XMS.SourceOffset, SADD(Temp$), SSEG(Temp$))
;                XMS.NumberOfBytes = MotherStringL%
;                XMS.TargetHandle = HIMEMhandle%
;                XMS.TargetOffset = EMBoffsetOfDATA& + (Indx - 1) * MotherStringL%
;                CALL HIMEMMove(ErrorBL%, VARSEG(XMS), VARPTR(XMS), ErrorStatus%)
;        END IF
;                Indx = Indx + 1
;                Jndx = Jndx - 1
;        END IF
;LOOP UNTIL Indx > Jndx
;
;IF Indx < Right THEN
;        ' PUSH Indx
;                StackPtr = StackPtr + 1
;                XMS.SourceHandle = 0
;                CALL ToLong(XMS.SourceOffset, VARPTR(Indx), VARSEG(Indx))
;                XMS.NumberOfBytes = 4
;                XMS.TargetHandle = HIMEMhandle%
;                XMS.TargetOffset = EMBoffsetForStack& + (StackPtr - 1) * 4
;                CALL HIMEMMove(ErrorBL%, VARSEG(XMS), VARPTR(XMS), ErrorStatus%)
;        ' PUSH Right
;                StackPtr = StackPtr + 1
;                XMS.SourceHandle = 0
;                CALL ToLong(XMS.SourceOffset, VARPTR(Right), VARSEG(Right))
;                XMS.NumberOfBytes = 4
;                XMS.TargetHandle = HIMEMhandle%
;                XMS.TargetOffset = EMBoffsetForStack& + (StackPtr - 1) * 4
;                CALL HIMEMMove(ErrorBL%, VARSEG(XMS), VARPTR(XMS), ErrorStatus%)
;END IF
;        Right = Jndx
;
;LOOP UNTIL Left >= Right
;LOOP UNTIL StackPtr = 0
;END SUB
*/

/*
'DEFINT A-Z
'SUB QSdouble (SortArray#())
'left = LBOUND(SortArray#)
'Right = UBOUND(SortArray#)
'LeftMargin = left
'REDIM Stack%(left TO Right)
'CONST LocalFalse = 0, LocalTrue = NOT LocalFalse
'Tiller = LocalFalse
'DO
'IF left < Right THEN
'   Position = (left + Right) \ 2
'   SWAP SortArray#(Position), SortArray#(Right)
'   Pivot# = SortArray#(Right)
'   Indx = left
'   Jndx = Right
'DO
'DO WHILE (Indx < Jndx) AND (SortArray#(Indx) <= Pivot#)
'   Indx = Indx + 1
'LOOP
'DO WHILE (Jndx > Indx) AND (SortArray#(Jndx) >= Pivot#)
'   Jndx = Jndx - 1
'LOOP
'   SWAP SortArray#(Indx), SortArray#(Jndx)
'LOOP UNTIL Jndx = Indx
'   SWAP SortArray#(Indx), SortArray#(Right)
'IF Indx - left > Right - Indx THEN
'   StackPtr = StackPtr + 1
'   Stack%(StackPtr + LeftMargin) = left
'   StackPtr = StackPtr + 1
'   Stack%(StackPtr + LeftMargin) = Indx - 1
'   left = Indx + 1
'ELSE
'   StackPtr = StackPtr + 1
'   Stack%(StackPtr + LeftMargin) = Indx + 1
'   StackPtr = StackPtr + 1
'   Stack%(StackPtr + LeftMargin) = Right
'   Right = Indx - 1
'END IF
'ELSE
'IF StackPtr = 0 THEN
'   Tiller = LocalTrue
'ELSE
'   Right = Stack%(StackPtr + LeftMargin)
'   StackPtr = StackPtr - 1
'   left = Stack%(StackPtr + LeftMargin)
'   StackPtr = StackPtr - 1
'END IF
'END IF
'LOOP UNTIL Tiller
'END SUB
*/

/*
void quickSort(int l, int r) {
 int i = l, j = r, x = M[(i+j) / 2].Key;
 do {
   while (x > M[i].Key) i++;
   while (x < M[j].Key) j--;
   if (i <= j) {
     swap(M, i, j); i++; j--;
   }
 } while (j >= i);
 if (j>l) quickSort(l, j);
 if (i<r) quickSort(i, r);
}
*/

/*
      // FILE LOADING & RAILGUNNING [ Country-Region-City
      printf("FINAL-SHOWDOWN ...\n");
   if ((linecounterNotRL = readlines("Column1.txt", &backupPAT1, 0)) >= 0)
   {  printf("Number of TriadS uploaded: %lu\n", linecounterNotRL);
      nlines1 = linecounterNotRL;

      printf("Flushing sorted & railguned TriadS ...\n");
      if( ( fp_out = fopen( "Column1.txt", "wb+" ) ) == NULL )
      { printf( "IP_ELF: Can't create file %s \n", "Column1.txt" ); return( 1 ); }
      linecounterRL = 0;

     printf("Sorting(with 'MultiKeyQuickSortSort' by J. Bentley and R. Sedgewick) ...\n");
     mkqsort_main(backupPAT1, linecounterNotRL); // backup[0..nlines-1]
      // Railgunning ... [
      jFirst = 0;
                                      if (linecounterNotRL == 1) {
                                          fprintf(fp_out, "%s", backupPAT1[jFirst]);
                                          fwrite(CRdLFa, 2, 1, fp_out );
                                            fprintf(fp_outC2, "%lu\n", 1);
                                          linecounterRL++;
                                      }
      jPrevLine = jFirst;
                linecounterNotRL--;
      TimesOverItem = 1;
      for( j = jFirst + 1; j < nlines1; j++ )
      {
                if (linecounterNotRL != 0) {
                linecounterNotRL--;


                if ( strcmpKAZE(backupPAT1[jPrevLine], backupPAT1[j]) != 0 ) {
                     fprintf(fp_out, "%s", backupPAT1[jPrevLine]);
                     fwrite(CRdLFa, 2, 1, fp_out );
                       fprintf(fp_outC2, "%lu\n", TimesOverItem);
                       TimesOverItem = 0;
                     linecounterRL++;
                }
                TimesOverItem++;

                if (linecounterNotRL == 0) {
                                          fprintf(fp_out, "%s", backupPAT1[j]);
                                          fwrite(CRdLFa, 2, 1, fp_out );
                                            fprintf(fp_outC2, "%lu\n", TimesOverItem);
                                          linecounterRL++;
                }
                jPrevLine = j;
                }
      }
      // Railgunning ... ]
   }
   else 
   {  printf("IP_ELF: Input file too large, IPs remain unsorted!\n");
      return 1;
   }
      // FILE LOADING & RAILGUNNING ]
*/