How do I perform shell sort using sequence {3,2,1}? - c

Suppose I have an array:
30 20 29 19 28 18 27 17 26 16 25 15 24 14 23 13 22 12 21 11
I am not understanding how to do the shell sort using sequence 3:
Would I simply do this:
30 20 29 19 28 18 27 17 | 26 16 25 15 24 14 |23 13 22 12 21 11
Where I split it into 3 parts and sort the respective parts? And then do the same with 2 sorting after, except split into halves? What is the right way to do this? Can someone please explain?

If you look at your array and number the locations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
30 20 29 19 28 18 27 17 26 16 25 15 24 14 23 13 22 12 21 11
In a shell sort, what you do is start with a skip number (in your case 3) so to make the first "list" you take a number and skip. With 3 this would be 1st, 4th, 7th etc.
So you would have a list of
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
30 19 27 16 24 13 21
and a second list of
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
20 28 17 25 14 22 11
The 3rd list is the remaining items.
For the next round you do it with one less... so items at odd number locations and items at even number locations.
In response to comment below
A Shell sort is an in-place sort — that means you don't remove the items to new lists or create any new data structures. You are using the array to "treat" items which are "far apart" in terms of array locations as next to each other. You don't actually make new lists or new arrays (that is why I showed my diagrams as I did); you just look at these locations.
Why?
Because it means that when you start (for example with 3) you are moving stuff farther) -- eg the 13 that starts at location 16 gets moved to location 1 in the first pass. Then as you reduce the number you start doing more local changes. This means you gain an advantage over a typical bubble sort. Still not good — but MUCH better than a bubble sort.

Related

C code implementing bubble sort for linked list isn't working

I am trying to apply bubble sort on linklist. for that I have implemented my own list but the code isn't working as it somehow isn't printing any value when all of the linklist values are printed.
The course I was writing code for required me to write everything from scratch. I wrote a bubble sort function which isn't working as it should, It is somehow tempering the root due to which I am not able to print all of the values of the linklist.
I also tried to print string "values swapped" to understand how many times is the loop running, turns out it is running the number of times it should run. but doing something due to which I can't print the values from the root.
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <stdbool.h>
typedef struct Node
{
int value;
struct Node *next;
} Node;
Node *insert(Node *root, int val)
{
Node *new = (Node *)malloc(sizeof(Node));
new->value = val;
new->next = NULL;
if (root == NULL)
{
root = new;
return root;
}
while (root->next != NULL)
{
root = root->next;
}
root->next = new;
return NULL;
}
void swap(Node *n1, Node *n2)
{
int temp = n1->value;
n1->value = n2->value;
n2->value = temp;
}
void print(Node *root)
{
if (root == NULL)
return;
printf("%d ", root->value);
print(root->next);
}
void bubbleSort(Node *root)
{
bool toSwap = true;
Node *trav = root;
while (toSwap)
{
toSwap = false;
while (trav != NULL)
{
if (trav->value > trav->next->value)
{
swap(trav, trav->next);
printf("Values Swapped \n");
toSwap = true;
}
trav = trav->next;
}
}
}
int main(void)
{
Node *root = NULL;
root = insert(root, 4);
insert(root, 1);
insert(root, 5);
insert(root, 3);
bubbleSort(root);
print(root);
return 0;
}
Your code runs in O(n) time, since trav moves forward at every iteration and the algorithm terminates when trav has reached the end of the list. However, Bubble Sort is a O(n^2) time algorithm.
You need to use two pointers. Let's call the second pointer trav_2. The first pointer (trav) simply acts as a counter to make sure that the second pointer (trav_2) iterates through the list performing the necessary swaps n times. If you replace your while loop with the following logic, it should work fine:
while (trav!=NULL)
{
toSwap = false;
Node *trav_2 = root;
while (trav_2 != NULL && trav_2->next!=NULL)
{
if (trav_2->value > trav_2->next->value)
{
swap(trav_2, trav_2->next);
printf("Values Swapped \n");
toSwap = true;
}
trav_2 = trav_2->next;
}
trav = trav->next;
}
I have also fixed some pointer dereferencing errors you had in your code (the ones others have mentioned). However, fixing them wasn't enough. The logic was flawed too.
Fixing the existing code has already been done by Harsh. I'm going to show you how this is done by pure pointer juggling rather than swapping datum across nodes. Normally that is the purpose of this exercise. Imagine an enormous data payload held within each node that makes it obtrusive to copy. You don't have to if you just jostle the pointers to rearrange the list.
For each enumeration the "largest" element will bubble to the end. it is pruned from there and pushed on to the head of a new list. When the algorithm is done one of two things will have transpired:
We ran out of nodes. OR
We ejected early due to noswap-optimization.
The first of these is trivial. We already have all the nodes and they're already sorted. The latter complicates things because we still have two sorted lists: one is the list of items we've pruned thus far as we push-built our sorted result, the other is the remaining list that we detected as already-sorted and ejected the sorting loop. Fortunately, due to the manner in which we tracked the last node pointer in remaining source list, it makes linking them easy and we'll have our final result.
Finally, because root can change, the algorithm requires the new root be returned from the function. That, in turn, requires a change in main. This is not specific to the aforementioned algorithm. It would have to be done regardless as a separate, but important, bug fix.
The sorting implementation appears below:
Node *bubbleSort(Node *root)
{
Node *result = NULL;
Node **pp;
bool swapped = (root != NULL);
while (swapped)
{
// reset swap state
swapped = false;
pp = &root;
while (*pp && (*pp)->next)
{
// compare the two node values
if ((*pp)->next->value < (*pp)->value)
{
Node *p = *pp;
*pp = (*pp)->next;
p->next = (*pp)->next;
(*pp)->next = p;
swapped = true;
}
pp = &(*pp)->next;
}
// pp holds the address of the pointer pointing to
// the last node in the source list. So, we...
// 1. prune off the end node.
// 2. terminate the source list
// 3. push the pruned node on to the front of
// the result list where it belongs.
Node *p = *pp;
*pp = NULL;
p->next = result;
result = p;
// TODO: fun thing here. print both lists (result and root)
}
// the above loop could have exited early, leaving root
// holding the sorted low half of the list. the *last*
// pointer in that list is addressed by pp, so we can
// just link the rest of the list we already pruned to
// that end and we're done.
*pp = result;
return root;
}
The change in main is likewise below:
int main(void)
{
Node *root = insert(root, 4);
insert(root, 1);
insert(root, 5);
insert(root, 3);
root = bubbleSort(root);
print(root);
return 0;
}
And finally, the result:
1 3 4 5
Worth noting: bubble-sort is already dreadful enough. It is a terrible fit for nearly all sorting purposes, and especially for linked lists, where the ideal sorting mechanic would be merge-sort. But for academic purposes it makes for an interesting exercise, especially if you embrace the challenge of doing it exclusively with pointer jostling; not datum swapping.
An Interesting View
Modifying the code to do the following:
Generate a random shuffle of the sequence 1...30
Do the sort as shown above, but print the source and result lists after each iteration.
the results show how the pruning, pushing, and final fix up happen. The original shuffled list is:
11 28 16 6 12 23 13 1 20 14 27 3 2 7 21 4 8 30 19 15 22 17 26 29 24 9
Printing each list (the remaining source list and the result we're building), the outcome looks like this:
root: 11 16 6 12 23 13 1 20 14 27 3 2 7 21 4 8 28 19 15 22 17 26 29 24 9 5 18 25 10
result: 30
root: 11 6 12 16 13 1 20 14 23 3 2 7 21 4 8 27 19 15 22 17 26 28 24 9 5 18 25 10
result: 29 30
root: 6 11 12 13 1 16 14 20 3 2 7 21 4 8 23 19 15 22 17 26 27 24 9 5 18 25 10
result: 28 29 30
root: 6 11 12 1 13 14 16 3 2 7 20 4 8 21 19 15 22 17 23 26 24 9 5 18 25 10
result: 27 28 29 30
root: 6 11 1 12 13 14 3 2 7 16 4 8 20 19 15 21 17 22 23 24 9 5 18 25 10
result: 26 27 28 29 30
root: 6 1 11 12 13 3 2 7 14 4 8 16 19 15 20 17 21 22 23 9 5 18 24 10
result: 25 26 27 28 29 30
root: 1 6 11 12 3 2 7 13 4 8 14 16 15 19 17 20 21 22 9 5 18 23 10
result: 24 25 26 27 28 29 30
root: 1 6 11 3 2 7 12 4 8 13 14 15 16 17 19 20 21 9 5 18 22 10
result: 23 24 25 26 27 28 29 30
root: 1 6 3 2 7 11 4 8 12 13 14 15 16 17 19 20 9 5 18 21 10
result: 22 23 24 25 26 27 28 29 30
root: 1 3 2 6 7 4 8 11 12 13 14 15 16 17 19 9 5 18 20 10
result: 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 6 4 7 8 11 12 13 14 15 16 17 9 5 18 19 10
result: 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 13 14 15 16 9 5 17 18 10
result: 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 13 14 15 9 5 16 17 10
result: 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 13 14 9 5 15 16 10
result: 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 13 9 5 14 15 10
result: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 12 9 5 13 14 10
result: 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 11 9 5 12 13 10
result: 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 9 5 11 12 10
result: 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 8 5 9 11 10
result: 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 7 5 8 9 10
result: 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 6 5 7 8 9
result: 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 5 6 7 8
result: 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
root: 1 2 3 4 5 6 7
result: 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
The final result is as expected:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Change your inner while loop to this:
while (trav != NULL && trav->next != NULL) {
if (trav->value > trav->next->value) {
printf("Swapping values %d %d\n", trav->value, trav->next->value);
swap(trav, trav->next);
toSwap = true;
}
trav = trav->next;
}
It corrects the NULL pointer dereferencement.
You'll see why it doesn't work by clearly showing what is being swapped.
That being said, you should rather do what is mentioned in the second comment.

Data field shifting through a vector of data in matlab

I need to create a data field that will go through a vector. Data field is constant length, and it is going through the data vector shifting data field with data field length. I need the mean value of that field (A vector) that corresponds to a mean value of another field (B vector).
Example:
A=[1 5 7 8 9 10 11 13 15 18 19 25 28 30 35 40 45 48 50 51];
B=[2 4 8 9 12 15 16 18 19 20 25 27 30 35 39 40 45 48 50 55];
I want to do next:
A=[{1 5 7 8 9} 10 11 13 15 18 19 25 28 30 35 40 45 48 50 51];
B=[{2 4 8 9 12} 15 16 18 19 20 25 27 30 35 39 40 45 48 50 55];
I want to take data from field of 5 points and get mean value. And then shift whole data field with data field length.
A=[1 5 7 8 9 {10 11 13 15 18} 19 25 28 30 35 40 45 48 50 51];
B=[2 4 8 9 12 {15 16 18 19 20} 25 27 30 35 39 40 45 48 50 55];
I need two vectors, C and D with mean values of this method.
C=[6 13.4 27.4 45.2];
D=[7 17.6 31.2 47.6];
I started something with
n = length(A);
for k = 1:n
....
but nothing I tried worked.
reshape the vector into a 5-row matrix and then compute the mean of each column:
C = mean(reshape(A,5,[]),1);
D = mean(reshape(B,5,[]),1)

Same column of different files into the same new file

I have multiple folders Case-1, Case-2....Case-N and they all have a file named PPD. I want to extract all 2nd columns and put them into one file named 123.dat.
It seems that I cannot use awk in a for loop.
case=$1
for (( i = 1; i <= $case ; i ++ ))
do
file=Case-$i
cp $file/PPD temp$i.dat
awk 'FNR==1{f++}{a[f,FNR]=$2}
END
{for(x=1;x<=FNR;x++)
{for(y=1;y<ARGC;y++)
printf("%s ",a[y,x]);print ""} }'
temp$i.dat >> 123.dat
done
Now 123.dat only has the date of the last PPD in Case-N
I know I can use join(I used that command before) if every PPD file has at least one column the same, but it turns out to be extremely slow if I have lots of Case folders
Maybe
eval paste $(printf ' <(cut -f2 %s)' Case-*/PPD)
There is probably a limit to how many process substitutions you can perform in one go. I did this with 20 columns and it was fine. Process substitutions are a Bash feature, so not portable to other Bourne-compatible shells in general.
The wildcard will be expanded in alphabetical order. If you want the cases in numerical order, maybe use case-[1-9] case-[1-9][0-9] case-[1-9][0-9][0-9] to force the expansion to get the single digits first, then the double digits, etc.
The interaction between the outer shell script and inner awk invocation aren't working the way you expect.
Every time through the loop, the shell script calls awk a new time, which means that f will be unset, and then that first clause will set it to 1. It will never become 2. That is, you are starting a new awk process for each iteration through the outer loop, and awk is starting from scratch each time.
There are other ways to structure your code, but as a minimal tweak, you can pass in the number $i to the awk invocation using the -v option, e.g. awk -v i="$i" ....
Note that there are better ways to structure your overall solution, as other answerers have already suggested; I meant this response to be an answer the question, "Why doesn't this work?" and not "Please rewrite this code."
The below AWK program can help you.
#!/usr/bin/awk -f
BEGIN {
# Defaults
nrecord=1
nfiles=0
}
BEGINFILE {
# Check if the input file is accessible,
# if not skip the file and print error.
if (ERRNO != "") {
print("Error: ",FILENAME, ERRNO)
nextfile
}
}
{
# Check if the file is accessed for the first time
# if so then increment nfiles. This is to keep count of
# number of files processed.
if ( FNR == 1 ) {
nfiles++
} else if (FNR > nrecord) {
# Fetching the maximum size of the record processed so far.
nrecord=FNR
}
# Fetch the second column from the file.
array[nfiles,FNR]=$2
}
END {
# Iterate through the array and print the records.
for (i=1; i<=nrecord; i++) {
for (j=1; j<=nfiles; j++) {
printf("%5s", array[j,i])
}
print ""
}
}
Output:
$ ./get.awk Case-*/PPD
1 11 21
2 12 22
3 13 23
4 14 24
5 15 25
6 16 26
7 17 27
8 18 28
9 19 29
10 20 30
Here the Case*/PPD expands to Case-1/PPD, Case-2/PPD, Case-3/PPD and so on. Below are the source files for which the output was generated.
$ cat Case-1/PPD
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
5 5 5 5
6 6 6 6
7 7 7 7
8 8 8 8
9 9 9 9
10 10 10 10
$ cat Case-2/PPD
11 11 11 11
12 12 12 12
13 13 13 13
14 14 14 14
15 15 15 15
16 16 16 16
17 17 17 17
18 18 18 18
19 19 19 19
20 20 20 20
$ cat Case-3/PPD
21 21 21 21
22 22 22 22
23 23 23 23
24 24 24 24
25 25 25 25
26 26 26 26
27 27 27 27
28 28 28 28
29 29 29 29
30 30 30 30

XOR File Decryption

So I have to decrypt a .txt file that is crypted with XOR code and with a repeated password that is unknown, and the goal is to discover the message.
Here are the things that I already know because of the professor:
First I need to find the length of the unknown password
The message has been altered and it doesn't have spaces (this may add a bit more difficulty because the space character has the highest frequency in a message)
Any ideas on how to solve this?
thx in advanced :)
First you need to find out the length of the password. You do this by assessing the Index of Coincidence or Kappa-test. XOR the ciphertext with itself shifted 1 step and count the number of characters that are the same (value 0). You get the Kappa value by dividing the result with the total number of characters minus 1. Shift one more time and again calculate the Kappa value. Shift the ciphertext as many times as needed until you discover the password length. If the length is 4 you should see something similar to this:
Offset Hits
-------------------------
1 2.68695%
2 2.36399%
3 3.79009%
4 6.74012%
5 3.6953%
6 1.81582%
7 3.82744%
8 6.03504%
9 3.60273%
10 1.98052%
11 3.83241%
12 6.5627%
As you see the Kappa value is significantly higher on multiples of 4 (4, 8 and 12) than the others. This suggests that the length of the password is 4.
Now that you have the password length you should again XOR the cipher text with itself but now you shift by multiples of the length. Why? Since the ciphertext looks like this:
THISISTHEPLAINTEXT <- Plaintext
PASSPASSPASSPASSPA <- Password
------------------
EJKELDOSOSKDOWQLAG <- Ciphertext
When two values which are the same are XOR:ed the result is 0:
EJKELDOSOSKDOWQLAG <- Ciphertext
EJKELDOSOSKDOWQLAG <- Ciphertext shifted 4.
Is in reality:
THISISTHEPLAINTEXT <- Plaintext
PASSPASSPASSPASSPA <- Password
THISISTHEPLAINTEXT <- Plaintext
PASSPASSPASSPASSPA <- Password
Which is:
THISISTHEPLAINTEXT <- Plaintext
THISISTHEPLAINTEXT <- Plaintext
As you see the password "disappears" and the plaintext is XOR:ed with itself.
So what can we do now then? You wrote that the spaces are removed. This makes it a bit harder to get the plaintext or password. But not at all impossible.
The following table shows the ciphertext values for all english characters:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
A 0
B 3 0
C 2 1 0
D 5 6 7 0
E 4 7 6 1 0
F 7 4 5 2 3 0
G 6 5 4 3 2 1 0
H 9 10 11 12 13 14 15 0
I 8 11 10 13 12 15 14 1 0
J 11 8 9 14 15 12 13 2 3 0
K 10 9 8 15 14 13 12 3 2 1 0
L 13 14 15 8 9 10 11 4 5 6 7 0
M 12 15 14 9 8 11 10 5 4 7 6 1 0
N 15 12 13 10 11 8 9 6 7 4 5 2 3 0
O 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
P 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0
Q 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 1 0
R 19 16 17 22 23 20 21 26 27 24 25 30 31 28 29 2 3 0
S 18 17 16 23 22 21 20 27 26 25 24 31 30 29 28 3 2 1 0
T 21 22 23 16 17 18 19 28 29 30 31 24 25 26 27 4 5 6 7 0
U 20 23 22 17 16 19 18 29 28 31 30 25 24 27 26 5 4 7 6 1 0
V 23 20 21 18 19 16 17 30 31 28 29 26 27 24 25 6 7 4 5 2 3 0
W 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 7 6 5 4 3 2 1 0
X 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0
Y 24 27 26 29 28 31 30 17 16 19 18 21 20 23 22 9 8 11 10 13 12 15 14 1 0
Z 27 24 25 30 31 28 29 18 19 16 17 22 23 20 21 10 11 8 9 14 15 12 13 2 3 0
What does this mean then? If an A and a B is XOR:ed then the resulting value is 3. E and P will result in 21. Etc. OK but how will this help you?
Remember that the plaintext is XOR:ed with itself shifted by multiples of the password length. For each value you can check the above table and determine what combinations that position could have. Lets say the value is 25 then the two characters that resulted in the value 25 could be one of the following combinations:(I-P), (H-Q), (K-R), (J-S), (M-T), (L-U), (O-V), (N-W), (A-X) or (C-Z). But which one? Now you do more shifts and look up the corresponding values in the table again for each position. Next time the value might be 7 and since you already have a list of possible character combinations you only check against them. At the next two shifts the values are 3 and 1. Now you can determine that the character is W since that is the only common character in each shift, (N-W), (P-W), (T-W), (V-W). You can do this for most positions.
You will not get all the plaintext but you will get enough characters to discover the password. Take the known characters and XOR them in the correct position in the ciphertext. This will yield the password. The number of known characters you need atleast is the number of characters in the password if they are at the "correct" positions in regards to the password.
Good luck!
you should look at cracking a vigenere chiffre, especially at auto-correlation. The latter will help you finding out the length of the password and the rest is usually just bruteforcing on the normal distribution of letters (where the most common one is the letter e in the english language).
Although spaces are the most common characters and make decryptions like this easy, the other character also have different frequencies. For example, see this Wikipedia article. If you've got enough encrypted text and the password length isn't too large, it might just be enough to find out the most common bytes in the encrypted text. They will most likely be the encrypted versions of e that has the highest frequency in english texts.
This alone won't give you the decrypted text, but it's very likely you can find out the password length and (part of) the password itself with it. For example, let's assume the most frequent encrypted bytes are
w x m z y
with almost the same frequency and there's a significant drop in frequency after the last one. This will tell you two things:
The password length most likely is 5, because statistically, all encrypted e will be equally likely. EDIT: OK, this isn't correct, it will be 5 or above because the password can contain the same character multiple times.
The password will be some permutation of (w x m z y XOR e e e e e) - you can use the byte offsets modulo the password length to get the correct permutation.
EDIT: The same character occuring in the password multiple times makes things a bit harder, but you'll most likely be able to identify those because as I said, encrypted versions of e will cluster around frequency f - now if the character occurs n times, it will have a frequency near n*f.
The most common three letter trigram in English (assuming the language is probably English) is "the". Place "the" at all possible points on your cyphertext to derive a possible 3 characters of the key. Try each possible key fragment at all other possible positions on the cyphertext and see what you get. For example, "qzg" is unlikely to be correct, but "fen" could be. Look at the spacing between possible positions to derive the key length. With a key length and a key fragment you can place a lot more of the key.
As Lars said, look at ways of decrypting Vigenère, which is effectively what you have here.

need hint with a custom Linux/UNIX command line utlity "cal" in C

Ok I need to make this program to display "cal" 3 month(one month before and one month after) side by side, rather than just one single month it displays in any Linux/UNIX. I got it working to display 3 calendar by using "system(customCommand)" three times; but then it's not side by side.
I got some hint to use the following system calls:
close(..) pipe(..) dup2(..) read(..) and write(..)
my question is what should I start with? Do I need to create child process and than catch it in pipe(..)?
How can I display three calendar side by side.
ex.
February 2009 March 2009 April 2009
S M Tu W Th F S S M Tu W Th F S S M Tu W Th F S
1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4
8 9 10 11 12 13 14 8 9 10 11 12 13 14 5 6 7 8 9 10 11
15 16 17 18 19 20 21 15 16 17 18 19 20 21 12 13 14 15 16 17 18
22 23 24 25 26 27 28 22 23 24 25 26 27 28 19 20 21 22 23 24 25
29 30 31 26 27 28 29 30
Assuming you want to write it yourself instead of using "cal -3", what I'd do (in psuedo code):
popen three calls to "cal" with the appropriate args
while (at least one of the three pipes hasn't hit EOF yet)
{
read a line from the first if it isn't at EOF
pad the results out to a width W, print it
read a line from the second if it isn't at EOF
pad the results out to a width W, print it
read a line from the third if it isn't at EOF
print it
print "\n"
}
pclose all three.
if "cal -3" doesn't work, just use paste :)
$ TERM=linux setterm -regtabs 24
$ paste <(cal 2 2009) <(cal 3 2009) <(cal 4 2009)
febbraio 2009 marzo 2009 aprile 2009
do lu ma me gi ve sa do lu ma me gi ve sa do lu ma me gi ve sa
1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 2 3 4
8 9 10 11 12 13 14 8 9 10 11 12 13 14 5 6 7 8 9 10 11
15 16 17 18 19 20 21 15 16 17 18 19 20 21 12 13 14 15 16 17 18
22 23 24 25 26 27 28 22 23 24 25 26 27 28 19 20 21 22 23 24 25
29 30 31 26 27 28 29 30
$
(setterm ignores -regtabs unless TERM=linux or TERM=con.)
just do
cal -3
Does this not work?
cal -3
Ok, how about cal -3?
cal -3 12 2120 to make it a special month and year, with one before and one after.
The approach I would use for this would be to capture the output, split it into lines, and printf the lines out next to each other. I'd probably do it in Perl, though, rather than C.
Or just use cal -3, if your cal has it.

Resources