diff --git a/exercises1/Makefile b/exercises1/Makefile deleted file mode 100644 index 1301c3a..0000000 --- a/exercises1/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -BIN_FILES = p1 p2 p3 p4 p5 p6 p7 - -CC = gcc - -CPPFLAGS = -I$(INSTALL_PATH)/include -Wall - -LDFLAGS = -L$(INSTALL_PATH)/lib/ -LDLIBS = -lpthread - - -all: $(BIN_FILES) -.PHONY : all - - -p1: p1.o - $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -p2: p2.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -p3: p3.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -p4: p4.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -p5: p5.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -p6: p6.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -p7: p7.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -%.o: %.c - $(CC) $(CPPFLAGS) $(CFLAGS) -c $< - -clean: - rm -f $(BIN_FILES) *.o - -.SUFFIXES: -.PHONY : clean diff --git a/exercises1/p1.c b/exercises1/p1.c deleted file mode 100644 index e0bfa04..0000000 --- a/exercises1/p1.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define NUM_THREADS 2 -#define ITER 10 - -void funcion(int *id) { - int j; - int s; - double k; - int mid = *id; - for(j=0 ; j < ITER; j++) { - k = (double) rand_r((unsigned int *) &s) / RAND_MAX; - usleep((int) (k * 100000)); // sleep between 0 and 100 ms - printf("Thread %d iteration %d \n", mid, j ); - } - - pthread_exit(NULL); - -} - -int main(int argc, char *argv[]) -{ - int j; - pthread_attr_t attr; - pthread_t thid[NUM_THREADS]; - struct timeval t; - - gettimeofday(&t, NULL); - srand(t.tv_sec); // initialization of a random seed - - pthread_attr_init(&attr); - - for (j = 0; j < NUM_THREADS; j++) - if (pthread_create(&thid[j], NULL, (void *) funcion, &j) == -1){ - printf("Error creating threads\n"); - exit(0); - } - - for (j = 0; j < NUM_THREADS; j++) - pthread_join(thid[j], NULL); - - exit(0); - -} - - - - - diff --git a/exercises1/p6.c b/exercises1/p6.c deleted file mode 100644 index 1fb725d..0000000 --- a/exercises1/p6.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -#include -#include -#include - -#define BUF_SIZE 256 - -char buffer[BUF_SIZE]; -int n_elem = 0; - -void producer(int *f) { - char c; - int pos = 0; - - while (read (*f, &c, 1) >0) { - buffer[pos] = c; - pos = (pos + 1) % BUF_SIZE; - } - - pthread_exit(NULL); - -} - -void consumer(int *f){ - char c; - int pos = 0; - - for(;;) { - c = buffer[pos]; - pos = (pos + 1) % BUF_SIZE; - - - if (write(*f, &c, 1) < 0) { - printf("Error write \n"); - exit(0); - } - } - - pthread_exit(NULL); -} - -int main(int argc, char *argv[]) -{ - pthread_attr_t attr; - pthread_t thid[2]; - int fe, fs; - - - if (argc < 3) { - printf("Usage: %s \n", argv[0]); - exit(0); - } - - fe = open (argv[1], O_RDONLY); - if (fe < 0) { - printf("Error opening file %s\n", argv[1]); - exit(0); - } - - fs = creat (argv[2], 0700); - if (fs < 0) { - printf("Error creating file %s\n", argv[2]); - close(fe); - exit(0); - } - - pthread_attr_init(&attr); - - if (pthread_create(&thid[0], NULL, (void *) producer, &fe) == -1){ - printf("Error creating producer\n"); - exit(0); - } - - if (pthread_create(&thid[1], NULL, (void *) consumer, &fs) == -1){ - printf("Error creating consumer\n"); - exit(0); - } - - pthread_join(thid[0], NULL); - pthread_join(thid[1], NULL); - - close(fe); - close(fs); - - exit(0); - -} - - - - diff --git a/exercises1/p7.c b/exercises1/p7.c deleted file mode 100644 index 0ac2b44..0000000 --- a/exercises1/p7.c +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define NUM_READERS 10 -#define NUM_THREADS 11 // 10 readers and 1 writer -#define ITER 40 - -pthread_mutex_t mutex_writers; -pthread_mutex_t mutex_readers; -int num_readers; -int resource = 0; - -void reader(void) { - int j; - int s; - double k; - - for(j=0 ; j < ITER; j++) { - k = (double) rand_r((unsigned int *) &s) / RAND_MAX; - usleep((int) 1+(k * 6000000)); - - if (pthread_mutex_lock(&mutex_readers)!=0) - printf("....... Error in mutex lock 1 \n"); - num_readers++; - - if (num_readers == 1) { - printf("First %lu \n", (unsigned long int) pthread_self()); - pthread_mutex_lock(&mutex_writers); - } - - if (pthread_mutex_unlock(&mutex_readers)!=0) - printf("....... Error in mutex unlock 1 \n"); - - printf(" Executing reader %lu reads %d \n", (unsigned long int) pthread_self(), resource ); - - if (pthread_mutex_lock(&mutex_writers)!=0) - printf("....... Error in mutex lock 2 \n"); - num_readers--; - - if (num_readers == 0){ - printf("Last %lu \n", (unsigned long int) pthread_self()); - if( pthread_mutex_unlock(&mutex_writers) !=0) - printf("________________ Error in unlock\n"); - } - - if (pthread_mutex_unlock(&mutex_readers)!=0) - printf("....... Error in mutex unlock 2 \n"); - } - - pthread_exit(NULL); - -} - -void writer(void) { - int j; - int s; - double k; - - for(j=0 ; j < ITER; j++) { - k = (double) rand_r((unsigned int *) &s) / RAND_MAX; - usleep((int) 2 + (k * 5000000)); - - pthread_mutex_lock(&mutex_writers); - - resource = resource + 1; - printf(" Writer: New value %d\n", resource); - - pthread_mutex_unlock(&mutex_writers); - - } - - pthread_exit(NULL); - -} - -int main(int argc, char *argv[]) -{ - int j; - pthread_attr_t attr; - pthread_t thid[NUM_THREADS]; - struct timeval t; - pthread_mutexattr_t mattr; - - gettimeofday(&t, NULL); - srand(t.tv_sec); - - pthread_attr_init(&attr); - - pthread_mutexattr_init(&mattr); - pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ERRORCHECK); - - - pthread_mutex_init(&mutex_writers, &mattr); - pthread_mutex_init(&mutex_readers, &mattr); - - - for (j = 0; j < NUM_READERS; j++) - if (pthread_create(&thid[j], NULL, (void *) reader, NULL) == -1){ - printf("Error creating a reader\n"); - exit(0); - } - if (pthread_create(&thid[j], NULL, (void *) writer, NULL) == -1){ - printf("Error creating a writer\n"); - exit(0); - } - - for (j = 0; j < NUM_THREADS; j++) - pthread_join(thid[j], NULL); - - exit(0); - -} - - - - diff --git a/exercises2/client.c b/exercises2/client.c deleted file mode 100644 index e69de29..0000000 diff --git a/exercises2/read_line.o b/exercises2/read_line.o deleted file mode 100644 index 2761ee7..0000000 Binary files a/exercises2/read_line.o and /dev/null differ diff --git a/exercises2/server.c b/exercises2/server.c deleted file mode 100644 index e69de29..0000000 diff --git a/exercises2/test b/exercises2/test deleted file mode 100755 index 223e012..0000000 Binary files a/exercises2/test and /dev/null differ diff --git a/exercises2/test.c b/exercises2/test.c deleted file mode 100644 index 68979d3..0000000 --- a/exercises2/test.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include "read_line.h" - -#define MAX_LINE 256 - - - -int main(int argc, char **argv) -{ - char buffer[MAX_LINE]; - int err = 0; - int n; - - - while (err != -1) { - n = readLine(0, buffer, MAX_LINE); - if (n!=-1) - write(1, buffer, n); - } - - exit(0); -} - - diff --git a/exercises2/test.o b/exercises2/test.o deleted file mode 100644 index fffe833..0000000 Binary files a/exercises2/test.o and /dev/null differ diff --git a/ssdd_p1_100291121_100292107.zip b/ssdd_p1_100291121_100292107.zip new file mode 100644 index 0000000..396ca08 Binary files /dev/null and b/ssdd_p1_100291121_100292107.zip differ diff --git a/exercises2/Makefile b/ssdd_p1_100291121_100292107/Makefile similarity index 59% rename from exercises2/Makefile rename to ssdd_p1_100291121_100292107/Makefile index e0f3b2f..3a28c57 100644 --- a/exercises2/Makefile +++ b/ssdd_p1_100291121_100292107/Makefile @@ -1,4 +1,4 @@ -BIN_FILES = test client server +BIN_FILES = server CC = gcc @@ -13,13 +13,7 @@ all: CFLAGS=$(CCGLAGS) all: $(BIN_FILES) .PHONY : all -test: test.o read_line.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -client: client.o read_line.o - $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ - -server: server.o read_line.o +server: server.o read_line.o user_list.o msg_list.o $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ %.o: %.c diff --git a/ssdd_p1_100291121_100292107/authors.txt b/ssdd_p1_100291121_100292107/authors.txt new file mode 100644 index 0000000..f5b361b --- /dev/null +++ b/ssdd_p1_100291121_100292107/authors.txt @@ -0,0 +1,2 @@ +GUTIÉRREZ PARADELA, CARLOS 100291121 GROUP 89 +LÓPEZ LOZOYA, RUBÉN 100292107 GROUP 89 \ No newline at end of file diff --git a/ssdd_p1_100291121_100292107/client.java b/ssdd_p1_100291121_100292107/client.java new file mode 100644 index 0000000..11d9e02 --- /dev/null +++ b/ssdd_p1_100291121_100292107/client.java @@ -0,0 +1,711 @@ +import java.io.*; +import gnu.getopt.Getopt; +import java.net.Socket; +import java.net.ServerSocket; + + +class client { + + /********************* TYPES **********************/ + + /** + * @brief Return codes for the protocol methods + */ + private static enum RC { + OK, + ERROR, + USER_ERROR + }; + + /******************* ATTRIBUTES *******************/ + + private static String _server = null; + private static int _port = -1; + /* Controls the user bound to the client when executing a CONNECT command */ + private static String connected_user = null; + /* Instantiate and prepare an empty ServerThread for further connection */ + private static ServerThread server_thread = new ServerThread(); + + + /********************* METHODS ********************/ + + /** + * @param user - User name to register in the system + * + * @return OK if successful + * @return USER_ERROR if the user is already registered + * @return ERROR if another error occurred + */ + static RC register(String user) + { + // Write your code here + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + //2. The string "REGISTER" is sent indicating the operation + String operation = new String("REGISTER"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user to be registered + out.writeBytes(user); + out.write(0); + + //4. Check response from the server. If 0, success; if 1 user is previously registered; if 2 other case + byte response = in.readByte(); + + //5. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + System.out.println("c> REGISTER OK"); + return RC.OK; + case 1: + System.out.println("c> USERNAME IN USE"); + return RC.USER_ERROR; + case 2: + System.out.println("c> REGISTER FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + System.out.println("c> REGISTER FAIL"); + return RC.ERROR; + } + + /** + * @param user - User name to unregister from the system + * + * @return OK if successful + * @return USER_ERROR if the user does not exist + * @return ERROR if another error occurred + */ + static RC unregister(String user) + { + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + //2. The string "UNREGISTER" is sent indicating the operation + String operation = new String("UNREGISTER"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user to be unregistered + out.writeBytes(user); + out.write(0); + + //4. Check response from the server. If 0, success; if 1 user does not exist; if 2 other case + byte response = in.readByte(); + + //5. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + /* If we try to unregister the user that is currently bound and connected + to the client, it is unbound from the client */ + if(connected_user != null){ + /* This protects against null pointer exception when a CONNECT command is executed and + the server marks the user as connected, but then the client is terminated without + executing DISCONNECT from the server */ + if(connected_user.equals(user)){ + connected_user = null; + /* If the unregister also disconnect a user linked to the client (connected and with a + server thread running, kill also the running thread*/ + server_thread.kill(); + } + } + + System.out.println("c> UNREGISTER OK"); + return RC.OK; + case 1: + System.out.println("c> USER DOES NOT EXIST"); + return RC.USER_ERROR; + case 2: + System.out.println("c> UNREGISTER FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + System.out.println("c> UNREGISTER FAIL"); + return RC.ERROR; + } + + /** + * @param user - User name to connect to the system + * + * @return OK if successful + * @return USER_ERROR if the user does not exist or if it is already connected + * @return ERROR if another error occurred + */ + static RC connect(String user) + { + + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + /* Before trying to connect, if a user is already connected, quit the function with RC.ERROR */ + if(connected_user != null){ + System.out.println("c> CONNECT FAIL"); + return RC.ERROR; + } + + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + //2. The string "CONNECT" is sent indicating the operation + String operation = new String("CONNECT"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user to be connected + out.writeBytes(user); + out.write(0); + + /* Create ServerSocket. We provide 0 to assign any available port number and 10 as maximum + number of queued requests */ + ServerSocket sock = new ServerSocket(0, 10); + /* Get the port at which the socket is listening */ + int port = sock.getLocalPort(); + + //4. A string is sent with the port number listening in the client + out.writeBytes(String.valueOf(port)); + out.write(0); + + //5. Check response from the server. If 0, success; if 1 user does not exist; if 2 other case + byte response = in.readByte(); + + //6. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + /* Start a new thread where */ + server_thread.start(sock); + /* Bind the user to the client */ + connected_user = user; + System.out.println("c> CONNECT OK"); + return RC.OK; + case 1: + System.out.println("c> CONNECT FAIL, USER DOES NOT EXIST"); + return RC.USER_ERROR; + case 2: + System.out.println("c> USER ALREADY CONNECTED"); + return RC.USER_ERROR; + case 3: + System.out.println("c> CONNECT FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + System.out.println("c> CONNECT FAIL"); + return RC.ERROR; + } + + /** + * @param user - User name to disconnect from the system + * + * @return OK if successful + * @return USER_ERROR if the user does not exist or if it is already disconnected + * @return ERROR if another error occurred + */ + static RC disconnect(String user) + { + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + //2. The string "DISCONNECT" is sent indicating the operation + String operation = new String("DISCONNECT"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user to be disconnected + out.writeBytes(user); + out.write(0); + + //4. Check response from the server. If 0, success; if 1 user does not exist; if 2 other case + byte response = in.readByte(); + + //5. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + /* Unbind the user from the client */ + connected_user = null; + server_thread.kill(); + System.out.println("c> DISCONNECT OK"); + return RC.OK; + case 1: + System.out.println("c> DISCONNECT FAIL / USER DOES NOT EXIST"); + return RC.USER_ERROR; + case 2: + System.out.println("c> DISCONNECT FAIL / USER NOT CONNECTED"); + return RC.USER_ERROR; + case 3: + /* In case of error in the disconnection process, stop the execution of the thread + and unbind the user from the client as if the disconnection has been made. But if the + disconnect command executed was not executed for the user that is bound to the client + then nothing is done */ + if(connected_user != null){ + /* Check if the user coincides with the linked user */ + if(connected_user.equals(user)){ + connected_user = null; + server_thread.kill(); + } + } + System.out.println("c> DISCONNECT FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + /* In case of error in the disconnection process, stop the execution of the thread + and unbind the user from the client as if the disconnection has been made. But if the + disconnect command executed was not executed for the user that is bound to the client + then nothing is done */ + if(connected_user != null){ + /* Check if the user coincides with the linked user */ + if(connected_user.equals(user)){ + connected_user = null; + server_thread.kill(); + } + } + System.out.println("c> DISCONNECT FAIL"); + return RC.ERROR; + } + + /** + * @param user - Receiver user name + * @param message - Message to be sent + * + * @return OK if the server had successfully delivered the message + * @return USER_ERROR if the user is not connected (the message is queued for delivery) + * @return ERROR the user does not exist or another error occurred + */ + static RC send(String user, String message) + { + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + /* If there is not a user connected in the client, return error RC.ERROR */ + if(connected_user == null){ + System.out.println("c> SEND FAIL"); + return RC.ERROR; + } + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + + //2. The string "SEND" is sent indicating the operation + String operation = new String("SEND"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user that sends the message + out.writeBytes(connected_user); + out.write(0); + + //4. A string of characters is sent with the user that receives the message + out.writeBytes(user); + out.write(0); + + //5. A string of maximum 256 (including ASCII 0) characters is sent with the message to be sent + out.writeBytes(trimMessage(message)); //Sends a string of 255 characters + out.write(0); + + //6. Check response from the server. If 0, success; if 1 user does not exist; if 2 other case + byte response = in.readByte(); + + String msg_id = new String(); + /* If response is 0 (OK), prepare to read the ID of the message */ + if(response == 0){ + + /* Create BufferedReader for easy reading a string */ + /* + BufferedReader inString = new BufferedReader(new InputStreamReader(sc.getInputStream())); + msg_id = inString.readLine();*/ + byte ch; + do{ + ch = in.readByte(); + if (ch != 0) msg_id = msg_id + ((char) ch); + } while(ch != 0); + } + + //7. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + System.out.println("c> SEND OK - MESSAGE " + msg_id); + return RC.OK; + case 1: + System.out.println("c> SEND FAIL / USER DOES NOT EXIST"); + return RC.USER_ERROR; + case 2: + System.out.println("c> SEND FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + System.out.println("c> SEND FAIL"); + return RC.ERROR; + } + /** + * @brief Trims the input message to 255 characters + * + * @param message - String to be trimmed + * + * @return message - Result String + */ + static String trimMessage(String message){ + /* Maximum length is of 255 characters because 1 character is reserved for ASCII 0 */ + int maxLength = 255; + + if(message.length() > maxLength){ + message = message.substring(0, maxLength); + } + + return message; + } + + /** + * @brief Command interpreter for the client. It calls the protocol functions. + */ + static void shell() + { + boolean exit = false; + String input; + String [] line; + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + + while (!exit) { + try { + System.out.print("c> "); + input = in.readLine(); + line = input.split("\\s"); + + if (line.length > 0) { + /*********** REGISTER *************/ + if (line[0].equals("REGISTER")) { + if (line.length == 2) { + register(line[1]); // userName = line[1] + } else { + System.out.println("Syntax error. Usage: REGISTER "); + } + } + + /********** UNREGISTER ************/ + else if (line[0].equals("UNREGISTER")) { + if (line.length == 2) { + unregister(line[1]); // userName = line[1] + } else { + System.out.println("Syntax error. Usage: UNREGISTER "); + } + } + + /************ CONNECT *************/ + else if (line[0].equals("CONNECT")) { + if (line.length == 2) { + connect(line[1]); // userName = line[1] AQUI CREAMOS EL HILO SERVIDOR + } else { + System.out.println("Syntax error. Usage: CONNECT "); + } + } + + /********** DISCONNECT ************/ + else if (line[0].equals("DISCONNECT")) { + if (line.length == 2) { + disconnect(line[1]); // userName = line[1] + } else { + System.out.println("Syntax error. Usage: DISCONNECT "); + } + } + + /************** SEND **************/ + else if (line[0].equals("SEND")) { + if (line.length >= 3) { + // Remove first two words + String message = input.substring(input.indexOf(' ')+1); + message = message.substring(message.indexOf(' ')+1); + send(line[1], message); // userName = line[1] + } else { + System.out.println("Syntax error. Usage: SEND "); + } + } + + /************** QUIT **************/ + else if (line[0].equals("QUIT")){ + if (line.length == 1) { + exit = true; + } else { + System.out.println("Syntax error. Use: QUIT"); + } + } + + /************* UNKNOWN ************/ + else { + System.out.println("Error: command '" + line[0] + "' not valid."); + } + } + } catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + } + } + + /** + * @brief Prints program usage + */ + static void usage() + { + System.out.println("Usage: java -cp . client -s -p "); + } + + /** + * @brief Parses program execution arguments + */ + static boolean parseArguments(String [] argv) + { + Getopt g = new Getopt("client", argv, "ds:p:"); + + int c; + String arg; + + while ((c = g.getopt()) != -1) { + switch(c) { + //case 'd': + // _debug = true; + // break; + case 's': + _server = g.getOptarg(); + break; + case 'p': + arg = g.getOptarg(); + _port = Integer.parseInt(arg); + break; + case '?': + System.out.print("getopt() returned " + c + "\n"); + break; // getopt() already printed an error + default: + System.out.print("getopt() returned " + c + "\n"); + } + } + + if (_server == null) + return false; + + if ((_port < 1024) || (_port > 65535)) { + System.out.println("Error: Port must be in the range 1024 <= port <= 65535"); + return false; + } + + return true; + } + + + + /********************* MAIN **********************/ + + public static void main(String[] argv) + { + if(!parseArguments(argv)) { + usage(); + return; + } + + /* Creates a thread that catches Ctrl+C kill command from the CLI and disconnects from the server the + connected user of the client (bound to the client) */ + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + if(connected_user != null){ + disconnect(connected_user); + } + } + }); + + shell(); + System.out.println("+++ FINISHED +++"); + } +} + +/********************* SERVERTHREAD **********************/ + +class ServerThread extends Thread{ + + private ServerSocket sc; //ServerSocket of the listening thread + private volatile Thread blinker; //Thread of type volatile that will be attached to the ServerThread + private Socket sd; + + /** + * @brief Constructor. Starts the server thread and initializes the ServerSocket property + * + * @param sc - Initialized ServerSocket + * + */ + public void start(ServerSocket sc){ + blinker = new Thread(this); + blinker.start(); + this.sc = sc; + } + + /** + * @brief Destroys the server thread + */ + public void kill(){ + try{ + this.sd.close(); + } + catch(IOException e){ + System.out.println("Exception: " + e); + } + blinker = null; + } + + /** + * @brief Main execution code sequence of the server thread. Listens to incoming connections + */ + public void run(){ + Thread thisThread = Thread.currentThread(); + sd = null; + while(blinker == thisThread){ + try{ + /* Waiting for connection */ + sd = this.sc.accept(); + + DataInputStream msg_in = new DataInputStream(sd.getInputStream()); + /* Receive the string encoding the operation */ + String operation = new String(); + byte ch; + do{ + ch = msg_in.readByte(); + if (ch != 0) operation = operation + ((char) ch); + + } while(ch != 0); + /* Prepare the string for the ID of the message sent/received */ + String id = new String(); + + switch(operation){ + case "SEND_MESSAGE": + /* Read the sender username from the socket */ + String sender = new String(); + do{ + ch = msg_in.readByte(); + if (ch != 0) sender = sender + ((char) ch); + + } while(ch != 0); + /* Read the ID of the received message */ + do{ + ch = msg_in.readByte(); + if (ch != 0) id = id + ((char) ch); + } while(ch != 0); + /* Read the string containing the body of the message */ + String msg = new String(); + do{ + ch = msg_in.readByte(); + if (ch != 0) msg = msg + ((char) ch); + + } while(ch != 0); + /* Prompt */ + System.out.println("MESSAGE " + id + " FROM " + sender + ":"); + System.out.println("\t" + msg); + System.out.println("END"); + System.out.print("c> "); + break; + + case "SEND_MESS_ACK": + /* Read the id of the message being acknowledged */ + do{ + ch = msg_in.readByte(); + if (ch != 0) id = id + ((char) ch); + } while(ch != 0); + + System.out.println("SEND MESSAGE " + id + " OK"); + System.out.print("c> "); + break; + } + sd.close(); + + } + catch(Exception e){ + System.out.println("Exception: " + e); + //e.printStackTrace(); + this.kill(); + } + } + /* If the thread exits the loop for any reason, try to close the socket */ + try{ + sd.close(); + } + catch(Exception e){ + System.out.println("Exception: " + e); + this.kill(); + } + } +} diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/COPYING.LIB b/ssdd_p1_100291121_100292107/gnu/getopt/COPYING.LIB new file mode 100755 index 0000000..161a3d1 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/ChangeLog b/ssdd_p1_100291121_100292107/gnu/getopt/ChangeLog new file mode 100755 index 0000000..7fed6d2 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/ChangeLog @@ -0,0 +1,114 @@ +For release 1.0.14 (2012/02/08) + +David Zhang (david290@qq.com) provided Chinese language messages. +Daniel Thomas (drt24@srcf.ucam.org) contributed a patch to fix a static +access warning message. + +For release 1.0.13 (2006/08/29) + +Krzysztof Szymanski (sirch.s@gmail.com) provided Polish language messages. + +For release 1.0.12 (2005/11/12) + +Sandro Tossi (matrixhasu@gmail.com) provided Italian language messages. + +For release 1.0.11 (2005/02/19) + +Daniel Perez Alvarez (dondani@gmail.com) provided Spanish language +messages. + +For release 1.0.10 (2004/09/12) + +Marian-Nicolae V. Ion (mion@neocom.fr) provided Romanian language messages. + +For release 1.0.9 (2002/01/16) + +Yasuoka Masahiko provided Japanese langauge messages. + +Csom Gyula provided Hungarian language messages. + +Guillaume Rousse supplied the ant build file +and documentation. + +For release 1.0.8 (2000/09/11) + +Ernst de Haan provided Dutch language messages. + +For release 1.0.7 (2000/02/02) + +Fixed an obscure POSIX compatibility issue. When an optstring is "o:", +then "-o -- foo" should result in -o having an optarg of "foo", not "--" +as was previously returned. This new parsing behavior is only enabled +in POSIX compatibility mode. Thank to Don Suit (dsuit@fc.hp.com) for +reporting this and help in communicating proper POSIX behavior. + +For release 1.0.6 (1999/06/27) + +Added French language messages. Thanks to Edouard G. Parmelan +(Edouard.Parmelan@quadratec.fr) for this contribution. + +For release 1.0.5 (1999/03/23) + +Fixed bug that caused getopt to throw a StringIndexOutOfBoundsException +when an empty string ("") argument was encountered. Thanks to +Steffen Siebert (siebert@logware.de) for this bug report and a patch. + +For release 1.0.4 + +Added Norwegian language messages. Thanks to Bjrn-Ove Heimsund +(s811@drone.ii.uib.no) for this contribution. + +For release 1.0.3 + +Added German language messages. Thanks to Bernhard Bablok +(bablokb@gmx.net) for this contribution. + +For release 1.0.2 + +Prevent ArrayIndexOutOfBounds exception if "optstring" is null. David Karr +(dkarr@nmo.gtegsc.com) had a problem with this when commenting out options +during debugging, so I have fixed it. + +For release 1.0.1 + +Added Czech language messages. Thanks to Roman Szturc (Roman.Szturc@vsb.cz) +for this contribution. + +For release 1.0 + +No changes. Just increment release number to 1.0 + +For release 0.9.2 + +The sample code has been moved into a separate file called "GetoptDemo.java". +This is so that it can be legally placed into the public domain and not +subsumed into the LGPL as would be the case if it were in Getopt.java. +While I do not encourage anyone to write proprietary software, I feel that +there is no good purpose served in restricting what someone can do with +a short example program. + +Modified the Makefile and various other files to support the change +above. + +For release 0.9.1 + +This release contains only minor fixes. It's always possible it introduces +some bugs though so unless you are keen on internationalization or are +having a line separator problem, there is no need to upgrade from 0.9. + +-- Messages are now internationalized. Thanks to Bill King + (wrking@eng.sun.com) for this. + +-- Changes all print's to println's to avoid system dependent line + separators. + +-- All internal variables are now protected. Several people suggested + doing this in response to my request for comments in the help file. + No one suggested keeping any variables public. + +-- Fixed parts of licensing that mentioned the regular GPL. Getopt is + and always has been licensed under the LPGL. Thanks to Arieh Markel + (arieh.markel@sun.com) for pointing this out. + + + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/Getopt.class b/ssdd_p1_100291121_100292107/gnu/getopt/Getopt.class new file mode 100755 index 0000000..735a7f1 Binary files /dev/null and b/ssdd_p1_100291121_100292107/gnu/getopt/Getopt.class differ diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/Getopt.java b/ssdd_p1_100291121_100292107/gnu/getopt/Getopt.java new file mode 100755 index 0000000..429301b --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/Getopt.java @@ -0,0 +1,1337 @@ +/************************************************************************** +/* Getopt.java -- Java port of GNU getopt from glibc 2.0.6 +/* +/* Copyright (c) 1987-1997 Free Software Foundation, Inc. +/* Java Port Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +package gnu.getopt; + +import java.util.Locale; +import java.util.ResourceBundle; +import java.text.MessageFormat; + +/**************************************************************************/ + +/** + * This is a Java port of GNU getopt, a class for parsing command line + * arguments passed to programs. It it based on the C getopt() functions + * in glibc 2.0.6 and should parse options in a 100% compatible manner. + * If it does not, that is a bug. The programmer's interface is also + * very compatible. + *

+ * To use Getopt, create a Getopt object with a argv array passed to the + * main method, then call the getopt() method in a loop. It will return an + * int that contains the value of the option character parsed from the + * command line. When there are no more options to be parsed, it + * returns -1. + *

+ * A command line option can be defined to take an argument. If an + * option has an argument, the value of that argument is stored in an + * instance variable called optarg, which can be accessed using the + * getOptarg() method. If an option that requires an argument is + * found, but there is no argument present, then an error message is + * printed. Normally getopt() returns a '?' in this situation, but + * that can be changed as described below. + *

+ * If an invalid option is encountered, an error message is printed + * to the standard error and getopt() returns a '?'. The value of the + * invalid option encountered is stored in the instance variable optopt + * which can be retrieved using the getOptopt() method. To suppress + * the printing of error messages for this or any other error, set + * the value of the opterr instance variable to false using the + * setOpterr() method. + *

+ * Between calls to getopt(), the instance variable optind is used to + * keep track of where the object is in the parsing process. After all + * options have been returned, optind is the index in argv of the first + * non-option argument. This variable can be accessed with the getOptind() + * method. + *

+ * Note that this object expects command line options to be passed in the + * traditional Unix manner. That is, proceeded by a '-' character. + * Multiple options can follow the '-'. For example "-abc" is equivalent + * to "-a -b -c". If an option takes a required argument, the value + * of the argument can immediately follow the option character or be + * present in the next argv element. For example, "-cfoo" and "-c foo" + * both represent an option character of 'c' with an argument of "foo" + * assuming c takes a required argument. If an option takes an argument + * that is not required, then any argument must immediately follow the + * option character in the same argv element. For example, if c takes + * a non-required argument, then "-cfoo" represents option character 'c' + * with an argument of "foo" while "-c foo" represents the option + * character 'c' with no argument, and a first non-option argv element + * of "foo". + *

+ * The user can stop getopt() from scanning any further into a command line + * by using the special argument "--" by itself. For example: + * "-a -- -d" would return an option character of 'a', then return -1 + * The "--" is discarded and "-d" is pointed to by optind as the first + * non-option argv element. + *

+ * Here is a basic example of using Getopt: + *

+ *

+  * Getopt g = new Getopt("testprog", argv, "ab:c::d");
+  * //
+  * int c;
+  * String arg;
+  * while ((c = g.getopt()) != -1)
+  *   {
+  *     switch(c)
+  *       {
+  *          case 'a':
+  *          case 'd':
+  *            System.out.print("You picked " + (char)c + "\n");
+  *            break;
+  *            //
+  *          case 'b':
+  *          case 'c':
+  *            arg = g.getOptarg();
+  *            System.out.print("You picked " + (char)c + 
+  *                             " with an argument of " +
+  *                             ((arg != null) ? arg : "null") + "\n");
+  *            break;
+  *            //
+  *          case '?':
+  *            break; // getopt() already printed an error
+  *            //
+  *          default:
+  *            System.out.print("getopt() returned " + c + "\n");
+  *       }
+  *   }
+  * 
+ *

+ * In this example, a new Getopt object is created with three params. + * The first param is the program name. This is for printing error + * messages in the form "program: error message". In the C version, this + * value is taken from argv[0], but in Java the program name is not passed + * in that element, thus the need for this parameter. The second param is + * the argument list that was passed to the main() method. The third + * param is the list of valid options. Each character represents a valid + * option. If the character is followed by a single colon, then that + * option has a required argument. If the character is followed by two + * colons, then that option has an argument that is not required. + *

+ * Note in this example that the value returned from getopt() is cast to + * a char prior to printing. This is required in order to make the value + * display correctly as a character instead of an integer. + *

+ * If the first character in the option string is a colon, for example + * ":abc::d", then getopt() will return a ':' instead of a '?' when it + * encounters an option with a missing required argument. This allows the + * caller to distinguish between invalid options and valid options that + * are simply incomplete. + *

+ * In the traditional Unix getopt(), -1 is returned when the first non-option + * charcter is encountered. In GNU getopt(), the default behavior is to + * allow options to appear anywhere on the command line. The getopt() + * method permutes the argument to make it appear to the caller that all + * options were at the beginning of the command line, and all non-options + * were at the end. For example, calling getopt() with command line args + * of "-a foo bar -d" returns options 'a' and 'd', then sets optind to + * point to "foo". The program would read the last two argv elements as + * "foo" and "bar", just as if the user had typed "-a -d foo bar". + *

+ * The user can force getopt() to stop scanning the command line with + * the special argument "--" by itself. Any elements occuring before the + * "--" are scanned and permuted as normal. Any elements after the "--" + * are returned as is as non-option argv elements. For example, + * "foo -a -- bar -d" would return option 'a' then -1. optind would point + * to "foo", "bar" and "-d" as the non-option argv elements. The "--" + * is discarded by getopt(). + *

+ * There are two ways this default behavior can be modified. The first is + * to specify traditional Unix getopt() behavior (which is also POSIX + * behavior) in which scanning stops when the first non-option argument + * encountered. (Thus "-a foo bar -d" would return 'a' as an option and + * have "foo", "bar", and "-d" as non-option elements). The second is to + * allow options anywhere, but to return all elements in the order they + * occur on the command line. When a non-option element is ecountered, + * an integer 1 is returned and the value of the non-option element is + * stored in optarg is if it were the argument to that option. For + * example, "-a foo -d", returns first 'a', then 1 (with optarg set to + * "foo") then 'd' then -1. When this "return in order" functionality + * is enabled, the only way to stop getopt() from scanning all command + * line elements is to use the special "--" string by itself as described + * above. An example is "-a foo -b -- bar", which would return 'a', then + * integer 1 with optarg set to "foo", then 'b', then -1. optind would + * then point to "bar" as the first non-option argv element. The "--" + * is discarded. + *

+ * The POSIX/traditional behavior is enabled by either setting the + * property "gnu.posixly_correct" or by putting a '+' sign as the first + * character of the option string. The difference between the two + * methods is that setting the gnu.posixly_correct property also forces + * certain error messages to be displayed in POSIX format. To enable + * the "return in order" functionality, put a '-' as the first character + * of the option string. Note that after determining the proper + * behavior, Getopt strips this leading '+' or '-', meaning that a ':' + * placed as the second character after one of those two will still cause + * getopt() to return a ':' instead of a '?' if a required option + * argument is missing. + *

+ * In addition to traditional single character options, GNU Getopt also + * supports long options. These are preceeded by a "--" sequence and + * can be as long as desired. Long options provide a more user-friendly + * way of entering command line options. For example, in addition to a + * "-h" for help, a program could support also "--help". + *

+ * Like short options, long options can also take a required or non-required + * argument. Required arguments can either be specified by placing an + * equals sign after the option name, then the argument, or by putting the + * argument in the next argv element. For example: "--outputdir=foo" and + * "--outputdir foo" both represent an option of "outputdir" with an + * argument of "foo", assuming that outputdir takes a required argument. + * If a long option takes a non-required argument, then the equals sign + * form must be used to specify the argument. In this case, + * "--outputdir=foo" would represent option outputdir with an argument of + * "foo" while "--outputdir foo" would represent the option outputdir + * with no argument and a first non-option argv element of "foo". + *

+ * Long options can also be specified using a special POSIX argument + * format (one that I highly discourage). This form of entry is + * enabled by placing a "W;" (yes, 'W' then a semi-colon) in the valid + * option string. This causes getopt to treat the name following the + * "-W" as the name of the long option. For example, "-W outputdir=foo" + * would be equivalent to "--outputdir=foo". The name can immediately + * follow the "-W" like so: "-Woutputdir=foo". Option arguments are + * handled identically to normal long options. If a string follows the + * "-W" that does not represent a valid long option, then getopt() returns + * 'W' and the caller must decide what to do. Otherwise getopt() returns + * a long option value as described below. + *

+ * While long options offer convenience, they can also be tedious to type + * in full. So it is permissible to abbreviate the option name to as + * few characters as required to uniquely identify it. If the name can + * represent multiple long options, then an error message is printed and + * getopt() returns a '?'. + *

+ * If an invalid option is specified or a required option argument is + * missing, getopt() prints an error and returns a '?' or ':' exactly + * as for short options. Note that when an invalid long option is + * encountered, the optopt variable is set to integer 0 and so cannot + * be used to identify the incorrect option the user entered. + *

+ * Long options are defined by LongOpt objects. These objects are created + * with a contructor that takes four params: a String representing the + * object name, a integer specifying what arguments the option takes + * (the value is one of LongOpt.NO_ARGUMENT, LongOpt.REQUIRED_ARGUMENT, + * or LongOpt.OPTIONAL_ARGUMENT), a StringBuffer flag object (described + * below), and an integer value (described below). + *

+ * To enable long option parsing, create an array of LongOpt's representing + * the legal options and pass it to the Getopt() constructor. WARNING: If + * all elements of the array are not populated with LongOpt objects, the + * getopt() method will throw a NullPointerException. + *

+ * When getopt() is called and a long option is encountered, one of two + * things can be returned. If the flag field in the LongOpt object + * representing the long option is non-null, then the integer value field + * is stored there and an integer 0 is returned to the caller. The val + * field can then be retrieved from the flag field. Note that since the + * flag field is a StringBuffer, the appropriate String to integer converions + * must be performed in order to get the actual int value stored there. + * If the flag field in the LongOpt object is null, then the value field + * of the LongOpt is returned. This can be the character of a short option. + * This allows an app to have both a long and short option sequence + * (say, "-h" and "--help") that do the exact same thing. + *

+ * With long options, there is an alternative method of determining + * which option was selected. The method getLongind() will return the + * the index in the long option array (NOT argv) of the long option found. + * So if multiple long options are configured to return the same value, + * the application can use getLongind() to distinguish between them. + *

+ * Here is an expanded Getopt example using long options and various + * techniques described above: + *

+ *

+  * int c;
+  * String arg;
+  * LongOpt[] longopts = new LongOpt[3];
+  * // 
+  * StringBuffer sb = new StringBuffer();
+  * longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h');
+  * longopts[1] = new LongOpt("outputdir", LongOpt.REQUIRED_ARGUMENT, sb, 'o'); 
+  * longopts[2] = new LongOpt("maximum", LongOpt.OPTIONAL_ARGUMENT, null, 2);
+  * // 
+  * Getopt g = new Getopt("testprog", argv, "-:bc::d:hW;", longopts);
+  * g.setOpterr(false); // We'll do our own error handling
+  * //
+  * while ((c = g.getopt()) != -1)
+  *   switch (c)
+  *     {
+  *        case 0:
+  *          arg = g.getOptarg();
+  *          System.out.println("Got long option with value '" +
+  *                             (char)(new Integer(sb.toString())).intValue()
+  *                             + "' with argument " +
+  *                             ((arg != null) ? arg : "null"));
+  *          break;
+  *          //
+  *        case 1:
+  *          System.out.println("I see you have return in order set and that " +
+  *                             "a non-option argv element was just found " +
+  *                             "with the value '" + g.getOptarg() + "'");
+  *          break;
+  *          //
+  *        case 2:
+  *          arg = g.getOptarg();
+  *          System.out.println("I know this, but pretend I didn't");
+  *          System.out.println("We picked option " +
+  *                             longopts[g.getLongind()].getName() +
+  *                           " with value " + 
+  *                           ((arg != null) ? arg : "null"));
+  *          break;
+  *          //
+  *        case 'b':
+  *          System.out.println("You picked plain old option " + (char)c);
+  *          break;
+  *          //
+  *        case 'c':
+  *        case 'd':
+  *          arg = g.getOptarg();
+  *          System.out.println("You picked option '" + (char)c + 
+  *                             "' with argument " +
+  *                             ((arg != null) ? arg : "null"));
+  *          break;
+  *          //
+  *        case 'h':
+  *          System.out.println("I see you asked for help");
+  *          break;
+  *          //
+  *        case 'W':
+  *          System.out.println("Hmmm. You tried a -W with an incorrect long " +
+  *                             "option name");
+  *          break;
+  *          //
+  *        case ':':
+  *          System.out.println("Doh! You need an argument for option " +
+  *                             (char)g.getOptopt());
+  *          break;
+  *          //
+  *        case '?':
+  *          System.out.println("The option '" + (char)g.getOptopt() + 
+  *                           "' is not valid");
+  *          break;
+  *          //
+  *        default:
+  *          System.out.println("getopt() returned " + c);
+  *          break;
+  *     }
+  * //
+  * for (int i = g.getOptind(); i < argv.length ; i++)
+  *   System.out.println("Non option argv element: " + argv[i] + "\n");
+  * 
+ *

+ * There is an alternative form of the constructor used for long options + * above. This takes a trailing boolean flag. If set to false, Getopt + * performs identically to the example, but if the boolean flag is true + * then long options are allowed to start with a single '-' instead of + * "--". If the first character of the option is a valid short option + * character, then the option is treated as if it were the short option. + * Otherwise it behaves as if the option is a long option. Note that + * the name given to this option - long_only - is very counter-intuitive. + * It does not cause only long options to be parsed but instead enables + * the behavior described above. + *

+ * Note that the functionality and variable names used are driven from + * the C lib version as this object is a port of the C code, not a + * new implementation. This should aid in porting existing C/C++ code, + * as well as helping programmers familiar with the glibc version to + * adapt to the Java version even if it seems very non-Java at times. + *

+ * In this release I made all instance variables protected due to + * overwhelming public demand. Any code which relied on optarg, + * opterr, optind, or optopt being public will need to be modified to + * use the appropriate access methods. + *

+ * Please send all bug reports, requests, and comments to + * arenn@urbanophile.com. + * + * @version 1.0.7 + * + * @author Roland McGrath (roland@gnu.ai.mit.edu) + * @author Ulrich Drepper (drepper@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @see LongOpt + */ +public class Getopt extends Object +{ + +/**************************************************************************/ + +/* + * Class Variables + */ + +/** + * Describe how to deal with options that follow non-option ARGV-elements. + * + * If the caller did not specify anything, + * the default is REQUIRE_ORDER if the property + * gnu.posixly_correct is defined, PERMUTE otherwise. + * + * The special argument `--' forces an end of option-scanning regardless + * of the value of `ordering'. In the case of RETURN_IN_ORDER, only + * `--' can cause `getopt' to return -1 with `optind' != ARGC. + * + * REQUIRE_ORDER means don't recognize them as options; + * stop option processing when the first non-option is seen. + * This is what Unix does. + * This mode of operation is selected by either setting the property + * gnu.posixly_correct, or using `+' as the first character + * of the list of option characters. + */ +protected static final int REQUIRE_ORDER = 1; + +/** + * PERMUTE is the default. We permute the contents of ARGV as we scan, + * so that eventually all the non-options are at the end. This allows options + * to be given in any order, even with programs that were not written to + * expect this. + */ +protected static final int PERMUTE = 2; + +/** + * RETURN_IN_ORDER is an option available to programs that were written + * to expect options and other ARGV-elements in any order and that care about + * the ordering of the two. We describe each non-option ARGV-element + * as if it were the argument of an option with character code 1. + * Using `-' as the first character of the list of option characters + * selects this mode of operation. + */ +protected static final int RETURN_IN_ORDER = 3; + +/**************************************************************************/ + +/* + * Instance Variables + */ + +/** + * For communication from `getopt' to the caller. + * When `getopt' finds an option that takes an argument, + * the argument value is returned here. + * Also, when `ordering' is RETURN_IN_ORDER, + * each non-option ARGV-element is returned here. + */ +protected String optarg; + +/** + * Index in ARGV of the next element to be scanned. + * This is used for communication to and from the caller + * and for communication between successive calls to `getopt'. + * + * On entry to `getopt', zero means this is the first call; initialize. + * + * When `getopt' returns -1, this is the index of the first of the + * non-option elements that the caller should itself scan. + * + * Otherwise, `optind' communicates from one call to the next + * how much of ARGV has been scanned so far. + */ +protected int optind = 0; + +/** + * Callers store false here to inhibit the error message + * for unrecognized options. + */ +protected boolean opterr = true; + +/** + * When an unrecognized option is encountered, getopt will return a '?' + * and store the value of the invalid option here. + */ +protected int optopt = '?'; + +/** + * The next char to be scanned in the option-element + * in which the last option character we returned was found. + * This allows us to pick up the scan where we left off. + * + * If this is zero, or a null string, it means resume the scan + * by advancing to the next ARGV-element. + */ +protected String nextchar; + +/** + * This is the string describing the valid short options. + */ +protected String optstring; + +/** + * This is an array of LongOpt objects which describ the valid long + * options. + */ +protected LongOpt[] long_options; + +/** + * This flag determines whether or not we are parsing only long args + */ +protected boolean long_only; + +/** + * Stores the index into the long_options array of the long option found + */ +protected int longind; + +/** + * The flag determines whether or not we operate in strict POSIX compliance + */ +protected boolean posixly_correct; + +/** + * A flag which communicates whether or not checkLongOption() did all + * necessary processing for the current option + */ +protected boolean longopt_handled; + +/** + * The index of the first non-option in argv[] + */ +protected int first_nonopt = 1; + +/** + * The index of the last non-option in argv[] + */ +protected int last_nonopt = 1; + +/** + * Flag to tell getopt to immediately return -1 the next time it is + * called. + */ +private boolean endparse = false; + +/** + * Saved argument list passed to the program + */ +protected String[] argv; + +/** + * Determines whether we permute arguments or not + */ +protected int ordering; + +/** + * Name to print as the program name in error messages. This is necessary + * since Java does not place the program name in argv[0] + */ +protected String progname; + +/** + * The localized strings are kept in a separate file + */ +private ResourceBundle _messages = ResourceBundle.getBundle( + "gnu/getopt/MessagesBundle", Locale.getDefault()); + +/**************************************************************************/ + +/* + * Constructors + */ + +/** + * Construct a basic Getopt instance with the given input data. Note that + * this handles "short" options only. + * + * @param progname The name to display as the program name when printing errors + * @param argv The String array passed as the command line to the program. + * @param optstring A String containing a description of the valid args for this program + */ +public +Getopt(String progname, String[] argv, String optstring) +{ + this(progname, argv, optstring, null, false); +} + +/**************************************************************************/ + +/** + * Construct a Getopt instance with given input data that is capable of + * parsing long options as well as short. + * + * @param progname The name to display as the program name when printing errors + * @param argv The String array passed as the command ilne to the program + * @param optstring A String containing a description of the valid short args for this program + * @param long_options An array of LongOpt objects that describes the valid long args for this program + */ +public +Getopt(String progname, String[] argv, String optstring, + LongOpt[] long_options) +{ + this(progname, argv, optstring, long_options, false); +} + +/**************************************************************************/ + +/** + * Construct a Getopt instance with given input data that is capable of + * parsing long options and short options. Contrary to what you might + * think, the flag 'long_only' does not determine whether or not we + * scan for only long arguments. Instead, a value of true here allows + * long arguments to start with a '-' instead of '--' unless there is a + * conflict with a short option name. + * + * @param progname The name to display as the program name when printing errors + * @param argv The String array passed as the command ilne to the program + * @param optstring A String containing a description of the valid short args for this program + * @param long_options An array of LongOpt objects that describes the valid long args for this program + * @param long_only true if long options that do not conflict with short options can start with a '-' as well as '--' + */ +public +Getopt(String progname, String[] argv, String optstring, + LongOpt[] long_options, boolean long_only) +{ + if (optstring.length() == 0) + optstring = " "; + + // This function is essentially _getopt_initialize from GNU getopt + this.progname = progname; + this.argv = argv; + this.optstring = optstring; + this.long_options = long_options; + this.long_only = long_only; + + // Check for property "gnu.posixly_correct" to determine whether to + // strictly follow the POSIX standard. This replaces the "POSIXLY_CORRECT" + // environment variable in the C version + if (System.getProperty("gnu.posixly_correct", null) == null) + posixly_correct = false; + else + { + posixly_correct = true; + _messages = ResourceBundle.getBundle("gnu/getopt/MessagesBundle", + Locale.US); + } + + // Determine how to handle the ordering of options and non-options + if (optstring.charAt(0) == '-') + { + ordering = RETURN_IN_ORDER; + if (optstring.length() > 1) + this.optstring = optstring.substring(1); + } + else if (optstring.charAt(0) == '+') + { + ordering = REQUIRE_ORDER; + if (optstring.length() > 1) + this.optstring = optstring.substring(1); + } + else if (posixly_correct) + { + ordering = REQUIRE_ORDER; + } + else + { + ordering = PERMUTE; // The normal default case + } +} + +/**************************************************************************/ + +/* + * Instance Methods + */ + +/** + * In GNU getopt, it is possible to change the string containg valid options + * on the fly because it is passed as an argument to getopt() each time. In + * this version we do not pass the string on every call. In order to allow + * dynamic option string changing, this method is provided. + * + * @param optstring The new option string to use + */ +public void +setOptstring(String optstring) +{ + if (optstring.length() == 0) + optstring = " "; + + this.optstring = optstring; +} + +/**************************************************************************/ + +/** + * optind it the index in ARGV of the next element to be scanned. + * This is used for communication to and from the caller + * and for communication between successive calls to `getopt'. + * + * When `getopt' returns -1, this is the index of the first of the + * non-option elements that the caller should itself scan. + * + * Otherwise, `optind' communicates from one call to the next + * how much of ARGV has been scanned so far. + */ +public int +getOptind() +{ + return(optind); +} + +/**************************************************************************/ + +/** + * This method allows the optind index to be set manually. Normally this + * is not necessary (and incorrect usage of this method can lead to serious + * lossage), but optind is a public symbol in GNU getopt, so this method + * was added to allow it to be modified by the caller if desired. + * + * @param optind The new value of optind + */ +public void +setOptind(int optind) +{ + this.optind = optind; +} + +/**************************************************************************/ + +/** + * Since in GNU getopt() the argument vector is passed back in to the + * function every time, the caller can swap out argv on the fly. Since + * passing argv is not required in the Java version, this method allows + * the user to override argv. Note that incorrect use of this method can + * lead to serious lossage. + * + * @param argv New argument list + */ +public void +setArgv(String[] argv) +{ + this.argv = argv; +} + +/**************************************************************************/ + +/** + * For communication from `getopt' to the caller. + * When `getopt' finds an option that takes an argument, + * the argument value is returned here. + * Also, when `ordering' is RETURN_IN_ORDER, + * each non-option ARGV-element is returned here. + * No set method is provided because setting this variable has no effect. + */ +public String +getOptarg() +{ + return(optarg); +} + +/**************************************************************************/ + +/** + * Normally Getopt will print a message to the standard error when an + * invalid option is encountered. This can be suppressed (or re-enabled) + * by calling this method. There is no get method for this variable + * because if you can't remember the state you set this to, why should I? + */ +public void +setOpterr(boolean opterr) +{ + this.opterr = opterr; +} + +/**************************************************************************/ + +/** + * When getopt() encounters an invalid option, it stores the value of that + * option in optopt which can be retrieved with this method. There is + * no corresponding set method because setting this variable has no effect. + */ +public int +getOptopt() +{ + return(optopt); +} + +/**************************************************************************/ + +/** + * Returns the index into the array of long options (NOT argv) representing + * the long option that was found. + */ +public int +getLongind() +{ + return(longind); +} + +/**************************************************************************/ + +/** + * Exchange the shorter segment with the far end of the longer segment. + * That puts the shorter segment into the right place. + * It leaves the longer segment in the right place overall, + * but it consists of two parts that need to be swapped next. + * This method is used by getopt() for argument permutation. + */ +protected void +exchange(String[] argv) +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + String tem; + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + // Bottom segment is the short one. + int len = middle - bottom; + int i; + + // Swap it with the top part of the top segment. + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + // Exclude the moved bottom segment from further swapping. + top -= len; + } + else + { + // Top segment is the short one. + int len = top - middle; + int i; + + // Swap it with the bottom part of the bottom segment. + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + // Exclude the moved top segment from further swapping. + bottom += len; + } + } + + // Update records for the slots the non-options now occupy. + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/**************************************************************************/ + +/** + * Check to see if an option is a valid long option. Called by getopt(). + * Put in a separate method because this needs to be done twice. (The + * C getopt authors just copy-pasted the code!). + * + * @param longind A buffer in which to store the 'val' field of found LongOpt + * + * @return Various things depending on circumstances + */ +protected int +checkLongOption() +{ + LongOpt pfound = null; + int nameend; + boolean ambig; + boolean exact; + + longopt_handled = true; + ambig = false; + exact = false; + longind = -1; + + nameend = nextchar.indexOf("="); + if (nameend == -1) + nameend = nextchar.length(); + + // Test all lnog options for either exact match or abbreviated matches + for (int i = 0; i < long_options.length; i++) + { + if (long_options[i].getName().startsWith(nextchar.substring(0, nameend))) + { + if (long_options[i].getName().equals(nextchar.substring(0, nameend))) + { + // Exact match found + pfound = long_options[i]; + longind = i; + exact = true; + break; + } + else if (pfound == null) + { + // First nonexact match found + pfound = long_options[i]; + longind = i; + } + else + { + // Second or later nonexact match found + ambig = true; + } + } + } // for + + // Print out an error if the option specified was ambiguous + if (ambig && !exact) + { + if (opterr) + { + Object[] msgArgs = { progname, argv[optind] }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.ambigious"), + msgArgs)); + } + + nextchar = ""; + optopt = 0; + ++optind; + + return('?'); + } + + if (pfound != null) + { + ++optind; + + if (nameend != nextchar.length()) + { + if (pfound.has_arg != LongOpt.NO_ARGUMENT) + { + if (nextchar.substring(nameend).length() > 1) + optarg = nextchar.substring(nameend+1); + else + optarg = ""; + } + else + { + if (opterr) + { + // -- option + if (argv[optind - 1].startsWith("--")) + { + Object[] msgArgs = { progname, pfound.name }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.arguments1"), + msgArgs)); + } + // +option or -option + else + { + Object[] msgArgs = { progname, new + Character(argv[optind-1].charAt(0)).toString(), + pfound.name }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.arguments2"), + msgArgs)); + } + } + + nextchar = ""; + optopt = pfound.val; + + return('?'); + } + } // if (nameend) + else if (pfound.has_arg == LongOpt.REQUIRED_ARGUMENT) + { + if (optind < argv.length) + { + optarg = argv[optind]; + ++optind; + } + else + { + if (opterr) + { + Object[] msgArgs = { progname, argv[optind-1] }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.requires"), + msgArgs)); + } + + nextchar = ""; + optopt = pfound.val; + if (optstring.charAt(0) == ':') + return(':'); + else + return('?'); + } + } // else if (pfound) + + nextchar = ""; + + if (pfound.flag != null) + { + pfound.flag.setLength(0); + pfound.flag.append(pfound.val); + + return(0); + } + + return(pfound.val); + } // if (pfound != null) + + longopt_handled = false; + + return(0); +} + +/**************************************************************************/ + +/** + * This method returns a char that is the current option that has been + * parsed from the command line. If the option takes an argument, then + * the internal variable 'optarg' is set which is a String representing + * the the value of the argument. This value can be retrieved by the + * caller using the getOptarg() method. If an invalid option is found, + * an error message is printed and a '?' is returned. The name of the + * invalid option character can be retrieved by calling the getOptopt() + * method. When there are no more options to be scanned, this method + * returns -1. The index of first non-option element in argv can be + * retrieved with the getOptind() method. + * + * @return Various things as described above + */ +public int +getopt() +{ + optarg = null; + + if (endparse == true) + return(-1); + + if ((nextchar == null) || (nextchar.equals(""))) + { + // If we have just processed some options following some non-options, + // exchange them so that the options come first. + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + // If we have just processed some options following some non-options, + // exchange them so that the options come first. + if ((first_nonopt != last_nonopt) && (last_nonopt != optind)) + exchange(argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + // Skip any additional non-options + // and extend the range of non-options previously skipped. + while ((optind < argv.length) && (argv[optind].equals("") || + (argv[optind].charAt(0) != '-') || argv[optind].equals("-"))) + { + optind++; + } + + last_nonopt = optind; + } + + // The special ARGV-element `--' means premature end of options. + // Skip it like a null option, + // then exchange with previous non-options as if it were an option, + // then skip everything else like a non-option. + if ((optind != argv.length) && argv[optind].equals("--")) + { + optind++; + + if ((first_nonopt != last_nonopt) && (last_nonopt != optind)) + exchange (argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + + last_nonopt = argv.length; + + optind = argv.length; + } + + // If we have done all the ARGV-elements, stop the scan + // and back over any non-options that we skipped and permuted. + if (optind == argv.length) + { + // Set the next-arg-index to point at the non-options + // that we previously skipped, so the caller will digest them. + if (first_nonopt != last_nonopt) + optind = first_nonopt; + + return(-1); + } + + // If we have come to a non-option and did not permute it, + // either stop the scan or describe it to the caller and pass it by. + if (argv[optind].equals("") || (argv[optind].charAt(0) != '-') || + argv[optind].equals("-")) + { + if (ordering == REQUIRE_ORDER) + return(-1); + + optarg = argv[optind++]; + return(1); + } + + // We have found another option-ARGV-element. + // Skip the initial punctuation. + if (argv[optind].startsWith("--")) + nextchar = argv[optind].substring(2); + else + nextchar = argv[optind].substring(1); + } + + // Decode the current option-ARGV-element. + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + if ((long_options != null) && (argv[optind].startsWith("--") + || (long_only && ((argv[optind].length() > 2) || + (optstring.indexOf(argv[optind].charAt(1)) == -1))))) + { + int c = checkLongOption(); + + if (longopt_handled) + return(c); + + // Can't find it as a long option. If this is not getopt_long_only, + // or the option starts with '--' or is not a valid short + // option, then it's an error. + // Otherwise interpret it as a short option. + if (!long_only || argv[optind].startsWith("--") + || (optstring.indexOf(nextchar.charAt(0)) == -1)) + { + if (opterr) + { + if (argv[optind].startsWith("--")) + { + Object[] msgArgs = { progname, nextchar }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.unrecognized"), + msgArgs)); + } + else + { + Object[] msgArgs = { progname, new + Character(argv[optind].charAt(0)).toString(), + nextchar }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.unrecognized2"), + msgArgs)); + } + } + + nextchar = ""; + ++optind; + optopt = 0; + + return('?'); + } + } // if (longopts) + + // Look at and handle the next short option-character */ + int c = nextchar.charAt(0); //**** Do we need to check for empty str? + if (nextchar.length() > 1) + nextchar = nextchar.substring(1); + else + nextchar = ""; + + String temp = null; + if (optstring.indexOf(c) != -1) + temp = optstring.substring(optstring.indexOf(c)); + + if (nextchar.equals("")) + ++optind; + + if ((temp == null) || (c == ':')) + { + if (opterr) + { + if (posixly_correct) + { + // 1003.2 specifies the format of this message + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.illegal"), msgArgs)); + } + else + { + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.invalid"), msgArgs)); + } + } + + optopt = c; + + return('?'); + } + + // Convenience. Treat POSIX -W foo same as long option --foo + if ((temp.charAt(0) == 'W') && (temp.length() > 1) && (temp.charAt(1) == ';')) + { + if (!nextchar.equals("")) + { + optarg = nextchar; + } + // No further cars in this argv element and no more argv elements + else if (optind == argv.length) + { + if (opterr) + { + // 1003.2 specifies the format of this message. + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.requires2"), msgArgs)); + } + + optopt = c; + if (optstring.charAt(0) == ':') + return(':'); + else + return('?'); + } + else + { + // We already incremented `optind' once; + // increment it again when taking next ARGV-elt as argument. + nextchar = argv[optind]; + optarg = argv[optind]; + } + + c = checkLongOption(); + + if (longopt_handled) + return(c); + else + // Let the application handle it + { + nextchar = null; + ++optind; + return('W'); + } + } + + if ((temp.length() > 1) && (temp.charAt(1) == ':')) + { + if ((temp.length() > 2) && (temp.charAt(2) == ':')) + // This is an option that accepts and argument optionally + { + if (!nextchar.equals("")) + { + optarg = nextchar; + ++optind; + } + else + { + optarg = null; + } + + nextchar = null; + } + else + { + if (!nextchar.equals("")) + { + optarg = nextchar; + ++optind; + } + else if (optind == argv.length) + { + if (opterr) + { + // 1003.2 specifies the format of this message + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.requires2"), msgArgs)); + } + + optopt = c; + + if (optstring.charAt(0) == ':') + return(':'); + else + return('?'); + } + else + { + optarg = argv[optind]; + ++optind; + + // Ok, here's an obscure Posix case. If we have o:, and + // we get -o -- foo, then we're supposed to skip the --, + // end parsing of options, and make foo an operand to -o. + // Only do this in Posix mode. + if ((posixly_correct) && optarg.equals("--")) + { + // If end of argv, error out + if (optind == argv.length) + { + if (opterr) + { + // 1003.2 specifies the format of this message + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.requires2"), msgArgs)); + } + + optopt = c; + + if (optstring.charAt(0) == ':') + return(':'); + else + return('?'); + } + + // Set new optarg and set to end + // Don't permute as we do on -- up above since we + // know we aren't in permute mode because of Posix. + optarg = argv[optind]; + ++optind; + first_nonopt = optind; + last_nonopt = argv.length; + endparse = true; + } + } + + nextchar = null; + } + } + + return(c); +} + +} // Class Getopt + + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/GetoptDemo.class b/ssdd_p1_100291121_100292107/gnu/getopt/GetoptDemo.class new file mode 100755 index 0000000..5182187 Binary files /dev/null and b/ssdd_p1_100291121_100292107/gnu/getopt/GetoptDemo.class differ diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/GetoptDemo.java b/ssdd_p1_100291121_100292107/gnu/getopt/GetoptDemo.java new file mode 100755 index 0000000..b57c5a8 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/GetoptDemo.java @@ -0,0 +1,97 @@ +import gnu.getopt.LongOpt; +import gnu.getopt.Getopt; + +/* + * This sample code was written by Aaron M. Renn and is a demonstration + * of how to utilize some of the features of the GNU getopt package. This + * sample code is hereby placed into the public domain by the author and + * may be used without restriction. + */ + +public class GetoptDemo +{ + +public static void +main(String[] argv) +{ + int c; + String arg; + LongOpt[] longopts = new LongOpt[3]; + // + StringBuffer sb = new StringBuffer(); + longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'); + longopts[1] = new LongOpt("outputdir", LongOpt.REQUIRED_ARGUMENT, sb, 'o'); + longopts[2] = new LongOpt("maximum", LongOpt.OPTIONAL_ARGUMENT, null, 2); + // + Getopt g = new Getopt("testprog", argv, "-:bc::d:hW;", longopts); + g.setOpterr(false); // We'll do our own error handling + // + while ((c = g.getopt()) != -1) + switch (c) + { + case 0: + arg = g.getOptarg(); + System.out.println("Got long option with value '" + + (char)(new Integer(sb.toString())).intValue() + + "' with argument " + + ((arg != null) ? arg : "null")); + break; + // + case 1: + System.out.println("I see you have return in order set and that " + + "a non-option argv element was just found " + + "with the value '" + g.getOptarg() + "'"); + break; + // + case 2: + arg = g.getOptarg(); + System.out.println("I know this, but pretend I didn't"); + System.out.println("We picked option " + + longopts[g.getLongind()].getName() + + " with value " + + ((arg != null) ? arg : "null")); + break; + // + case 'b': + System.out.println("You picked plain old option " + (char)c); + break; + // + case 'c': + case 'd': + arg = g.getOptarg(); + System.out.println("You picked option '" + (char)c + + "' with argument " + + ((arg != null) ? arg : "null")); + break; + // + case 'h': + System.out.println("I see you asked for help"); + break; + // + case 'W': + System.out.println("Hmmm. You tried a -W with an incorrect long " + + "option name"); + break; + // + case ':': + System.out.println("Doh! You need an argument for option " + + (char)g.getOptopt()); + break; + // + case '?': + System.out.println("The option '" + (char)g.getOptopt() + + "' is not valid"); + break; + // + default: + System.out.println("getopt() returned " + c); + break; + } + // + for (int i = g.getOptind(); i < argv.length ; i++) + System.out.println("Non option argv element: " + argv[i] + "\n"); +} + +} // Class GetoptDemo + + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/LANGUAGES b/ssdd_p1_100291121_100292107/gnu/getopt/LANGUAGES new file mode 100755 index 0000000..d8e1399 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/LANGUAGES @@ -0,0 +1,23 @@ +Getopt supports error messages in the following languages: + +English (default) +Chinese (simplified and traditional) +Czech +Dutch +French +German +Hungarian +Italian +Japanese +Norwegian +Polish +Romanian +Spanish + +Anyone can create a translation without knowing how to program Java. +Simply supply me with a MessagesBundle file for your locale and I'm happy +to include it. See MessagesBundle.properties as an example with reference +English messages. + +Aaron (arenn@urbanophile.com) + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/LongOpt.class b/ssdd_p1_100291121_100292107/gnu/getopt/LongOpt.class new file mode 100755 index 0000000..fb602e9 Binary files /dev/null and b/ssdd_p1_100291121_100292107/gnu/getopt/LongOpt.class differ diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/LongOpt.java b/ssdd_p1_100291121_100292107/gnu/getopt/LongOpt.java new file mode 100755 index 0000000..6357085 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/LongOpt.java @@ -0,0 +1,195 @@ +/************************************************************************** +/* LongOpt.java -- Long option object for Getopt +/* +/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +package gnu.getopt; + +import java.util.Locale; +import java.util.ResourceBundle; +import java.text.MessageFormat; + +/**************************************************************************/ + +/** + * This object represents the definition of a long option in the Java port + * of GNU getopt. An array of LongOpt objects is passed to the Getopt + * object to define the list of valid long options for a given parsing + * session. Refer to the getopt documentation for details on the + * format of long options. + * + * @version 1.0.5 + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @see Getopt + */ +public class LongOpt extends Object +{ + +/**************************************************************************/ + +/* + * Class Variables + */ + +/** + * Constant value used for the "has_arg" constructor argument. This + * value indicates that the option takes no argument. + */ +public static final int NO_ARGUMENT = 0; + +/** + * Constant value used for the "has_arg" constructor argument. This + * value indicates that the option takes an argument that is required. + */ +public static final int REQUIRED_ARGUMENT = 1; + +/** + * Constant value used for the "has_arg" constructor argument. This + * value indicates that the option takes an argument that is optional. + */ +public static final int OPTIONAL_ARGUMENT = 2; + +/**************************************************************************/ + +/* + * Instance Variables + */ + +/** + * The name of the long option + */ +protected String name; + +/** + * Indicates whether the option has no argument, a required argument, or + * an optional argument. + */ +protected int has_arg; + +/** + * If this variable is not null, then the value stored in "val" is stored + * here when this long option is encountered. If this is null, the value + * stored in "val" is treated as the name of an equivalent short option. + */ +protected StringBuffer flag; + +/** + * The value to store in "flag" if flag is not null, otherwise the + * equivalent short option character for this long option. + */ +protected int val; + +/** + * Localized strings for error messages + */ +private ResourceBundle _messages = ResourceBundle.getBundle( + "gnu/getopt/MessagesBundle", Locale.getDefault()); + +/**************************************************************************/ + +/* + * Constructors + */ + +/** + * Create a new LongOpt object with the given parameter values. If the + * value passed as has_arg is not valid, then an exception is thrown. + * + * @param name The long option String. + * @param has_arg Indicates whether the option has no argument (NO_ARGUMENT), a required argument (REQUIRED_ARGUMENT) or an optional argument (OPTIONAL_ARGUMENT). + * @param flag If non-null, this is a location to store the value of "val" when this option is encountered, otherwise "val" is treated as the equivalent short option character. + * @param val The value to return for this long option, or the equivalent single letter option to emulate if flag is null. + * + * @exception IllegalArgumentException If the has_arg param is not one of NO_ARGUMENT, REQUIRED_ARGUMENT or OPTIONAL_ARGUMENT. + */ +public +LongOpt(String name, int has_arg, + StringBuffer flag, int val) throws IllegalArgumentException +{ + // Validate has_arg + if ((has_arg != NO_ARGUMENT) && (has_arg != REQUIRED_ARGUMENT) + && (has_arg != OPTIONAL_ARGUMENT)) + { + Object[] msgArgs = { new Integer(has_arg).toString() }; + throw new IllegalArgumentException(MessageFormat.format( + _messages.getString("getopt.invalidValue"), msgArgs)); + } + + // Store off values + this.name = name; + this.has_arg = has_arg; + this.flag = flag; + this.val = val; +} + +/**************************************************************************/ + +/** + * Returns the name of this LongOpt as a String + * + * @return Then name of the long option + */ +public String +getName() +{ + return(name); +} + +/**************************************************************************/ + +/** + * Returns the value set for the 'has_arg' field for this long option + * + * @return The value of 'has_arg' + */ +public int +getHasArg() +{ + return(has_arg); +} + +/**************************************************************************/ + +/** + * Returns the value of the 'flag' field for this long option + * + * @return The value of 'flag' + */ +public StringBuffer +getFlag() +{ + return(flag); +} + +/** + * Returns the value of the 'val' field for this long option + * + * @return The value of 'val' + */ +public int +getVal() +{ + return(val); +} + +/**************************************************************************/ + +} // Class LongOpt + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/Makefile b/ssdd_p1_100291121_100292107/gnu/getopt/Makefile new file mode 100755 index 0000000..6ff789c --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/Makefile @@ -0,0 +1,7 @@ +# Makefile for Java port of GNU getopt + +all: + javac LongOpt.java Getopt.java GetoptDemo.java + +docs: + javadoc -author -version -public Getopt.java LongOpt.java diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle.properties new file mode 100755 index 0000000..9356ee1 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle.properties -- English language error messages +/* +/* Copyright (c) 1998 by William King (wrking@eng.sun.com) and +/* Aaron M. Renn (arenn@urbanophile.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: option ''{1}'' is ambiguous +getopt.arguments1={0}: option ''--{1}'' doesn't allow an argument +getopt.arguments2={0}: option ''{1}{2}'' doesn't allow an argument +getopt.requires={0}: option ''{1}'' requires an argument +getopt.unrecognized={0}: unrecognized option ''--{1}'' +getopt.unrecognized2={0}: unrecognized option ''{1}{2}'' +getopt.illegal={0}: illegal option -- {1} +getopt.invalid={0}: invalid option -- {1} +getopt.requires2={0}: option requires an argument -- {1} +getopt.invalidValue=Invalid value {0} for parameter 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_chs.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_chs.properties new file mode 100755 index 0000000..1090dc6 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_chs.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle.properties CSimple Chinese language error messages +/* +/* Copyright (c) 2012 by David Zhang (david290@qq.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: ѡ ''{1}'' +getopt.arguments1={0}:ѡ''--{1}'' ܴ +getopt.arguments2={0}:ѡ''{1}{2}''ܴ +getopt.requires={0}: ѡ ''{1}'' Ҫв +getopt.unrecognized={0}: ޷ʶѡ ''--{1}'' +getopt.unrecognized2={0}:޷ʶѡ''{1}{2}'' +getopt.illegal={0}: Ƿѡ -- {1} +getopt.invalid={0}: Чѡ -- {1} +getopt.requires2={0}:ѡҪв -- {1} +getopt.invalidValue=ѡ 'has_arg'ֵ {0} Ƿ + + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_cht.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_cht.properties new file mode 100755 index 0000000..270e4f1 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_cht.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle.properties - Triditional Chinese language error messages +/* +/* Copyright (c) 2012 by David Zhang (david290@qq.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: 選項 ''{1}'' 有歧義 +getopt.arguments1={0}:選項''--{1}'' 不能帶參數 +getopt.arguments2={0}:選項''{1}{2}''不能帶參數 +getopt.requires={0}: 選項 ''{1}'' 要求帶有參數 +getopt.unrecognized={0}: 無法識別的選項 ''--{1}'' +getopt.unrecognized2={0}:無法識別的選項''{1}{2}'' +getopt.illegal={0}: 非法選項 -- {1} +getopt.invalid={0}: 無效選項 -- {1} +getopt.requires2={0}:選項需要有參數 -- {1} +getopt.invalidValue=選項 'has_arg'的值 {0} 非法 + + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_cs.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_cs.properties new file mode 100755 index 0000000..3c14a03 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_cs.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle_cs.properties -- Czech language error messages +/* +/* Czech Messages Copyright (c) 1998 by Roman Szturc (Roman.Szturc@vsb.cz) +/* These messages are encoded in ISO-8859-2 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: volba ''{1}'' je nejednoznan +getopt.arguments1={0}: volba ''--{1}'' nepipout argument +getopt.arguments2={0}: volba ''{1}{2}'' nepipout argument +getopt.requires={0}: volba ''{1}'' vyaduje argument +getopt.unrecognized={0}: neppustn volba ''--{1}'' +getopt.unrecognized2={0}: neppustn volba ''{1}{2}'' +getopt.illegal={0}: neppustn volba -- {1} +getopt.invalid={0}: neplatn volba -- {1} +getopt.requires2={0}: volba vyaduje argument -- {1} +getopt.invalidValue=Neplatn hodnota {0} parameteru 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_de.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_de.properties new file mode 100755 index 0000000..f741386 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_de.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle.properties -- German language error messages +/* +/* German Messages Copyright (c) 1999 by Bernhard Bablok (bablokb@gmx.net) +/* These messages are encoded in ISO-8859-1 +//* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: Option ''{1}'' ist zweideutig +getopt.arguments1={0}: Option ''--{1}'' erlaubt kein Argument +getopt.arguments2={0}: Option ''{1}{2}'' erlaubt kein Argument +getopt.requires={0}: Option ''{1}'' bentigt ein Argument +getopt.unrecognized={0}: Unbekannte Option ''--{1}'' +getopt.unrecognized2={0}: Unbekannte Option ''{1}{2}'' +getopt.illegal={0}: Verbotene Option -- {1} +getopt.invalid={0}: Ungltige Option -- {1} +getopt.requires2={0}: Option bentigt ein Argument -- {1} +getopt.invalidValue=Ungltiger Wert {0} fr Parameter 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_es.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_es.properties new file mode 100755 index 0000000..ef358f4 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_es.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle_es.properties -- Spanish language error messages +/* +/* Spanish Messages Copyright (c) 2004 by Daniel Prez (dondani@gmail.com) +/* These messages are encoded in ISO-8859-1 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: la opcin ''{1}'' es ambigua +getopt.arguments1={0}: la opcin ''--{1}'' no permite un argumento +getopt.arguments2={0}: la opcin ''{1}{2}'' no permite un argumento +getopt.requires={0}: la opcin ''{1}'' requiere un argumento +getopt.unrecognized={0}: opcin no reconocida ''--{1}'' +getopt.unrecognized2={0}: opcin no reconocida ''{1}{2}'' +getopt.illegal={0}: opcin ilegal -- {1} +getopt.invalid={0}: opcin no vlida -- {1} +getopt.requires2={0}: la opcin requiere un argumento -- {1} +getopt.invalidValue=Valor no vlido {0} para el parmetro 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_fr.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_fr.properties new file mode 100755 index 0000000..400447c --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_fr.properties @@ -0,0 +1,35 @@ +/************************************************************************** +/* MessagesBundle_fr.properties -- French language error messages +/* +/* Copyright (c) 1999 Free Software Foundation, Inc. +/* Michel Robitaille , 1996, +/* Edouard G. Parmelan , 1999. +/* These messages are encoded in ISO-8859-1 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: l'option ''{1}'' est ambigu +getopt.arguments1={0}: l'option ''--{1}'' ne permet pas de paramtre +getopt.arguments2={0}: l'option ''{1}{2}'' ne permet pas de paramtre +getopt.requires={0}: l'option ''{1}'' requiert un paramtre +getopt.unrecognized={0}: option non reconnue ''--{1}'' +getopt.unrecognized2={0}: option non reconnue ''{1}{2}'' +getopt.illegal={0}: option illgale -- {1} +getopt.invalid={0}: option invalide -- {1} +getopt.requires2={0}: cette option requiert un paramtre -- {1} +getopt.invalidValue=Valeur invalide {0} pour le paramtre 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_hu.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_hu.properties new file mode 100755 index 0000000..f7af03b --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_hu.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle.properties -- Hungarian language error messages +/* +/* Copyright (c) 2001 by Gyula Csom (csom@informix.hu) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: opci ''{1}'' flrerthet +getopt.arguments1={0}: opci ''--{1}'' nem enged meg argumentumot +getopt.arguments2={0}: opci ''{1}{2}'' nem enged meg argumentumot +getopt.requires={0}: opci ''{1}'' argumentumot ignyel +getopt.unrecognized={0}: ismeretlen opci ''--{1}'' +getopt.unrecognized2={0}: ismeretlen opci ''{1}{2}'' +getopt.illegal={0}: illeglis opci -- {1} +getopt.invalid={0}: rvnytelen opci -- {1} +getopt.requires2={0}: az opci argumentumot ignyel -- {1} +getopt.invalidValue=rvnytelen rtk {0} a kvetkez paramterhez 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_it.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_it.properties new file mode 100755 index 0000000..c596c26 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_it.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle.properties -- Italian language error messages +/* +/* Copyright (c) 2005 by Sandro Tosi (matrixhasu@gmail.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: l'opzione ''{1}'' ambigua +getopt.arguments1={0}: l'opzione ''--{1}'' non ammette un argomento +getopt.arguments2={0}: l'opzione ''{1}{2}'' non ammette un argomento +getopt.requires={0}: l'opzione ''{1}'' richiede un argomento +getopt.unrecognized={0}: opzione non riconosciuta ''--{1}'' +getopt.unrecognized2={0}: opzione non riconosciuta ''{1}{2}'' +getopt.illegal={0}: opzione illegale -- {1} +getopt.invalid={0}: opzione invalida -- {1} +getopt.requires2={0}: l'opzione richiede un argomento -- {1} +getopt.invalidValue=Valore non valido {0} per il parametro 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_ja.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_ja.properties new file mode 100755 index 0000000..5578972 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_ja.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle.properties -- Japanese language error messages +/* +/* Copyright (c) 2001 by Yasuoka Masahiko (yasuoka@yasuoka.net) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: ''{1}'' \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u66d6\u6627\u3067\u3059\u3002 +getopt.arguments1={0}: ''--{1}'' \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u3092\u3082\u3061\u307e\u305b\u3093\u3002 +getopt.arguments2={0}: ''{1}{2}'' \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u3092\u3082\u3061\u307e\u305b\u3093\u3002 +getopt.requires={0}: ''{1}'' \u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u5fc5\u8981\u3067\u3059\u3002 +getopt.unrecognized={0}: ''--{1}'' \u306f\u7121\u52b9\u306a\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u3059\u3002 +getopt.unrecognized2={0}: ''{1}{2}'' \u306f\u7121\u52b9\u306a\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u3059\u3002 +getopt.illegal={0}: -- {1} \u306f\u4e0d\u6b63\u306a\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u3059\u3002 +getopt.invalid={0}: -- {1} \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093\u3002 +getopt.requires2={0}: -- {1} \u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u5fc5\u8981\u3067\u3059\u3002 +getopt.invalidValue={0} \u306f\u3001'has_arg' \u30d1\u30e9\u30e1\u30fc\u30bf\u3068\u3057\u3066\u4e0d\u6b63\u306a\u5024\u3067\u3059\u3002 + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_nl.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_nl.properties new file mode 100755 index 0000000..c614922 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_nl.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle_nl.properties -- Dutch language error messages +/* +/* Copyright (c) 1999 by Ernst de Haan (ernst@jollem.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: optie ''{1}'' is ambigue +getopt.arguments1={0}: optie ''--{1}'' staat geen argumenten toe +getopt.arguments2={0}: optie ''{1}{2}'' staat geen argumenten toe +getopt.requires={0}: optie ''{1}'' heeft een argument nodig +getopt.unrecognized={0}: onbekende optie ''--{1}'' +getopt.unrecognized2={0}: onbekende optie ''{1}{2}'' +getopt.illegal={0}: niet-toegestane optie -- {1} +getopt.invalid={0}: onjuiste optie -- {1} +getopt.requires2={0}: optie heeft een argument nodig -- {1} +getopt.invalidValue=Ongeldige waarde {0} voor parameter 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_no.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_no.properties new file mode 100755 index 0000000..bcb8c50 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_no.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle.properties -- Norwegian language error messages +/* +/* Copyright (c) 1999 by Bjrn-Ove Heimsund (s811@ii.uib.no) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: flagget ''{1}'' er flertydig +getopt.arguments1={0}: flagget ''--{1}'' tillater ikke et argument +getopt.arguments2={0}: flagget ''{1}{2}'' tillater ikke et argument +getopt.requires={0}: flagget ''{1}'' krever et argument +getopt.unrecognized={0}: ukjent flagg ''--{1}'' +getopt.unrecognized2={0}: ukjent flagg ''{1}{2}'' +getopt.illegal={0}: ugyldig flagg -- {1} +getopt.invalid={0}: ugyldig flagg -- {1} +getopt.requires2={0}: flagget krever et argument -- {1} +getopt.invalidValue=Ugyldig verdi {0} for parameter 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_pl.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_pl.properties new file mode 100755 index 0000000..9580853 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_pl.properties @@ -0,0 +1,36 @@ +/************************************************************************** +/* MessagesBundle_pl.properties -- Polish language error messages +/* +/* Polish Messages Copyright (c) 2006 by Krzysztof Szyma?ski (sirch.s@gmail.com) +/* These messages are encoded in ISO-8859-2 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + + +getopt.ambigious={0}: opcja ''{1}''jest wieloznaczna +getopt.arguments1={0}: opcja ''--{1}'' nie akceptuje argumentu +getopt.arguments2={0}: opcja ''{1}{2}'' nie akceptuje argumentu +getopt.requires={0}: opcja ''{1}'' wymaga argumentu +getopt.unrecognized={0}: nierozpoznana opcja ''--{1}'' +getopt.unrecognized2={0}: nierozpoznana opcja ''{1}{2}'' +getopt.illegal={0}: nie dopuszczalna opcja --{1} +getopt.invalid={0}: b??dna opcja --{1} +getopt.requires2={0}: opcja --{1} oczekuje argumentu +getopt.invalidValue=Nie poprawna warto?? {0} argument 'has_arg' + + + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_ro.properties b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_ro.properties new file mode 100755 index 0000000..3c0b08b --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/MessagesBundle_ro.properties @@ -0,0 +1,34 @@ +/************************************************************************** +/* MessagesBundle_fr.properties -- Romanian language error messages +/* +/* Copyright (c) 1999 Free Software Foundation, Inc. +/* Marian-Nicolae Ion , 2004, +/* These messages are encoded in ISO-8859-2 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your optiunea) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: opţiunea ''{1}'' este ambiguă +getopt.arguments1={0}: opţiunea ''--{1}'' nu acceptă parametru +getopt.arguments2={0}: opţiunea ''{1}{2}'' nu acceptă parametru +getopt.requires={0}: opţiunea ''{1}'' cere un parametru +getopt.unrecognized={0}: opţiune necunoscută ''--{1}'' +getopt.unrecognized2={0}: opţiune necunoscută ''{1}{2}'' +getopt.illegal={0}: opţiune ilegală -- {1} +getopt.invalid={0}: opţiune invalidă -- {1} +getopt.requires2={0}: această opţiune cere un parametru -- {1} +getopt.invalidValue=Valoare invalidă {0} pentru parametrul 'has_arg' + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/README b/ssdd_p1_100291121_100292107/gnu/getopt/README new file mode 100755 index 0000000..48451f7 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/README @@ -0,0 +1,57 @@ +This is a Java port of the GNU getopt functions based on the versions +contained in glibc 2.0.6. I have attempted to keep the functionality +and programmer's interface as faithful to the original as possible. +However, due to differences between Java and C, some minor changes +has to me made. (Given the obtuse interface in the clib version, +perhaps some major changes should have been made). This should not +affect the way options appear to be parsed to the end user of program +that uses this Java getopt. The use of these classes are completely +documented in the javadoc comments, so I will not repeat that info here. + +Note that since these objects are part of a package called "gnu.getopt", +they need to be in a subdirectory called gnu/getopt somewhere in your +CLASSPATH. This includes the "MessagesBundle" files. + +I am not aware of any bugs. If you find one though, please send email +to me at arenn@urbanophile.com. The more detailed a bug report the better. +Bug fixes are also welcome at the same address. Please reference +release number "1.0.13". If you use this code, it would be helpful +if you let me know so that I can let you know if anything changes or +if any major bugs have been found/fixed. + +I have included a Makefile for compiling the code. If you do not have +access to make, then you can simply do a "javac *.java" at the OS +command line (or follow your vendor's instructions for compiling a +Java class). To build the documentation, do a "make docs" +or "javadoc -public *.java". Note that the images needed by the html +generated by javadoc are not included. You will need to get those +from some other Java documentation package. + +Note that the Makefile is not compliant with the GNU makefile +standards as I anticipate that at some point a master makefile will +be created for various GNU Java packages. And it is serious overkill +to create a megabloat makefile (kinda like this megabloat README) for +such a simple package. + +There is sample code showing how to use getopt available in the +GetoptDemo.java file. + +NEW: A support file for the "ant" build process was contributed. Here are +some brief things you can do with it. Note that I have not ever used this +so it is doubly AS IS. + +Get ant from jakarta project (see jakarta.apache.org/ant), and run it with +one of these target (all is default target): +ant prepare: create the needed directories +ant classes: compile the java classes +ant jar: create the jar archive +ant javadoc: create the javadoc +ant all: create jar and javadoc +ant clean: clean everything + +Happy hacking, + +Aaron. +arenn@urbanophile.com +http://www.urbanophile.com/arenn/ + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/buildx.xml b/ssdd_p1_100291121_100292107/gnu/getopt/buildx.xml new file mode 100755 index 0000000..ad51e8f --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/buildx.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/gnu.getopt.Getopt.html b/ssdd_p1_100291121_100292107/gnu/getopt/gnu.getopt.Getopt.html new file mode 100755 index 0000000..425de42 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/gnu.getopt.Getopt.html @@ -0,0 +1,639 @@ + + + + + + + Class gnu.getopt.Getopt + + + + +

+All Packages  Class Hierarchy  This Package  Previous  Next  Index
+
+

+ Class gnu.getopt.Getopt +

+
+java.lang.Object
+   |
+   +----gnu.getopt.Getopt
+
+
+
+
public class Getopt +
extends Object +
+This is a Java port of GNU getopt, a class for parsing command line + arguments passed to programs. It it based on the C getopt() functions + in glibc 2.0.6 and should parse options in a 100% compatible manner. + If it does not, that is a bug. The programmer's interface is also + very compatible. +

+ To use Getopt, create a Getopt object with a argv array passed to the + main method, then call the getopt() method in a loop. It will return an + int that contains the value of the option character parsed from the + command line. When there are no more options to be parsed, it + returns -1. +

+ A command line option can be defined to take an argument. If an + option has an argument, the value of that argument is stored in an + instance variable called optarg, which can be accessed using the + getOptarg() method. If an option that requires an argument is + found, but there is no argument present, then an error message is + printed. Normally getopt() returns a '?' in this situation, but + that can be changed as described below. +

+ If an invalid option is encountered, an error message is printed + to the standard error and getopt() returns a '?'. The value of the + invalid option encountered is stored in the instance variable optopt + which can be retrieved using the getOptopt() method. To suppress + the printing of error messages for this or any other error, set + the value of the opterr instance variable to false using the + setOpterr() method. +

+ Between calls to getopt(), the instance variable optind is used to + keep track of where the object is in the parsing process. After all + options have been returned, optind is the index in argv of the first + non-option argument. This variable can be accessed with the getOptind() + method. +

+ Note that this object expects command line options to be passed in the + traditional Unix manner. That is, proceeded by a '-' character. + Multiple options can follow the '-'. For example "-abc" is equivalent + to "-a -b -c". If an option takes a required argument, the value + of the argument can immediately follow the option character or be + present in the next argv element. For example, "-cfoo" and "-c foo" + both represent an option character of 'c' with an argument of "foo" + assuming c takes a required argument. If an option takes an argument + that is not required, then any argument must immediately follow the + option character in the same argv element. For example, if c takes + a non-required argument, then "-cfoo" represents option character 'c' + with an argument of "foo" while "-c foo" represents the option + character 'c' with no argument, and a first non-option argv element + of "foo". +

+ The user can stop getopt() from scanning any further into a command line + by using the special argument "--" by itself. For example: + "-a -- -d" would return an option character of 'a', then return -1 + The "--" is discarded and "-d" is pointed to by optind as the first + non-option argv element. +

+ Here is a basic example of using Getopt: +

+

+ Getopt g = new Getopt("testprog", argv, "ab:c::d");
+ //
+ int c;
+ String arg;
+ while ((c = g.getopt()) != -1)
+   {
+     switch(c)
+       {
+          case 'a':
+          case 'd':
+            System.out.print("You picked " + (char)c + "\n");
+            break;
+            //
+          case 'b':
+          case 'c':
+            arg = g.getOptarg();
+            System.out.print("You picked " + (char)c + 
+                             " with an argument of " +
+                             ((arg != null) ? arg : "null") + "\n");
+            break;
+            //
+          case '?':
+            break; // getopt() already printed an error
+            //
+          default:
+            System.out.print("getopt() returned " + c + "\n");
+       }
+   }
+ 
+

+ In this example, a new Getopt object is created with three params. + The first param is the program name. This is for printing error + messages in the form "program: error message". In the C version, this + value is taken from argv[0], but in Java the program name is not passed + in that element, thus the need for this parameter. The second param is + the argument list that was passed to the main() method. The third + param is the list of valid options. Each character represents a valid + option. If the character is followed by a single colon, then that + option has a required argument. If the character is followed by two + colons, then that option has an argument that is not required. +

+ Note in this example that the value returned from getopt() is cast to + a char prior to printing. This is required in order to make the value + display correctly as a character instead of an integer. +

+ If the first character in the option string is a colon, for example + ":abc::d", then getopt() will return a ':' instead of a '?' when it + encounters an option with a missing required argument. This allows the + caller to distinguish between invalid options and valid options that + are simply incomplete. +

+ In the traditional Unix getopt(), -1 is returned when the first non-option + charcter is encountered. In GNU getopt(), the default behavior is to + allow options to appear anywhere on the command line. The getopt() + method permutes the argument to make it appear to the caller that all + options were at the beginning of the command line, and all non-options + were at the end. For example, calling getopt() with command line args + of "-a foo bar -d" returns options 'a' and 'd', then sets optind to + point to "foo". The program would read the last two argv elements as + "foo" and "bar", just as if the user had typed "-a -d foo bar". +

+ The user can force getopt() to stop scanning the command line with + the special argument "--" by itself. Any elements occuring before the + "--" are scanned and permuted as normal. Any elements after the "--" + are returned as is as non-option argv elements. For example, + "foo -a -- bar -d" would return option 'a' then -1. optind would point + to "foo", "bar" and "-d" as the non-option argv elements. The "--" + is discarded by getopt(). +

+ There are two ways this default behavior can be modified. The first is + to specify traditional Unix getopt() behavior (which is also POSIX + behavior) in which scanning stops when the first non-option argument + encountered. (Thus "-a foo bar -d" would return 'a' as an option and + have "foo", "bar", and "-d" as non-option elements). The second is to + allow options anywhere, but to return all elements in the order they + occur on the command line. When a non-option element is ecountered, + an integer 1 is returned and the value of the non-option element is + stored in optarg is if it were the argument to that option. For + example, "-a foo -d", returns first 'a', then 1 (with optarg set to + "foo") then 'd' then -1. When this "return in order" functionality + is enabled, the only way to stop getopt() from scanning all command + line elements is to use the special "--" string by itself as described + above. An example is "-a foo -b -- bar", which would return 'a', then + integer 1 with optarg set to "foo", then 'b', then -1. optind would + then point to "bar" as the first non-option argv element. The "--" + is discarded. +

+ The POSIX/traditional behavior is enabled by either setting the + property "gnu.posixly_correct" or by putting a '+' sign as the first + character of the option string. The difference between the two + methods is that setting the gnu.posixly_correct property also forces + certain error messages to be displayed in POSIX format. To enable + the "return in order" functionality, put a '-' as the first character + of the option string. Note that after determining the proper + behavior, Getopt strips this leading '+' or '-', meaning that a ':' + placed as the second character after one of those two will still cause + getopt() to return a ':' instead of a '?' if a required option + argument is missing. +

+ In addition to traditional single character options, GNU Getopt also + supports long options. These are preceeded by a "--" sequence and + can be as long as desired. Long options provide a more user-friendly + way of entering command line options. For example, in addition to a + "-h" for help, a program could support also "--help". +

+ Like short options, long options can also take a required or non-required + argument. Required arguments can either be specified by placing an + equals sign after the option name, then the argument, or by putting the + argument in the next argv element. For example: "--outputdir=foo" and + "--outputdir foo" both represent an option of "outputdir" with an + argument of "foo", assuming that outputdir takes a required argument. + If a long option takes a non-required argument, then the equals sign + form must be used to specify the argument. In this case, + "--outputdir=foo" would represent option outputdir with an argument of + "foo" while "--outputdir foo" would represent the option outputdir + with no argument and a first non-option argv element of "foo". +

+ Long options can also be specified using a special POSIX argument + format (one that I highly discourage). This form of entry is + enabled by placing a "W;" (yes, 'W' then a semi-colon) in the valid + option string. This causes getopt to treat the name following the + "-W" as the name of the long option. For example, "-W outputdir=foo" + would be equivalent to "--outputdir=foo". The name can immediately + follow the "-W" like so: "-Woutputdir=foo". Option arguments are + handled identically to normal long options. If a string follows the + "-W" that does not represent a valid long option, then getopt() returns + 'W' and the caller must decide what to do. Otherwise getopt() returns + a long option value as described below. +

+ While long options offer convenience, they can also be tedious to type + in full. So it is permissible to abbreviate the option name to as + few characters as required to uniquely identify it. If the name can + represent multiple long options, then an error message is printed and + getopt() returns a '?'. +

+ If an invalid option is specified or a required option argument is + missing, getopt() prints an error and returns a '?' or ':' exactly + as for short options. Note that when an invalid long option is + encountered, the optopt variable is set to integer 0 and so cannot + be used to identify the incorrect option the user entered. +

+ Long options are defined by LongOpt objects. These objects are created + with a contructor that takes four params: a String representing the + object name, a integer specifying what arguments the option takes + (the value is one of LongOpt.NO_ARGUMENT, LongOpt.REQUIRED_ARGUMENT, + or LongOpt.OPTIONAL_ARGUMENT), a StringBuffer flag object (described + below), and an integer value (described below). +

+ To enable long option parsing, create an array of LongOpt's representing + the legal options and pass it to the Getopt() constructor. WARNING: If + all elements of the array are not populated with LongOpt objects, the + getopt() method will throw a NullPointerException. +

+ When getopt() is called and a long option is encountered, one of two + things can be returned. If the flag field in the LongOpt object + representing the long option is non-null, then the integer value field + is stored there and an integer 0 is returned to the caller. The val + field can then be retrieved from the flag field. Note that since the + flag field is a StringBuffer, the appropriate String to integer converions + must be performed in order to get the actual int value stored there. + If the flag field in the LongOpt object is null, then the value field + of the LongOpt is returned. This can be the character of a short option. + This allows an app to have both a long and short option sequence + (say, "-h" and "--help") that do the exact same thing. +

+ With long options, there is an alternative method of determining + which option was selected. The method getLongind() will return the + the index in the long option array (NOT argv) of the long option found. + So if multiple long options are configured to return the same value, + the application can use getLongind() to distinguish between them. +

+ Here is an expanded Getopt example using long options and various + techniques described above: +

+

+ int c;
+ String arg;
+ LongOpt[] longopts = new LongOpt[3];
+ // 
+ StringBuffer sb = new StringBuffer();
+ longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h');
+ longopts[1] = new LongOpt("outputdir", LongOpt.REQUIRED_ARGUMENT, sb, 'o'); 
+ longopts[2] = new LongOpt("maximum", LongOpt.OPTIONAL_ARGUMENT, null, 2);
+ // 
+ Getopt g = new Getopt("testprog", argv, "-:bc::d:hW;", longopts);
+ g.setOpterr(false); // We'll do our own error handling
+ //
+ while ((c = g.getopt()) != -1)
+   switch (c)
+     {
+        case 0:
+          arg = g.getOptarg();
+          System.out.println("Got long option with value '" +
+                             (char)(new Integer(sb.toString())).intValue()
+                             + "' with argument " +
+                             ((arg != null) ? arg : "null"));
+          break;
+          //
+        case 1:
+          System.out.println("I see you have return in order set and that " +
+                             "a non-option argv element was just found " +
+                             "with the value '" + g.getOptarg() + "'");
+          break;
+          //
+        case 2:
+          arg = g.getOptarg();
+          System.out.println("I know this, but pretend I didn't");
+          System.out.println("We picked option " +
+                             longopts[g.getLongind()].getName() +
+                           " with value " + 
+                           ((arg != null) ? arg : "null"));
+          break;
+          //
+        case 'b':
+          System.out.println("You picked plain old option " + (char)c);
+          break;
+          //
+        case 'c':
+        case 'd':
+          arg = g.getOptarg();
+          System.out.println("You picked option '" + (char)c + 
+                             "' with argument " +
+                             ((arg != null) ? arg : "null"));
+          break;
+          //
+        case 'h':
+          System.out.println("I see you asked for help");
+          break;
+          //
+        case 'W':
+          System.out.println("Hmmm. You tried a -W with an incorrect long " +
+                             "option name");
+          break;
+          //
+        case ':':
+          System.out.println("Doh! You need an argument for option " +
+                             (char)g.getOptopt());
+          break;
+          //
+        case '?':
+          System.out.println("The option '" + (char)g.getOptopt() + 
+                           "' is not valid");
+          break;
+          //
+        default:
+          System.out.println("getopt() returned " + c);
+          break;
+     }
+ //
+ for (int i = g.getOptind(); i < argv.length ; i++)
+   System.out.println("Non option argv element: " + argv[i] + "\n");
+ 
+

+ There is an alternative form of the constructor used for long options + above. This takes a trailing boolean flag. If set to false, Getopt + performs identically to the example, but if the boolean flag is true + then long options are allowed to start with a single '-' instead of + "--". If the first character of the option is a valid short option + character, then the option is treated as if it were the short option. + Otherwise it behaves as if the option is a long option. Note that + the name given to this option - long_only - is very counter-intuitive. + It does not cause only long options to be parsed but instead enables + the behavior described above. +

+ Note that the functionality and variable names used are driven from + the C lib version as this object is a port of the C code, not a + new implementation. This should aid in porting existing C/C++ code, + as well as helping programmers familiar with the glibc version to + adapt to the Java version even if it seems very non-Java at times. +

+ In this release I made all instance variables protected due to + overwhelming public demand. Any code which relied on optarg, + opterr, optind, or optopt being public will need to be modified to + use the appropriate access methods. +

+ Please send all bug reports, requests, and comments to + arenn@urbanophile.com. +

+

+
Version: +
1.0.3 +
Author: +
Roland McGrath (roland@gnu.ai.mit.edu), Ulrich Drepper (drepper@cygnus.com), Aaron M. Renn (arenn@urbanophile.com) +
See Also: +
LongOpt +
+
+ +

+ Constructor Index +

+
+
 o + Getopt(String, String[], String) +
Construct a basic Getopt instance with the given input data. +
 o + Getopt(String, String[], String, LongOpt[]) +
Construct a Getopt instance with given input data that is capable of + parsing long options as well as short. +
 o + Getopt(String, String[], String, LongOpt[], boolean) +
Construct a Getopt instance with given input data that is capable of + parsing long options and short options. +
+

+ Method Index +

+
+
 o + getLongind() +
Returns the index into the array of long options (NOT argv) representing + the long option that was found. +
 o + getopt() +
This method returns a char that is the current option that has been + parsed from the command line. +
 o + getOptarg() +
+ For communication from `getopt' to the caller. +
 o + getOptind() +
optind it the index in ARGV of the next element to be scanned. +
 o + getOptopt() +
When getopt() encounters an invalid option, it stores the value of that + option in optopt which can be retrieved with this method. +
 o + setArgv(String[]) +
Since in GNU getopt() the argument vector is passed back in to the + function every time, the caller can swap out argv on the fly. +
 o + setOpterr(boolean) +
Normally Getopt will print a message to the standard error when an + invalid option is encountered. +
 o + setOptind(int) +
This method allows the optind index to be set manually. +
 o + setOptstring(String) +
In GNU getopt, it is possible to change the string containg valid options + on the fly because it is passed as an argument to getopt() each time. +
+ +

+ Constructors +

+ + o +Getopt +
+ public Getopt(String progname,
+               String argv[],
+               String optstring)
+
+
+
Construct a basic Getopt instance with the given input data. Note that + this handles "short" options only. +

+

+
Parameters: +
progname - The name to display as the program name when printing errors +
argv - The String array passed as the command line to the program. +
optstring - A String containing a description of the valid args for this program +
+
+ o +Getopt +
+ public Getopt(String progname,
+               String argv[],
+               String optstring,
+               LongOpt long_options[])
+
+
+
Construct a Getopt instance with given input data that is capable of + parsing long options as well as short. +

+

+
Parameters: +
progname - The name to display as the program name when printing errors +
argv - The String array passed as the command ilne to the program +
optstring - A String containing a description of the valid short args for this program +
long_options - An array of LongOpt objects that describes the valid long args for this program +
+
+ o +Getopt +
+ public Getopt(String progname,
+               String argv[],
+               String optstring,
+               LongOpt long_options[],
+               boolean long_only)
+
+
+
Construct a Getopt instance with given input data that is capable of + parsing long options and short options. Contrary to what you might + think, the flag 'long_only' does not determine whether or not we + scan for only long arguments. Instead, a value of true here allows + long arguments to start with a '-' instead of '--' unless there is a + conflict with a short option name. +

+

+
Parameters: +
progname - The name to display as the program name when printing errors +
argv - The String array passed as the command ilne to the program +
optstring - A String containing a description of the valid short args for this program +
long_options - An array of LongOpt objects that describes the valid long args for this program +
long_only - true if long options that do not conflict with short options can start with a '-' as well as '--' +
+
+ +

+ Methods +

+ o +setOptstring +
+ public void setOptstring(String optstring)
+
+
+
In GNU getopt, it is possible to change the string containg valid options + on the fly because it is passed as an argument to getopt() each time. In + this version we do not pass the string on every call. In order to allow + dynamic option string changing, this method is provided. +

+

+
Parameters: +
optstring - The new option string to use +
+
+ o +getOptind +
+ public int getOptind()
+
+
+
optind it the index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. +

+

+ o +setOptind +
+ public void setOptind(int optind)
+
+
+
This method allows the optind index to be set manually. Normally this + is not necessary (and incorrect usage of this method can lead to serious + lossage), but optind is a public symbol in GNU getopt, so this method + was added to allow it to be modified by the caller if desired. +

+

+
Parameters: +
optind - The new value of optind +
+
+ o +setArgv +
+ public void setArgv(String argv[])
+
+
+
Since in GNU getopt() the argument vector is passed back in to the + function every time, the caller can swap out argv on the fly. Since + passing argv is not required in the Java version, this method allows + the user to override argv. Note that incorrect use of this method can + lead to serious lossage. +

+

+
Parameters: +
argv - New argument list +
+
+ o +getOptarg +
+ public String getOptarg()
+
+
+
For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. + No set method is provided because setting this variable has no effect. +

+

+ o +setOpterr +
+ public void setOpterr(boolean opterr)
+
+
+
Normally Getopt will print a message to the standard error when an + invalid option is encountered. This can be suppressed (or re-enabled) + by calling this method. There is no get method for this variable + because if you can't remember the state you set this to, why should I? +

+

+ o +getOptopt +
+ public int getOptopt()
+
+
+
When getopt() encounters an invalid option, it stores the value of that + option in optopt which can be retrieved with this method. There is + no corresponding set method because setting this variable has no effect. +

+

+ o +getLongind +
+ public int getLongind()
+
+
+
Returns the index into the array of long options (NOT argv) representing + the long option that was found. +

+

+ o +getopt +
+ public int getopt()
+
+
+
This method returns a char that is the current option that has been + parsed from the command line. If the option takes an argument, then + the internal variable 'optarg' is set which is a String representing + the the value of the argument. This value can be retrieved by the + caller using the getOptarg() method. If an invalid option is found, + an error message is printed and a '?' is returned. The name of the + invalid option character can be retrieved by calling the getOptopt() + method. When there are no more options to be scanned, this method + returns -1. The index of first non-option element in argv can be + retrieved with the getOptind() method. +

+

+
Returns: +
Various things as described above +
+
+
+
+All Packages  Class Hierarchy  This Package  Previous  Next  Index
+ + diff --git a/ssdd_p1_100291121_100292107/gnu/getopt/gnu.getopt.LongOpt.html b/ssdd_p1_100291121_100292107/gnu/getopt/gnu.getopt.LongOpt.html new file mode 100755 index 0000000..ddc1186 --- /dev/null +++ b/ssdd_p1_100291121_100292107/gnu/getopt/gnu.getopt.LongOpt.html @@ -0,0 +1,210 @@ + + + + + + + Class gnu.getopt.LongOpt + + + + +
+All Packages  Class Hierarchy  This Package  Previous  Next  Index
+
+

+ Class gnu.getopt.LongOpt +

+
+java.lang.Object
+   |
+   +----gnu.getopt.LongOpt
+
+
+
+
public class LongOpt +
extends Object +
+This object represents the definition of a long option in the Java port + of GNU getopt. An array of LongOpt objects is passed to the Getopt + object to define the list of valid long options for a given parsing + session. Refer to the getopt documentation for details on the + format of long options. +

+

+
Version: +
1.0.3 +
Author: +
Aaron M. Renn (arenn@urbanophile.com) +
See Also: +
Getopt +
+
+ +

+ Variable Index +

+
+
 o + NO_ARGUMENT +
Constant value used for the "has_arg" constructor argument. +
 o + OPTIONAL_ARGUMENT +
Constant value used for the "has_arg" constructor argument. +
 o + REQUIRED_ARGUMENT +
+ Constant value used for the "has_arg" constructor argument. +
+

+ Constructor Index +

+
+
 o + LongOpt(String, int, StringBuffer, int) +
Create a new LongOpt object with the given parameter values. +
+

+ Method Index +

+
+
 o + getFlag() +
Returns the value of the 'flag' field for this long option + + +
 o + getHasArg() +
Returns the value set for the 'has_arg' field for this long option + + +
 o + getName() +
Returns the name of this LongOpt as a String + + +
 o + getVal() +
Returns the value of the 'val' field for this long option + + +
+ +

+ Variables +

+ o +NO_ARGUMENT +
+ public static final int NO_ARGUMENT
+
+
+
Constant value used for the "has_arg" constructor argument. This + value indicates that the option takes no argument.

+

+ o +REQUIRED_ARGUMENT +
+ public static final int REQUIRED_ARGUMENT
+
+
+
Constant value used for the "has_arg" constructor argument. This + value indicates that the option takes an argument that is required.

+

+ o +OPTIONAL_ARGUMENT +
+ public static final int OPTIONAL_ARGUMENT
+
+
+
Constant value used for the "has_arg" constructor argument. This + value indicates that the option takes an argument that is optional.

+

+ +

+ Constructors +

+ + o +LongOpt +
+ public LongOpt(String name,
+                int has_arg,
+                StringBuffer flag,
+                int val) throws IllegalArgumentException
+
+
+
Create a new LongOpt object with the given parameter values. If the + value passed as has_arg is not valid, then an exception is thrown. +

+

+
Parameters: +
name - The long option String. +
has_arg - Indicates whether the option has no argument (NO_ARGUMENT), a required argument (REQUIRED_ARGUMENT) or an optional argument (OPTIONAL_ARGUMENT). +
flag - If non-null, this is a location to store the value of "val" when this option is encountered, otherwise "val" is treated as the equivalent short option character. +
val - The value to return for this long option, or the equivalent single letter option to emulate if flag is null. +
Throws: IllegalArgumentException +
If the has_arg param is not one of NO_ARGUMENT, REQUIRED_ARGUMENT or OPTIONAL_ARGUMENT. +
+
+ +

+ Methods +

+ o +getName +
+ public String getName()
+
+
+
Returns the name of this LongOpt as a String +

+

+
Returns: +
Then name of the long option +
+
+ o +getHasArg +
+ public int getHasArg()
+
+
+
Returns the value set for the 'has_arg' field for this long option +

+

+
Returns: +
The value of 'has_arg' +
+
+ o +getFlag +
+ public StringBuffer getFlag()
+
+
+
Returns the value of the 'flag' field for this long option +

+

+
Returns: +
The value of 'flag' +
+
+ o +getVal +
+ public int getVal()
+
+
+
Returns the value of the 'val' field for this long option +

+

+
Returns: +
The value of 'val' +
+
+
+
+All Packages  Class Hierarchy  This Package  Previous  Next  Index
+ + diff --git a/ssdd_p1_100291121_100292107/msg_list.c b/ssdd_p1_100291121_100292107/msg_list.c new file mode 100644 index 0000000..ce0b614 --- /dev/null +++ b/ssdd_p1_100291121_100292107/msg_list.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include "msg_list.h" + + +/* Creates a new message struct and enqueues it to the end of the message queue + Returns 0 if the message is stored + -1 if malloc error */ +int enqueueMsg(struct msg **head, char * message, unsigned int id, char * sender){ + struct msg *temp; + /* Allocate the space for the new message */ + temp = (struct msg *) malloc(sizeof(struct msg)); + /* If malloc returns error (full memory or other) */ + if(temp == NULL) return -1; + strcpy(temp->body, message); + strcpy(temp->sender, sender); + temp->id = id; + temp->next = NULL; + + if (*head == NULL){ /* Queue is empty */ + temp->next = *head; + *head = temp; + } + else{ + /* If the queue is not empty, iterate to the end and append the message */ + struct msg *last = *head; + while(last->next != NULL){ + last = last->next; + } + last->next = temp; + } + return 0; +} +/* Deletes the message at the head of the queue and returns the new + head of the list + Return a pointer to the next message in the queue + NULL if the list is left empty */ +struct msg * dequeueMsg(struct msg **head){ + struct msg* temp = *head; + /* Head pointing to the next element */ + *head = temp->next; + /* Free the resources of the first message */ + free(temp); + /* Return the new head of the queue */ + return *head; +} + +/* Deletes all the messages in the list from the head of the list +passed as paremeter */ +void deleteAllMsgs(struct msg ** head){ + struct msg **temp = head; + while(*temp != NULL){ + *temp = dequeueMsg(&(*temp)); + } + return; +} \ No newline at end of file diff --git a/ssdd_p1_100291121_100292107/msg_list.h b/ssdd_p1_100291121_100292107/msg_list.h new file mode 100644 index 0000000..afe2e09 --- /dev/null +++ b/ssdd_p1_100291121_100292107/msg_list.h @@ -0,0 +1,13 @@ +#define MAX_MSG 256 + +struct msg{ + char body[MAX_MSG]; /* Content of the message */ + char sender[MAX_MSG]; /* Sender of the message */ + unsigned int id; /* ID assigned to the message */ + struct msg *next; /* Pointer to the next message in the list */ +}; + +/* ================FUNCTION HEADERS================ */ +int enqueueMsg(struct msg **head, char * message, unsigned int id, char * sender); +struct msg * dequeueMsg(struct msg **head); +void deleteAllMsgs(struct msg ** head); \ No newline at end of file diff --git a/exercises2/read_line.c b/ssdd_p1_100291121_100292107/read_line.c similarity index 77% rename from exercises2/read_line.c rename to ssdd_p1_100291121_100292107/read_line.c index 4cfefe3..c2038c3 100644 --- a/exercises2/read_line.c +++ b/ssdd_p1_100291121_100292107/read_line.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "read_line.h" int send_msg(int socket, char *message, int length) @@ -9,10 +11,10 @@ int send_msg(int socket, char *message, int length) do { - r = write(socket, message, l); - l = l -r; - message = message + r; - } while ((l>0) && (r>=0)); + r = send(socket, message, l, 0); + l = l -r; /* Pending data to send */ + message = message + r; /* */ + } while ((l>0) && (r>=0)); /* We check the returned value in case all the data was not sent */ if (r < 0) return (-1); /* fail */ @@ -20,26 +22,6 @@ int send_msg(int socket, char *message, int length) return(0); /* success */ } -int recv_msg(int socket, char *message, int length) -{ - int r; - int l = length; - - - do { - r = read(socket, message, l); - l = l -r ; - message = message + r; - } while ((l>0) && (r>=0)); - - if (r < 0) - return (-1); /* fail */ - else - return(0); /* success */ -} - - - ssize_t readLine(int fd, void *buffer, size_t n) { ssize_t numRead; /* num of bytes fetched by last read() */ diff --git a/exercises2/read_line.h b/ssdd_p1_100291121_100292107/read_line.h similarity index 100% rename from exercises2/read_line.h rename to ssdd_p1_100291121_100292107/read_line.h diff --git a/ssdd_p1_100291121_100292107/report.pdf b/ssdd_p1_100291121_100292107/report.pdf new file mode 100644 index 0000000..a186cbb Binary files /dev/null and b/ssdd_p1_100291121_100292107/report.pdf differ diff --git a/ssdd_p1_100291121_100292107/server.c b/ssdd_p1_100291121_100292107/server.c new file mode 100644 index 0000000..f4dd5b7 --- /dev/null +++ b/ssdd_p1_100291121_100292107/server.c @@ -0,0 +1,615 @@ +#include /* For addresses in PF_INET */ +#include /* Address-->Network and Network-->Address library; gethostbyname; gethostbyaddr */ +#include +#include /* To use ifreq */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "read_line.h" +#include "user_list.h" +#include "msg_list.h" +#include "server.h" + +/* Handler for interrupts */ +void interruptHandler(int sig){ + printf("[SERVER]: Handling interrupt. Closing server socket...\n"); + /* Close the server socket and exit with the resulting return value. 0 if OK, -1 if error */ + exit(close(s_server)); +} + +int main(int argc, char * argv[]){ + struct sockaddr_in server_addr, client_addr; + int sc; + int val; + int server_port; + + /* Check command */ + if(argc != 3 || strcmp(argv[1],"-p") != 0){ + printf("Usage: ./server -p \n"); + exit(-1); + } + + /* Check if the port number passed as parameter is valid */ + server_port = atoi(argv[2]); + if ((server_port < 1024) || (server_port > 65535)) { + printf("Error: Port must be in the range 1024 <= port <= 65535\n"); + exit(-1); + } + + /* Initialize mutexes */ + if(pthread_mutex_init(&socket_mtx, NULL) != 0) { + perror("[SERVER]: Error when initializing the mutex"); + exit(-1); + } + if(pthread_mutex_init(&list_mtx, NULL) != 0) { + perror("[SERVER]: Error when initializing the mutex"); + exit(-1); + } + /* Initialize condition variable for copying the socket descriptor in the thread */ + if(pthread_cond_init(&free_socket, NULL) != 0) { + perror("[SERVER]: Error when initializing the mutex"); + exit(-1); + } + + /* Prepare thread conditions */ + thread = (pthread_t) malloc((sizeof(thread))); + pthread_attr_init(&thread_att); + pthread_attr_setdetachstate(&thread_att, PTHREAD_CREATE_DETACHED); + + s_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* This socket has no address assigned */ + if(s_server == -1){ + perror("Error when creating the socket"); + exit(-1); + } + + /* Obtain the IP address attached to interface eth0 */ + struct ifreq ifr; + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1); + ioctl(s_server, SIOCGIFADDR, &ifr); + + val = 1; + setsockopt(s_server, SOL_SOCKET, SO_REUSEADDR, (char*) &val, sizeof(int)); /* Makes the address of the socket reusable */ + + /* Initialize the address that will be attached to the listening socket */ + bzero((char*) &server_addr, sizeof(server_addr)); /* Initialize the socket address of the server to 0 */ + server_addr.sin_family = AF_INET; + server_addr.sin_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; /* Listens to IP address in eth0 interface*/ + server_addr.sin_port = htons(server_port); /* Port number */ + + /* Bind the address to the listening socket */ + if((bind(s_server, (struct sockaddr*) &server_addr, sizeof(server_addr))) == -1){ + perror("Error when binding the address to the socket"); + exit(-1); + } + + /* Set the socket to listen incoming requests */ + if(listen(s_server, 5) == -1){ + perror("Error when listening to the socket"); + exit(-1); + } /* Backlog is 5, maximum number of queued requests is 5 */ + + /* Once the server is listening, print inicial prompt */ + printf("s> init server %s:%d\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), + ntohs(server_addr.sin_port)); + + /* Define the variable for the client address size. It should be declared + as variable because the size depends on the incoming request and is an + output parameter of the 'accept' function */ + socklen_t cl_addr_size = sizeof(client_addr); + + /* Set the control variable to TRUE so that the listening thread waits + until the thread stores a local copy of the socket descriptor */ + busy_socket = TRUE; + + signal(SIGINT, interruptHandler); /* Handles the ctrl+c signal to interrupt the server */ + fprintf(stderr, "%s", "s> "); /* Prompt */ + + /* Loop for accepting and creating threads for each incoming request */ + while(1){ + /* Accept client connections. If error, shut down the server */ + sc = accept(s_server, (struct sockaddr *) &client_addr, &cl_addr_size); + if(sc == -1){ + perror("Error when accepting the connection"); + /* Close listening server socket */ + close(s_server); + exit(-1); + } + /* Once accepted, create a thread to handle the request. If error, shut down the server */ + if(pthread_create(&thread, &thread_att, (void *) manageRequest, &sc) != 0) { + perror("[SERVER]: Error when creating the thread"); + /* Close both listening socket and the one resulting from the accept operation */ + close(s_server); + close(sc); + exit(-1); + } + + /* Wait for the thread to copy the socket descriptor locally */ + pthread_mutex_lock(&socket_mtx); + while(busy_socket == TRUE) + pthread_cond_wait(&free_socket, &socket_mtx); + busy_socket = TRUE; + pthread_mutex_unlock(&socket_mtx); + + } + + exit(0); +} + +void * manageRequest(int *sd){ + int s_local; + char operation_buff[MAX_COMMAND]; + char user_buff[MAX_USERNAME]; + char msg_buff[MAX_MSG]; + int n; + int m; + char out; + + /* Copy locally the socket descriptor */ + pthread_mutex_lock(&socket_mtx); + s_local = *sd; + busy_socket = FALSE; + pthread_cond_signal(&free_socket); + pthread_mutex_unlock(&socket_mtx); + + /* Read the operation. If error, close the socket and terminate the thread */ + n = readLine(s_local, operation_buff, MAX_COMMAND); + if(n == -1){ + perror("[SERVER_THREAD]: Error when reading from the socket"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Read the username and convert to uppercase. If error, close the socket + and terminate the thread */ + m = readLine(s_local, user_buff, MAX_USERNAME); + if(m == -1){ + perror("[SERVER_THREAD]: Error when reading from the socket\n"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* For convention of the server, convert every username to uppercase */ + toUpperCase(user_buff); + + /* Check the operation */ + if (strcmp(operation_buff, "REGISTER") == 0){ + /* Register the user */ + pthread_mutex_lock(&list_mtx); + out = registerUser(user_buff); + pthread_mutex_unlock(&list_mtx); + + } + else if (strcmp(operation_buff, "UNREGISTER") == 0){ + /* Unregister the user */ + pthread_mutex_lock(&list_mtx); + out = unregisterUser(user_buff); + pthread_mutex_unlock(&list_mtx); + + } + else if(strcmp(operation_buff, "CONNECT") == 0){ + + struct sockaddr_in client_addr_local; + socklen_t addr_len = sizeof(client_addr_local); + uint16_t client_port; + + n = readLine(s_local, msg_buff, MAX_MSG); + if(n == -1){ + perror("[SERVER_THREAD]: Error when reading from the socket"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Get the port number from the socket */ + client_port = (uint16_t) atoi(msg_buff); + /* Get the client IP address attached to the socket */ + int err = getpeername(s_local, (struct sockaddr *) &client_addr_local, &addr_len); + if (err == -1){ + perror("[SERVER_THREAD]: Error when getting client address"); + /* Send error 3 to client and close socket */ + out = 3; + goto respond_to_client; + } + /* Connect the user to the server */ + pthread_mutex_lock(&list_mtx); + out = connectUser(user_buff, inet_ntoa(client_addr_local.sin_addr), client_port); + pthread_mutex_unlock(&list_mtx); + + + /* If result is 0, then check for the pending messages and send them */ + if(out == 0){ + /* Send code 0 for the client to open the listening thread */ + if((send_msg(s_local, &out, sizeof(out))) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + fprintf(stderr, "%s %s %s", operation_buff, user_buff, "OK"); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + + /* Send Pending Messages */ + pthread_mutex_lock(&list_mtx); + struct msg **pend_msg = getPendMsgHead(user_buff); + while(*pend_msg != NULL){ + pthread_mutex_unlock(&list_mtx); + char sender[MAX_USERNAME]; + char msg_body[MAX_MSG]; + + /* Get the name of the sender, the id and the body associated to the message to be sent */ + pthread_mutex_lock(&list_mtx); + strcpy(sender, (*pend_msg)->sender); + int msg_id = (*pend_msg)->id; + strcpy(msg_body, (*pend_msg)->body); + pthread_mutex_unlock(&list_mtx); + + /* Try to send the message. The 'stored' flag is set to 1 because the message + is already stored in the server */ + int err = sendMessage(sender, user_buff, msg_body, msg_id, 1); + + /* If the message could not be delivered/stored, then exit the loop */ + if(err != 0) goto destroy_thread; + + /* Send acknowledge to the sender. No return value is checked */ + sendAck(sender, msg_id); + + /* Remove the message from the pending message queue and iterate with the next message */ + pthread_mutex_lock(&list_mtx); + *pend_msg = dequeueMsg(&(*pend_msg)); + } + pthread_mutex_unlock(&list_mtx); + } + goto destroy_thread; + } + else if(strcmp(operation_buff, "DISCONNECT") == 0){ + /* Get the IP from which the command is being executed */ + struct sockaddr_in client_addr_local; + socklen_t addr_len = sizeof(client_addr_local); + + int err = getpeername(s_local, (struct sockaddr *) &client_addr_local, &addr_len); + if (err == -1){ + perror("Error when getting client address"); + /* Send error 3 to client and close socket */ + out = 3; + goto respond_to_client; + } + /* Try to disconnect the user passing the IP from which the request is being made + as parameter to the function */ + pthread_mutex_lock(&list_mtx); + out = disconnectUser(user_buff, inet_ntoa(client_addr_local.sin_addr)); + pthread_mutex_unlock(&list_mtx); + + } + else if(strcmp(operation_buff, "SEND") == 0){ + /* Reserve a buffer for the username of the receiver */ + char dest_user_buff[MAX_USERNAME]; + + /* Read the destination user from the socket */ + m = readLine(s_local, dest_user_buff, MAX_USERNAME); + if(m == -1){ + perror("[SERVER_THREAD]: Error when reading from the socket\n"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Convert username to uppercase by convention */ + toUpperCase(dest_user_buff); + + /* Read the message from the socket */ + n = readLine(s_local, msg_buff, MAX_MSG); + if(m == -1){ + perror("[SERVER_THREAD]: Error when reading from the socket\n"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + /* Check if one of the two users is not registered */ + pthread_mutex_lock(&list_mtx); + if(!isRegistered(user_buff) || !isRegistered(dest_user_buff)){ + pthread_mutex_unlock(&list_mtx); + /* Send code 1 to the client and close the socket */ + out = 1; + goto respond_to_client; + } + pthread_mutex_unlock(&list_mtx); + + /* Check the status of the destination user */ + pthread_mutex_lock(&list_mtx); + char status = isConnected(dest_user_buff); + unsigned int last_id = updateLastID(user_buff); //Update the last id of the sender message + pthread_mutex_unlock(&list_mtx); + + if(status == 0){ //Not connected + /* Store the message */ + if (storeMessage(user_buff, dest_user_buff, msg_buff, last_id) != 0){ + /* Message could not be stored so send code 2 to the client and close the socket */ + out = 2; + goto respond_to_client; + } + /* Message was stored successfully, send code 0 and message ID to the client */ + out = 0; + if((send_msg(s_local, &out, sizeof(out))) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Send string with the message ID back to the sender */ + char id_string[11]; + sprintf(id_string, "%d", last_id); + if((send_msg(s_local, id_string, strlen(id_string)+1)) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + }else if(status == 1){ //Connected + /* Try to send the message to the receiver. We set the 'stored' flag to 0 because the message + is being sent for the first time and was not previously stored int he server */ + int err = sendMessage(user_buff, dest_user_buff, msg_buff, last_id, 0); + /* If while trying to store the message, the user unregisters, value 1 will be returned */ + if(err == 1){ + out = 1; + goto respond_to_client; + }else if(err == -1){ + /* If any server error occurred and the message was not stored or sent, then send code 2 + back to the client */ + out = 2; + goto respond_to_client; + } + + /* If no server error occured, then the message was either sent or stored, so we send back + the code 0 (OK) to the client */ + out = 0; + if ((send_msg(s_local, &out, sizeof(out))) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Send string with the message ID back to the sender */ + char id_string[11]; + sprintf(id_string, "%d", last_id); + if((send_msg(s_local, id_string, strlen(id_string)+1)) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + /* At this point, the message is assumed to */ + sendAck(user_buff, last_id); + } + /* The response to the client is handled within this else-of statement, so the + 'respond_to_client' label is skipped and proceed to close the socket */ + goto destroy_thread; + } + + /* Default print template */ + switch(out){ + case 0: + fprintf(stderr, "%s %s %s", operation_buff, user_buff, "OK"); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + break; + default: + fprintf(stderr, "%s %s %s", operation_buff, user_buff, "FAIL"); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + } + + /* Label to jump previous code to respond the client and skip the default print right above, + in case other commands (as SEND) do not use a template print */ + respond_to_client: + if((send_msg(s_local, &out, sizeof(out))) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + destroy_thread: + if(close(s_local) == -1){ + perror("[SERVER_THREAD]: Error when closing the socket in the thread"); + exit(-1); + } + pthread_exit(NULL); +} + +/* Capitalizes the input string. String is both an input and output parameter */ +void toUpperCase(char * string){ + /* Convert to uppercase */ + int i; + for(i = 0; string[i]; i++){ + string[i] = toupper(string[i]); + } +} + +/* Return 0: Message is stored OK + Return -1: Server error (Memory space error) */ +int storeMessage(char * sender, char * receiver, char * msg, unsigned int msg_id){ + /* Store the message to the receiver pending list */ + pthread_mutex_lock(&list_mtx); + int err = storeMsg(receiver, msg, msg_id, sender); + pthread_mutex_unlock(&list_mtx); + + /* Error when trying to store the message */ + if(err == -1) return -1; + + fprintf(stderr, "MESSAGE %d FROM %s TO %s STORED", msg_id, + sender, receiver); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + + /* Return store OK */ + return 0; +} + +/* Return 0: Message is sent OK + Return 1: User did not exist when trying to store/send the message. Message not stored + Return 2: Message is stored, or not stored if was already stored + Return -1: Server error */ +int sendMessage(char * sender, char * receiver, char * msg, unsigned int msg_id, char stored){ + int s_receiver; //Socket for the receiver of the message + struct sockaddr_in recv_addr; //Receiver address + struct hostent *recv_hp; //Host entity structure for the receiver + + s_receiver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(s_receiver == -1){ + return -1; //Send error message. -1 is internally encoded as server error + } + + bzero((char *) &recv_addr, sizeof(recv_addr)); //Reserve space for the address of the receiver + + pthread_mutex_lock(&list_mtx); + recv_hp = gethostbyname(getUserIP(receiver)); //Get the IP of the receiver + pthread_mutex_unlock(&list_mtx); + /* If error when getting the host, return -1 */ + if(recv_hp == NULL) return -1; + + memcpy(&(recv_addr.sin_addr), recv_hp->h_addr, recv_hp->h_length); //Get the IP addres in network format + recv_addr.sin_family = AF_INET; + pthread_mutex_lock(&list_mtx); + recv_addr.sin_port = htons(getUserPort(receiver)); //Get the port number of the receiver listening thread + pthread_mutex_unlock(&list_mtx); + + /* Try to connect to the listening thread of the receiver to send the message */ + if (connect(s_receiver, (struct sockaddr *) &recv_addr, sizeof(recv_addr)) == -1){ + /* If the connection with the receiver fails, assume the client + to be disconnected, disconnect it and store the message */ + pthread_mutex_lock(&list_mtx); + /* As we are internally disconnecting the user from the server, we need to bypass the + IP check, so we pass the IP of the receiver as parameter to always fulfill the condition */ + char reg = disconnectUser(receiver, getUserIP(receiver)); // No need to check for output + pthread_mutex_unlock(&list_mtx); + /* If the disconnect method returns 1, it means that the user was not found so is not + registered (it unregister while trying to store the message, so we return 1 */ + if(reg == 1){ + return 1; + } + /* If the stored parameter is set to 0, it means that the message was not prevoiusly stored by the + server so we need to push it to the end of the queue. If it was stored, then nothing is done */ + if(!stored){ + if(storeMessage(sender, receiver, msg, msg_id) == -1) return -1; //Return -1 if store error + } + + if(close(s_receiver) == -1){ //Close the socket + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + /* Return 2 to indicate the message is stored but not sent */ + return 2; + } + /* Send the SEND_MESSAGE string to the receiver to detect an incoming message */ + char op[13]; + strcpy(op, "SEND_MESSAGE"); + send_msg(s_receiver, op, strlen(op)+1); + /* Send the sender name */ + send_msg(s_receiver, sender, strlen(sender)+1); + /* Send the identifier of the message */ + char id_string[11]; + sprintf(id_string, "%d", msg_id); + send_msg(s_receiver, id_string, strlen(id_string)+1); + /* Send the message */ + send_msg(s_receiver, msg, strlen(msg)+1); + + if(close(s_receiver) == -1){ //Close the socket + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + + fprintf(stderr, "SEND MESSAGE %d FROM %s TO %s", msg_id, + sender, receiver); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + return 0; +} + +/* Tries to send acknowledge to the sender. No return value */ +void sendAck(char * sender, unsigned int msg_id){ + int s_sender; //Socket for the receiver of the message + struct sockaddr_in sender_addr; //Sender address + struct hostent *sender_hp; //Host entity structure for the sender + + s_sender = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(s_sender == -1){ + /* If error when allocating resources for the socket, then exit */ + return; + } + + char ack_op[14]; + strcpy(ack_op, "SEND_MESS_ACK"); + + bzero((char *) &sender_addr, sizeof(sender_addr)); + + pthread_mutex_lock(&list_mtx); + sender_hp = gethostbyname(getUserIP(sender)); + pthread_mutex_unlock(&list_mtx); + /* If any error when getting the hoset, exit the function */ + if(sender_hp == NULL) return; + + memcpy(&(sender_addr.sin_addr), sender_hp->h_addr, sender_hp->h_length); + sender_addr.sin_family = AF_INET; + + pthread_mutex_lock(&list_mtx); + sender_addr.sin_port = htons(getUserPort(sender)); + pthread_mutex_unlock(&list_mtx); + + if((connect(s_sender, (struct sockaddr *) &sender_addr, sizeof(sender_addr))) == -1){ + /* If error when connecting, exit the function */ + return; + } + + + char id_string[11]; + sprintf(id_string, "%d", msg_id); + if((send_msg(s_sender, ack_op, strlen(ack_op)+1)) == -1){ + /* If error when sending the ACK, close the socket and exit the function */ + if(close(s_sender) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + return; + } + if((send_msg(s_sender, id_string, strlen(id_string)+1)) == -1){ + /* If error when sending the ACK, close the socket and exit the function */ + if(close(s_sender) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + return; + } + + if(close(s_sender) == -1){ //Close the socket + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + return; +} \ No newline at end of file diff --git a/ssdd_p1_100291121_100292107/server.h b/ssdd_p1_100291121_100292107/server.h new file mode 100644 index 0000000..f1acb08 --- /dev/null +++ b/ssdd_p1_100291121_100292107/server.h @@ -0,0 +1,27 @@ +#define MAX_COMMAND 11 + +/* Mutex & Threads */ +pthread_mutex_t socket_mtx; +pthread_mutex_t list_mtx; +pthread_t thread; +pthread_attr_t thread_att; +/* Controls the access to the socket generated by the connection 'accept' */ +pthread_cond_t free_socket; +pthread_cond_t free_list; + +/* Variable that controls the state of the socket created by the connection 'accept' */ +int busy_socket; + +/* Declare the server socket as global variable */ +int s_server; + +/* Declare the list of users */ +struct user *users; + +/* ================FUNCTION HEADERS================ */ +void interruptHandler(int sig); +void * manageRequest(int *sd); +void toUpperCase(char * string); +int sendMessage(char * sender, char * receiver, char * msg, unsigned int msg_id, char stored); +void sendAck(char * sender, unsigned int msg_id); +int storeMessage(char * sender, char * receiver, char * msg, unsigned int mgs_id); \ No newline at end of file diff --git a/ssdd_p1_100291121_100292107/user_list.c b/ssdd_p1_100291121_100292107/user_list.c new file mode 100644 index 0000000..cd2c93b --- /dev/null +++ b/ssdd_p1_100291121_100292107/user_list.c @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include "msg_list.h" +#include "user_list.h" + +/* Checks if the input user is already registered + Return 0 if is registered + 1 if is not registered */ +char isRegistered(char * username){ + struct user *temp; + temp = user_head; + + /* Iterate over the list */ + while (temp != NULL){ + if (strcmp(temp->username, username) == 0){ //Check if the username exists + return 1; + } + temp = temp->next; + } + + return 0; + } + +/* Registers a user (if not previously registered) and appends it to the end of the s list + Returns 1 if already registered + 0 if registered correctly */ +char registerUser(char * username){ + /* Check if the user already exists */ + if(isRegistered(username)) return 1; + + /* Prepare new user */ + struct user *temp; + temp = (struct user *) malloc(sizeof(struct user)); + /* If memory is full and malloc is not possible, we return code 2 */ + if(temp == NULL) return 2; + /* Initialize user values */ + strcpy(temp->username, username); + temp->status = 0; + strcpy(temp->ip, "-1"); + temp->port = 0; + temp->pend_msgs_head = NULL; + temp->next = NULL; + temp->last_id = 0; + + if (user_head == NULL){ //If list is empty + temp->next = user_head; + user_head = temp; + } + else{ + struct user *last = user_head; + + /* Iterate over the list */ + while(last->next != NULL){ + last = last->next; + } + last->next = temp; + } + + return 0; +} + +/* Changes the status of a user to 1 (ON) and links an IP and port number to it + Return 0 if connect OK + 1 if user is not registered + 2 if registered but not connected */ +char connectUser(char * username, char * ip, uint16_t port){ + struct user *temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + if (temp->status == 1) return 2; //User already connected + /* Change status to 1 ("ON") and update IP and Port */ + temp->status = 1; + strcpy(temp->ip, ip); + temp->port = port; + return 0; + } + temp = temp->next; + } + /* No user was found, so send code 1 */ + return 1; +} + +/* Changes the status of a user to 0 (OFF) and cleans the IP and port number + Return 0 if disconnect OK; + 1 if user is not registered; + 2 if registered but not connected; + 3 if trying to disconnect from a different IP */ +char disconnectUser(char * username, char * used_ip){ + struct user *temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + if (temp->status == 0) return 2; //User already disconnected + if(strcmp(temp->ip, used_ip) != 0) return 3; //Trying to disconnect from a different IP + /* Change status to 0 ("OFF") and delete IP and Port */ + temp->status = 0; + strcpy(temp->ip, "-1"); + temp->port = 0; + return 0; + } + temp = temp->next; + } + + return 1; +} + + +/* Unregisters a user, deleting it and its pending messages (if any) from the list + Returns 1 if the user does not exist. + 0 if the user is deleted correctly */ +char unregisterUser(char * username){ + struct user *temp, *prev; //temp is the current user, prev is the previous user in the list + temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + if(temp == user_head){ //If the user is at the user_head of the list + user_head = temp->next; //change the user_head to the next element + /* Delete the pending messages if any */ + deleteAllMsgs(&(temp->pend_msgs_head)); + free(temp); //Free the resources of the user + return 0; + } + else{ //User is not at the user_head + prev->next = temp->next; + /* Delete the pending messages if any */ + deleteAllMsgs(&(temp->pend_msgs_head)); + /* Free the memory resources of the user structure */ + free(temp); + return 0; + } + } + else{ + prev = temp; + temp = temp->next; + } + } + //If we reach this point, no user was found + return 1; +} + +/* Returns 0 if store OK. -1 if server error (malloc error because of full memory) */ +int storeMsg(char * username, char* msg, unsigned int msg_id, char * sender){ + struct user *temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + //Enqueue message + return enqueueMsg(&(temp->pend_msgs_head), msg, msg_id, sender); + } + temp = temp->next; + } + + return -1; //User was not found +} + +/* Increments the last-sent-message ID associated to the input user + Return the value of the updated ID */ +unsigned int updateLastID(char * username){ + struct user *temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + //Increment the ID in 1 + temp->last_id = temp->last_id+1; + //If it results in 0, then the maximum representable number is overflown + if(temp->last_id == 0) temp->last_id = 1; + + return temp->last_id; + } + temp = temp->next; + } + + return 0; +} + +/* Checks if the input user is connected + Return 0 if the user is disconnected + 1 if the user is connected + 2 if error (user was not found) */ +char isConnected(char * username){ + struct user *temp = user_head; + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + return temp->status; //Returns 0 if OFF, 1 if ON + } + temp = temp->next; + } + /* Return error 2 if we reach this point. No user was found */ + return 2; +} + +/* Retrieves the IP associated to a user in the list + Returns a char array with the IP of the user + NULL if the user was not found */ +char * getUserIP(char * username){ + struct user *temp = user_head; + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + return temp->ip; //Returns the IP of the user + } + temp = temp->next; + } + return NULL; +} + +/* Retrieves the port number associated to a user in the list + Return the port number + 0 if the user was not found */ +uint16_t getUserPort(char * username){ + struct user *temp = user_head; + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + return temp->port; //Returns the IP of the user + } + temp = temp->next; + } + return 0; +} + +/* Retrieves a pointer to the head of the pending message list associated to a user + Return the pointer to the head of the message list + NULL if the user was not found */ +struct msg ** getPendMsgHead(char * username){ + struct user *temp = user_head; + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + return &(temp->pend_msgs_head); //Returns the IP of the user + } + temp = temp->next; + } + return NULL; +} + diff --git a/ssdd_p1_100291121_100292107/user_list.h b/ssdd_p1_100291121_100292107/user_list.h new file mode 100644 index 0000000..03b964b --- /dev/null +++ b/ssdd_p1_100291121_100292107/user_list.h @@ -0,0 +1,27 @@ +#define MAX_USERNAME 256 +#define MAX_IP 16 +#define TRUE 1 +#define FALSE 0 + +struct user{ + char username[MAX_USERNAME]; /* Username that acts as ID */ + char status; /* Status of the client: 0 if "OFF"; 1 if "ON" */ + char ip[MAX_IP]; /* IP of the user from which the connect operation was made */ + uint16_t port; /* Port number of the user from which the connect operation was made */ + unsigned int last_id; /* ID assigned to the last sent message */ + struct msg *pend_msgs_head; /* Pointer to the head of the pending messages queue */ + struct user *next; /* Pointer to the next user in the list */ +} *user_head; + +/* ================FUNCTION HEADERS================ */ +char isRegistered(char * username); +char registerUser(char * username); +char unregisterUser(char * username); +char connectUser(char * username, char * ip, uint16_t port); +char disconnectUser(char * username, char * used_ip); +int storeMsg(char * username, char* msg, unsigned int msg_id, char * sender); +unsigned int updateLastID(char * username); +char isConnected(char * username); +char * getUserIP(char * username); +uint16_t getUserPort(char * username); +struct msg ** getPendMsgHead(char * username); \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107.zip b/ssdd_p2_100291121_100292107.zip new file mode 100644 index 0000000..88812a3 Binary files /dev/null and b/ssdd_p2_100291121_100292107.zip differ diff --git a/ssdd_p2_100291121_100292107/Makefile b/ssdd_p2_100291121_100292107/Makefile new file mode 100644 index 0000000..a06fb56 --- /dev/null +++ b/ssdd_p2_100291121_100292107/Makefile @@ -0,0 +1,54 @@ + +# Parameters +RPC_PATH = ./rpc_store_service +LISTS_PATH = ./lists + +SERVER = server +CLIENT = client +MD5_WS = ./md5/server/endpoint/MD5Publisher +MONITOR = monitor +RPC_SERVER = storeServer + +SOURCES_CLNT.c = +SOURCES_CLNT.h = +SOURCES_SVC.c = +SOURCES_SVC.h = +SOURCES.x = $(RPC_PATH)/store_service.x + +TARGETS_SERVER.c = $(LISTS_PATH)/user_list.c $(LISTS_PATH)/msg_list.c $(LISTS_PATH)/read_line.c +TARGETS_SVC.c = $(RPC_PATH)/store_service_svc.c $(RPC_PATH)/store_service_xdr.c +TARGETS_CLNT.c = $(RPC_PATH)/store_service_clnt.c $(RPC_PATH)/store_service_xdr.c + +OBJECTS_SERVER = $(TARGETS_SERVER.c:%.c=%.o) +OBJECTS_CLNT = $(SOURCES_CLNT.c:%.c=%.o) $(TARGETS_CLNT.c:%.c=%.o) +OBJECTS_SVC = $(SOURCES_SVC.c:%.c=%.o) $(TARGETS_SVC.c:%.c=%.o) +# Compiler flags + +CPPFLAGS += -D_REENTRANT +CFLAGS += -g -Wall +LDLIBS += -lnsl -lpthread +LDFLAGS = -L$(INSTALL_PATH)/lib/ + RPCGENFLAGS = + +# Targets + +all : $(MONITOR) $(RPC_SERVER) $(SERVER) $(CLIENT) $(MD5_WS) + +$(MONITOR) : $(MONITOR).o $(OBJECTS_CLNT) + $(LINK.c) -o $(MONITOR) $(MONITOR).o $(OBJECTS_CLNT) $(LDLIBS) + +$(RPC_SERVER) : $(RPC_SERVER).o $(OBJECTS_SVC) + $(LINK.c) -o $(RPC_SERVER) $(RPC_SERVER).o $(OBJECTS_SVC) $(LDLIBS) + +$(SERVER) : $(SERVER).o $(OBJECTS_SERVER) $(OBJECTS_CLNT) + $(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +$(CLIENT) : + javac $(CLIENT).java + +$(MD5_WS) : + javac -cp . $(MD5_WS).java + + clean: + $(RM) core $(SERVER) $(MONITOR) $(RPC_SERVER) *.o ./*/*.o *.class ./*/*.class ./*/*/*.class + diff --git a/ssdd_p2_100291121_100292107/README.txt b/ssdd_p2_100291121_100292107/README.txt new file mode 100644 index 0000000..083f83c --- /dev/null +++ b/ssdd_p2_100291121_100292107/README.txt @@ -0,0 +1,47 @@ +Carlos Gutierrez - 100291121 +Ruben Lopez - 100292107 + + +INSTRUCTIONS FOR COMPILING AND EXECUTING THE PROGRAM: + +**IMPORTANT NOTE: IF THE PROGRAMS ARE TO BE RUN IN THE SAME MACHINE, IT IS RECOMMENDED TO USE LOOPBACK +IP ADDRESSES (INSTEAD OF THE PUBLIC IP) TO AVOID CONNECTIVITY PROBLEMS** + +------------ +COMPILATION +------------ +- Extract the ZIP folder by running 'unzip ssdd_p2_100291121_100292107.zip -d '. +This will extract the contents in the provided. + +- Navigate to the + +- Execute the command 'ls' and make sure that the 'Makefile' is located in the directory + +- Run the command 'make' and wait until the process is finished. Now all the necessary files +will be compiled and ready to be executed. + +---------- +EXECUTION +---------- +Open 5 terminals and navigate to the root directory where the files are located, and then execute the +following commands: + +-Terminal 1: 'java -cp . md5.server.endpoint.MD5Publisher' + +-Terminal 2: './storeServer' + +-Terminal 3: './server -p -s ' +where is the port number in which the service will be running, and is the IP +address that is shown in Terminal 2 after executing the command shown above + +-Terminal 4: 'java -cp . client -s -p -w ' +where is the IP address of the messaging service that is shown after executing the command +in Terminal 3; is the same port number indicated in the command of Terminal 3; +and is the IP address and the port number that are shown after executing the +command in Terminal 1, in the format IP:port + +-Terminal 5: './monitor ' +where is the IP address that is shown in Terminal 2 after executing the command shown above + +Terminal 4 will execute the client and can be replicated more times to create more clients and communicate between them +in real time diff --git a/ssdd_p2_100291121_100292107/authors.txt b/ssdd_p2_100291121_100292107/authors.txt new file mode 100644 index 0000000..f5b361b --- /dev/null +++ b/ssdd_p2_100291121_100292107/authors.txt @@ -0,0 +1,2 @@ +GUTIÉRREZ PARADELA, CARLOS 100291121 GROUP 89 +LÓPEZ LOZOYA, RUBÉN 100292107 GROUP 89 \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107/client.java b/ssdd_p2_100291121_100292107/client.java new file mode 100644 index 0000000..21aefa9 --- /dev/null +++ b/ssdd_p2_100291121_100292107/client.java @@ -0,0 +1,743 @@ +import java.io.*; +import gnu.getopt.Getopt; +import java.net.Socket; +import java.net.ServerSocket; +import md5.client.MD5; +import md5.client.MD5ImplService; +import java.net.URL; + + +class client { + + /********************* TYPES **********************/ + + /** + * @brief Return codes for the protocol methods + */ + private static enum RC { + OK, + ERROR, + USER_ERROR + }; + + /******************* ATTRIBUTES *******************/ + + private static String _server = null; + private static int _port = -1; + /* Controls the user bound to the client when executing a CONNECT command */ + private static String connected_user = null; + /* Instantiate and prepare an empty ServerThread for further connection */ + private static ServerThread server_thread = new ServerThread(); + /* Variable for storing the IP address of the md5 web service server */ + private static String _md5_ws = null; + + + /********************* METHODS ********************/ + + /** + * @param user - User name to register in the system + * + * @return OK if successful + * @return USER_ERROR if the user is already registered + * @return ERROR if another error occurred + */ + static RC register(String user) + { + // Write your code here + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + //2. The string "REGISTER" is sent indicating the operation + String operation = new String("REGISTER"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user to be registered + out.writeBytes(user); + out.write(0); + + //4. Check response from the server. If 0, success; if 1 user is previously registered; if 2 other case + byte response = in.readByte(); + + //5. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + System.out.println("c> REGISTER OK"); + return RC.OK; + case 1: + System.out.println("c> USERNAME IN USE"); + return RC.USER_ERROR; + case 2: + System.out.println("c> REGISTER FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + System.out.println("c> REGISTER FAIL"); + return RC.ERROR; + } + + /** + * @param user - User name to unregister from the system + * + * @return OK if successful + * @return USER_ERROR if the user does not exist + * @return ERROR if another error occurred + */ + static RC unregister(String user) + { + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + //2. The string "UNREGISTER" is sent indicating the operation + String operation = new String("UNREGISTER"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user to be unregistered + out.writeBytes(user); + out.write(0); + + //4. Check response from the server. If 0, success; if 1 user does not exist; if 2 other case + byte response = in.readByte(); + + //5. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + /* If we try to unregister the user that is currently bound and connected + to the client, it is unbound from the client */ + if(connected_user != null){ + /* This protects against null pointer exception when a CONNECT command is executed and + the server marks the user as connected, but then the client is terminated without + executing DISCONNECT from the server */ + if(connected_user.equals(user)){ + connected_user = null; + /* If the unregister also disconnect a user linked to the client (connected and with a + server thread running, kill also the running thread*/ + server_thread.kill(); + } + } + + System.out.println("c> UNREGISTER OK"); + return RC.OK; + case 1: + System.out.println("c> USER DOES NOT EXIST"); + return RC.USER_ERROR; + case 2: + System.out.println("c> UNREGISTER FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + System.out.println("c> UNREGISTER FAIL"); + return RC.ERROR; + } + + /** + * @param user - User name to connect to the system + * + * @return OK if successful + * @return USER_ERROR if the user does not exist or if it is already connected + * @return ERROR if another error occurred + */ + static RC connect(String user) + { + + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + /* Before trying to connect, if a user is already connected, quit the function with RC.ERROR */ + if(connected_user != null){ + System.out.println("c> CONNECT FAIL"); + return RC.ERROR; + } + + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + //2. The string "CONNECT" is sent indicating the operation + String operation = new String("CONNECT"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user to be connected + out.writeBytes(user); + out.write(0); + + /* Create ServerSocket. We provide 0 to assign any available port number and 10 as maximum + number of queued requests */ + ServerSocket sock = new ServerSocket(0, 10); + /* Get the port at which the socket is listening */ + int port = sock.getLocalPort(); + + //4. A string is sent with the port number listening in the client + out.writeBytes(String.valueOf(port)); + out.write(0); + + //5. Check response from the server. If 0, success; if 1 user does not exist; if 2 other case + byte response = in.readByte(); + + //6. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + /* Start a new thread where */ + server_thread.start(sock); + /* Bind the user to the client */ + connected_user = user; + System.out.println("c> CONNECT OK"); + return RC.OK; + case 1: + System.out.println("c> CONNECT FAIL, USER DOES NOT EXIST"); + return RC.USER_ERROR; + case 2: + System.out.println("c> USER ALREADY CONNECTED"); + return RC.USER_ERROR; + case 3: + System.out.println("c> CONNECT FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + e.printStackTrace(); + } + System.out.println("c> CONNECT FAIL"); + return RC.ERROR; + } + + /** + * @param user - User name to disconnect from the system + * + * @return OK if successful + * @return USER_ERROR if the user does not exist or if it is already disconnected + * @return ERROR if another error occurred + */ + static RC disconnect(String user) + { + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + //2. The string "DISCONNECT" is sent indicating the operation + String operation = new String("DISCONNECT"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user to be disconnected + out.writeBytes(user); + out.write(0); + + //4. Check response from the server. If 0, success; if 1 user does not exist; if 2 other case + byte response = in.readByte(); + + //5. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + /* Unbind the user from the client */ + connected_user = null; + server_thread.kill(); + System.out.println("c> DISCONNECT OK"); + return RC.OK; + case 1: + checkAndUnbindUser(user); + System.out.println("c> DISCONNECT FAIL / USER DOES NOT EXIST"); + return RC.USER_ERROR; + case 2: + checkAndUnbindUser(user); + System.out.println("c> DISCONNECT FAIL / USER NOT CONNECTED"); + return RC.USER_ERROR; + case 3: + checkAndUnbindUser(user); + System.out.println("c> DISCONNECT FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + checkAndUnbindUser(user); + System.out.println("c> DISCONNECT FAIL"); + return RC.ERROR; + } + private static void checkAndUnbindUser(String user){ + /* In case of error in the disconnection process, stop the execution of the thread + and unbind the user from the client as if the disconnection has been made. But if the + disconnect command executed was not executed for the user that is bound to the client + then nothing is done */ + if(connected_user != null){ + /* Check if the user coincides with the linked user */ + if(connected_user.equals(user)){ + connected_user = null; + server_thread.kill(); + } + } + } + + /** + * @param user - Receiver user name + * @param message - Message to be sent + * + * @return OK if the server had successfully delivered the message + * @return USER_ERROR if the user is not connected (the message is queued for delivery) + * @return ERROR the user does not exist or another error occurred + */ + static RC send(String user, String message) + { + String md5; + /* Calculate the MD5 of the message */ + try{ + /* Build the URL of the web service based on the IP passed in the command */ + URL url = new URL(new String("http://" + _md5_ws + "/ws/md5")); + /* Define the MD5 Web service variables */ + MD5ImplService md5Service = new MD5ImplService(url); + MD5 md5_ws = md5Service.getMD5ImplPort(); + /* Call the web service that calculates de MD5 of the message */ + md5 = md5_ws.getMD5(message); + } + catch(Exception e){ + /* If exception occurs, nothing is sent to the server. Print error */ + System.out.println("c> ERROR , SEND FAIL / ERROR IN MD5"); + return RC.ERROR; + } + /////////////////////////////////////////////// + /////////////// PROTOCOL /////////////// + /////////////////////////////////////////////// + try{ + /* If there is not a user connected in the client, return error RC.ERROR */ + if(connected_user == null){ + System.out.println("c> SEND FAIL"); + return RC.ERROR; + } + //1. Connect to the server, using the IP and port passed in the command line + Socket sc = new Socket(_server, _port); + + DataOutputStream out = new DataOutputStream(sc.getOutputStream()); + DataInputStream in = new DataInputStream(sc.getInputStream()); + + + //2. The string "SEND" is sent indicating the operation + String operation = new String("SEND"); + out.writeBytes(operation); + out.write(0); //Insert ASCII 0 at the end + + //3. A string of characters is sent with the user that sends the message + out.writeBytes(connected_user); + out.write(0); + + //4. A string of characters is sent with the user that receives the message + out.writeBytes(user); + out.write(0); + + //5. A string of maximum 256 (including ASCII 0) characters is sent with the message to be sent + out.writeBytes(trimMessage(message)); //Sends a string of 255 characters + out.write(0); + + //6. A string of characters is sent with the MD5 hash of the message to be sent + out.writeBytes(md5); //Sends a string of 255 characters + out.write(0); + + //7. Check response from the server. If 0, success; if 1 user does not exist; if 2 other case + byte response = in.readByte(); + + String msg_id = new String(); + /* If response is 0 (OK), prepare to read the ID of the message */ + if(response == 0){ + + /* Create BufferedReader for easy reading a string */ + /* + BufferedReader inString = new BufferedReader(new InputStreamReader(sc.getInputStream())); + msg_id = inString.readLine();*/ + byte ch; + do{ + ch = in.readByte(); + if (ch != 0) msg_id = msg_id + ((char) ch); + } while(ch != 0); + } + + //8. Close connection + sc.close(); + out.close(); + in.close(); + + //Decode the response from the server + switch(response){ + case 0: + System.out.println("c> SEND OK - MESSAGE " + msg_id); + return RC.OK; + case 1: + System.out.println("c> SEND FAIL / USER DOES NOT EXIST"); + return RC.USER_ERROR; + case 2: + System.out.println("c> SEND FAIL"); + return RC.ERROR; + } + + } + catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + System.out.println("c> SEND FAIL"); + return RC.ERROR; + } + /** + * @brief Trims the input message to 255 characters + * + * @param message - String to be trimmed + * + * @return message - Result String + */ + static String trimMessage(String message){ + /* Maximum length is of 255 characters because 1 character is reserved for ASCII 0 */ + int maxLength = 255; + + if(message.length() > maxLength){ + message = message.substring(0, maxLength); + } + + return message; + } + + /** + * @brief Command interpreter for the client. It calls the protocol functions. + */ + static void shell() + { + boolean exit = false; + String input; + String [] line; + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + + while (!exit) { + try { + System.out.print("c> "); + input = in.readLine(); + line = input.split("\\s"); + + if (line.length > 0) { + /*********** REGISTER *************/ + if (line[0].equals("REGISTER")) { + if (line.length == 2) { + register(line[1]); // userName = line[1] + } else { + System.out.println("Syntax error. Usage: REGISTER "); + } + } + + /********** UNREGISTER ************/ + else if (line[0].equals("UNREGISTER")) { + if (line.length == 2) { + unregister(line[1]); // userName = line[1] + } else { + System.out.println("Syntax error. Usage: UNREGISTER "); + } + } + + /************ CONNECT *************/ + else if (line[0].equals("CONNECT")) { + if (line.length == 2) { + connect(line[1]); // userName = line[1] AQUI CREAMOS EL HILO SERVIDOR + } else { + System.out.println("Syntax error. Usage: CONNECT "); + } + } + + /********** DISCONNECT ************/ + else if (line[0].equals("DISCONNECT")) { + if (line.length == 2) { + disconnect(line[1]); // userName = line[1] + } else { + System.out.println("Syntax error. Usage: DISCONNECT "); + } + } + + /************** SEND **************/ + else if (line[0].equals("SEND")) { + if (line.length >= 3) { + // Remove first two words + String message = input.substring(input.indexOf(' ')+1); + message = message.substring(message.indexOf(' ')+1); + send(line[1], message); // userName = line[1] + } else { + System.out.println("Syntax error. Usage: SEND "); + } + } + + /************** QUIT **************/ + else if (line[0].equals("QUIT")){ + if (line.length == 1) { + exit = true; + } else { + System.out.println("Syntax error. Use: QUIT"); + } + } + + /************* UNKNOWN ************/ + else { + System.out.println("Error: command '" + line[0] + "' not valid."); + } + } + } catch (java.io.IOException e) { + System.out.println("Exception: " + e); + //e.printStackTrace(); + } + } + } + + /** + * @brief Prints program usage + */ + static void usage() + { + System.out.println("Usage: java -cp . client -s -p "); + } + + /** + * @brief Parses program execution arguments + */ + static boolean parseArguments(String [] argv) + { + Getopt g = new Getopt("client", argv, "ds:p:w:"); + + int c; + String arg; + + while ((c = g.getopt()) != -1) { + switch(c) { + //case 'd': + // _debug = true; + // break; + case 's': + _server = g.getOptarg(); + break; + case 'p': + arg = g.getOptarg(); + _port = Integer.parseInt(arg); + break; + case 'w': + _md5_ws = g.getOptarg(); + break; + case '?': + System.out.print("getopt() returned " + c + "\n"); + break; // getopt() already printed an error + default: + System.out.print("getopt() returned " + c + "\n"); + } + } + + if (_server == null) + return false; + + if ((_port < 1024) || (_port > 65535)) { + System.out.println("Error: Port must be in the range 1024 <= port <= 65535"); + return false; + } + + return true; + } + + + + /********************* MAIN **********************/ + + public static void main(String[] argv) + { + if(!parseArguments(argv)) { + usage(); + return; + } + + /* Creates a thread that catches Ctrl+C kill command from the CLI and disconnects from the server the + connected user of the client (bound to the client) */ + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + if(connected_user != null){ + disconnect(connected_user); + } + } + }); + + shell(); + System.out.println("+++ FINISHED +++"); + } +} + +/********************* SERVERTHREAD **********************/ + +class ServerThread extends Thread{ + + private ServerSocket sc; //ServerSocket of the listening thread + private volatile Thread blinker; //Thread of type volatile that will be attached to the ServerThread + private Socket sd; + + /** + * @brief Constructor. Starts the server thread and initializes the ServerSocket property + * + * @param sc - Initialized ServerSocket + * + */ + public void start(ServerSocket sc){ + blinker = new Thread(this); + blinker.start(); + this.sc = sc; + } + + /** + * @brief Destroys the server thread + */ + public void kill(){ + try{ + if(sd != null) this.sd.close(); + } + catch(IOException e){ + System.out.println("Exception: " + e); + } + blinker = null; + } + + /** + * @brief Main execution code sequence of the server thread. Listens to incoming connections + */ + public void run(){ + Thread thisThread = Thread.currentThread(); + sd = null; + while(blinker == thisThread){ + try{ + /* Waiting for connection */ + sd = this.sc.accept(); + + DataInputStream msg_in = new DataInputStream(sd.getInputStream()); + /* Receive the string encoding the operation */ + String operation = new String(); + byte ch; + do{ + ch = msg_in.readByte(); + if (ch != 0) operation = operation + ((char) ch); + + } while(ch != 0); + /* Prepare the string for the ID of the message sent/received */ + String id = new String(); + + switch(operation){ + case "SEND_MESSAGE": + /* Read the sender username from the socket */ + String sender = new String(); + do{ + ch = msg_in.readByte(); + if (ch != 0) sender = sender + ((char) ch); + + } while(ch != 0); + /* Read the ID of the received message */ + do{ + ch = msg_in.readByte(); + if (ch != 0) id = id + ((char) ch); + } while(ch != 0); + /* Read the string containing the MD5 of the message */ + String md5 = new String(); + do{ + ch = msg_in.readByte(); + if (ch != 0) md5 = md5 + ((char) ch); + + } while(ch != 0); + /* Read the string containing the body of the message */ + String msg = new String(); + do{ + ch = msg_in.readByte(); + if (ch != 0) msg = msg + ((char) ch); + + } while(ch != 0); + /* Prompt */ + System.out.println("MESSAGE " + id + " FROM " + sender + ":"); + System.out.println("\t" + msg); + System.out.println("\tMD5:"); + System.out.println("\t" + md5); + System.out.println("\tEND"); + System.out.print("c> "); + break; + + case "SEND_MESS_ACK": + /* Read the id of the message being acknowledged */ + do{ + ch = msg_in.readByte(); + if (ch != 0) id = id + ((char) ch); + } while(ch != 0); + + System.out.println("SEND MESSAGE " + id + " OK"); + System.out.print("c> "); + break; + } + sd.close(); + + } + catch(Exception e){ + System.out.println("Exception: " + e); + //e.printStackTrace(); + this.kill(); + } + } + /* If the thread exits the loop for any reason, try to close the socket */ + try{ + sd.close(); + } + catch(Exception e){ + System.out.println("Exception: " + e); + this.kill(); + } + } +} diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/COPYING.LIB b/ssdd_p2_100291121_100292107/gnu/getopt/COPYING.LIB new file mode 100755 index 0000000..161a3d1 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/ChangeLog b/ssdd_p2_100291121_100292107/gnu/getopt/ChangeLog new file mode 100755 index 0000000..7fed6d2 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/ChangeLog @@ -0,0 +1,114 @@ +For release 1.0.14 (2012/02/08) + +David Zhang (david290@qq.com) provided Chinese language messages. +Daniel Thomas (drt24@srcf.ucam.org) contributed a patch to fix a static +access warning message. + +For release 1.0.13 (2006/08/29) + +Krzysztof Szymanski (sirch.s@gmail.com) provided Polish language messages. + +For release 1.0.12 (2005/11/12) + +Sandro Tossi (matrixhasu@gmail.com) provided Italian language messages. + +For release 1.0.11 (2005/02/19) + +Daniel Perez Alvarez (dondani@gmail.com) provided Spanish language +messages. + +For release 1.0.10 (2004/09/12) + +Marian-Nicolae V. Ion (mion@neocom.fr) provided Romanian language messages. + +For release 1.0.9 (2002/01/16) + +Yasuoka Masahiko provided Japanese langauge messages. + +Csom Gyula provided Hungarian language messages. + +Guillaume Rousse supplied the ant build file +and documentation. + +For release 1.0.8 (2000/09/11) + +Ernst de Haan provided Dutch language messages. + +For release 1.0.7 (2000/02/02) + +Fixed an obscure POSIX compatibility issue. When an optstring is "o:", +then "-o -- foo" should result in -o having an optarg of "foo", not "--" +as was previously returned. This new parsing behavior is only enabled +in POSIX compatibility mode. Thank to Don Suit (dsuit@fc.hp.com) for +reporting this and help in communicating proper POSIX behavior. + +For release 1.0.6 (1999/06/27) + +Added French language messages. Thanks to Edouard G. Parmelan +(Edouard.Parmelan@quadratec.fr) for this contribution. + +For release 1.0.5 (1999/03/23) + +Fixed bug that caused getopt to throw a StringIndexOutOfBoundsException +when an empty string ("") argument was encountered. Thanks to +Steffen Siebert (siebert@logware.de) for this bug report and a patch. + +For release 1.0.4 + +Added Norwegian language messages. Thanks to Bjrn-Ove Heimsund +(s811@drone.ii.uib.no) for this contribution. + +For release 1.0.3 + +Added German language messages. Thanks to Bernhard Bablok +(bablokb@gmx.net) for this contribution. + +For release 1.0.2 + +Prevent ArrayIndexOutOfBounds exception if "optstring" is null. David Karr +(dkarr@nmo.gtegsc.com) had a problem with this when commenting out options +during debugging, so I have fixed it. + +For release 1.0.1 + +Added Czech language messages. Thanks to Roman Szturc (Roman.Szturc@vsb.cz) +for this contribution. + +For release 1.0 + +No changes. Just increment release number to 1.0 + +For release 0.9.2 + +The sample code has been moved into a separate file called "GetoptDemo.java". +This is so that it can be legally placed into the public domain and not +subsumed into the LGPL as would be the case if it were in Getopt.java. +While I do not encourage anyone to write proprietary software, I feel that +there is no good purpose served in restricting what someone can do with +a short example program. + +Modified the Makefile and various other files to support the change +above. + +For release 0.9.1 + +This release contains only minor fixes. It's always possible it introduces +some bugs though so unless you are keen on internationalization or are +having a line separator problem, there is no need to upgrade from 0.9. + +-- Messages are now internationalized. Thanks to Bill King + (wrking@eng.sun.com) for this. + +-- Changes all print's to println's to avoid system dependent line + separators. + +-- All internal variables are now protected. Several people suggested + doing this in response to my request for comments in the help file. + No one suggested keeping any variables public. + +-- Fixed parts of licensing that mentioned the regular GPL. Getopt is + and always has been licensed under the LPGL. Thanks to Arieh Markel + (arieh.markel@sun.com) for pointing this out. + + + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/Getopt.java b/ssdd_p2_100291121_100292107/gnu/getopt/Getopt.java new file mode 100755 index 0000000..429301b --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/Getopt.java @@ -0,0 +1,1337 @@ +/************************************************************************** +/* Getopt.java -- Java port of GNU getopt from glibc 2.0.6 +/* +/* Copyright (c) 1987-1997 Free Software Foundation, Inc. +/* Java Port Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +package gnu.getopt; + +import java.util.Locale; +import java.util.ResourceBundle; +import java.text.MessageFormat; + +/**************************************************************************/ + +/** + * This is a Java port of GNU getopt, a class for parsing command line + * arguments passed to programs. It it based on the C getopt() functions + * in glibc 2.0.6 and should parse options in a 100% compatible manner. + * If it does not, that is a bug. The programmer's interface is also + * very compatible. + *

+ * To use Getopt, create a Getopt object with a argv array passed to the + * main method, then call the getopt() method in a loop. It will return an + * int that contains the value of the option character parsed from the + * command line. When there are no more options to be parsed, it + * returns -1. + *

+ * A command line option can be defined to take an argument. If an + * option has an argument, the value of that argument is stored in an + * instance variable called optarg, which can be accessed using the + * getOptarg() method. If an option that requires an argument is + * found, but there is no argument present, then an error message is + * printed. Normally getopt() returns a '?' in this situation, but + * that can be changed as described below. + *

+ * If an invalid option is encountered, an error message is printed + * to the standard error and getopt() returns a '?'. The value of the + * invalid option encountered is stored in the instance variable optopt + * which can be retrieved using the getOptopt() method. To suppress + * the printing of error messages for this or any other error, set + * the value of the opterr instance variable to false using the + * setOpterr() method. + *

+ * Between calls to getopt(), the instance variable optind is used to + * keep track of where the object is in the parsing process. After all + * options have been returned, optind is the index in argv of the first + * non-option argument. This variable can be accessed with the getOptind() + * method. + *

+ * Note that this object expects command line options to be passed in the + * traditional Unix manner. That is, proceeded by a '-' character. + * Multiple options can follow the '-'. For example "-abc" is equivalent + * to "-a -b -c". If an option takes a required argument, the value + * of the argument can immediately follow the option character or be + * present in the next argv element. For example, "-cfoo" and "-c foo" + * both represent an option character of 'c' with an argument of "foo" + * assuming c takes a required argument. If an option takes an argument + * that is not required, then any argument must immediately follow the + * option character in the same argv element. For example, if c takes + * a non-required argument, then "-cfoo" represents option character 'c' + * with an argument of "foo" while "-c foo" represents the option + * character 'c' with no argument, and a first non-option argv element + * of "foo". + *

+ * The user can stop getopt() from scanning any further into a command line + * by using the special argument "--" by itself. For example: + * "-a -- -d" would return an option character of 'a', then return -1 + * The "--" is discarded and "-d" is pointed to by optind as the first + * non-option argv element. + *

+ * Here is a basic example of using Getopt: + *

+ *

+  * Getopt g = new Getopt("testprog", argv, "ab:c::d");
+  * //
+  * int c;
+  * String arg;
+  * while ((c = g.getopt()) != -1)
+  *   {
+  *     switch(c)
+  *       {
+  *          case 'a':
+  *          case 'd':
+  *            System.out.print("You picked " + (char)c + "\n");
+  *            break;
+  *            //
+  *          case 'b':
+  *          case 'c':
+  *            arg = g.getOptarg();
+  *            System.out.print("You picked " + (char)c + 
+  *                             " with an argument of " +
+  *                             ((arg != null) ? arg : "null") + "\n");
+  *            break;
+  *            //
+  *          case '?':
+  *            break; // getopt() already printed an error
+  *            //
+  *          default:
+  *            System.out.print("getopt() returned " + c + "\n");
+  *       }
+  *   }
+  * 
+ *

+ * In this example, a new Getopt object is created with three params. + * The first param is the program name. This is for printing error + * messages in the form "program: error message". In the C version, this + * value is taken from argv[0], but in Java the program name is not passed + * in that element, thus the need for this parameter. The second param is + * the argument list that was passed to the main() method. The third + * param is the list of valid options. Each character represents a valid + * option. If the character is followed by a single colon, then that + * option has a required argument. If the character is followed by two + * colons, then that option has an argument that is not required. + *

+ * Note in this example that the value returned from getopt() is cast to + * a char prior to printing. This is required in order to make the value + * display correctly as a character instead of an integer. + *

+ * If the first character in the option string is a colon, for example + * ":abc::d", then getopt() will return a ':' instead of a '?' when it + * encounters an option with a missing required argument. This allows the + * caller to distinguish between invalid options and valid options that + * are simply incomplete. + *

+ * In the traditional Unix getopt(), -1 is returned when the first non-option + * charcter is encountered. In GNU getopt(), the default behavior is to + * allow options to appear anywhere on the command line. The getopt() + * method permutes the argument to make it appear to the caller that all + * options were at the beginning of the command line, and all non-options + * were at the end. For example, calling getopt() with command line args + * of "-a foo bar -d" returns options 'a' and 'd', then sets optind to + * point to "foo". The program would read the last two argv elements as + * "foo" and "bar", just as if the user had typed "-a -d foo bar". + *

+ * The user can force getopt() to stop scanning the command line with + * the special argument "--" by itself. Any elements occuring before the + * "--" are scanned and permuted as normal. Any elements after the "--" + * are returned as is as non-option argv elements. For example, + * "foo -a -- bar -d" would return option 'a' then -1. optind would point + * to "foo", "bar" and "-d" as the non-option argv elements. The "--" + * is discarded by getopt(). + *

+ * There are two ways this default behavior can be modified. The first is + * to specify traditional Unix getopt() behavior (which is also POSIX + * behavior) in which scanning stops when the first non-option argument + * encountered. (Thus "-a foo bar -d" would return 'a' as an option and + * have "foo", "bar", and "-d" as non-option elements). The second is to + * allow options anywhere, but to return all elements in the order they + * occur on the command line. When a non-option element is ecountered, + * an integer 1 is returned and the value of the non-option element is + * stored in optarg is if it were the argument to that option. For + * example, "-a foo -d", returns first 'a', then 1 (with optarg set to + * "foo") then 'd' then -1. When this "return in order" functionality + * is enabled, the only way to stop getopt() from scanning all command + * line elements is to use the special "--" string by itself as described + * above. An example is "-a foo -b -- bar", which would return 'a', then + * integer 1 with optarg set to "foo", then 'b', then -1. optind would + * then point to "bar" as the first non-option argv element. The "--" + * is discarded. + *

+ * The POSIX/traditional behavior is enabled by either setting the + * property "gnu.posixly_correct" or by putting a '+' sign as the first + * character of the option string. The difference between the two + * methods is that setting the gnu.posixly_correct property also forces + * certain error messages to be displayed in POSIX format. To enable + * the "return in order" functionality, put a '-' as the first character + * of the option string. Note that after determining the proper + * behavior, Getopt strips this leading '+' or '-', meaning that a ':' + * placed as the second character after one of those two will still cause + * getopt() to return a ':' instead of a '?' if a required option + * argument is missing. + *

+ * In addition to traditional single character options, GNU Getopt also + * supports long options. These are preceeded by a "--" sequence and + * can be as long as desired. Long options provide a more user-friendly + * way of entering command line options. For example, in addition to a + * "-h" for help, a program could support also "--help". + *

+ * Like short options, long options can also take a required or non-required + * argument. Required arguments can either be specified by placing an + * equals sign after the option name, then the argument, or by putting the + * argument in the next argv element. For example: "--outputdir=foo" and + * "--outputdir foo" both represent an option of "outputdir" with an + * argument of "foo", assuming that outputdir takes a required argument. + * If a long option takes a non-required argument, then the equals sign + * form must be used to specify the argument. In this case, + * "--outputdir=foo" would represent option outputdir with an argument of + * "foo" while "--outputdir foo" would represent the option outputdir + * with no argument and a first non-option argv element of "foo". + *

+ * Long options can also be specified using a special POSIX argument + * format (one that I highly discourage). This form of entry is + * enabled by placing a "W;" (yes, 'W' then a semi-colon) in the valid + * option string. This causes getopt to treat the name following the + * "-W" as the name of the long option. For example, "-W outputdir=foo" + * would be equivalent to "--outputdir=foo". The name can immediately + * follow the "-W" like so: "-Woutputdir=foo". Option arguments are + * handled identically to normal long options. If a string follows the + * "-W" that does not represent a valid long option, then getopt() returns + * 'W' and the caller must decide what to do. Otherwise getopt() returns + * a long option value as described below. + *

+ * While long options offer convenience, they can also be tedious to type + * in full. So it is permissible to abbreviate the option name to as + * few characters as required to uniquely identify it. If the name can + * represent multiple long options, then an error message is printed and + * getopt() returns a '?'. + *

+ * If an invalid option is specified or a required option argument is + * missing, getopt() prints an error and returns a '?' or ':' exactly + * as for short options. Note that when an invalid long option is + * encountered, the optopt variable is set to integer 0 and so cannot + * be used to identify the incorrect option the user entered. + *

+ * Long options are defined by LongOpt objects. These objects are created + * with a contructor that takes four params: a String representing the + * object name, a integer specifying what arguments the option takes + * (the value is one of LongOpt.NO_ARGUMENT, LongOpt.REQUIRED_ARGUMENT, + * or LongOpt.OPTIONAL_ARGUMENT), a StringBuffer flag object (described + * below), and an integer value (described below). + *

+ * To enable long option parsing, create an array of LongOpt's representing + * the legal options and pass it to the Getopt() constructor. WARNING: If + * all elements of the array are not populated with LongOpt objects, the + * getopt() method will throw a NullPointerException. + *

+ * When getopt() is called and a long option is encountered, one of two + * things can be returned. If the flag field in the LongOpt object + * representing the long option is non-null, then the integer value field + * is stored there and an integer 0 is returned to the caller. The val + * field can then be retrieved from the flag field. Note that since the + * flag field is a StringBuffer, the appropriate String to integer converions + * must be performed in order to get the actual int value stored there. + * If the flag field in the LongOpt object is null, then the value field + * of the LongOpt is returned. This can be the character of a short option. + * This allows an app to have both a long and short option sequence + * (say, "-h" and "--help") that do the exact same thing. + *

+ * With long options, there is an alternative method of determining + * which option was selected. The method getLongind() will return the + * the index in the long option array (NOT argv) of the long option found. + * So if multiple long options are configured to return the same value, + * the application can use getLongind() to distinguish between them. + *

+ * Here is an expanded Getopt example using long options and various + * techniques described above: + *

+ *

+  * int c;
+  * String arg;
+  * LongOpt[] longopts = new LongOpt[3];
+  * // 
+  * StringBuffer sb = new StringBuffer();
+  * longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h');
+  * longopts[1] = new LongOpt("outputdir", LongOpt.REQUIRED_ARGUMENT, sb, 'o'); 
+  * longopts[2] = new LongOpt("maximum", LongOpt.OPTIONAL_ARGUMENT, null, 2);
+  * // 
+  * Getopt g = new Getopt("testprog", argv, "-:bc::d:hW;", longopts);
+  * g.setOpterr(false); // We'll do our own error handling
+  * //
+  * while ((c = g.getopt()) != -1)
+  *   switch (c)
+  *     {
+  *        case 0:
+  *          arg = g.getOptarg();
+  *          System.out.println("Got long option with value '" +
+  *                             (char)(new Integer(sb.toString())).intValue()
+  *                             + "' with argument " +
+  *                             ((arg != null) ? arg : "null"));
+  *          break;
+  *          //
+  *        case 1:
+  *          System.out.println("I see you have return in order set and that " +
+  *                             "a non-option argv element was just found " +
+  *                             "with the value '" + g.getOptarg() + "'");
+  *          break;
+  *          //
+  *        case 2:
+  *          arg = g.getOptarg();
+  *          System.out.println("I know this, but pretend I didn't");
+  *          System.out.println("We picked option " +
+  *                             longopts[g.getLongind()].getName() +
+  *                           " with value " + 
+  *                           ((arg != null) ? arg : "null"));
+  *          break;
+  *          //
+  *        case 'b':
+  *          System.out.println("You picked plain old option " + (char)c);
+  *          break;
+  *          //
+  *        case 'c':
+  *        case 'd':
+  *          arg = g.getOptarg();
+  *          System.out.println("You picked option '" + (char)c + 
+  *                             "' with argument " +
+  *                             ((arg != null) ? arg : "null"));
+  *          break;
+  *          //
+  *        case 'h':
+  *          System.out.println("I see you asked for help");
+  *          break;
+  *          //
+  *        case 'W':
+  *          System.out.println("Hmmm. You tried a -W with an incorrect long " +
+  *                             "option name");
+  *          break;
+  *          //
+  *        case ':':
+  *          System.out.println("Doh! You need an argument for option " +
+  *                             (char)g.getOptopt());
+  *          break;
+  *          //
+  *        case '?':
+  *          System.out.println("The option '" + (char)g.getOptopt() + 
+  *                           "' is not valid");
+  *          break;
+  *          //
+  *        default:
+  *          System.out.println("getopt() returned " + c);
+  *          break;
+  *     }
+  * //
+  * for (int i = g.getOptind(); i < argv.length ; i++)
+  *   System.out.println("Non option argv element: " + argv[i] + "\n");
+  * 
+ *

+ * There is an alternative form of the constructor used for long options + * above. This takes a trailing boolean flag. If set to false, Getopt + * performs identically to the example, but if the boolean flag is true + * then long options are allowed to start with a single '-' instead of + * "--". If the first character of the option is a valid short option + * character, then the option is treated as if it were the short option. + * Otherwise it behaves as if the option is a long option. Note that + * the name given to this option - long_only - is very counter-intuitive. + * It does not cause only long options to be parsed but instead enables + * the behavior described above. + *

+ * Note that the functionality and variable names used are driven from + * the C lib version as this object is a port of the C code, not a + * new implementation. This should aid in porting existing C/C++ code, + * as well as helping programmers familiar with the glibc version to + * adapt to the Java version even if it seems very non-Java at times. + *

+ * In this release I made all instance variables protected due to + * overwhelming public demand. Any code which relied on optarg, + * opterr, optind, or optopt being public will need to be modified to + * use the appropriate access methods. + *

+ * Please send all bug reports, requests, and comments to + * arenn@urbanophile.com. + * + * @version 1.0.7 + * + * @author Roland McGrath (roland@gnu.ai.mit.edu) + * @author Ulrich Drepper (drepper@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @see LongOpt + */ +public class Getopt extends Object +{ + +/**************************************************************************/ + +/* + * Class Variables + */ + +/** + * Describe how to deal with options that follow non-option ARGV-elements. + * + * If the caller did not specify anything, + * the default is REQUIRE_ORDER if the property + * gnu.posixly_correct is defined, PERMUTE otherwise. + * + * The special argument `--' forces an end of option-scanning regardless + * of the value of `ordering'. In the case of RETURN_IN_ORDER, only + * `--' can cause `getopt' to return -1 with `optind' != ARGC. + * + * REQUIRE_ORDER means don't recognize them as options; + * stop option processing when the first non-option is seen. + * This is what Unix does. + * This mode of operation is selected by either setting the property + * gnu.posixly_correct, or using `+' as the first character + * of the list of option characters. + */ +protected static final int REQUIRE_ORDER = 1; + +/** + * PERMUTE is the default. We permute the contents of ARGV as we scan, + * so that eventually all the non-options are at the end. This allows options + * to be given in any order, even with programs that were not written to + * expect this. + */ +protected static final int PERMUTE = 2; + +/** + * RETURN_IN_ORDER is an option available to programs that were written + * to expect options and other ARGV-elements in any order and that care about + * the ordering of the two. We describe each non-option ARGV-element + * as if it were the argument of an option with character code 1. + * Using `-' as the first character of the list of option characters + * selects this mode of operation. + */ +protected static final int RETURN_IN_ORDER = 3; + +/**************************************************************************/ + +/* + * Instance Variables + */ + +/** + * For communication from `getopt' to the caller. + * When `getopt' finds an option that takes an argument, + * the argument value is returned here. + * Also, when `ordering' is RETURN_IN_ORDER, + * each non-option ARGV-element is returned here. + */ +protected String optarg; + +/** + * Index in ARGV of the next element to be scanned. + * This is used for communication to and from the caller + * and for communication between successive calls to `getopt'. + * + * On entry to `getopt', zero means this is the first call; initialize. + * + * When `getopt' returns -1, this is the index of the first of the + * non-option elements that the caller should itself scan. + * + * Otherwise, `optind' communicates from one call to the next + * how much of ARGV has been scanned so far. + */ +protected int optind = 0; + +/** + * Callers store false here to inhibit the error message + * for unrecognized options. + */ +protected boolean opterr = true; + +/** + * When an unrecognized option is encountered, getopt will return a '?' + * and store the value of the invalid option here. + */ +protected int optopt = '?'; + +/** + * The next char to be scanned in the option-element + * in which the last option character we returned was found. + * This allows us to pick up the scan where we left off. + * + * If this is zero, or a null string, it means resume the scan + * by advancing to the next ARGV-element. + */ +protected String nextchar; + +/** + * This is the string describing the valid short options. + */ +protected String optstring; + +/** + * This is an array of LongOpt objects which describ the valid long + * options. + */ +protected LongOpt[] long_options; + +/** + * This flag determines whether or not we are parsing only long args + */ +protected boolean long_only; + +/** + * Stores the index into the long_options array of the long option found + */ +protected int longind; + +/** + * The flag determines whether or not we operate in strict POSIX compliance + */ +protected boolean posixly_correct; + +/** + * A flag which communicates whether or not checkLongOption() did all + * necessary processing for the current option + */ +protected boolean longopt_handled; + +/** + * The index of the first non-option in argv[] + */ +protected int first_nonopt = 1; + +/** + * The index of the last non-option in argv[] + */ +protected int last_nonopt = 1; + +/** + * Flag to tell getopt to immediately return -1 the next time it is + * called. + */ +private boolean endparse = false; + +/** + * Saved argument list passed to the program + */ +protected String[] argv; + +/** + * Determines whether we permute arguments or not + */ +protected int ordering; + +/** + * Name to print as the program name in error messages. This is necessary + * since Java does not place the program name in argv[0] + */ +protected String progname; + +/** + * The localized strings are kept in a separate file + */ +private ResourceBundle _messages = ResourceBundle.getBundle( + "gnu/getopt/MessagesBundle", Locale.getDefault()); + +/**************************************************************************/ + +/* + * Constructors + */ + +/** + * Construct a basic Getopt instance with the given input data. Note that + * this handles "short" options only. + * + * @param progname The name to display as the program name when printing errors + * @param argv The String array passed as the command line to the program. + * @param optstring A String containing a description of the valid args for this program + */ +public +Getopt(String progname, String[] argv, String optstring) +{ + this(progname, argv, optstring, null, false); +} + +/**************************************************************************/ + +/** + * Construct a Getopt instance with given input data that is capable of + * parsing long options as well as short. + * + * @param progname The name to display as the program name when printing errors + * @param argv The String array passed as the command ilne to the program + * @param optstring A String containing a description of the valid short args for this program + * @param long_options An array of LongOpt objects that describes the valid long args for this program + */ +public +Getopt(String progname, String[] argv, String optstring, + LongOpt[] long_options) +{ + this(progname, argv, optstring, long_options, false); +} + +/**************************************************************************/ + +/** + * Construct a Getopt instance with given input data that is capable of + * parsing long options and short options. Contrary to what you might + * think, the flag 'long_only' does not determine whether or not we + * scan for only long arguments. Instead, a value of true here allows + * long arguments to start with a '-' instead of '--' unless there is a + * conflict with a short option name. + * + * @param progname The name to display as the program name when printing errors + * @param argv The String array passed as the command ilne to the program + * @param optstring A String containing a description of the valid short args for this program + * @param long_options An array of LongOpt objects that describes the valid long args for this program + * @param long_only true if long options that do not conflict with short options can start with a '-' as well as '--' + */ +public +Getopt(String progname, String[] argv, String optstring, + LongOpt[] long_options, boolean long_only) +{ + if (optstring.length() == 0) + optstring = " "; + + // This function is essentially _getopt_initialize from GNU getopt + this.progname = progname; + this.argv = argv; + this.optstring = optstring; + this.long_options = long_options; + this.long_only = long_only; + + // Check for property "gnu.posixly_correct" to determine whether to + // strictly follow the POSIX standard. This replaces the "POSIXLY_CORRECT" + // environment variable in the C version + if (System.getProperty("gnu.posixly_correct", null) == null) + posixly_correct = false; + else + { + posixly_correct = true; + _messages = ResourceBundle.getBundle("gnu/getopt/MessagesBundle", + Locale.US); + } + + // Determine how to handle the ordering of options and non-options + if (optstring.charAt(0) == '-') + { + ordering = RETURN_IN_ORDER; + if (optstring.length() > 1) + this.optstring = optstring.substring(1); + } + else if (optstring.charAt(0) == '+') + { + ordering = REQUIRE_ORDER; + if (optstring.length() > 1) + this.optstring = optstring.substring(1); + } + else if (posixly_correct) + { + ordering = REQUIRE_ORDER; + } + else + { + ordering = PERMUTE; // The normal default case + } +} + +/**************************************************************************/ + +/* + * Instance Methods + */ + +/** + * In GNU getopt, it is possible to change the string containg valid options + * on the fly because it is passed as an argument to getopt() each time. In + * this version we do not pass the string on every call. In order to allow + * dynamic option string changing, this method is provided. + * + * @param optstring The new option string to use + */ +public void +setOptstring(String optstring) +{ + if (optstring.length() == 0) + optstring = " "; + + this.optstring = optstring; +} + +/**************************************************************************/ + +/** + * optind it the index in ARGV of the next element to be scanned. + * This is used for communication to and from the caller + * and for communication between successive calls to `getopt'. + * + * When `getopt' returns -1, this is the index of the first of the + * non-option elements that the caller should itself scan. + * + * Otherwise, `optind' communicates from one call to the next + * how much of ARGV has been scanned so far. + */ +public int +getOptind() +{ + return(optind); +} + +/**************************************************************************/ + +/** + * This method allows the optind index to be set manually. Normally this + * is not necessary (and incorrect usage of this method can lead to serious + * lossage), but optind is a public symbol in GNU getopt, so this method + * was added to allow it to be modified by the caller if desired. + * + * @param optind The new value of optind + */ +public void +setOptind(int optind) +{ + this.optind = optind; +} + +/**************************************************************************/ + +/** + * Since in GNU getopt() the argument vector is passed back in to the + * function every time, the caller can swap out argv on the fly. Since + * passing argv is not required in the Java version, this method allows + * the user to override argv. Note that incorrect use of this method can + * lead to serious lossage. + * + * @param argv New argument list + */ +public void +setArgv(String[] argv) +{ + this.argv = argv; +} + +/**************************************************************************/ + +/** + * For communication from `getopt' to the caller. + * When `getopt' finds an option that takes an argument, + * the argument value is returned here. + * Also, when `ordering' is RETURN_IN_ORDER, + * each non-option ARGV-element is returned here. + * No set method is provided because setting this variable has no effect. + */ +public String +getOptarg() +{ + return(optarg); +} + +/**************************************************************************/ + +/** + * Normally Getopt will print a message to the standard error when an + * invalid option is encountered. This can be suppressed (or re-enabled) + * by calling this method. There is no get method for this variable + * because if you can't remember the state you set this to, why should I? + */ +public void +setOpterr(boolean opterr) +{ + this.opterr = opterr; +} + +/**************************************************************************/ + +/** + * When getopt() encounters an invalid option, it stores the value of that + * option in optopt which can be retrieved with this method. There is + * no corresponding set method because setting this variable has no effect. + */ +public int +getOptopt() +{ + return(optopt); +} + +/**************************************************************************/ + +/** + * Returns the index into the array of long options (NOT argv) representing + * the long option that was found. + */ +public int +getLongind() +{ + return(longind); +} + +/**************************************************************************/ + +/** + * Exchange the shorter segment with the far end of the longer segment. + * That puts the shorter segment into the right place. + * It leaves the longer segment in the right place overall, + * but it consists of two parts that need to be swapped next. + * This method is used by getopt() for argument permutation. + */ +protected void +exchange(String[] argv) +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + String tem; + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + // Bottom segment is the short one. + int len = middle - bottom; + int i; + + // Swap it with the top part of the top segment. + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + // Exclude the moved bottom segment from further swapping. + top -= len; + } + else + { + // Top segment is the short one. + int len = top - middle; + int i; + + // Swap it with the bottom part of the bottom segment. + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + // Exclude the moved top segment from further swapping. + bottom += len; + } + } + + // Update records for the slots the non-options now occupy. + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/**************************************************************************/ + +/** + * Check to see if an option is a valid long option. Called by getopt(). + * Put in a separate method because this needs to be done twice. (The + * C getopt authors just copy-pasted the code!). + * + * @param longind A buffer in which to store the 'val' field of found LongOpt + * + * @return Various things depending on circumstances + */ +protected int +checkLongOption() +{ + LongOpt pfound = null; + int nameend; + boolean ambig; + boolean exact; + + longopt_handled = true; + ambig = false; + exact = false; + longind = -1; + + nameend = nextchar.indexOf("="); + if (nameend == -1) + nameend = nextchar.length(); + + // Test all lnog options for either exact match or abbreviated matches + for (int i = 0; i < long_options.length; i++) + { + if (long_options[i].getName().startsWith(nextchar.substring(0, nameend))) + { + if (long_options[i].getName().equals(nextchar.substring(0, nameend))) + { + // Exact match found + pfound = long_options[i]; + longind = i; + exact = true; + break; + } + else if (pfound == null) + { + // First nonexact match found + pfound = long_options[i]; + longind = i; + } + else + { + // Second or later nonexact match found + ambig = true; + } + } + } // for + + // Print out an error if the option specified was ambiguous + if (ambig && !exact) + { + if (opterr) + { + Object[] msgArgs = { progname, argv[optind] }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.ambigious"), + msgArgs)); + } + + nextchar = ""; + optopt = 0; + ++optind; + + return('?'); + } + + if (pfound != null) + { + ++optind; + + if (nameend != nextchar.length()) + { + if (pfound.has_arg != LongOpt.NO_ARGUMENT) + { + if (nextchar.substring(nameend).length() > 1) + optarg = nextchar.substring(nameend+1); + else + optarg = ""; + } + else + { + if (opterr) + { + // -- option + if (argv[optind - 1].startsWith("--")) + { + Object[] msgArgs = { progname, pfound.name }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.arguments1"), + msgArgs)); + } + // +option or -option + else + { + Object[] msgArgs = { progname, new + Character(argv[optind-1].charAt(0)).toString(), + pfound.name }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.arguments2"), + msgArgs)); + } + } + + nextchar = ""; + optopt = pfound.val; + + return('?'); + } + } // if (nameend) + else if (pfound.has_arg == LongOpt.REQUIRED_ARGUMENT) + { + if (optind < argv.length) + { + optarg = argv[optind]; + ++optind; + } + else + { + if (opterr) + { + Object[] msgArgs = { progname, argv[optind-1] }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.requires"), + msgArgs)); + } + + nextchar = ""; + optopt = pfound.val; + if (optstring.charAt(0) == ':') + return(':'); + else + return('?'); + } + } // else if (pfound) + + nextchar = ""; + + if (pfound.flag != null) + { + pfound.flag.setLength(0); + pfound.flag.append(pfound.val); + + return(0); + } + + return(pfound.val); + } // if (pfound != null) + + longopt_handled = false; + + return(0); +} + +/**************************************************************************/ + +/** + * This method returns a char that is the current option that has been + * parsed from the command line. If the option takes an argument, then + * the internal variable 'optarg' is set which is a String representing + * the the value of the argument. This value can be retrieved by the + * caller using the getOptarg() method. If an invalid option is found, + * an error message is printed and a '?' is returned. The name of the + * invalid option character can be retrieved by calling the getOptopt() + * method. When there are no more options to be scanned, this method + * returns -1. The index of first non-option element in argv can be + * retrieved with the getOptind() method. + * + * @return Various things as described above + */ +public int +getopt() +{ + optarg = null; + + if (endparse == true) + return(-1); + + if ((nextchar == null) || (nextchar.equals(""))) + { + // If we have just processed some options following some non-options, + // exchange them so that the options come first. + if (last_nonopt > optind) + last_nonopt = optind; + if (first_nonopt > optind) + first_nonopt = optind; + + if (ordering == PERMUTE) + { + // If we have just processed some options following some non-options, + // exchange them so that the options come first. + if ((first_nonopt != last_nonopt) && (last_nonopt != optind)) + exchange(argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + // Skip any additional non-options + // and extend the range of non-options previously skipped. + while ((optind < argv.length) && (argv[optind].equals("") || + (argv[optind].charAt(0) != '-') || argv[optind].equals("-"))) + { + optind++; + } + + last_nonopt = optind; + } + + // The special ARGV-element `--' means premature end of options. + // Skip it like a null option, + // then exchange with previous non-options as if it were an option, + // then skip everything else like a non-option. + if ((optind != argv.length) && argv[optind].equals("--")) + { + optind++; + + if ((first_nonopt != last_nonopt) && (last_nonopt != optind)) + exchange (argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + + last_nonopt = argv.length; + + optind = argv.length; + } + + // If we have done all the ARGV-elements, stop the scan + // and back over any non-options that we skipped and permuted. + if (optind == argv.length) + { + // Set the next-arg-index to point at the non-options + // that we previously skipped, so the caller will digest them. + if (first_nonopt != last_nonopt) + optind = first_nonopt; + + return(-1); + } + + // If we have come to a non-option and did not permute it, + // either stop the scan or describe it to the caller and pass it by. + if (argv[optind].equals("") || (argv[optind].charAt(0) != '-') || + argv[optind].equals("-")) + { + if (ordering == REQUIRE_ORDER) + return(-1); + + optarg = argv[optind++]; + return(1); + } + + // We have found another option-ARGV-element. + // Skip the initial punctuation. + if (argv[optind].startsWith("--")) + nextchar = argv[optind].substring(2); + else + nextchar = argv[optind].substring(1); + } + + // Decode the current option-ARGV-element. + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + if ((long_options != null) && (argv[optind].startsWith("--") + || (long_only && ((argv[optind].length() > 2) || + (optstring.indexOf(argv[optind].charAt(1)) == -1))))) + { + int c = checkLongOption(); + + if (longopt_handled) + return(c); + + // Can't find it as a long option. If this is not getopt_long_only, + // or the option starts with '--' or is not a valid short + // option, then it's an error. + // Otherwise interpret it as a short option. + if (!long_only || argv[optind].startsWith("--") + || (optstring.indexOf(nextchar.charAt(0)) == -1)) + { + if (opterr) + { + if (argv[optind].startsWith("--")) + { + Object[] msgArgs = { progname, nextchar }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.unrecognized"), + msgArgs)); + } + else + { + Object[] msgArgs = { progname, new + Character(argv[optind].charAt(0)).toString(), + nextchar }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.unrecognized2"), + msgArgs)); + } + } + + nextchar = ""; + ++optind; + optopt = 0; + + return('?'); + } + } // if (longopts) + + // Look at and handle the next short option-character */ + int c = nextchar.charAt(0); //**** Do we need to check for empty str? + if (nextchar.length() > 1) + nextchar = nextchar.substring(1); + else + nextchar = ""; + + String temp = null; + if (optstring.indexOf(c) != -1) + temp = optstring.substring(optstring.indexOf(c)); + + if (nextchar.equals("")) + ++optind; + + if ((temp == null) || (c == ':')) + { + if (opterr) + { + if (posixly_correct) + { + // 1003.2 specifies the format of this message + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.illegal"), msgArgs)); + } + else + { + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.invalid"), msgArgs)); + } + } + + optopt = c; + + return('?'); + } + + // Convenience. Treat POSIX -W foo same as long option --foo + if ((temp.charAt(0) == 'W') && (temp.length() > 1) && (temp.charAt(1) == ';')) + { + if (!nextchar.equals("")) + { + optarg = nextchar; + } + // No further cars in this argv element and no more argv elements + else if (optind == argv.length) + { + if (opterr) + { + // 1003.2 specifies the format of this message. + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.requires2"), msgArgs)); + } + + optopt = c; + if (optstring.charAt(0) == ':') + return(':'); + else + return('?'); + } + else + { + // We already incremented `optind' once; + // increment it again when taking next ARGV-elt as argument. + nextchar = argv[optind]; + optarg = argv[optind]; + } + + c = checkLongOption(); + + if (longopt_handled) + return(c); + else + // Let the application handle it + { + nextchar = null; + ++optind; + return('W'); + } + } + + if ((temp.length() > 1) && (temp.charAt(1) == ':')) + { + if ((temp.length() > 2) && (temp.charAt(2) == ':')) + // This is an option that accepts and argument optionally + { + if (!nextchar.equals("")) + { + optarg = nextchar; + ++optind; + } + else + { + optarg = null; + } + + nextchar = null; + } + else + { + if (!nextchar.equals("")) + { + optarg = nextchar; + ++optind; + } + else if (optind == argv.length) + { + if (opterr) + { + // 1003.2 specifies the format of this message + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.requires2"), msgArgs)); + } + + optopt = c; + + if (optstring.charAt(0) == ':') + return(':'); + else + return('?'); + } + else + { + optarg = argv[optind]; + ++optind; + + // Ok, here's an obscure Posix case. If we have o:, and + // we get -o -- foo, then we're supposed to skip the --, + // end parsing of options, and make foo an operand to -o. + // Only do this in Posix mode. + if ((posixly_correct) && optarg.equals("--")) + { + // If end of argv, error out + if (optind == argv.length) + { + if (opterr) + { + // 1003.2 specifies the format of this message + Object[] msgArgs = { progname, new + Character((char)c).toString() }; + System.err.println(MessageFormat.format( + _messages.getString("getopt.requires2"), msgArgs)); + } + + optopt = c; + + if (optstring.charAt(0) == ':') + return(':'); + else + return('?'); + } + + // Set new optarg and set to end + // Don't permute as we do on -- up above since we + // know we aren't in permute mode because of Posix. + optarg = argv[optind]; + ++optind; + first_nonopt = optind; + last_nonopt = argv.length; + endparse = true; + } + } + + nextchar = null; + } + } + + return(c); +} + +} // Class Getopt + + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/GetoptDemo.java b/ssdd_p2_100291121_100292107/gnu/getopt/GetoptDemo.java new file mode 100755 index 0000000..b57c5a8 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/GetoptDemo.java @@ -0,0 +1,97 @@ +import gnu.getopt.LongOpt; +import gnu.getopt.Getopt; + +/* + * This sample code was written by Aaron M. Renn and is a demonstration + * of how to utilize some of the features of the GNU getopt package. This + * sample code is hereby placed into the public domain by the author and + * may be used without restriction. + */ + +public class GetoptDemo +{ + +public static void +main(String[] argv) +{ + int c; + String arg; + LongOpt[] longopts = new LongOpt[3]; + // + StringBuffer sb = new StringBuffer(); + longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'); + longopts[1] = new LongOpt("outputdir", LongOpt.REQUIRED_ARGUMENT, sb, 'o'); + longopts[2] = new LongOpt("maximum", LongOpt.OPTIONAL_ARGUMENT, null, 2); + // + Getopt g = new Getopt("testprog", argv, "-:bc::d:hW;", longopts); + g.setOpterr(false); // We'll do our own error handling + // + while ((c = g.getopt()) != -1) + switch (c) + { + case 0: + arg = g.getOptarg(); + System.out.println("Got long option with value '" + + (char)(new Integer(sb.toString())).intValue() + + "' with argument " + + ((arg != null) ? arg : "null")); + break; + // + case 1: + System.out.println("I see you have return in order set and that " + + "a non-option argv element was just found " + + "with the value '" + g.getOptarg() + "'"); + break; + // + case 2: + arg = g.getOptarg(); + System.out.println("I know this, but pretend I didn't"); + System.out.println("We picked option " + + longopts[g.getLongind()].getName() + + " with value " + + ((arg != null) ? arg : "null")); + break; + // + case 'b': + System.out.println("You picked plain old option " + (char)c); + break; + // + case 'c': + case 'd': + arg = g.getOptarg(); + System.out.println("You picked option '" + (char)c + + "' with argument " + + ((arg != null) ? arg : "null")); + break; + // + case 'h': + System.out.println("I see you asked for help"); + break; + // + case 'W': + System.out.println("Hmmm. You tried a -W with an incorrect long " + + "option name"); + break; + // + case ':': + System.out.println("Doh! You need an argument for option " + + (char)g.getOptopt()); + break; + // + case '?': + System.out.println("The option '" + (char)g.getOptopt() + + "' is not valid"); + break; + // + default: + System.out.println("getopt() returned " + c); + break; + } + // + for (int i = g.getOptind(); i < argv.length ; i++) + System.out.println("Non option argv element: " + argv[i] + "\n"); +} + +} // Class GetoptDemo + + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/LANGUAGES b/ssdd_p2_100291121_100292107/gnu/getopt/LANGUAGES new file mode 100755 index 0000000..d8e1399 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/LANGUAGES @@ -0,0 +1,23 @@ +Getopt supports error messages in the following languages: + +English (default) +Chinese (simplified and traditional) +Czech +Dutch +French +German +Hungarian +Italian +Japanese +Norwegian +Polish +Romanian +Spanish + +Anyone can create a translation without knowing how to program Java. +Simply supply me with a MessagesBundle file for your locale and I'm happy +to include it. See MessagesBundle.properties as an example with reference +English messages. + +Aaron (arenn@urbanophile.com) + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/LongOpt.java b/ssdd_p2_100291121_100292107/gnu/getopt/LongOpt.java new file mode 100755 index 0000000..6357085 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/LongOpt.java @@ -0,0 +1,195 @@ +/************************************************************************** +/* LongOpt.java -- Long option object for Getopt +/* +/* Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +package gnu.getopt; + +import java.util.Locale; +import java.util.ResourceBundle; +import java.text.MessageFormat; + +/**************************************************************************/ + +/** + * This object represents the definition of a long option in the Java port + * of GNU getopt. An array of LongOpt objects is passed to the Getopt + * object to define the list of valid long options for a given parsing + * session. Refer to the getopt documentation for details on the + * format of long options. + * + * @version 1.0.5 + * @author Aaron M. Renn (arenn@urbanophile.com) + * + * @see Getopt + */ +public class LongOpt extends Object +{ + +/**************************************************************************/ + +/* + * Class Variables + */ + +/** + * Constant value used for the "has_arg" constructor argument. This + * value indicates that the option takes no argument. + */ +public static final int NO_ARGUMENT = 0; + +/** + * Constant value used for the "has_arg" constructor argument. This + * value indicates that the option takes an argument that is required. + */ +public static final int REQUIRED_ARGUMENT = 1; + +/** + * Constant value used for the "has_arg" constructor argument. This + * value indicates that the option takes an argument that is optional. + */ +public static final int OPTIONAL_ARGUMENT = 2; + +/**************************************************************************/ + +/* + * Instance Variables + */ + +/** + * The name of the long option + */ +protected String name; + +/** + * Indicates whether the option has no argument, a required argument, or + * an optional argument. + */ +protected int has_arg; + +/** + * If this variable is not null, then the value stored in "val" is stored + * here when this long option is encountered. If this is null, the value + * stored in "val" is treated as the name of an equivalent short option. + */ +protected StringBuffer flag; + +/** + * The value to store in "flag" if flag is not null, otherwise the + * equivalent short option character for this long option. + */ +protected int val; + +/** + * Localized strings for error messages + */ +private ResourceBundle _messages = ResourceBundle.getBundle( + "gnu/getopt/MessagesBundle", Locale.getDefault()); + +/**************************************************************************/ + +/* + * Constructors + */ + +/** + * Create a new LongOpt object with the given parameter values. If the + * value passed as has_arg is not valid, then an exception is thrown. + * + * @param name The long option String. + * @param has_arg Indicates whether the option has no argument (NO_ARGUMENT), a required argument (REQUIRED_ARGUMENT) or an optional argument (OPTIONAL_ARGUMENT). + * @param flag If non-null, this is a location to store the value of "val" when this option is encountered, otherwise "val" is treated as the equivalent short option character. + * @param val The value to return for this long option, or the equivalent single letter option to emulate if flag is null. + * + * @exception IllegalArgumentException If the has_arg param is not one of NO_ARGUMENT, REQUIRED_ARGUMENT or OPTIONAL_ARGUMENT. + */ +public +LongOpt(String name, int has_arg, + StringBuffer flag, int val) throws IllegalArgumentException +{ + // Validate has_arg + if ((has_arg != NO_ARGUMENT) && (has_arg != REQUIRED_ARGUMENT) + && (has_arg != OPTIONAL_ARGUMENT)) + { + Object[] msgArgs = { new Integer(has_arg).toString() }; + throw new IllegalArgumentException(MessageFormat.format( + _messages.getString("getopt.invalidValue"), msgArgs)); + } + + // Store off values + this.name = name; + this.has_arg = has_arg; + this.flag = flag; + this.val = val; +} + +/**************************************************************************/ + +/** + * Returns the name of this LongOpt as a String + * + * @return Then name of the long option + */ +public String +getName() +{ + return(name); +} + +/**************************************************************************/ + +/** + * Returns the value set for the 'has_arg' field for this long option + * + * @return The value of 'has_arg' + */ +public int +getHasArg() +{ + return(has_arg); +} + +/**************************************************************************/ + +/** + * Returns the value of the 'flag' field for this long option + * + * @return The value of 'flag' + */ +public StringBuffer +getFlag() +{ + return(flag); +} + +/** + * Returns the value of the 'val' field for this long option + * + * @return The value of 'val' + */ +public int +getVal() +{ + return(val); +} + +/**************************************************************************/ + +} // Class LongOpt + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/Makefile b/ssdd_p2_100291121_100292107/gnu/getopt/Makefile new file mode 100755 index 0000000..6ff789c --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/Makefile @@ -0,0 +1,7 @@ +# Makefile for Java port of GNU getopt + +all: + javac LongOpt.java Getopt.java GetoptDemo.java + +docs: + javadoc -author -version -public Getopt.java LongOpt.java diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle.properties new file mode 100755 index 0000000..9356ee1 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle.properties -- English language error messages +/* +/* Copyright (c) 1998 by William King (wrking@eng.sun.com) and +/* Aaron M. Renn (arenn@urbanophile.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: option ''{1}'' is ambiguous +getopt.arguments1={0}: option ''--{1}'' doesn't allow an argument +getopt.arguments2={0}: option ''{1}{2}'' doesn't allow an argument +getopt.requires={0}: option ''{1}'' requires an argument +getopt.unrecognized={0}: unrecognized option ''--{1}'' +getopt.unrecognized2={0}: unrecognized option ''{1}{2}'' +getopt.illegal={0}: illegal option -- {1} +getopt.invalid={0}: invalid option -- {1} +getopt.requires2={0}: option requires an argument -- {1} +getopt.invalidValue=Invalid value {0} for parameter 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_chs.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_chs.properties new file mode 100755 index 0000000..1090dc6 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_chs.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle.properties CSimple Chinese language error messages +/* +/* Copyright (c) 2012 by David Zhang (david290@qq.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: ѡ ''{1}'' +getopt.arguments1={0}:ѡ''--{1}'' ܴ +getopt.arguments2={0}:ѡ''{1}{2}''ܴ +getopt.requires={0}: ѡ ''{1}'' Ҫв +getopt.unrecognized={0}: ޷ʶѡ ''--{1}'' +getopt.unrecognized2={0}:޷ʶѡ''{1}{2}'' +getopt.illegal={0}: Ƿѡ -- {1} +getopt.invalid={0}: Чѡ -- {1} +getopt.requires2={0}:ѡҪв -- {1} +getopt.invalidValue=ѡ 'has_arg'ֵ {0} Ƿ + + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_cht.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_cht.properties new file mode 100755 index 0000000..270e4f1 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_cht.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle.properties - Triditional Chinese language error messages +/* +/* Copyright (c) 2012 by David Zhang (david290@qq.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: 選項 ''{1}'' 有歧義 +getopt.arguments1={0}:選項''--{1}'' 不能帶參數 +getopt.arguments2={0}:選項''{1}{2}''不能帶參數 +getopt.requires={0}: 選項 ''{1}'' 要求帶有參數 +getopt.unrecognized={0}: 無法識別的選項 ''--{1}'' +getopt.unrecognized2={0}:無法識別的選項''{1}{2}'' +getopt.illegal={0}: 非法選項 -- {1} +getopt.invalid={0}: 無效選項 -- {1} +getopt.requires2={0}:選項需要有參數 -- {1} +getopt.invalidValue=選項 'has_arg'的值 {0} 非法 + + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_cs.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_cs.properties new file mode 100755 index 0000000..3c14a03 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_cs.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle_cs.properties -- Czech language error messages +/* +/* Czech Messages Copyright (c) 1998 by Roman Szturc (Roman.Szturc@vsb.cz) +/* These messages are encoded in ISO-8859-2 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: volba ''{1}'' je nejednoznan +getopt.arguments1={0}: volba ''--{1}'' nepipout argument +getopt.arguments2={0}: volba ''{1}{2}'' nepipout argument +getopt.requires={0}: volba ''{1}'' vyaduje argument +getopt.unrecognized={0}: neppustn volba ''--{1}'' +getopt.unrecognized2={0}: neppustn volba ''{1}{2}'' +getopt.illegal={0}: neppustn volba -- {1} +getopt.invalid={0}: neplatn volba -- {1} +getopt.requires2={0}: volba vyaduje argument -- {1} +getopt.invalidValue=Neplatn hodnota {0} parameteru 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_de.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_de.properties new file mode 100755 index 0000000..f741386 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_de.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle.properties -- German language error messages +/* +/* German Messages Copyright (c) 1999 by Bernhard Bablok (bablokb@gmx.net) +/* These messages are encoded in ISO-8859-1 +//* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: Option ''{1}'' ist zweideutig +getopt.arguments1={0}: Option ''--{1}'' erlaubt kein Argument +getopt.arguments2={0}: Option ''{1}{2}'' erlaubt kein Argument +getopt.requires={0}: Option ''{1}'' bentigt ein Argument +getopt.unrecognized={0}: Unbekannte Option ''--{1}'' +getopt.unrecognized2={0}: Unbekannte Option ''{1}{2}'' +getopt.illegal={0}: Verbotene Option -- {1} +getopt.invalid={0}: Ungltige Option -- {1} +getopt.requires2={0}: Option bentigt ein Argument -- {1} +getopt.invalidValue=Ungltiger Wert {0} fr Parameter 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_es.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_es.properties new file mode 100755 index 0000000..ef358f4 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_es.properties @@ -0,0 +1,33 @@ +/************************************************************************** +/* MessagesBundle_es.properties -- Spanish language error messages +/* +/* Spanish Messages Copyright (c) 2004 by Daniel Prez (dondani@gmail.com) +/* These messages are encoded in ISO-8859-1 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: la opcin ''{1}'' es ambigua +getopt.arguments1={0}: la opcin ''--{1}'' no permite un argumento +getopt.arguments2={0}: la opcin ''{1}{2}'' no permite un argumento +getopt.requires={0}: la opcin ''{1}'' requiere un argumento +getopt.unrecognized={0}: opcin no reconocida ''--{1}'' +getopt.unrecognized2={0}: opcin no reconocida ''{1}{2}'' +getopt.illegal={0}: opcin ilegal -- {1} +getopt.invalid={0}: opcin no vlida -- {1} +getopt.requires2={0}: la opcin requiere un argumento -- {1} +getopt.invalidValue=Valor no vlido {0} para el parmetro 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_fr.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_fr.properties new file mode 100755 index 0000000..400447c --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_fr.properties @@ -0,0 +1,35 @@ +/************************************************************************** +/* MessagesBundle_fr.properties -- French language error messages +/* +/* Copyright (c) 1999 Free Software Foundation, Inc. +/* Michel Robitaille , 1996, +/* Edouard G. Parmelan , 1999. +/* These messages are encoded in ISO-8859-1 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: l'option ''{1}'' est ambigu +getopt.arguments1={0}: l'option ''--{1}'' ne permet pas de paramtre +getopt.arguments2={0}: l'option ''{1}{2}'' ne permet pas de paramtre +getopt.requires={0}: l'option ''{1}'' requiert un paramtre +getopt.unrecognized={0}: option non reconnue ''--{1}'' +getopt.unrecognized2={0}: option non reconnue ''{1}{2}'' +getopt.illegal={0}: option illgale -- {1} +getopt.invalid={0}: option invalide -- {1} +getopt.requires2={0}: cette option requiert un paramtre -- {1} +getopt.invalidValue=Valeur invalide {0} pour le paramtre 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_hu.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_hu.properties new file mode 100755 index 0000000..f7af03b --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_hu.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle.properties -- Hungarian language error messages +/* +/* Copyright (c) 2001 by Gyula Csom (csom@informix.hu) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: opci ''{1}'' flrerthet +getopt.arguments1={0}: opci ''--{1}'' nem enged meg argumentumot +getopt.arguments2={0}: opci ''{1}{2}'' nem enged meg argumentumot +getopt.requires={0}: opci ''{1}'' argumentumot ignyel +getopt.unrecognized={0}: ismeretlen opci ''--{1}'' +getopt.unrecognized2={0}: ismeretlen opci ''{1}{2}'' +getopt.illegal={0}: illeglis opci -- {1} +getopt.invalid={0}: rvnytelen opci -- {1} +getopt.requires2={0}: az opci argumentumot ignyel -- {1} +getopt.invalidValue=rvnytelen rtk {0} a kvetkez paramterhez 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_it.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_it.properties new file mode 100755 index 0000000..c596c26 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_it.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle.properties -- Italian language error messages +/* +/* Copyright (c) 2005 by Sandro Tosi (matrixhasu@gmail.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: l'opzione ''{1}'' ambigua +getopt.arguments1={0}: l'opzione ''--{1}'' non ammette un argomento +getopt.arguments2={0}: l'opzione ''{1}{2}'' non ammette un argomento +getopt.requires={0}: l'opzione ''{1}'' richiede un argomento +getopt.unrecognized={0}: opzione non riconosciuta ''--{1}'' +getopt.unrecognized2={0}: opzione non riconosciuta ''{1}{2}'' +getopt.illegal={0}: opzione illegale -- {1} +getopt.invalid={0}: opzione invalida -- {1} +getopt.requires2={0}: l'opzione richiede un argomento -- {1} +getopt.invalidValue=Valore non valido {0} per il parametro 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_ja.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_ja.properties new file mode 100755 index 0000000..5578972 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_ja.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle.properties -- Japanese language error messages +/* +/* Copyright (c) 2001 by Yasuoka Masahiko (yasuoka@yasuoka.net) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: ''{1}'' \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u66d6\u6627\u3067\u3059\u3002 +getopt.arguments1={0}: ''--{1}'' \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u3092\u3082\u3061\u307e\u305b\u3093\u3002 +getopt.arguments2={0}: ''{1}{2}'' \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u3092\u3082\u3061\u307e\u305b\u3093\u3002 +getopt.requires={0}: ''{1}'' \u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u5fc5\u8981\u3067\u3059\u3002 +getopt.unrecognized={0}: ''--{1}'' \u306f\u7121\u52b9\u306a\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u3059\u3002 +getopt.unrecognized2={0}: ''{1}{2}'' \u306f\u7121\u52b9\u306a\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u3059\u3002 +getopt.illegal={0}: -- {1} \u306f\u4e0d\u6b63\u306a\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u3059\u3002 +getopt.invalid={0}: -- {1} \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093\u3002 +getopt.requires2={0}: -- {1} \u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u5fc5\u8981\u3067\u3059\u3002 +getopt.invalidValue={0} \u306f\u3001'has_arg' \u30d1\u30e9\u30e1\u30fc\u30bf\u3068\u3057\u3066\u4e0d\u6b63\u306a\u5024\u3067\u3059\u3002 + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_nl.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_nl.properties new file mode 100755 index 0000000..c614922 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_nl.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle_nl.properties -- Dutch language error messages +/* +/* Copyright (c) 1999 by Ernst de Haan (ernst@jollem.com) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: optie ''{1}'' is ambigue +getopt.arguments1={0}: optie ''--{1}'' staat geen argumenten toe +getopt.arguments2={0}: optie ''{1}{2}'' staat geen argumenten toe +getopt.requires={0}: optie ''{1}'' heeft een argument nodig +getopt.unrecognized={0}: onbekende optie ''--{1}'' +getopt.unrecognized2={0}: onbekende optie ''{1}{2}'' +getopt.illegal={0}: niet-toegestane optie -- {1} +getopt.invalid={0}: onjuiste optie -- {1} +getopt.requires2={0}: optie heeft een argument nodig -- {1} +getopt.invalidValue=Ongeldige waarde {0} voor parameter 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_no.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_no.properties new file mode 100755 index 0000000..bcb8c50 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_no.properties @@ -0,0 +1,32 @@ +/************************************************************************** +/* MessagesBundle.properties -- Norwegian language error messages +/* +/* Copyright (c) 1999 by Bjrn-Ove Heimsund (s811@ii.uib.no) +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: flagget ''{1}'' er flertydig +getopt.arguments1={0}: flagget ''--{1}'' tillater ikke et argument +getopt.arguments2={0}: flagget ''{1}{2}'' tillater ikke et argument +getopt.requires={0}: flagget ''{1}'' krever et argument +getopt.unrecognized={0}: ukjent flagg ''--{1}'' +getopt.unrecognized2={0}: ukjent flagg ''{1}{2}'' +getopt.illegal={0}: ugyldig flagg -- {1} +getopt.invalid={0}: ugyldig flagg -- {1} +getopt.requires2={0}: flagget krever et argument -- {1} +getopt.invalidValue=Ugyldig verdi {0} for parameter 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_pl.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_pl.properties new file mode 100755 index 0000000..9580853 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_pl.properties @@ -0,0 +1,36 @@ +/************************************************************************** +/* MessagesBundle_pl.properties -- Polish language error messages +/* +/* Polish Messages Copyright (c) 2006 by Krzysztof Szyma?ski (sirch.s@gmail.com) +/* These messages are encoded in ISO-8859-2 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your option) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + + +getopt.ambigious={0}: opcja ''{1}''jest wieloznaczna +getopt.arguments1={0}: opcja ''--{1}'' nie akceptuje argumentu +getopt.arguments2={0}: opcja ''{1}{2}'' nie akceptuje argumentu +getopt.requires={0}: opcja ''{1}'' wymaga argumentu +getopt.unrecognized={0}: nierozpoznana opcja ''--{1}'' +getopt.unrecognized2={0}: nierozpoznana opcja ''{1}{2}'' +getopt.illegal={0}: nie dopuszczalna opcja --{1} +getopt.invalid={0}: b??dna opcja --{1} +getopt.requires2={0}: opcja --{1} oczekuje argumentu +getopt.invalidValue=Nie poprawna warto?? {0} argument 'has_arg' + + + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_ro.properties b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_ro.properties new file mode 100755 index 0000000..3c0b08b --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/MessagesBundle_ro.properties @@ -0,0 +1,34 @@ +/************************************************************************** +/* MessagesBundle_fr.properties -- Romanian language error messages +/* +/* Copyright (c) 1999 Free Software Foundation, Inc. +/* Marian-Nicolae Ion , 2004, +/* These messages are encoded in ISO-8859-2 +/* +/* This program is free software; you can redistribute it and/or modify +/* it under the terms of the GNU Library General Public License as published +/* by the Free Software Foundation; either version 2 of the License or +/* (at your optiunea) any later version. +/* +/* This program is distributed in the hope that it will be useful, but +/* WITHOUT ANY WARRANTY; without even the implied warranty of +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/* GNU Library General Public License for more details. +/* +/* You should have received a copy of the GNU Library General Public License +/* along with this program; see the file COPYING.LIB. If not, write to +/* the Free Software Foundation Inc., 59 Temple Place - Suite 330, +/* Boston, MA 02111-1307 USA +/**************************************************************************/ + +getopt.ambigious={0}: opţiunea ''{1}'' este ambiguă +getopt.arguments1={0}: opţiunea ''--{1}'' nu acceptă parametru +getopt.arguments2={0}: opţiunea ''{1}{2}'' nu acceptă parametru +getopt.requires={0}: opţiunea ''{1}'' cere un parametru +getopt.unrecognized={0}: opţiune necunoscută ''--{1}'' +getopt.unrecognized2={0}: opţiune necunoscută ''{1}{2}'' +getopt.illegal={0}: opţiune ilegală -- {1} +getopt.invalid={0}: opţiune invalidă -- {1} +getopt.requires2={0}: această opţiune cere un parametru -- {1} +getopt.invalidValue=Valoare invalidă {0} pentru parametrul 'has_arg' + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/README b/ssdd_p2_100291121_100292107/gnu/getopt/README new file mode 100755 index 0000000..48451f7 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/README @@ -0,0 +1,57 @@ +This is a Java port of the GNU getopt functions based on the versions +contained in glibc 2.0.6. I have attempted to keep the functionality +and programmer's interface as faithful to the original as possible. +However, due to differences between Java and C, some minor changes +has to me made. (Given the obtuse interface in the clib version, +perhaps some major changes should have been made). This should not +affect the way options appear to be parsed to the end user of program +that uses this Java getopt. The use of these classes are completely +documented in the javadoc comments, so I will not repeat that info here. + +Note that since these objects are part of a package called "gnu.getopt", +they need to be in a subdirectory called gnu/getopt somewhere in your +CLASSPATH. This includes the "MessagesBundle" files. + +I am not aware of any bugs. If you find one though, please send email +to me at arenn@urbanophile.com. The more detailed a bug report the better. +Bug fixes are also welcome at the same address. Please reference +release number "1.0.13". If you use this code, it would be helpful +if you let me know so that I can let you know if anything changes or +if any major bugs have been found/fixed. + +I have included a Makefile for compiling the code. If you do not have +access to make, then you can simply do a "javac *.java" at the OS +command line (or follow your vendor's instructions for compiling a +Java class). To build the documentation, do a "make docs" +or "javadoc -public *.java". Note that the images needed by the html +generated by javadoc are not included. You will need to get those +from some other Java documentation package. + +Note that the Makefile is not compliant with the GNU makefile +standards as I anticipate that at some point a master makefile will +be created for various GNU Java packages. And it is serious overkill +to create a megabloat makefile (kinda like this megabloat README) for +such a simple package. + +There is sample code showing how to use getopt available in the +GetoptDemo.java file. + +NEW: A support file for the "ant" build process was contributed. Here are +some brief things you can do with it. Note that I have not ever used this +so it is doubly AS IS. + +Get ant from jakarta project (see jakarta.apache.org/ant), and run it with +one of these target (all is default target): +ant prepare: create the needed directories +ant classes: compile the java classes +ant jar: create the jar archive +ant javadoc: create the javadoc +ant all: create jar and javadoc +ant clean: clean everything + +Happy hacking, + +Aaron. +arenn@urbanophile.com +http://www.urbanophile.com/arenn/ + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/buildx.xml b/ssdd_p2_100291121_100292107/gnu/getopt/buildx.xml new file mode 100755 index 0000000..ad51e8f --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/buildx.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/gnu.getopt.Getopt.html b/ssdd_p2_100291121_100292107/gnu/getopt/gnu.getopt.Getopt.html new file mode 100755 index 0000000..425de42 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/gnu.getopt.Getopt.html @@ -0,0 +1,639 @@ + + + + + + + Class gnu.getopt.Getopt + + + + +

+All Packages  Class Hierarchy  This Package  Previous  Next  Index
+
+

+ Class gnu.getopt.Getopt +

+
+java.lang.Object
+   |
+   +----gnu.getopt.Getopt
+
+
+
+
public class Getopt +
extends Object +
+This is a Java port of GNU getopt, a class for parsing command line + arguments passed to programs. It it based on the C getopt() functions + in glibc 2.0.6 and should parse options in a 100% compatible manner. + If it does not, that is a bug. The programmer's interface is also + very compatible. +

+ To use Getopt, create a Getopt object with a argv array passed to the + main method, then call the getopt() method in a loop. It will return an + int that contains the value of the option character parsed from the + command line. When there are no more options to be parsed, it + returns -1. +

+ A command line option can be defined to take an argument. If an + option has an argument, the value of that argument is stored in an + instance variable called optarg, which can be accessed using the + getOptarg() method. If an option that requires an argument is + found, but there is no argument present, then an error message is + printed. Normally getopt() returns a '?' in this situation, but + that can be changed as described below. +

+ If an invalid option is encountered, an error message is printed + to the standard error and getopt() returns a '?'. The value of the + invalid option encountered is stored in the instance variable optopt + which can be retrieved using the getOptopt() method. To suppress + the printing of error messages for this or any other error, set + the value of the opterr instance variable to false using the + setOpterr() method. +

+ Between calls to getopt(), the instance variable optind is used to + keep track of where the object is in the parsing process. After all + options have been returned, optind is the index in argv of the first + non-option argument. This variable can be accessed with the getOptind() + method. +

+ Note that this object expects command line options to be passed in the + traditional Unix manner. That is, proceeded by a '-' character. + Multiple options can follow the '-'. For example "-abc" is equivalent + to "-a -b -c". If an option takes a required argument, the value + of the argument can immediately follow the option character or be + present in the next argv element. For example, "-cfoo" and "-c foo" + both represent an option character of 'c' with an argument of "foo" + assuming c takes a required argument. If an option takes an argument + that is not required, then any argument must immediately follow the + option character in the same argv element. For example, if c takes + a non-required argument, then "-cfoo" represents option character 'c' + with an argument of "foo" while "-c foo" represents the option + character 'c' with no argument, and a first non-option argv element + of "foo". +

+ The user can stop getopt() from scanning any further into a command line + by using the special argument "--" by itself. For example: + "-a -- -d" would return an option character of 'a', then return -1 + The "--" is discarded and "-d" is pointed to by optind as the first + non-option argv element. +

+ Here is a basic example of using Getopt: +

+

+ Getopt g = new Getopt("testprog", argv, "ab:c::d");
+ //
+ int c;
+ String arg;
+ while ((c = g.getopt()) != -1)
+   {
+     switch(c)
+       {
+          case 'a':
+          case 'd':
+            System.out.print("You picked " + (char)c + "\n");
+            break;
+            //
+          case 'b':
+          case 'c':
+            arg = g.getOptarg();
+            System.out.print("You picked " + (char)c + 
+                             " with an argument of " +
+                             ((arg != null) ? arg : "null") + "\n");
+            break;
+            //
+          case '?':
+            break; // getopt() already printed an error
+            //
+          default:
+            System.out.print("getopt() returned " + c + "\n");
+       }
+   }
+ 
+

+ In this example, a new Getopt object is created with three params. + The first param is the program name. This is for printing error + messages in the form "program: error message". In the C version, this + value is taken from argv[0], but in Java the program name is not passed + in that element, thus the need for this parameter. The second param is + the argument list that was passed to the main() method. The third + param is the list of valid options. Each character represents a valid + option. If the character is followed by a single colon, then that + option has a required argument. If the character is followed by two + colons, then that option has an argument that is not required. +

+ Note in this example that the value returned from getopt() is cast to + a char prior to printing. This is required in order to make the value + display correctly as a character instead of an integer. +

+ If the first character in the option string is a colon, for example + ":abc::d", then getopt() will return a ':' instead of a '?' when it + encounters an option with a missing required argument. This allows the + caller to distinguish between invalid options and valid options that + are simply incomplete. +

+ In the traditional Unix getopt(), -1 is returned when the first non-option + charcter is encountered. In GNU getopt(), the default behavior is to + allow options to appear anywhere on the command line. The getopt() + method permutes the argument to make it appear to the caller that all + options were at the beginning of the command line, and all non-options + were at the end. For example, calling getopt() with command line args + of "-a foo bar -d" returns options 'a' and 'd', then sets optind to + point to "foo". The program would read the last two argv elements as + "foo" and "bar", just as if the user had typed "-a -d foo bar". +

+ The user can force getopt() to stop scanning the command line with + the special argument "--" by itself. Any elements occuring before the + "--" are scanned and permuted as normal. Any elements after the "--" + are returned as is as non-option argv elements. For example, + "foo -a -- bar -d" would return option 'a' then -1. optind would point + to "foo", "bar" and "-d" as the non-option argv elements. The "--" + is discarded by getopt(). +

+ There are two ways this default behavior can be modified. The first is + to specify traditional Unix getopt() behavior (which is also POSIX + behavior) in which scanning stops when the first non-option argument + encountered. (Thus "-a foo bar -d" would return 'a' as an option and + have "foo", "bar", and "-d" as non-option elements). The second is to + allow options anywhere, but to return all elements in the order they + occur on the command line. When a non-option element is ecountered, + an integer 1 is returned and the value of the non-option element is + stored in optarg is if it were the argument to that option. For + example, "-a foo -d", returns first 'a', then 1 (with optarg set to + "foo") then 'd' then -1. When this "return in order" functionality + is enabled, the only way to stop getopt() from scanning all command + line elements is to use the special "--" string by itself as described + above. An example is "-a foo -b -- bar", which would return 'a', then + integer 1 with optarg set to "foo", then 'b', then -1. optind would + then point to "bar" as the first non-option argv element. The "--" + is discarded. +

+ The POSIX/traditional behavior is enabled by either setting the + property "gnu.posixly_correct" or by putting a '+' sign as the first + character of the option string. The difference between the two + methods is that setting the gnu.posixly_correct property also forces + certain error messages to be displayed in POSIX format. To enable + the "return in order" functionality, put a '-' as the first character + of the option string. Note that after determining the proper + behavior, Getopt strips this leading '+' or '-', meaning that a ':' + placed as the second character after one of those two will still cause + getopt() to return a ':' instead of a '?' if a required option + argument is missing. +

+ In addition to traditional single character options, GNU Getopt also + supports long options. These are preceeded by a "--" sequence and + can be as long as desired. Long options provide a more user-friendly + way of entering command line options. For example, in addition to a + "-h" for help, a program could support also "--help". +

+ Like short options, long options can also take a required or non-required + argument. Required arguments can either be specified by placing an + equals sign after the option name, then the argument, or by putting the + argument in the next argv element. For example: "--outputdir=foo" and + "--outputdir foo" both represent an option of "outputdir" with an + argument of "foo", assuming that outputdir takes a required argument. + If a long option takes a non-required argument, then the equals sign + form must be used to specify the argument. In this case, + "--outputdir=foo" would represent option outputdir with an argument of + "foo" while "--outputdir foo" would represent the option outputdir + with no argument and a first non-option argv element of "foo". +

+ Long options can also be specified using a special POSIX argument + format (one that I highly discourage). This form of entry is + enabled by placing a "W;" (yes, 'W' then a semi-colon) in the valid + option string. This causes getopt to treat the name following the + "-W" as the name of the long option. For example, "-W outputdir=foo" + would be equivalent to "--outputdir=foo". The name can immediately + follow the "-W" like so: "-Woutputdir=foo". Option arguments are + handled identically to normal long options. If a string follows the + "-W" that does not represent a valid long option, then getopt() returns + 'W' and the caller must decide what to do. Otherwise getopt() returns + a long option value as described below. +

+ While long options offer convenience, they can also be tedious to type + in full. So it is permissible to abbreviate the option name to as + few characters as required to uniquely identify it. If the name can + represent multiple long options, then an error message is printed and + getopt() returns a '?'. +

+ If an invalid option is specified or a required option argument is + missing, getopt() prints an error and returns a '?' or ':' exactly + as for short options. Note that when an invalid long option is + encountered, the optopt variable is set to integer 0 and so cannot + be used to identify the incorrect option the user entered. +

+ Long options are defined by LongOpt objects. These objects are created + with a contructor that takes four params: a String representing the + object name, a integer specifying what arguments the option takes + (the value is one of LongOpt.NO_ARGUMENT, LongOpt.REQUIRED_ARGUMENT, + or LongOpt.OPTIONAL_ARGUMENT), a StringBuffer flag object (described + below), and an integer value (described below). +

+ To enable long option parsing, create an array of LongOpt's representing + the legal options and pass it to the Getopt() constructor. WARNING: If + all elements of the array are not populated with LongOpt objects, the + getopt() method will throw a NullPointerException. +

+ When getopt() is called and a long option is encountered, one of two + things can be returned. If the flag field in the LongOpt object + representing the long option is non-null, then the integer value field + is stored there and an integer 0 is returned to the caller. The val + field can then be retrieved from the flag field. Note that since the + flag field is a StringBuffer, the appropriate String to integer converions + must be performed in order to get the actual int value stored there. + If the flag field in the LongOpt object is null, then the value field + of the LongOpt is returned. This can be the character of a short option. + This allows an app to have both a long and short option sequence + (say, "-h" and "--help") that do the exact same thing. +

+ With long options, there is an alternative method of determining + which option was selected. The method getLongind() will return the + the index in the long option array (NOT argv) of the long option found. + So if multiple long options are configured to return the same value, + the application can use getLongind() to distinguish between them. +

+ Here is an expanded Getopt example using long options and various + techniques described above: +

+

+ int c;
+ String arg;
+ LongOpt[] longopts = new LongOpt[3];
+ // 
+ StringBuffer sb = new StringBuffer();
+ longopts[0] = new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h');
+ longopts[1] = new LongOpt("outputdir", LongOpt.REQUIRED_ARGUMENT, sb, 'o'); 
+ longopts[2] = new LongOpt("maximum", LongOpt.OPTIONAL_ARGUMENT, null, 2);
+ // 
+ Getopt g = new Getopt("testprog", argv, "-:bc::d:hW;", longopts);
+ g.setOpterr(false); // We'll do our own error handling
+ //
+ while ((c = g.getopt()) != -1)
+   switch (c)
+     {
+        case 0:
+          arg = g.getOptarg();
+          System.out.println("Got long option with value '" +
+                             (char)(new Integer(sb.toString())).intValue()
+                             + "' with argument " +
+                             ((arg != null) ? arg : "null"));
+          break;
+          //
+        case 1:
+          System.out.println("I see you have return in order set and that " +
+                             "a non-option argv element was just found " +
+                             "with the value '" + g.getOptarg() + "'");
+          break;
+          //
+        case 2:
+          arg = g.getOptarg();
+          System.out.println("I know this, but pretend I didn't");
+          System.out.println("We picked option " +
+                             longopts[g.getLongind()].getName() +
+                           " with value " + 
+                           ((arg != null) ? arg : "null"));
+          break;
+          //
+        case 'b':
+          System.out.println("You picked plain old option " + (char)c);
+          break;
+          //
+        case 'c':
+        case 'd':
+          arg = g.getOptarg();
+          System.out.println("You picked option '" + (char)c + 
+                             "' with argument " +
+                             ((arg != null) ? arg : "null"));
+          break;
+          //
+        case 'h':
+          System.out.println("I see you asked for help");
+          break;
+          //
+        case 'W':
+          System.out.println("Hmmm. You tried a -W with an incorrect long " +
+                             "option name");
+          break;
+          //
+        case ':':
+          System.out.println("Doh! You need an argument for option " +
+                             (char)g.getOptopt());
+          break;
+          //
+        case '?':
+          System.out.println("The option '" + (char)g.getOptopt() + 
+                           "' is not valid");
+          break;
+          //
+        default:
+          System.out.println("getopt() returned " + c);
+          break;
+     }
+ //
+ for (int i = g.getOptind(); i < argv.length ; i++)
+   System.out.println("Non option argv element: " + argv[i] + "\n");
+ 
+

+ There is an alternative form of the constructor used for long options + above. This takes a trailing boolean flag. If set to false, Getopt + performs identically to the example, but if the boolean flag is true + then long options are allowed to start with a single '-' instead of + "--". If the first character of the option is a valid short option + character, then the option is treated as if it were the short option. + Otherwise it behaves as if the option is a long option. Note that + the name given to this option - long_only - is very counter-intuitive. + It does not cause only long options to be parsed but instead enables + the behavior described above. +

+ Note that the functionality and variable names used are driven from + the C lib version as this object is a port of the C code, not a + new implementation. This should aid in porting existing C/C++ code, + as well as helping programmers familiar with the glibc version to + adapt to the Java version even if it seems very non-Java at times. +

+ In this release I made all instance variables protected due to + overwhelming public demand. Any code which relied on optarg, + opterr, optind, or optopt being public will need to be modified to + use the appropriate access methods. +

+ Please send all bug reports, requests, and comments to + arenn@urbanophile.com. +

+

+
Version: +
1.0.3 +
Author: +
Roland McGrath (roland@gnu.ai.mit.edu), Ulrich Drepper (drepper@cygnus.com), Aaron M. Renn (arenn@urbanophile.com) +
See Also: +
LongOpt +
+
+ +

+ Constructor Index +

+
+
 o + Getopt(String, String[], String) +
Construct a basic Getopt instance with the given input data. +
 o + Getopt(String, String[], String, LongOpt[]) +
Construct a Getopt instance with given input data that is capable of + parsing long options as well as short. +
 o + Getopt(String, String[], String, LongOpt[], boolean) +
Construct a Getopt instance with given input data that is capable of + parsing long options and short options. +
+

+ Method Index +

+
+
 o + getLongind() +
Returns the index into the array of long options (NOT argv) representing + the long option that was found. +
 o + getopt() +
This method returns a char that is the current option that has been + parsed from the command line. +
 o + getOptarg() +
+ For communication from `getopt' to the caller. +
 o + getOptind() +
optind it the index in ARGV of the next element to be scanned. +
 o + getOptopt() +
When getopt() encounters an invalid option, it stores the value of that + option in optopt which can be retrieved with this method. +
 o + setArgv(String[]) +
Since in GNU getopt() the argument vector is passed back in to the + function every time, the caller can swap out argv on the fly. +
 o + setOpterr(boolean) +
Normally Getopt will print a message to the standard error when an + invalid option is encountered. +
 o + setOptind(int) +
This method allows the optind index to be set manually. +
 o + setOptstring(String) +
In GNU getopt, it is possible to change the string containg valid options + on the fly because it is passed as an argument to getopt() each time. +
+ +

+ Constructors +

+ + o +Getopt +
+ public Getopt(String progname,
+               String argv[],
+               String optstring)
+
+
+
Construct a basic Getopt instance with the given input data. Note that + this handles "short" options only. +

+

+
Parameters: +
progname - The name to display as the program name when printing errors +
argv - The String array passed as the command line to the program. +
optstring - A String containing a description of the valid args for this program +
+
+ o +Getopt +
+ public Getopt(String progname,
+               String argv[],
+               String optstring,
+               LongOpt long_options[])
+
+
+
Construct a Getopt instance with given input data that is capable of + parsing long options as well as short. +

+

+
Parameters: +
progname - The name to display as the program name when printing errors +
argv - The String array passed as the command ilne to the program +
optstring - A String containing a description of the valid short args for this program +
long_options - An array of LongOpt objects that describes the valid long args for this program +
+
+ o +Getopt +
+ public Getopt(String progname,
+               String argv[],
+               String optstring,
+               LongOpt long_options[],
+               boolean long_only)
+
+
+
Construct a Getopt instance with given input data that is capable of + parsing long options and short options. Contrary to what you might + think, the flag 'long_only' does not determine whether or not we + scan for only long arguments. Instead, a value of true here allows + long arguments to start with a '-' instead of '--' unless there is a + conflict with a short option name. +

+

+
Parameters: +
progname - The name to display as the program name when printing errors +
argv - The String array passed as the command ilne to the program +
optstring - A String containing a description of the valid short args for this program +
long_options - An array of LongOpt objects that describes the valid long args for this program +
long_only - true if long options that do not conflict with short options can start with a '-' as well as '--' +
+
+ +

+ Methods +

+ o +setOptstring +
+ public void setOptstring(String optstring)
+
+
+
In GNU getopt, it is possible to change the string containg valid options + on the fly because it is passed as an argument to getopt() each time. In + this version we do not pass the string on every call. In order to allow + dynamic option string changing, this method is provided. +

+

+
Parameters: +
optstring - The new option string to use +
+
+ o +getOptind +
+ public int getOptind()
+
+
+
optind it the index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. +

+

+ o +setOptind +
+ public void setOptind(int optind)
+
+
+
This method allows the optind index to be set manually. Normally this + is not necessary (and incorrect usage of this method can lead to serious + lossage), but optind is a public symbol in GNU getopt, so this method + was added to allow it to be modified by the caller if desired. +

+

+
Parameters: +
optind - The new value of optind +
+
+ o +setArgv +
+ public void setArgv(String argv[])
+
+
+
Since in GNU getopt() the argument vector is passed back in to the + function every time, the caller can swap out argv on the fly. Since + passing argv is not required in the Java version, this method allows + the user to override argv. Note that incorrect use of this method can + lead to serious lossage. +

+

+
Parameters: +
argv - New argument list +
+
+ o +getOptarg +
+ public String getOptarg()
+
+
+
For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. + No set method is provided because setting this variable has no effect. +

+

+ o +setOpterr +
+ public void setOpterr(boolean opterr)
+
+
+
Normally Getopt will print a message to the standard error when an + invalid option is encountered. This can be suppressed (or re-enabled) + by calling this method. There is no get method for this variable + because if you can't remember the state you set this to, why should I? +

+

+ o +getOptopt +
+ public int getOptopt()
+
+
+
When getopt() encounters an invalid option, it stores the value of that + option in optopt which can be retrieved with this method. There is + no corresponding set method because setting this variable has no effect. +

+

+ o +getLongind +
+ public int getLongind()
+
+
+
Returns the index into the array of long options (NOT argv) representing + the long option that was found. +

+

+ o +getopt +
+ public int getopt()
+
+
+
This method returns a char that is the current option that has been + parsed from the command line. If the option takes an argument, then + the internal variable 'optarg' is set which is a String representing + the the value of the argument. This value can be retrieved by the + caller using the getOptarg() method. If an invalid option is found, + an error message is printed and a '?' is returned. The name of the + invalid option character can be retrieved by calling the getOptopt() + method. When there are no more options to be scanned, this method + returns -1. The index of first non-option element in argv can be + retrieved with the getOptind() method. +

+

+
Returns: +
Various things as described above +
+
+
+
+All Packages  Class Hierarchy  This Package  Previous  Next  Index
+ + diff --git a/ssdd_p2_100291121_100292107/gnu/getopt/gnu.getopt.LongOpt.html b/ssdd_p2_100291121_100292107/gnu/getopt/gnu.getopt.LongOpt.html new file mode 100755 index 0000000..ddc1186 --- /dev/null +++ b/ssdd_p2_100291121_100292107/gnu/getopt/gnu.getopt.LongOpt.html @@ -0,0 +1,210 @@ + + + + + + + Class gnu.getopt.LongOpt + + + + +
+All Packages  Class Hierarchy  This Package  Previous  Next  Index
+
+

+ Class gnu.getopt.LongOpt +

+
+java.lang.Object
+   |
+   +----gnu.getopt.LongOpt
+
+
+
+
public class LongOpt +
extends Object +
+This object represents the definition of a long option in the Java port + of GNU getopt. An array of LongOpt objects is passed to the Getopt + object to define the list of valid long options for a given parsing + session. Refer to the getopt documentation for details on the + format of long options. +

+

+
Version: +
1.0.3 +
Author: +
Aaron M. Renn (arenn@urbanophile.com) +
See Also: +
Getopt +
+
+ +

+ Variable Index +

+
+
 o + NO_ARGUMENT +
Constant value used for the "has_arg" constructor argument. +
 o + OPTIONAL_ARGUMENT +
Constant value used for the "has_arg" constructor argument. +
 o + REQUIRED_ARGUMENT +
+ Constant value used for the "has_arg" constructor argument. +
+

+ Constructor Index +

+
+
 o + LongOpt(String, int, StringBuffer, int) +
Create a new LongOpt object with the given parameter values. +
+

+ Method Index +

+
+
 o + getFlag() +
Returns the value of the 'flag' field for this long option + + +
 o + getHasArg() +
Returns the value set for the 'has_arg' field for this long option + + +
 o + getName() +
Returns the name of this LongOpt as a String + + +
 o + getVal() +
Returns the value of the 'val' field for this long option + + +
+ +

+ Variables +

+ o +NO_ARGUMENT +
+ public static final int NO_ARGUMENT
+
+
+
Constant value used for the "has_arg" constructor argument. This + value indicates that the option takes no argument.

+

+ o +REQUIRED_ARGUMENT +
+ public static final int REQUIRED_ARGUMENT
+
+
+
Constant value used for the "has_arg" constructor argument. This + value indicates that the option takes an argument that is required.

+

+ o +OPTIONAL_ARGUMENT +
+ public static final int OPTIONAL_ARGUMENT
+
+
+
Constant value used for the "has_arg" constructor argument. This + value indicates that the option takes an argument that is optional.

+

+ +

+ Constructors +

+ + o +LongOpt +
+ public LongOpt(String name,
+                int has_arg,
+                StringBuffer flag,
+                int val) throws IllegalArgumentException
+
+
+
Create a new LongOpt object with the given parameter values. If the + value passed as has_arg is not valid, then an exception is thrown. +

+

+
Parameters: +
name - The long option String. +
has_arg - Indicates whether the option has no argument (NO_ARGUMENT), a required argument (REQUIRED_ARGUMENT) or an optional argument (OPTIONAL_ARGUMENT). +
flag - If non-null, this is a location to store the value of "val" when this option is encountered, otherwise "val" is treated as the equivalent short option character. +
val - The value to return for this long option, or the equivalent single letter option to emulate if flag is null. +
Throws: IllegalArgumentException +
If the has_arg param is not one of NO_ARGUMENT, REQUIRED_ARGUMENT or OPTIONAL_ARGUMENT. +
+
+ +

+ Methods +

+ o +getName +
+ public String getName()
+
+
+
Returns the name of this LongOpt as a String +

+

+
Returns: +
Then name of the long option +
+
+ o +getHasArg +
+ public int getHasArg()
+
+
+
Returns the value set for the 'has_arg' field for this long option +

+

+
Returns: +
The value of 'has_arg' +
+
+ o +getFlag +
+ public StringBuffer getFlag()
+
+
+
Returns the value of the 'flag' field for this long option +

+

+
Returns: +
The value of 'flag' +
+
+ o +getVal +
+ public int getVal()
+
+
+
Returns the value of the 'val' field for this long option +

+

+
Returns: +
The value of 'val' +
+
+
+
+All Packages  Class Hierarchy  This Package  Previous  Next  Index
+ + diff --git a/ssdd_p2_100291121_100292107/lists/msg_list.c b/ssdd_p2_100291121_100292107/lists/msg_list.c new file mode 100644 index 0000000..6112ae3 --- /dev/null +++ b/ssdd_p2_100291121_100292107/lists/msg_list.c @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include "msg_list.h" + + +/* Creates a new message struct and enqueues it to the end of the message queue + Returns 0 if the message is stored + -1 if malloc error */ +int enqueueMsg(struct msg **head, char * message, char * md5, unsigned int id, char * sender){ + struct msg *temp; + /* Allocate the space for the new message */ + temp = (struct msg *) malloc(sizeof(struct msg)); + /* If malloc returns error (full memory or other) */ + if(temp == NULL) return -1; + strcpy(temp->body, message); + strcpy(temp->md5, md5); + strcpy(temp->sender, sender); + temp->id = id; + temp->next = NULL; + + if (*head == NULL){ /* Queue is empty */ + temp->next = *head; + *head = temp; + } + else{ + /* If the queue is not empty, iterate to the end and append the message */ + struct msg *last = *head; + while(last->next != NULL){ + last = last->next; + } + last->next = temp; + } + return 0; +} +/* Deletes the message at the head of the queue and returns the new + head of the list + Return a pointer to the next message in the queue + NULL if the list is left empty */ +struct msg * dequeueMsg(struct msg **head){ + struct msg* temp = *head; + /* Head pointing to the next element */ + *head = temp->next; + /* Free the resources of the first message */ + free(temp); + /* Return the new head of the queue */ + return *head; +} + +/* Deletes all the messages in the list from the head of the list +passed as paremeter */ +void deleteAllMsgs(struct msg ** head){ + struct msg **temp = head; + while(*temp != NULL){ + *temp = dequeueMsg(&(*temp)); + } + return; +} \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107/lists/msg_list.h b/ssdd_p2_100291121_100292107/lists/msg_list.h new file mode 100644 index 0000000..bca5c01 --- /dev/null +++ b/ssdd_p2_100291121_100292107/lists/msg_list.h @@ -0,0 +1,15 @@ +#define MAX_MSG 256 +#define MAX_MD5 33 + +struct msg{ + char body[MAX_MSG]; /* Content of the message */ + char sender[MAX_MSG]; /* Sender of the message */ + char md5[MAX_MD5]; /* MD5 of the message */ + unsigned int id; /* ID assigned to the message */ + struct msg *next; /* Pointer to the next message in the list */ +}; + +/* ================FUNCTION HEADERS================ */ +int enqueueMsg(struct msg **head, char * message, char * md5, unsigned int id, char * sender); +struct msg * dequeueMsg(struct msg **head); +void deleteAllMsgs(struct msg ** head); \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107/lists/read_line.c b/ssdd_p2_100291121_100292107/lists/read_line.c new file mode 100644 index 0000000..c2038c3 --- /dev/null +++ b/ssdd_p2_100291121_100292107/lists/read_line.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include "read_line.h" + +int send_msg(int socket, char *message, int length) +{ + int r; + int l = length; + + + do { + r = send(socket, message, l, 0); + l = l -r; /* Pending data to send */ + message = message + r; /* */ + } while ((l>0) && (r>=0)); /* We check the returned value in case all the data was not sent */ + + if (r < 0) + return (-1); /* fail */ + else + return(0); /* success */ +} + +ssize_t readLine(int fd, void *buffer, size_t n) +{ + ssize_t numRead; /* num of bytes fetched by last read() */ + size_t totRead; /* total bytes read so far */ + char *buf; + char ch; + + + if (n <= 0 || buffer == NULL) { + errno = EINVAL; + return -1; + } + + buf = buffer; + totRead = 0; + + for (;;) { + numRead = read(fd, &ch, 1); /* read a byte */ + + if (numRead == -1) { + if (errno == EINTR) /* interrupted -> restart read() */ + continue; + else + return -1; /* some other error */ + } else if (numRead == 0) { /* EOF */ + if (totRead == 0) /* no byres read; return 0 */ + return 0; + else + break; + } else { /* numRead must be 1 if we get here*/ + if (ch == '\n') + break; + if (ch == '\0') + break; + if (totRead < n - 1) { /* discard > (n-1) bytes */ + totRead++; + *buf++ = ch; + } + } + } + + *buf = '\0'; + return totRead; +} diff --git a/ssdd_p2_100291121_100292107/lists/read_line.h b/ssdd_p2_100291121_100292107/lists/read_line.h new file mode 100644 index 0000000..e3d4c9e --- /dev/null +++ b/ssdd_p2_100291121_100292107/lists/read_line.h @@ -0,0 +1,5 @@ +#include + +int send_msg(int socket, char *message, int length); +int recv_msg(int socket, char *message, int length); +ssize_t readLine(int fd, void *buffer, size_t n); diff --git a/ssdd_p2_100291121_100292107/lists/user_list.c b/ssdd_p2_100291121_100292107/lists/user_list.c new file mode 100644 index 0000000..0280c16 --- /dev/null +++ b/ssdd_p2_100291121_100292107/lists/user_list.c @@ -0,0 +1,246 @@ +#include +#include +#include +#include +#include "msg_list.h" +#include "user_list.h" + +/* Checks if the input user is already registered + Return 0 if is registered + 1 if is not registered */ +char isRegistered(char * username){ + struct user *temp; + temp = user_head; + + /* Iterate over the list */ + while (temp != NULL){ + if (strcmp(temp->username, username) == 0){ //Check if the username exists + return 1; + } + temp = temp->next; + } + + return 0; + } + +/* Registers a user (if not previously registered) and appends it to the end of the s list + Returns 1 if already registered + 0 if registered correctly */ +char registerUser(char * username){ + /* Check if the user already exists */ + if(isRegistered(username)) return 1; + + /* Prepare new user */ + struct user *temp; + temp = (struct user *) malloc(sizeof(struct user)); + /* If memory is full and malloc is not possible, we return code 2 */ + if(temp == NULL) return 2; + /* Initialize user values */ + strcpy(temp->username, username); + temp->status = 0; + strcpy(temp->ip, "-1"); + temp->port = 0; + temp->pend_msgs_head = NULL; + temp->next = NULL; + temp->last_id = 0; + + if (user_head == NULL){ //If list is empty + temp->next = user_head; + user_head = temp; + } + else{ + struct user *last = user_head; + + /* Iterate over the list */ + while(last->next != NULL){ + last = last->next; + } + last->next = temp; + } + + return 0; +} + +/* Changes the status of a user to 1 (ON) and links an IP and port number to it + Return 0 if connect OK + 1 if user is not registered + 2 if registered but not connected */ +char connectUser(char * username, char * ip, uint16_t port){ + struct user *temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + if (temp->status == 1) return 2; //User already connected + /* Change status to 1 ("ON") and update IP and Port */ + temp->status = 1; + strcpy(temp->ip, ip); + temp->port = port; + return 0; + } + temp = temp->next; + } + /* No user was found, so send code 1 */ + return 1; +} + +/* Changes the status of a user to 0 (OFF) and cleans the IP and port number + Return 0 if disconnect OK; + 1 if user is not registered; + 2 if registered but not connected; + 3 if trying to disconnect from a different IP */ +char disconnectUser(char * username, char * used_ip){ + struct user *temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + if (temp->status == 0) return 2; //User already disconnected + if(strcmp(temp->ip, used_ip) != 0) return 3; //Trying to disconnect from a different IP + /* Change status to 0 ("OFF") and delete IP and Port */ + temp->status = 0; + strcpy(temp->ip, "-1"); + temp->port = 0; + return 0; + } + temp = temp->next; + } + + return 1; +} + + +/* Unregisters a user, deleting it and its pending messages (if any) from the list + Returns 1 if the user does not exist. + 0 if the user is deleted correctly */ +char unregisterUser(char * username){ + struct user *temp, *prev; //temp is the current user, prev is the previous user in the list + temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + if(temp == user_head){ //If the user is at the user_head of the list + user_head = temp->next; //change the user_head to the next element + /* Delete the pending messages if any */ + deleteAllMsgs(&(temp->pend_msgs_head)); + free(temp); //Free the resources of the user + return 0; + } + else{ //User is not at the user_head + prev->next = temp->next; + /* Delete the pending messages if any */ + deleteAllMsgs(&(temp->pend_msgs_head)); + /* Free the memory resources of the user structure */ + free(temp); + return 0; + } + } + else{ + prev = temp; + temp = temp->next; + } + } + //If we reach this point, no user was found + return 1; +} + +/* Returns 0 if store OK. -1 if server error (malloc error because of full memory) */ +int storeMsg(char * username, char* msg, unsigned int msg_id, char * md5, char * sender){ + struct user *temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + //Enqueue message + return enqueueMsg(&(temp->pend_msgs_head), msg, md5, msg_id, sender); + } + temp = temp->next; + } + + return -1; //User was not found +} + +/* Increments the last-sent-message ID associated to the input user + Return the value of the updated ID */ +unsigned int updateLastID(char * username){ + struct user *temp = user_head; + + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + //Increment the ID in 1 + temp->last_id = temp->last_id+1; + //If it results in 0, then the maximum representable number is overflown + if(temp->last_id == 0) temp->last_id = 1; + + return temp->last_id; + } + temp = temp->next; + } + + return 0; +} + +/* Checks if the input user is connected + Return 0 if the user is disconnected + 1 if the user is connected + 2 if error (user was not found) */ +char isConnected(char * username){ + struct user *temp = user_head; + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + return temp->status; //Returns 0 if OFF, 1 if ON + } + temp = temp->next; + } + /* Return error 2 if we reach this point. No user was found */ + return 2; +} + +/* Retrieves the IP associated to a user in the list + Returns a char array with the IP of the user + NULL if the user was not found */ +char * getUserIP(char * username){ + struct user *temp = user_head; + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + return temp->ip; //Returns the IP of the user + } + temp = temp->next; + } + return NULL; +} + +/* Retrieves the port number associated to a user in the list + Return the port number + 0 if the user was not found */ +uint16_t getUserPort(char * username){ + struct user *temp = user_head; + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + return temp->port; //Returns the IP of the user + } + temp = temp->next; + } + return 0; +} + +/* Retrieves a pointer to the head of the pending message list associated to a user + Return the pointer to the head of the message list + NULL if the user was not found */ +struct msg ** getPendMsgHead(char * username){ + struct user *temp = user_head; + /* Iterate over the list */ + while(temp != NULL){ + if(strcmp(temp->username, username) == 0){ //User found + return &(temp->pend_msgs_head); //Returns the IP of the user + } + temp = temp->next; + } + return NULL; +} + diff --git a/ssdd_p2_100291121_100292107/lists/user_list.h b/ssdd_p2_100291121_100292107/lists/user_list.h new file mode 100644 index 0000000..70dcc1e --- /dev/null +++ b/ssdd_p2_100291121_100292107/lists/user_list.h @@ -0,0 +1,27 @@ +#define MAX_USERNAME 256 +#define MAX_IP 16 +#define TRUE 1 +#define FALSE 0 + +struct user{ + char username[MAX_USERNAME]; /* Username that acts as ID */ + char status; /* Status of the client: 0 if "OFF"; 1 if "ON" */ + char ip[MAX_IP]; /* IP of the user from which the connect operation was made */ + uint16_t port; /* Port number of the user from which the connect operation was made */ + unsigned int last_id; /* ID assigned to the last sent message */ + struct msg *pend_msgs_head; /* Pointer to the head of the pending messages queue */ + struct user *next; /* Pointer to the next user in the list */ +} *user_head; + +/* ================FUNCTION HEADERS================ */ +char isRegistered(char * username); +char registerUser(char * username); +char unregisterUser(char * username); +char connectUser(char * username, char * ip, uint16_t port); +char disconnectUser(char * username, char * used_ip); +int storeMsg(char * username, char* msg, unsigned int msg_id, char * md5, char * sender); +unsigned int updateLastID(char * username); +char isConnected(char * username); +char * getUserIP(char * username); +uint16_t getUserPort(char * username); +struct msg ** getPendMsgHead(char * username); \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107/md5/client/Exception.java b/ssdd_p2_100291121_100292107/md5/client/Exception.java new file mode 100644 index 0000000..89fef0a --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/client/Exception.java @@ -0,0 +1,60 @@ + +package md5.client; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for Exception complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="Exception">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="message" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "Exception", propOrder = { + "message" +}) +public class Exception { + + protected String message; + + /** + * Gets the value of the message property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getMessage() { + return message; + } + + /** + * Sets the value of the message property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setMessage(String value) { + this.message = value; + } + +} diff --git a/ssdd_p2_100291121_100292107/md5/client/Exception_Exception.java b/ssdd_p2_100291121_100292107/md5/client/Exception_Exception.java new file mode 100644 index 0000000..9e68531 --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/client/Exception_Exception.java @@ -0,0 +1,54 @@ + +package md5.client; + +import javax.xml.ws.WebFault; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.4-b01 + * Generated source version: 2.2 + * + */ +@WebFault(name = "Exception", targetNamespace = "http://ws.server.md5/") +public class Exception_Exception + extends java.lang.Exception +{ + + /** + * Java type that goes as soapenv:Fault detail element. + * + */ + private md5.client.Exception faultInfo; + + /** + * + * @param message + * @param faultInfo + */ + public Exception_Exception(String message, md5.client.Exception faultInfo) { + super(message); + this.faultInfo = faultInfo; + } + + /** + * + * @param message + * @param faultInfo + * @param cause + */ + public Exception_Exception(String message, md5.client.Exception faultInfo, Throwable cause) { + super(message, cause); + this.faultInfo = faultInfo; + } + + /** + * + * @return + * returns fault bean: md5.client.Exception + */ + public md5.client.Exception getFaultInfo() { + return faultInfo; + } + +} diff --git a/ssdd_p2_100291121_100292107/md5/client/MD5.java b/ssdd_p2_100291121_100292107/md5/client/MD5.java new file mode 100644 index 0000000..77bf5ca --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/client/MD5.java @@ -0,0 +1,46 @@ + +package md5.client; + +import javax.jws.WebMethod; +import javax.jws.WebParam; +import javax.jws.WebResult; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.ws.Action; +import javax.xml.ws.FaultAction; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.4-b01 + * Generated source version: 2.2 + * + */ +@WebService(name = "MD5", targetNamespace = "http://ws.server.md5/") +@SOAPBinding(style = SOAPBinding.Style.RPC) +@XmlSeeAlso({ + ObjectFactory.class +}) +public interface MD5 { + + + /** + * + * @param arg0 + * @return + * returns java.lang.String + * @throws Exception_Exception + */ + @WebMethod + @WebResult(partName = "return") + @Action(input = "http://ws.server.md5/MD5/getMD5Request", output = "http://ws.server.md5/MD5/getMD5Response", fault = { + @FaultAction(className = Exception_Exception.class, value = "http://ws.server.md5/MD5/getMD5/Fault/Exception") + }) + public String getMD5( + @WebParam(name = "arg0", partName = "arg0") + String arg0) + throws Exception_Exception + ; + +} diff --git a/ssdd_p2_100291121_100292107/md5/client/MD5ImplService.java b/ssdd_p2_100291121_100292107/md5/client/MD5ImplService.java new file mode 100644 index 0000000..2608289 --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/client/MD5ImplService.java @@ -0,0 +1,94 @@ + +package md5.client; + +import java.net.MalformedURLException; +import java.net.URL; +import javax.xml.namespace.QName; +import javax.xml.ws.Service; +import javax.xml.ws.WebEndpoint; +import javax.xml.ws.WebServiceClient; +import javax.xml.ws.WebServiceException; +import javax.xml.ws.WebServiceFeature; + + +/** + * This class was generated by the JAX-WS RI. + * JAX-WS RI 2.2.4-b01 + * Generated source version: 2.2 + * + */ +@WebServiceClient(name = "MD5ImplService", targetNamespace = "http://ws.server.md5/", wsdlLocation = "http://127.0.1.1:8080/ws/md5?wsdl") +public class MD5ImplService + extends Service +{ + + private final static URL MD5IMPLSERVICE_WSDL_LOCATION; + private final static WebServiceException MD5IMPLSERVICE_EXCEPTION; + private final static QName MD5IMPLSERVICE_QNAME = new QName("http://ws.server.md5/", "MD5ImplService"); + + static { + URL url = null; + WebServiceException e = null; + try { + url = new URL("http://127.0.1.1:8080/ws/md5?wsdl"); + } catch (MalformedURLException ex) { + e = new WebServiceException(ex); + } + MD5IMPLSERVICE_WSDL_LOCATION = url; + MD5IMPLSERVICE_EXCEPTION = e; + } + + public MD5ImplService() { + super(__getWsdlLocation(), MD5IMPLSERVICE_QNAME); + } + + public MD5ImplService(WebServiceFeature... features) { + super(__getWsdlLocation(), MD5IMPLSERVICE_QNAME, features); + } + + public MD5ImplService(URL wsdlLocation) { + super(wsdlLocation, MD5IMPLSERVICE_QNAME); + } + + public MD5ImplService(URL wsdlLocation, WebServiceFeature... features) { + super(wsdlLocation, MD5IMPLSERVICE_QNAME, features); + } + + public MD5ImplService(URL wsdlLocation, QName serviceName) { + super(wsdlLocation, serviceName); + } + + public MD5ImplService(URL wsdlLocation, QName serviceName, WebServiceFeature... features) { + super(wsdlLocation, serviceName, features); + } + + /** + * + * @return + * returns MD5 + */ + @WebEndpoint(name = "MD5ImplPort") + public MD5 getMD5ImplPort() { + return super.getPort(new QName("http://ws.server.md5/", "MD5ImplPort"), MD5.class); + } + + /** + * + * @param features + * A list of {@link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the features parameter will have their default values. + * @return + * returns MD5 + */ + @WebEndpoint(name = "MD5ImplPort") + public MD5 getMD5ImplPort(WebServiceFeature... features) { + return super.getPort(new QName("http://ws.server.md5/", "MD5ImplPort"), MD5.class, features); + } + + private static URL __getWsdlLocation() { + if (MD5IMPLSERVICE_EXCEPTION!= null) { + throw MD5IMPLSERVICE_EXCEPTION; + } + return MD5IMPLSERVICE_WSDL_LOCATION; + } + +} diff --git a/ssdd_p2_100291121_100292107/md5/client/ObjectFactory.java b/ssdd_p2_100291121_100292107/md5/client/ObjectFactory.java new file mode 100644 index 0000000..c9865fe --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/client/ObjectFactory.java @@ -0,0 +1,53 @@ + +package md5.client; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the md5.client package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _Exception_QNAME = new QName("http://ws.server.md5/", "Exception"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: md5.client + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link Exception } + * + */ + public Exception createException() { + return new Exception(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link Exception }{@code >}} + * + */ + @XmlElementDecl(namespace = "http://ws.server.md5/", name = "Exception") + public JAXBElement createException(Exception value) { + return new JAXBElement(_Exception_QNAME, Exception.class, null, value); + } + +} diff --git a/ssdd_p2_100291121_100292107/md5/client/package-info.java b/ssdd_p2_100291121_100292107/md5/client/package-info.java new file mode 100644 index 0000000..35519b5 --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/client/package-info.java @@ -0,0 +1,2 @@ +@javax.xml.bind.annotation.XmlSchema(namespace = "http://ws.server.md5/") +package md5.client; diff --git a/ssdd_p2_100291121_100292107/md5/server/endpoint/MD5Publisher.class b/ssdd_p2_100291121_100292107/md5/server/endpoint/MD5Publisher.class new file mode 100644 index 0000000..7e0460e Binary files /dev/null and b/ssdd_p2_100291121_100292107/md5/server/endpoint/MD5Publisher.class differ diff --git a/ssdd_p2_100291121_100292107/md5/server/endpoint/MD5Publisher.java b/ssdd_p2_100291121_100292107/md5/server/endpoint/MD5Publisher.java new file mode 100644 index 0000000..c81ad99 --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/server/endpoint/MD5Publisher.java @@ -0,0 +1,27 @@ +package md5.server.endpoint; + +import javax.xml.ws.Endpoint; +import md5.server.ws.MD5Impl; +import java.net.Inet4Address; + +//Endpoint publisher +public class MD5Publisher{ + + public static void main(String[] args) { + String url = "http://"; + try{ + /* Get the machine's IP address in which the web service will be running */ + url += Inet4Address.getLocalHost().getHostAddress(); + } + catch(Exception e){ + System.out.println("Error when getting IP address"); + return; + } + /* Build the web service URI */ + url += ":8080/ws/md5"; + System.out.println("Publishing MD5 service at endpoint: " + url); + /* Publish the endpoint */ + Endpoint.publish(url, new MD5Impl()); + } + +} \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107/md5/server/ws/MD5.class b/ssdd_p2_100291121_100292107/md5/server/ws/MD5.class new file mode 100644 index 0000000..f16d81b Binary files /dev/null and b/ssdd_p2_100291121_100292107/md5/server/ws/MD5.class differ diff --git a/ssdd_p2_100291121_100292107/md5/server/ws/MD5.java b/ssdd_p2_100291121_100292107/md5/server/ws/MD5.java new file mode 100644 index 0000000..89fd071 --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/server/ws/MD5.java @@ -0,0 +1,15 @@ +package md5.server.ws; + +import javax.jws.WebMethod; +import javax.jws.WebService; +import javax.jws.soap.SOAPBinding; +import javax.jws.soap.SOAPBinding.Style; + +//Service Endpoint Interface +@WebService +@SOAPBinding(style = Style.RPC) +public interface MD5{ + + @WebMethod String getMD5(String text) throws Exception; + +} \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107/md5/server/ws/MD5Impl.class b/ssdd_p2_100291121_100292107/md5/server/ws/MD5Impl.class new file mode 100644 index 0000000..64a2b06 Binary files /dev/null and b/ssdd_p2_100291121_100292107/md5/server/ws/MD5Impl.class differ diff --git a/ssdd_p2_100291121_100292107/md5/server/ws/MD5Impl.java b/ssdd_p2_100291121_100292107/md5/server/ws/MD5Impl.java new file mode 100644 index 0000000..1383620 --- /dev/null +++ b/ssdd_p2_100291121_100292107/md5/server/ws/MD5Impl.java @@ -0,0 +1,34 @@ +// Based on http://www.mkyong.com/java/java-md5-hashing-example/ +package md5.server.ws; + +import java.io.FileInputStream; +import java.security.MessageDigest; +import javax.jws.WebService; + +//Service Implementation +@WebService(endpointInterface = "md5.server.ws.MD5") +public class MD5Impl implements MD5 +{ + /** + * Performs the MD5 algorithm in order to produce a 128-bit hash value. + * @param text input text argument. + * @return The calculated MD5 hash value (in hex format). + */ + @Override + public String getMD5(String text) throws Exception + { + // Calculate MD5(text) + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] dataBytes = text.getBytes(); + md.update(dataBytes, 0, text.length()); + byte[] mdbytes = md.digest(); + + // Convert byte to hex format + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < mdbytes.length; i++) { + sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1)); + } + + return sb.toString(); + } +} diff --git a/ssdd_p2_100291121_100292107/monitor.c b/ssdd_p2_100291121_100292107/monitor.c new file mode 100644 index 0000000..f3e2b03 --- /dev/null +++ b/ssdd_p2_100291121_100292107/monitor.c @@ -0,0 +1,54 @@ + +#include "rpc_store_service/store_service.h" + +int +main (int argc, char *argv[]) +{ + char *host; + enum clnt_stat retval; /* Return value for the getmessage call */ + /* Check the parameters of the command */ + if (argc < 4) { + printf ("usage: %s server_host \n", argv[0]); + exit (1); + } + /* Get the address of the host from the first paramete */ + host = argv[1]; + /* Get the ID from the third parameter and store it in an unsigned int */ + char *stopstring; + unsigned int id = strtoul(argv[3], &stopstring, 10); + + CLIENT *clnt; + /* Create the connection with the service */ + clnt = clnt_create (host, STORE_SERVICE, STORE_VERSION, "tcp"); + if (clnt == NULL) { + printf("ERROR , SERVICE NOT AVAILABLE\n"); + exit (1); + } + /* Allocate resources for the response */ + response *res = malloc(sizeof(response)); + res->msg = calloc(MAX_SIZE, sizeof(char)); + res->md5 = calloc(MAX_MD5, sizeof(char)); + /* Call the get message service with the client ID and message ID passed as parameters */ + retval = getmessage_1(argv[2], id, res, clnt); + /* If FALSE is returned, there was an internal server error */ + if(retval != RPC_SUCCESS) printf("ERROR , SERVICE NOT AVAILABLE\n"); + /* if the length of the receive message is 0, no message was found */ + if(strlen(res->msg) == 0) printf ("ERROR , MESSAGE DOES NOT EXIST\n"); + /* Otherwise, print the message and its MD5 hash */ + else{ + printf("MESS: %s\n", res->msg); + printf("MD5: %s\n", res->md5); + } + /*******************************************/ + /* Sample code for the getnummessages call */ + /*******************************************/ + /* + int result; + getnummessages_1(argv[2], &result, clnt); + if(result != -1) printf("Total number of messages: %d\n", result); + else printf("The tuple client-id does not exist.\n"); + */ + /* Destroy the connection */ + clnt_destroy (clnt); + exit (0); +} diff --git a/ssdd_p2_100291121_100292107/report.pdf b/ssdd_p2_100291121_100292107/report.pdf new file mode 100644 index 0000000..cc4e328 Binary files /dev/null and b/ssdd_p2_100291121_100292107/report.pdf differ diff --git a/ssdd_p2_100291121_100292107/rpc_store_service/store_service.h b/ssdd_p2_100291121_100292107/rpc_store_service/store_service.h new file mode 100644 index 0000000..25dff07 --- /dev/null +++ b/ssdd_p2_100291121_100292107/rpc_store_service/store_service.h @@ -0,0 +1,93 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _STORE_SERVICE_H_RPCGEN +#define _STORE_SERVICE_H_RPCGEN + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_SIZE 256 +#define MAX_MD5 33 + +struct response { + char *msg; + char *md5; +}; +typedef struct response response; + +struct store_1_argument { + char *sender; + char *receiver; + u_int msg_id; + char *msg; + char *md5; +}; +typedef struct store_1_argument store_1_argument; + +struct getmessage_1_argument { + char *user; + u_int msg_id; +}; +typedef struct getmessage_1_argument getmessage_1_argument; + +#define STORE_SERVICE 666 +#define STORE_VERSION 1 + +#if defined(__STDC__) || defined(__cplusplus) +#define init 1 +extern enum clnt_stat init_1(void *, CLIENT *); +extern bool_t init_1_svc(void *, struct svc_req *); +#define store 2 +extern enum clnt_stat store_1(char *, char *, u_int , char *, char *, int *, CLIENT *); +extern bool_t store_1_svc(char *, char *, u_int , char *, char *, int *, struct svc_req *); +#define getNumMessages 3 +extern enum clnt_stat getnummessages_1(char *, int *, CLIENT *); +extern bool_t getnummessages_1_svc(char *, int *, struct svc_req *); +#define getMessage 4 +extern enum clnt_stat getmessage_1(char *, u_int , response *, CLIENT *); +extern bool_t getmessage_1_svc(char *, u_int , response *, struct svc_req *); +extern int store_service_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#else /* K&R C */ +#define init 1 +extern enum clnt_stat init_1(); +extern bool_t init_1_svc(); +#define store 2 +extern enum clnt_stat store_1(); +extern bool_t store_1_svc(); +#define getNumMessages 3 +extern enum clnt_stat getnummessages_1(); +extern bool_t getnummessages_1_svc(); +#define getMessage 4 +extern enum clnt_stat getmessage_1(); +extern bool_t getmessage_1_svc(); +extern int store_service_1_freeresult (); +#endif /* K&R C */ + +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_response (XDR *, response*); +extern bool_t xdr_store_1_argument (XDR *, store_1_argument*); +extern bool_t xdr_getmessage_1_argument (XDR *, getmessage_1_argument*); + +#else /* K&R C */ +extern bool_t xdr_response (); +extern bool_t xdr_store_1_argument (); +extern bool_t xdr_getmessage_1_argument (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_STORE_SERVICE_H_RPCGEN */ diff --git a/ssdd_p2_100291121_100292107/rpc_store_service/store_service_clnt.c b/ssdd_p2_100291121_100292107/rpc_store_service/store_service_clnt.c new file mode 100644 index 0000000..91d8293 --- /dev/null +++ b/ssdd_p2_100291121_100292107/rpc_store_service/store_service_clnt.c @@ -0,0 +1,53 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include /* for memset */ +#include "store_service.h" + +/* Default timeout can be changed using clnt_control() */ +static struct timeval TIMEOUT = { 25, 0 }; + +enum clnt_stat +init_1(void *clnt_res, CLIENT *clnt) +{ + return (clnt_call (clnt, init, (xdrproc_t) xdr_void, (caddr_t) NULL, + (xdrproc_t) xdr_void, (caddr_t) clnt_res, + TIMEOUT)); + +} + +enum clnt_stat +store_1(char *sender, char *receiver, u_int msg_id, char *msg, char *md5, int *clnt_res, CLIENT *clnt) +{ + store_1_argument arg; + arg.sender = sender; + arg.receiver = receiver; + arg.msg_id = msg_id; + arg.msg = msg; + arg.md5 = md5; + return (clnt_call (clnt, store, (xdrproc_t) xdr_store_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_int, (caddr_t) clnt_res, + TIMEOUT)); +} + +enum clnt_stat +getnummessages_1(char *user, int *clnt_res, CLIENT *clnt) +{ + return (clnt_call(clnt, getNumMessages, + (xdrproc_t) xdr_wrapstring, (caddr_t) &user, + (xdrproc_t) xdr_int, (caddr_t) clnt_res, + TIMEOUT)); +} + +enum clnt_stat +getmessage_1(char *user, u_int msg_id, response *clnt_res, CLIENT *clnt) +{ + getmessage_1_argument arg; + arg.user = user; + arg.msg_id = msg_id; + return (clnt_call (clnt, getMessage, (xdrproc_t) xdr_getmessage_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_response, (caddr_t) clnt_res, + TIMEOUT)); +} diff --git a/ssdd_p2_100291121_100292107/rpc_store_service/store_service_svc.c b/ssdd_p2_100291121_100292107/rpc_store_service/store_service_svc.c new file mode 100644 index 0000000..1c97888 --- /dev/null +++ b/ssdd_p2_100291121_100292107/rpc_store_service/store_service_svc.c @@ -0,0 +1,155 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "store_service.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef SIG_PF +#define SIG_PF void(*)(int) +#endif + +int +_init_1 (void *argp, void *result, struct svc_req *rqstp) +{ + return (init_1_svc(result, rqstp)); +} + +int +_store_1 (store_1_argument *argp, void *result, struct svc_req *rqstp) +{ + return (store_1_svc(argp->sender, argp->receiver, argp->msg_id, argp->msg, argp->md5, result, rqstp)); +} + +int +_getnummessages_1 (char * *argp, void *result, struct svc_req *rqstp) +{ + return (getnummessages_1_svc(*argp, result, rqstp)); +} + +int +_getmessage_1 (getmessage_1_argument *argp, void *result, struct svc_req *rqstp) +{ + return (getmessage_1_svc(argp->user, argp->msg_id, result, rqstp)); +} + +static void +store_service_1(struct svc_req *rqstp, register SVCXPRT *transp) +{ + union { + store_1_argument store_1_arg; + char *getnummessages_1_arg; + getmessage_1_argument getmessage_1_arg; + } argument; + union { + int store_1_res; + int getnummessages_1_res; + response getmessage_1_res; + } result; + bool_t retval; + xdrproc_t _xdr_argument, _xdr_result; + bool_t (*local)(char *, void *, struct svc_req *); + + switch (rqstp->rq_proc) { + case NULLPROC: + (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); + return; + + case init: + _xdr_argument = (xdrproc_t) xdr_void; + _xdr_result = (xdrproc_t) xdr_void; + local = (bool_t (*) (char *, void *, struct svc_req *))_init_1; + break; + + case store: + _xdr_argument = (xdrproc_t) xdr_store_1_argument; + _xdr_result = (xdrproc_t) xdr_int; + local = (bool_t (*) (char *, void *, struct svc_req *))_store_1; + break; + + case getNumMessages: + _xdr_argument = (xdrproc_t) xdr_wrapstring; + _xdr_result = (xdrproc_t) xdr_int; + local = (bool_t (*) (char *, void *, struct svc_req *))_getnummessages_1; + break; + + case getMessage: + _xdr_argument = (xdrproc_t) xdr_getmessage_1_argument; + _xdr_result = (xdrproc_t) xdr_response; + local = (bool_t (*) (char *, void *, struct svc_req *))_getmessage_1; + break; + + default: + svcerr_noproc (transp); + return; + } + memset ((char *)&argument, 0, sizeof (argument)); + if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { + svcerr_decode (transp); + return; + } + retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp); + if (retval > 0 && !svc_sendreply(transp, (xdrproc_t) _xdr_result, (char *)&result)) { + svcerr_systemerr (transp); + } + if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { + fprintf (stderr, "%s", "unable to free arguments"); + exit (1); + } + if (!store_service_1_freeresult (transp, _xdr_result, (caddr_t) &result)) + fprintf (stderr, "%s", "unable to free results"); + + return; +} + +int +main (int argc, char **argv) +{ + register SVCXPRT *transp; + struct sockaddr_in service_addr; /* Struct to store the address of the server */ + + pmap_unset (STORE_SERVICE, STORE_VERSION); + + transp = svcudp_create(RPC_ANYSOCK); + if (transp == NULL) { + fprintf (stderr, "%s", "cannot create udp service."); + exit(1); + } + if (!svc_register(transp, STORE_SERVICE, STORE_VERSION, store_service_1, IPPROTO_UDP)) { + fprintf (stderr, "%s", "unable to register (STORE_SERVICE, STORE_VERSION, udp)."); + exit(1); + } + + transp = svctcp_create(RPC_ANYSOCK, 0, 0); + if (transp == NULL) { + fprintf (stderr, "%s", "cannot create tcp service."); + exit(1); + } + if (!svc_register(transp, STORE_SERVICE, STORE_VERSION, store_service_1, IPPROTO_TCP)) { + fprintf (stderr, "%s", "unable to register (STORE_SERVICE, STORE_VERSION, tcp)."); + exit(1); + } + /* Get the machine's IP address */ + get_myaddress(&service_addr); + char * ip = inet_ntoa(service_addr.sin_addr); + /* If the address could not be obtained (no network connection), then print error and exit */ + if(strlen(ip) == 0){ + fprintf (stderr, "%s", "cannot get the IP address of the service."); + exit(1); + } + printf("Store service running at: %s\n", ip); + /* Self-invoke the init process when starting the server */ + init_1_svc(NULL, NULL); + svc_run (); + fprintf (stderr, "%s", "svc_run returned"); + exit (1); + /* NOTREACHED */ +} diff --git a/ssdd_p2_100291121_100292107/rpc_store_service/store_service_xdr.c b/ssdd_p2_100291121_100292107/rpc_store_service/store_service_xdr.c new file mode 100644 index 0000000..2f68608 --- /dev/null +++ b/ssdd_p2_100291121_100292107/rpc_store_service/store_service_xdr.c @@ -0,0 +1,44 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "store_service.h" + +bool_t +xdr_response (XDR *xdrs, response *objp) +{ + //register int32_t *buf; + + if (!xdr_string (xdrs, &objp->msg, MAX_SIZE)) + return FALSE; + if (!xdr_string (xdrs, &objp->md5, MAX_MD5)) + return FALSE; + return TRUE; +} + +bool_t +xdr_store_1_argument (XDR *xdrs, store_1_argument *objp) +{ + if (!xdr_string (xdrs, &objp->sender, MAX_SIZE)) + return FALSE; + if (!xdr_string (xdrs, &objp->receiver, MAX_SIZE)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->msg_id)) + return FALSE; + if (!xdr_string (xdrs, &objp->msg, MAX_SIZE)) + return FALSE; + if (!xdr_string (xdrs, &objp->md5, MAX_MD5)) + return FALSE; + return TRUE; +} + +bool_t +xdr_getmessage_1_argument (XDR *xdrs, getmessage_1_argument *objp) +{ + if (!xdr_string (xdrs, &objp->user, MAX_SIZE)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->msg_id)) + return FALSE; + return TRUE; +} diff --git a/ssdd_p2_100291121_100292107/server.c b/ssdd_p2_100291121_100292107/server.c new file mode 100644 index 0000000..1d5f86b --- /dev/null +++ b/ssdd_p2_100291121_100292107/server.c @@ -0,0 +1,683 @@ +#include /* For addresses in PF_INET */ +#include /* Address-->Network and Network-->Address library; gethostbyname; gethostbyaddr */ +#include +#include /* To use ifreq */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lists/read_line.h" +#include "lists/user_list.h" +#include "lists/msg_list.h" +#include "server.h" +#include "rpc_store_service/store_service.h" + +/* Handler for interrupts */ +void interruptHandler(int sig){ + printf("[SERVER]: Handling interrupt. Closing server socket...\n"); + /* Close the server socket and exit with the resulting return value. 0 if OK, -1 if error */ + exit(close(s_server)); +} + +int main(int argc, char * argv[]){ + struct sockaddr_in server_addr, client_addr; + int sc; + int val; + int server_port; + + /* Check command */ + if(argc != 5 || strcmp(argv[1],"-p") != 0){ + printf("Usage: ./server -p -s \n"); + exit(-1); + } + + /* Check if the port number passed as parameter is valid */ + server_port = atoi(argv[2]); + if ((server_port < 1024) || (server_port > 65535)) { + printf("Error: Port must be in the range 1024 <= port <= 65535\n"); + exit(-1); + } + + /* Store the IP of the storage service */ + store_service_ip = argv[4]; + + /* Initialize mutexes */ + if(pthread_mutex_init(&socket_mtx, NULL) != 0) { + printf("[SERVER]: Error when initializing the mutex"); + exit(-1); + } + if(pthread_mutex_init(&list_mtx, NULL) != 0) { + printf("[SERVER]: Error when initializing the mutex"); + exit(-1); + } + /* Initialize condition variable for copying the socket descriptor in the thread */ + if(pthread_cond_init(&free_socket, NULL) != 0) { + printf("[SERVER]: Error when initializing the mutex"); + exit(-1); + } + + /* Prepare thread conditions */ + thread = (pthread_t) malloc((sizeof(thread))); + pthread_attr_init(&thread_att); + pthread_attr_setdetachstate(&thread_att, PTHREAD_CREATE_DETACHED); + + s_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* This socket has no address assigned */ + if(s_server == -1){ + printf("Error when creating the socket"); + exit(-1); + } + + /* Obtain the IP address attached to interface eth0 */ + struct ifreq ifr; + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1); + ioctl(s_server, SIOCGIFADDR, &ifr); + + val = 1; + setsockopt(s_server, SOL_SOCKET, SO_REUSEADDR, (char*) &val, sizeof(int)); /* Makes the address of the socket reusable */ + + /* Initialize the address that will be attached to the listening socket */ + bzero((char*) &server_addr, sizeof(server_addr)); /* Initialize the socket address of the server to 0 */ + server_addr.sin_family = AF_INET; + server_addr.sin_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr; /* Listens to IP address in eth0 interface*/ + server_addr.sin_port = htons(server_port); /* Port number */ + + /* Bind the address to the listening socket */ + if((bind(s_server, (struct sockaddr*) &server_addr, sizeof(server_addr))) == -1){ + printf("Error when binding the address to the socket"); + exit(-1); + } + + /* Set the socket to listen incoming requests */ + if(listen(s_server, 5) == -1){ + printf("Error when listening to the socket"); + exit(-1); + } /* Backlog is 5, maximum number of queued requests is 5 */ + + /* Once the server is listening, print inicial prompt */ + printf("s> init server %s:%d\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), + ntohs(server_addr.sin_port)); + + /* Define the variable for the client address size. It should be declared + as variable because the size depends on the incoming request and is an + output parameter of the 'accept' function */ + socklen_t cl_addr_size = sizeof(client_addr); + + /* Set the control variable to TRUE so that the listening thread waits + until the thread stores a local copy of the socket descriptor */ + busy_socket = TRUE; + + /**********************************/ + /* Initialize the storage service */ + CLIENT *clnt; + /* Create connection with the storage service */ + clnt = clnt_create (store_service_ip, STORE_SERVICE, STORE_VERSION, "tcp"); + /* If error, the service is unavailable. Show error and exit */ + if (clnt == NULL) { + fprintf(stderr, "s> ERROR, STORAGE SERVICE UNAVAILABLE\n"); + } + else{ + init_1(NULL, clnt); + clnt_destroy (clnt); + } + /**********************************/ + signal(SIGINT, interruptHandler); /* Handles the ctrl+c signal to interrupt the server */ + fprintf(stderr, "%s", "s> "); /* Prompt */ + + + /* Loop for accepting and creating threads for each incoming request */ + while(1){ + /* Accept client connections. If error, shut down the server */ + sc = accept(s_server, (struct sockaddr *) &client_addr, &cl_addr_size); + if(sc == -1){ + printf("Error when accepting the connection"); + /* Close listening server socket */ + close(s_server); + exit(-1); + } + /* Once accepted, create a thread to handle the request. If error, shut down the server */ + if(pthread_create(&thread, &thread_att, (void *) manageRequest, &sc) != 0) { + printf("[SERVER]: Error when creating the thread"); + /* Close both listening socket and the one resulting from the accept operation */ + close(s_server); + close(sc); + exit(-1); + } + + /* Wait for the thread to copy the socket descriptor locally */ + pthread_mutex_lock(&socket_mtx); + while(busy_socket == TRUE) + pthread_cond_wait(&free_socket, &socket_mtx); + busy_socket = TRUE; + pthread_mutex_unlock(&socket_mtx); + + } + + exit(0); +} + +void * manageRequest(int *sd){ + int s_local; + char operation_buff[MAX_COMMAND]; + char user_buff[MAX_USERNAME]; + char msg_buff[MAX_MSG]; + char md5_buff[MAX_MD5]; + int n; + int m; + char out; + + /* Copy locally the socket descriptor */ + pthread_mutex_lock(&socket_mtx); + s_local = *sd; + busy_socket = FALSE; + pthread_cond_signal(&free_socket); + pthread_mutex_unlock(&socket_mtx); + + /* Read the operation. If error, close the socket and terminate the thread */ + n = readLine(s_local, operation_buff, MAX_COMMAND); + if(n == -1){ + printf("[SERVER_THREAD]: Error when reading from the socket"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Read the username and convert to uppercase. If error, close the socket + and terminate the thread */ + m = readLine(s_local, user_buff, MAX_USERNAME); + if(m == -1){ + printf("[SERVER_THREAD]: Error when reading from the socket\n"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* For convention of the server, convert every username to uppercase */ + toUpperCase(user_buff); + + /* Check the operation */ + if (strcmp(operation_buff, "REGISTER") == 0){ + /* Register the user */ + pthread_mutex_lock(&list_mtx); + out = registerUser(user_buff); + pthread_mutex_unlock(&list_mtx); + + } + else if (strcmp(operation_buff, "UNREGISTER") == 0){ + /* Unregister the user */ + pthread_mutex_lock(&list_mtx); + out = unregisterUser(user_buff); + pthread_mutex_unlock(&list_mtx); + + } + else if(strcmp(operation_buff, "CONNECT") == 0){ + + struct sockaddr_in client_addr_local; + socklen_t addr_len = sizeof(client_addr_local); + uint16_t client_port; + + n = readLine(s_local, msg_buff, MAX_MSG); + if(n == -1){ + printf("[SERVER_THREAD]: Error when reading from the socket"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Get the port number from the socket */ + client_port = (uint16_t) atoi(msg_buff); + /* Get the client IP address attached to the socket */ + int err = getpeername(s_local, (struct sockaddr *) &client_addr_local, &addr_len); + if (err == -1){ + printf("[SERVER_THREAD]: Error when getting client address"); + /* Send error 3 to client and close socket */ + out = 3; + } + /* Connect the user to the server if no error */ + if(out != 3){ + pthread_mutex_lock(&list_mtx); + out = connectUser(user_buff, inet_ntoa(client_addr_local.sin_addr), client_port); + pthread_mutex_unlock(&list_mtx); + } + + /* If result is 0, then check for the pending messages and send them */ + if(out == 0){ + /* Send code 0 for the client to open the listening thread */ + if((send_msg(s_local, &out, sizeof(out))) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + fprintf(stderr, "%s %s %s", operation_buff, user_buff, "OK"); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + + /* Send Pending Messages */ + pthread_mutex_lock(&list_mtx); + struct msg **pend_msg = getPendMsgHead(user_buff); + while(*pend_msg != NULL){ + pthread_mutex_unlock(&list_mtx); + char sender[MAX_USERNAME]; + char msg_body[MAX_MSG]; + char msg_md5[MAX_MD5]; + + /* Get the name of the sender, the id and the body associated to the message to be sent */ + pthread_mutex_lock(&list_mtx); + strcpy(sender, (*pend_msg)->sender); + int msg_id = (*pend_msg)->id; + strcpy(msg_body, (*pend_msg)->body); + strcpy(msg_md5, (*pend_msg)->md5); + pthread_mutex_unlock(&list_mtx); + + /* Try to send the message. The 'stored' flag is set to 1 because the message + is already stored in the server */ + int err = sendMessage(sender, user_buff, msg_body, msg_md5, msg_id, 1); + + /* If the message could not be delivered/stored, then exit the loop */ + if(err != 0) goto destroy_thread; + + /* Send acknowledge to the sender. No return value is checked */ + sendAck(sender, msg_id); + + /* Remove the message from the pending message queue and iterate with the next message */ + pthread_mutex_lock(&list_mtx); + *pend_msg = dequeueMsg(&(*pend_msg)); + } + pthread_mutex_unlock(&list_mtx); + goto destroy_thread; + } + } + else if(strcmp(operation_buff, "DISCONNECT") == 0){ + /* Get the IP from which the command is being executed */ + struct sockaddr_in client_addr_local; + socklen_t addr_len = sizeof(client_addr_local); + + int err = getpeername(s_local, (struct sockaddr *) &client_addr_local, &addr_len); + if (err == -1){ + printf("Error when getting client address"); + /* Send error 3 to client and close socket */ + out = 3; + goto respond_to_client; + } + /* Try to disconnect the user passing the IP from which the request is being made + as parameter to the function */ + pthread_mutex_lock(&list_mtx); + out = disconnectUser(user_buff, inet_ntoa(client_addr_local.sin_addr)); + pthread_mutex_unlock(&list_mtx); + + } + else if(strcmp(operation_buff, "SEND") == 0){ + /* Reserve a buffer for the username of the receiver */ + char dest_user_buff[MAX_USERNAME]; + + /* Read the destination user from the socket */ + m = readLine(s_local, dest_user_buff, MAX_USERNAME); + if(m == -1){ + printf("[SERVER_THREAD]: Error when reading from the socket\n"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Convert username to uppercase by convention */ + toUpperCase(dest_user_buff); + + /* Read the message from the socket */ + n = readLine(s_local, msg_buff, MAX_MSG); + if(n == -1){ + printf("[SERVER_THREAD]: Error when reading from the socket\n"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + /* Read the MD5 hash from the socket */ + m = readLine(s_local, md5_buff, MAX_MD5); + if(m == -1){ + printf("[SERVER_THREAD]: Error when reading from the socket\n"); + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + /* Check if one of the two users is not registered */ + pthread_mutex_lock(&list_mtx); + if(!isRegistered(user_buff) || !isRegistered(dest_user_buff)){ + pthread_mutex_unlock(&list_mtx); + /* Send code 1 to the client and close the socket */ + out = 1; + goto respond_to_client; + } + pthread_mutex_unlock(&list_mtx); + + /* Check the status of the destination user */ + pthread_mutex_lock(&list_mtx); + char status = isConnected(dest_user_buff); + unsigned int last_id = updateLastID(user_buff); //Update the last id of the sender message + pthread_mutex_unlock(&list_mtx); + + if(status == 0){ //Not connected + /* Store the message */ + if (storeMessage(user_buff, dest_user_buff, msg_buff, md5_buff, last_id) != 0){ + /* Message could not be stored so send code 2 to the client and close the socket */ + out = 2; + goto respond_to_client; + } + /* Message was stored successfully, send code 0 and message ID to the client */ + out = 0; + ///////////////////////////////////////////// + /* Store the message in the storage server */ + storeMessage_svc(user_buff, dest_user_buff, last_id, msg_buff, md5_buff); + + if((send_msg(s_local, &out, sizeof(out))) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Send string with the message ID back to the sender */ + char id_string[11]; + sprintf(id_string, "%d", last_id); + if((send_msg(s_local, id_string, strlen(id_string)+1)) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + }else if(status == 1){ //Connected + /* Try to send the message to the receiver. We set the 'stored' flag to 0 because the message + is being sent for the first time and was not previously stored int he server */ + int err = sendMessage(user_buff, dest_user_buff, msg_buff, md5_buff, last_id, 0); + /* If while trying to store the message, the user unregisters, value 1 will be returned */ + if(err == 1){ + out = 1; + goto respond_to_client; + }else if(err == -1){ + /* If any server error occurred and the message was not stored or sent, then send code 2 + back to the client */ + out = 2; + goto respond_to_client; + } + + /* If no server error occured, then the message was either sent or stored, so we send back + the code 0 (OK) to the client */ + out = 0; + ///////////////////////////////////////////// + /* Store the message in the storage server */ + storeMessage_svc(user_buff, dest_user_buff, last_id, msg_buff, md5_buff); + + if ((send_msg(s_local, &out, sizeof(out))) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + /* Send string with the message ID back to the sender */ + char id_string[11]; + sprintf(id_string, "%d", last_id); + if((send_msg(s_local, id_string, strlen(id_string)+1)) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + /* At this point, the message is assumed to */ + sendAck(user_buff, last_id); + } + /* The response to the client is handled within this else-if statement, so the + 'respond_to_client' label is skipped and proceed to close the socket */ + goto destroy_thread; + } + + /* Default print template */ + switch(out){ + case 0: + fprintf(stderr, "%s %s %s", operation_buff, user_buff, "OK"); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + break; + default: + fprintf(stderr, "%s %s %s", operation_buff, user_buff, "FAIL"); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + } + + /* Label to jump previous code to respond the client and skip the default print right above, + in case other commands (as SEND) do not use a template print */ + respond_to_client: + if((send_msg(s_local, &out, sizeof(out))) == -1){ + /* If error when sending the message, close the socket and exit */ + if(close(s_local) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + pthread_exit((void *)-1); //Terminate thread with -1 return value + } + + destroy_thread: + if(close(s_local) == -1){ + printf("[SERVER_THREAD]: Error when closing the socket in the thread"); + exit(-1); + } + pthread_exit(NULL); +} + +/* Capitalizes the input string. String is both an input and output parameter */ +void toUpperCase(char * string){ + /* Convert to uppercase */ + int i; + for(i = 0; string[i]; i++){ + string[i] = toupper(string[i]); + } +} + +/* Return 0: Message is stored OK + Return -1: Server error (Memory space error) */ +int storeMessage(char * sender, char * receiver, char * msg, char * md5, unsigned int msg_id){ + /* Store the message to the receiver pending list */ + pthread_mutex_lock(&list_mtx); + int err = storeMsg(receiver, msg, msg_id, md5, sender); + pthread_mutex_unlock(&list_mtx); + + /* Error when trying to store the message */ + if(err == -1) return -1; + + fprintf(stderr, "MESSAGE %d FROM %s TO %s STORED", msg_id, + sender, receiver); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + + /* Return store OK */ + return 0; +} + +/* Return 0: Message is sent OK + Return 1: User did not exist when trying to store/send the message. Message not stored + Return 2: Message is stored, or not stored if was already stored + Return -1: Server error */ +int sendMessage(char * sender, char * receiver, char * msg, char * md5, unsigned int msg_id, char stored){ + int s_receiver; //Socket for the receiver of the message + struct sockaddr_in recv_addr; //Receiver address + struct hostent *recv_hp; //Host entity structure for the receiver + + s_receiver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(s_receiver == -1){ + return -1; //Send error message. -1 is internally encoded as server error + } + + bzero((char *) &recv_addr, sizeof(recv_addr)); //Reserve space for the address of the receiver + + pthread_mutex_lock(&list_mtx); + recv_hp = gethostbyname(getUserIP(receiver)); //Get the IP of the receiver + pthread_mutex_unlock(&list_mtx); + /* If error when getting the host, return -1 */ + if(recv_hp == NULL) return -1; + + memcpy(&(recv_addr.sin_addr), recv_hp->h_addr, recv_hp->h_length); //Get the IP addres in network format + recv_addr.sin_family = AF_INET; + pthread_mutex_lock(&list_mtx); + recv_addr.sin_port = htons(getUserPort(receiver)); //Get the port number of the receiver listening thread + pthread_mutex_unlock(&list_mtx); + + /* Try to connect to the listening thread of the receiver to send the message */ + if (connect(s_receiver, (struct sockaddr *) &recv_addr, sizeof(recv_addr)) == -1){ + /* If the connection with the receiver fails, assume the client + to be disconnected, disconnect it and store the message */ + pthread_mutex_lock(&list_mtx); + /* As we are internally disconnecting the user from the server, we need to bypass the + IP check, so we pass the IP of the receiver as parameter to always fulfill the condition */ + char reg = disconnectUser(receiver, getUserIP(receiver)); // No need to check for output + pthread_mutex_unlock(&list_mtx); + /* If the disconnect method returns 1, it means that the user was not found so is not + registered (it unregister while trying to store the message, so we return 1 */ + if(reg == 1){ + return 1; + } + /* If the stored parameter is set to 0, it means that the message was not prevoiusly stored by the + server so we need to push it to the end of the queue. If it was stored, then nothing is done */ + if(!stored){ + if(storeMessage(sender, receiver, msg, md5, msg_id) == -1) return -1; //Return -1 if store error + } + + if(close(s_receiver) == -1){ //Close the socket + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + /* Return 2 to indicate the message is stored but not sent */ + return 2; + } + /* Send the SEND_MESSAGE string to the receiver to detect an incoming message */ + char op[13]; + strcpy(op, "SEND_MESSAGE"); + send_msg(s_receiver, op, strlen(op)+1); + /* Send the sender name */ + send_msg(s_receiver, sender, strlen(sender)+1); + /* Send the identifier of the message */ + char id_string[11]; + sprintf(id_string, "%d", msg_id); + send_msg(s_receiver, id_string, strlen(id_string)+1); + /* Send the MD5 of the message */ + send_msg(s_receiver, md5, strlen(md5)+1); + /* Send the message */ + send_msg(s_receiver, msg, strlen(msg)+1); + + if(close(s_receiver) == -1){ //Close the socket + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + + fprintf(stderr, "SEND MESSAGE %d FROM %s TO %s", msg_id, + sender, receiver); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + + return 0; +} + +/* Tries to send acknowledge to the sender. No return value */ +void sendAck(char * sender, unsigned int msg_id){ + int s_sender; //Socket for the receiver of the message + struct sockaddr_in sender_addr; //Sender address + struct hostent *sender_hp; //Host entity structure for the sender + + s_sender = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(s_sender == -1){ + /* If error when allocating resources for the socket, then exit */ + return; + } + + char ack_op[14]; + strcpy(ack_op, "SEND_MESS_ACK"); + + bzero((char *) &sender_addr, sizeof(sender_addr)); + + pthread_mutex_lock(&list_mtx); + sender_hp = gethostbyname(getUserIP(sender)); + pthread_mutex_unlock(&list_mtx); + /* If any error when getting the hoset, exit the function */ + if(sender_hp == NULL) return; + + memcpy(&(sender_addr.sin_addr), sender_hp->h_addr, sender_hp->h_length); + sender_addr.sin_family = AF_INET; + + pthread_mutex_lock(&list_mtx); + sender_addr.sin_port = htons(getUserPort(sender)); + pthread_mutex_unlock(&list_mtx); + + if((connect(s_sender, (struct sockaddr *) &sender_addr, sizeof(sender_addr))) == -1){ + /* If error when connecting, exit the function */ + return; + } + + + char id_string[11]; + sprintf(id_string, "%d", msg_id); + if((send_msg(s_sender, ack_op, strlen(ack_op)+1)) == -1){ + /* If error when sending the ACK, close the socket and exit the function */ + if(close(s_sender) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + return; + } + if((send_msg(s_sender, id_string, strlen(id_string)+1)) == -1){ + /* If error when sending the ACK, close the socket and exit the function */ + if(close(s_sender) == -1){ + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + return; + } + + if(close(s_sender) == -1){ //Close the socket + /* If there is an error when closing the socket, shut down the server */ + interruptHandler(SIGINT); + } + return; +} +/* Connects to the storage service (if available) and stores the message with the corresponding information +passed as parameters */ +void storeMessage_svc(char * sender, char * receiver, unsigned int id, char * msg, char * md5){ + CLIENT *clnt; + /* Create connection with the storage service */ + clnt = clnt_create (store_service_ip, STORE_SERVICE, STORE_VERSION, "tcp"); + /* If error, the service is unavailable. Show error and exit */ + if (clnt == NULL) { + fprintf(stderr, "ERROR, STORAGE SERVICE UNAVAILABLE"); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + return; + } + int result; + /* Call the storage service */ + store_1(sender, receiver, id, msg, md5, &result, clnt); + /* Check for internal server error in the process */ + if(result == -1) fprintf(stderr, "ERROR IN THE STORAGE SERVICE"); + /* If everything went OK, prompt a message in the console */ + else fprintf(stderr, "MESSAGE %d STORED OK IN STORAGE SERVICE", id); + fprintf(stderr, "\n%s", "s> "); /* Prompt */ + /* Destroy the client and return */ + clnt_destroy (clnt); + return; +} \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107/server.h b/ssdd_p2_100291121_100292107/server.h new file mode 100644 index 0000000..4fa1935 --- /dev/null +++ b/ssdd_p2_100291121_100292107/server.h @@ -0,0 +1,30 @@ +#define MAX_COMMAND 11 + +/* Mutex & Threads */ +pthread_mutex_t socket_mtx; +pthread_mutex_t list_mtx; +pthread_t thread; +pthread_attr_t thread_att; +/* Controls the access to the socket generated by the connection 'accept' */ +pthread_cond_t free_socket; +pthread_cond_t free_list; + +/* Variable that controls the state of the socket created by the connection 'accept' */ +int busy_socket; + +/* Declare the server socket as global variable */ +int s_server; + +/* Declare the list of users */ +struct user *users; + +char * store_service_ip; /* Variable for the IP of the message storage service server */ + +/* ================FUNCTION HEADERS================ */ +void interruptHandler(int sig); +void * manageRequest(int *sd); +void toUpperCase(char * string); +int sendMessage(char * sender, char * receiver, char * msg, char * md5, unsigned int msg_id, char stored); +void sendAck(char * sender, unsigned int msg_id); +int storeMessage(char * sender, char * receiver, char * msg, char * md5, unsigned int mgs_id); +void storeMessage_svc(char * sender, char * receiver, unsigned int id, char * msg, char * md5); \ No newline at end of file diff --git a/ssdd_p2_100291121_100292107/storeServer.c b/ssdd_p2_100291121_100292107/storeServer.c new file mode 100644 index 0000000..0ad2058 --- /dev/null +++ b/ssdd_p2_100291121_100292107/storeServer.c @@ -0,0 +1,197 @@ + +#include "rpc_store_service/store_service.h" + +/* Define the structure of the message list nodes */ +struct msg{ + char body[MAX_SIZE]; /* Content of the message */ + char md5[MAX_MD5]; /* MD5 of the message */ + char sender[MAX_SIZE]; /* Sender of the message */ + char receiver[MAX_SIZE]; /* Receiver of the message */ + unsigned int id; /* ID assigned to the message */ + struct msg *next; /* Pointer to the next message in the list */ +}; +/* Define the structure of the user list nodes */ +struct user{ + char name[MAX_SIZE]; /* Name of the user */ + unsigned long num_msgs; /* Number of sent (stored) messages for the user */ + struct user *next; /* Pointer to the next user in the list */ + struct msg *sent_msgs_head; /* Pointer to the head of the messages sent by the user */ +}; + +/* ========================================================== */ +/* ======================== HEADERS ========================= */ +/* ========================================================== */ + +struct user * usr_head; + +int addMsg(struct msg **head,char * message, char * md5, unsigned int id, char * receiver); + +/* Initializes the user list in the server. If there is an existing user list in memory, this is +traversed and all the nodes in the list (including both messages and users) will be freed from +memory. + Returns always TRUE. No internal error can happen */ +bool_t +init_1_svc(void *result, struct svc_req *rqstp) +{ + bool_t retval = TRUE; + /* If the list of users is not empty, traverse the list and free each node */ + if(usr_head != NULL){ + struct user *prev = usr_head; + /* While the list is greater than 1, advance in the list and eliminate the first node of the list */ + while(usr_head->next != NULL){ + /* If the list of messages associated to the user is not empty, traverse it and free the memory */ + if(usr_head->sent_msgs_head != NULL){ + struct msg *prev_msg = usr_head->sent_msgs_head; + /* While the list is greater than 1, advance in the list and eliminate the first node */ + while(usr_head->sent_msgs_head->next != NULL){ + usr_head->sent_msgs_head = usr_head->sent_msgs_head->next; + free(prev_msg); + prev_msg = usr_head->sent_msgs_head; + } + /* Free the resources of the last element in the list */ + free(prev_msg); + } + usr_head = usr_head->next; + free(prev); + prev = usr_head; + } + /* Free the resources of the last element in the list */ + free(prev); + } + /* Initialize the list of users to NULL */ + usr_head = NULL; + + return retval; +} + +/* Stores the message and the associated information (receiver, ID, MD5) into the list of messages sent by +the input user passed in the 'sender'. + Returns TRUE no errors + Returns FALSE if there is a malloc error (memory full) */ +bool_t +store_1_svc(char *sender, char *receiver, u_int msg_id, char *msg, char *md5, int *result, struct svc_req *rqstp) +{ + bool_t retval = TRUE; + + struct user *temp = usr_head; + /* Iterate through the list of users that sent at least one message */ + while(temp != NULL){ + if(strcmp(temp->name, sender) == 0){ //User found in the list + /* Append the message to the list of sent messages by that user */ + *result = addMsg(&(temp->sent_msgs_head), msg, md5, msg_id, receiver); + /* If -1 is returned, the memory is full and message could not be stored. Return FALSE */ + if(*result == -1) return FALSE; + /* Update the message counter */ + temp->num_msgs = temp->num_msgs + 1; + return retval; + } + temp = temp->next; + } + /* If the code reaches this point, no user was found, so add it to the list and set + the message counter to 1 */ + temp = (struct user *) malloc(sizeof(struct user)); + /* If malloc returns error (full memory or other). Return FALSE */ + if(temp == NULL) return FALSE; + strcpy(temp->name, sender); + temp->next = NULL; + temp->sent_msgs_head = NULL; + /* Add message to the list of messages that the user sent */ + *result = addMsg(&(temp->sent_msgs_head), msg, md5, msg_id, receiver); + /* If -1 is returned, the memory is full and message could not be stored. Return FALSE */ + if(*result == -1) return FALSE; + temp->num_msgs = 1; /* Set the sent-message counter to 1 */ + + temp->next = usr_head; + usr_head = temp; + + return retval; +} + +/* Gets the number of messages sent by the input user. + Returns always TRUE. No internal error can happen */ +bool_t +getnummessages_1_svc(char *user, int *result, struct svc_req *rqstp) +{ + bool_t retval = TRUE; + + struct user *temp = usr_head; + *result = 0; + /* Traverse the list of users until the input username is found */ + while(temp != NULL){ + if(strcmp(temp->name, user) == 0){ //Sender is found in the list + /* Return the number of stored messages for that user */ + *result = temp->num_msgs; + return retval; + } + temp = temp->next; + } + *result = -1; //User was not found + + return retval; +} + +/* Gets the message corresponding to the ID and username of the sender of such message. +If the message or the user is not found, then an empty string will be sent back. + Returns always TRUE. No internal error can happen */ +bool_t +getmessage_1_svc(char *user, u_int msg_id, response *result, struct svc_req *rqstp) +{ + bool_t retval = TRUE; + + /* Initialize to zeroes the message and MD5 strings of the response struct */ + result->msg = calloc(MAX_SIZE, sizeof(char)); + result->md5 = calloc(MAX_MD5, sizeof(char)); + + struct user *temp = usr_head; + struct msg *msg_temp; + + /* Traverse the list of users looking for the input username */ + while(temp != NULL){ + if(strcmp(temp->name, user) == 0){ //Sender is found in the list + /* Search for the message with that ID */ + msg_temp = temp->sent_msgs_head; + /* Iterate through the list of sent messages */ + while(msg_temp != NULL){ + if(msg_temp->id == msg_id){ //Message ID found + strncpy(result->msg, msg_temp->body, strlen(msg_temp->body)+1); + strncpy(result->md5, msg_temp->md5, strlen(msg_temp->md5)+1); + return retval; + } + msg_temp = msg_temp->next; + } + /* At this point, no message with such ID was found for that user. Stop iterating */ + return retval; + } + temp = temp->next; + } + /* User was not found, thus message does not exist */ + + return retval; +} + +int +store_service_1_freeresult (SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result) +{ + xdr_free (xdr_result, result); + + return 1; +} + +/* Creates a new message struct and adds it to the message queue + Returns 0 if the message is stored + -1 if malloc error */ +int addMsg(struct msg **head, char * message, char * md5, unsigned int id, char * receiver){ + struct msg *temp; + /* Allocate the space for the new message */ + temp = (struct msg *) malloc(sizeof(struct msg)); + /* If malloc returns error (full memory or other) */ + if(temp == NULL) return -1; + strcpy(temp->body, message); + strcpy(temp->md5, md5); + strcpy(temp->receiver, receiver); + temp->id = id; + temp->next = *head; //If msg_head is null, then the list is empty + *head = temp; + + return 0; +} diff --git a/ssdd_p2_100291121_100292107/storeServer.x b/ssdd_p2_100291121_100292107/storeServer.x new file mode 100644 index 0000000..e5a8648 --- /dev/null +++ b/ssdd_p2_100291121_100292107/storeServer.x @@ -0,0 +1,17 @@ +const MAX_SIZE = 256; +const MAX_MD5 = 33; + +struct response{ + string msg; + string md5; +}; + +program STORE_SERVICE{ + version STORE_VERSION{ + void init() = 1; + int store(string sender, string receiver, + unsigned int msg_id, string msg, string md5) = 2; + int getNumMessages(string user) = 3; + response getMessage(string user, unsigned int msg_id) = 4; + } = 1; +} = 666; \ No newline at end of file