Hello community, here is the log from the commit of package multimon-ng for openSUSE:Factory checked in at 2018-06-13 15:35:26 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/multimon-ng (Old) and /work/SRC/openSUSE:Factory/.multimon-ng.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "multimon-ng" Wed Jun 13 15:35:26 2018 rev:3 rq:613887 version:1.1.5+git.20180527 Changes: -------- --- /work/SRC/openSUSE:Factory/multimon-ng/multimon-ng.changes 2018-04-16 12:46:57.553542850 +0200 +++ /work/SRC/openSUSE:Factory/.multimon-ng.new/multimon-ng.changes 2018-06-13 15:36:40.598552551 +0200 @@ -1,0 +2,28 @@ +Fri Jun 01 20:00:33 UTC 2018 - [email protected] + +- Update to version 1.1.5+git.20180527: + * Restore FSF copyright notices on win32_getopt.[ch] + * Version 0.8.7v (11 APR 2018) + * Modification (to this file) made by Bruce Quinton and Rob0101 + (as seen on github: https://github.com/rob0101) + * Issue *95 created by rob0101: '-a FLEX dropping first character + of some message on regular basis' + * Implemented Rob0101's suggestion of K, F and C flags to indicate + the message fragmentation: + 'K' message is complete and O'K' to display to the world. + 'F' message is a 'F'ragment and needs a 'C'ontinuation message + to complete it. + Message = Fragment + Continuation * 'C' message is a + 'C'ontinuation of another fragmented message + * I missed a null terminator on the 'Message' array and therefore + was printing garbage to the output. Fixed now! + * Addressed issue #101: group messaging misbehaving when the + message frame is a corrupt packet. + * Version 0.9.0v (22 May 2018) Modification (to this file) made + by Bruce Quinton ([email protected]) - Addded Define at top of + file to modify the way missed group messages are reported in + the debug output (default is 1; report missed capcodes on the + same line) REPORT_GROUP_CODES 1 // Report each cleared faulty + group capcode : 0 = Each on a new line; 1 = All on the same line; + +------------------------------------------------------------------- Old: ---- multimon-ng-1.1.5+git.20180402.tar.xz New: ---- multimon-ng-1.1.5+git.20180527.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ multimon-ng.spec ++++++ --- /var/tmp/diff_new_pack.WB4j1g/_old 2018-06-13 15:36:41.786508830 +0200 +++ /var/tmp/diff_new_pack.WB4j1g/_new 2018-06-13 15:36:41.794508535 +0200 @@ -1,7 +1,7 @@ # # spec file for package multimon-ng # -# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2017, Martin Hauke <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -18,10 +18,10 @@ Name: multimon-ng -Version: 1.1.5+git.20180402 +Version: 1.1.5+git.20180527 Release: 0 Summary: A fork of multimon, decodes multiple digital transmission modes -License: GPL-2.0 +License: GPL-2.0-only Group: Productivity/Hamradio/Other URL: https://github.com/EliasOenal/multimon-ng Source0: %{name}-%{version}.tar.xz @@ -55,7 +55,8 @@ %cmake_install %files -%doc COPYING README.md +%license COPYING +%doc README.md %{_bindir}/%{name} %changelog ++++++ _service ++++++ --- /var/tmp/diff_new_pack.WB4j1g/_old 2018-06-13 15:36:41.894504855 +0200 +++ /var/tmp/diff_new_pack.WB4j1g/_new 2018-06-13 15:36:41.898504707 +0200 @@ -5,7 +5,8 @@ <param name="scm">git</param> <param name="changesgenerate">enable</param> <param name="filename">multimon-ng</param> - <param name="versionformat">1.1.5+git.%cd</param> + <param name="versionrewrite-pattern">v(.*)</param> + <param name="versionformat">@PARENT_TAG@+git.%cd</param> </service> <service mode="disabled" name="recompress"> <param name="file">*.tar</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.WB4j1g/_old 2018-06-13 15:36:41.926503677 +0200 +++ /var/tmp/diff_new_pack.WB4j1g/_new 2018-06-13 15:36:41.930503529 +0200 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/EliasOenal/multimon-ng.git</param> - <param name="changesrevision">53de9fb479d643dfb83de4d3c800cc79b1ccc128</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">9b4936ccc688018ffc1040429f3e1cc4d9b4ec07</param></service></servicedata> \ No newline at end of file ++++++ multimon-ng-1.1.5+git.20180402.tar.xz -> multimon-ng-1.1.5+git.20180527.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/multimon-ng-1.1.5+git.20180402/demod_flex.c new/multimon-ng-1.1.5+git.20180527/demod_flex.c --- old/multimon-ng-1.1.5+git.20180402/demod_flex.c 2018-04-02 20:47:26.000000000 +0200 +++ new/multimon-ng-1.1.5+git.20180527/demod_flex.c 2018-05-27 20:10:42.000000000 +0200 @@ -20,6 +20,28 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* + * Version 0.9.0v (22 May 2018) + * Modification (to this file) made by Bruce Quinton ([email protected]) + * - Addded Define at top of file to modify the way missed group messages are reported in the debug output (default is 1; report missed capcodes on the same line) + * REPORT_GROUP_CODES 1 // Report each cleared faulty group capcode : 0 = Each on a new line; 1 = All on the same line; + * Version 0.8.9 (20 Mar 2018) + * Modification (to this file) made by Bruce Quinton ([email protected]) + * - Issue #101 created by bertinhollan (https://github.com/bertinholland): Bug flex: Wrong split up group message after a data corruption frame. + * - Added logic to the FIW decoding that checks for any 'Group Messages' and if the frame has past them remove the group message and log output + * - The following settings (at the top of this file, just under these comments) have changed from: + * PHASE_LOCKED_RATE 0.150 + * PHASE_UNLOCKED_RATE 0.150 + * these new settings appear to work better when attempting to locate the Sync lock in the message preamble. + * Version 0.8.8v (20 APR 2018) + * Modification (to this file) made by Bruce Quinton ([email protected]) + * - Issue #101 created by bertinhollan (https://github.com/bertinholland): Bug flex: Wrong split up group message after a data corruption frame. + * Version 0.8.7v (11 APR 2018) + * Modification (to this file) made by Bruce Quinton ([email protected]) and Rob0101 (as seen on github: https://github.com/rob0101) + * - Issue *#95 created by rob0101: '-a FLEX dropping first character of some message on regular basis' + * - Implemented Rob0101's suggestion of K, F and C flags to indicate the message fragmentation: + * 'K' message is complete and O'K' to display to the world. + * 'F' message is a 'F'ragment and needs a 'C'ontinuation message to complete it. Message = Fragment + Continuation + * 'C' message is a 'C'ontinuation of another fragmented message * Version 0.8.6v (18 Dec 2017) * Modification (to this file) made by Bruce Quinton ([email protected]) on behalf of bertinhollan (https://github.com/bertinholland) * - Issue #87 created by bertinhollan: Reported issue is that the flex period timeout was too short and therefore some group messages were not being processed correctly @@ -67,23 +89,25 @@ #include <string.h> #include <time.h> #include <stdlib.h> +#include <stdio.h> /* ---------------------------------------------------------------------- */ #define FREQ_SAMP 22050 #define FILTLEN 1 - +#define REPORT_GROUP_CODES 1 // Report each cleared faulty group capcode : 0 = Each on a new line; 1 = All on the same line; #define FLEX_SYNC_MARKER 0xA6C6AAAAul // Synchronisation code marker for FLEX #define SLICE_THRESHOLD 0.667 // For 4 level code, levels 0 and 3 have 3 times the amplitude of levels 1 and 2, so quantise at 2/3 #define DC_OFFSET_FILTER 0.010 // DC Offset removal IIR filter response (seconds) -#define PHASE_LOCKED_RATE 0.150 // Correction factor for locked state -#define PHASE_UNLOCKED_RATE 0.150 // Correction factor for unlocked state +#define PHASE_LOCKED_RATE 0.045 // Correction factor for locked state +#define PHASE_UNLOCKED_RATE 0.050 // Correction factor for unlocked state #define LOCK_LEN 24 // Number of symbols to check for phase locking (max 32) #define IDLE_THRESHOLD 0 // Number of idle codewords allowed in data section #define CAPCODES_INDEX 0 #define DEMOD_TIMEOUT 100 // Maximum number of periods with no zero crossings before we decide that the system is not longer within a Timing lock. + enum Flex_PageTypeEnum { FLEX_PAGETYPE_SECURE, FLEX_PAGETYPE_SHORT_INSTRUCTION, @@ -120,8 +144,9 @@ }; struct Flex_GroupHandler { - int64_t aGroupCodes[17][1000]; - int GroupFrame[17]; + int64_t GroupCodes[17][1000]; + int GroupCycle[17]; + int GroupFrame[17]; }; struct Flex_Modulation { @@ -394,7 +419,79 @@ flex->FIW.fix3, timeseconds/60, timeseconds%60); + // Lets check the FrameNo against the expected group message frames, if we have 'Missed a group message' tell the user and clear the Cap Codes + for(int g = 0; g < 17 ;g++) + { + // Do we have a group message pending for this groupbit? + if(flex->GroupHandler.GroupFrame[g] >= 0) + { + int Reset = 0; + verbprintf(4, "Flex: GroupBit %i, FrameNo: %i, Cycle No: %i target Cycle No: %i\n", g, flex->GroupHandler.GroupFrame[g], flex->GroupHandler.GroupCycle[g], (int)flex->FIW.cycleno); + // Now lets check if its expected in this frame.. + if((int)flex->FIW.cycleno == flex->GroupHandler.GroupCycle[g]) + { + if(flex->GroupHandler.GroupFrame[g] < (int)flex->FIW.frameno) + { + Reset = 1; + } + } + // Check if we should have sent a group message in the previous cycle + else if(flex->FIW.cycleno == 0) + { + if(flex->GroupHandler.GroupCycle[g] == 15) + { + Reset = 1; + } + } + // If we are waiting for the cycle to roll over then move onto the next for loop item + else if(flex->FIW.cycleno == 15 && flex->GroupHandler.GroupCycle[g] == 0) + { + continue; + } + // Otherwise if the target cycle is less than the current cycle, reset the data + else if(flex->GroupHandler.GroupCycle[g] < (int)flex->FIW.cycleno) + { + Reset = 1; + } + + + if(Reset == 1) + { + + int endpoint = flex->GroupHandler.GroupCodes[g][CAPCODES_INDEX]; + if(REPORT_GROUP_CODES > 0) + { + verbprintf(3,"FLEX: Group messages seem to have been missed; Groupbit: %i; Total Capcodes: %i; Clearing Data; Capcodes: ", g, endpoint); + } + + for(int capIndex = 1; capIndex <= endpoint; capIndex++) + { + if(REPORT_GROUP_CODES == 0) + { + verbprintf(3,"FLEX: Group messages seem to have been missed; Groupbit: %i; Clearing data; Capcode: [%09lld]\n", g, flex->GroupHandler.GroupCodes[g][capIndex]); + } + else + { + if(capIndex > 1) + { + verbprintf(3,","); + } + verbprintf(3,"[%09lld]", flex->GroupHandler.GroupCodes[g][capIndex]); + } + } + if(REPORT_GROUP_CODES > 0) + { + verbprintf(3,"\n"); + } + + // reset the value + flex->GroupHandler.GroupCodes[g][CAPCODES_INDEX] = 0; + flex->GroupHandler.GroupFrame[g] = -1; + flex->GroupHandler.GroupCycle[g] = -1; + } + } + } return 0; } else { verbprintf(3, "FLEX: Bad Checksum 0x%x\n", checksum); @@ -403,73 +500,81 @@ } } -static char* append_alphanumeric(char* buf, unsigned int dw) { - int i; - for (i = 0; i < 3; i++) { - unsigned char ch = (dw >> (i * 7)) & 0x7F; - if (ch && ch != 0x03) { - *buf = ch; - buf++; - } - } - return buf; -} - -// static void parse_alphanumeric(struct Flex * flex, unsigned int * phaseptr, char PhaseNo, int mw1, int mw2, int j, int flex_groupmessage) { static void parse_alphanumeric(struct Flex * flex, unsigned int * phaseptr, char PhaseNo, int mw1, int mw2, int flex_groupmessage) { - if (flex==NULL) return; - verbprintf(3, "FLEX: Parse Alpha Numeric\n"); + if (flex==NULL) return; + verbprintf(3, "FLEX: Parse Alpha Numeric\n"); - int i; - time_t now=time(NULL); - struct tm * gmt=gmtime(&now); - char buf[1024], *message; - - int frag = (phaseptr[mw1] >> 11) & 0x03; - - if (frag == 0x3) { - // fragment shifts the message data up by one word - message = buf; - mw2++; - } else { - // ignore control data in first byte - message = append_alphanumeric(buf, phaseptr[mw1] & ~0x7F); + int i; + time_t now=time(NULL); + struct tm * gmt=gmtime(&now); + // char buf[1024], *message; + char message[1024]; + int currentChar = 0; + char frag_flag = 'K'; + + int frag = (phaseptr[mw1] >> 11) & 0x03; + int cont = ( phaseptr[mw1] >> 0x0A ) & 0x01; + + if (cont == 1) frag_flag = 'F'; + if (cont == 0 && frag == 0) frag_flag = 'C'; + + mw1++; + + for (i = mw1; i <= mw2; i++) { + unsigned int dw = phaseptr[i]; + unsigned char ch; + + if (i > mw1 || frag != 0x03) { + ch = dw & 0x7F; + if (ch != 0x03) { + message[currentChar] = ch; + currentChar++; + } + } + + ch = (dw >> 7) & 0x7F; + if (ch != 0x03) { + message[currentChar] = ch; + currentChar++; + } + + ch = (dw >> 14) & 0x7F; + if (ch != 0x03) { + message[currentChar] = ch; + currentChar++; + } + } - } - for (i = mw1+1; i < mw2; i++) { - message = append_alphanumeric(message, phaseptr[i]); - } - *message = '\0'; - message = buf; - if (frag == 0x3) { - message++; - } + message[currentChar] = '\0'; - verbprintf(0, "FLEX: %04i-%02i-%02i %02i:%02i:%02i %i/%i/%c %02i.%03i [%09lld] ALN ", gmt->tm_year+1900, gmt->tm_mon+1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec, - flex->Sync.baud, flex->Sync.levels, PhaseNo, flex->FIW.cycleno, flex->FIW.frameno, flex->Decode.capcode); +// message = '\0'; + verbprintf(0, "FLEX: %04i-%02i-%02i %02i:%02i:%02i %i/%i/%c/%c %02i.%03i [%09lld] ALN ", + gmt->tm_year+1900, gmt->tm_mon+1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec, + flex->Sync.baud, flex->Sync.levels, frag_flag, PhaseNo, flex->FIW.cycleno, flex->FIW.frameno, flex->Decode.capcode); - verbprintf(0, "%s\n", message); + verbprintf(0, "%s\n", message); - if(flex_groupmessage == 1) { - int groupbit = flex->Decode.capcode-2029568; - if(groupbit < 0) return; - - int endpoint = flex->GroupHandler.aGroupCodes[groupbit][CAPCODES_INDEX]; - for(int g = 1; g <= endpoint;g++) - { - verbprintf(1, "FLEX Group message output: Groupbit: %i Total Capcodes; %i; index %i; Capcode: [%09lld]\n", groupbit, endpoint, g, flex->GroupHandler.aGroupCodes[groupbit][g]); + if(flex_groupmessage == 1) { + int groupbit = flex->Decode.capcode-2029568; + if(groupbit < 0) return; - verbprintf(0, "FLEX: %04i-%02i-%02i %02i:%02i:%02i %i/%i/%c %02i.%03i [%09lld] ALN ", gmt->tm_year+1900, gmt->tm_mon+1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec, - flex->Sync.baud, flex->Sync.levels, PhaseNo, flex->FIW.cycleno, flex->FIW.frameno, flex->GroupHandler.aGroupCodes[groupbit][g]); + int endpoint = flex->GroupHandler.GroupCodes[groupbit][CAPCODES_INDEX]; + for(int g = 1; g <= endpoint;g++) + { + verbprintf(1, "FLEX Group message output: Groupbit: %i Total Capcodes; %i; index %i; Capcode: [%09lld]\n", groupbit, endpoint, g, flex->GroupHandler.GroupCodes[groupbit][g]); - verbprintf(0, "%s\n", message); - } - // reset the value - flex->GroupHandler.aGroupCodes[groupbit][CAPCODES_INDEX] = 0; - } + verbprintf(0, "FLEX: %04i-%02i-%02i %02i:%02i:%02i %i/%i/%c/%c %02i.%03i [%09lld] ALN ", gmt->tm_year+1900, gmt->tm_mon+1, gmt->tm_mday, gmt->tm_hour, gmt->tm_min, gmt->tm_sec, + flex->Sync.baud, flex->Sync.levels, frag_flag, PhaseNo, flex->FIW.cycleno, flex->FIW.frameno, flex->GroupHandler.GroupCodes[groupbit][g]); -} + verbprintf(0, "%s\n", message); + } + // reset the value + flex->GroupHandler.GroupCodes[groupbit][CAPCODES_INDEX] = 0; + flex->GroupHandler.GroupFrame[groupbit] = -1; + flex->GroupHandler.GroupCycle[groupbit] = -1; + } +} static void parse_numeric(struct Flex * flex, unsigned int * phaseptr, char PhaseNo, int j) { if (flex==NULL) return; @@ -583,6 +688,11 @@ if (decode_error) { verbprintf(3, "FLEX: Garbled message at block %i\n", i); + + // If the previous frame was a short message then we need to Null out the Group Message pointer + // this issue and sugested resolution was presented by 'bertinholland' + + return; } @@ -652,17 +762,40 @@ if (flex->Decode.type == FLEX_PAGETYPE_SHORT_INSTRUCTION) { // if (flex_groupmessage == 1) continue; - int iAssignedFrame = (int)((viw >> 10) & 0x7f); // Frame with groupmessage + unsigned int iAssignedFrame = (int)((viw >> 10) & 0x7f); // Frame with groupmessage int groupbit = (int)((viw >> 17) & 0x7f); // Listen to this groupcode - - flex->GroupHandler.aGroupCodes[groupbit][CAPCODES_INDEX]++; - int CapcodePlacement = flex->GroupHandler.aGroupCodes[groupbit][CAPCODES_INDEX]; + ////////############################################################################# + ////////############################################################################# + flex->GroupHandler.GroupCodes[groupbit][CAPCODES_INDEX]++; + int CapcodePlacement = flex->GroupHandler.GroupCodes[groupbit][CAPCODES_INDEX]; verbprintf(1, "FLEX: Found Short Instruction, Group bit: %i capcodes in group so far %i, adding Capcode: [%09lld]\n", groupbit, CapcodePlacement, flex->Decode.capcode); - flex->GroupHandler.aGroupCodes[groupbit][CapcodePlacement] = flex->Decode.capcode; + flex->GroupHandler.GroupCodes[groupbit][CapcodePlacement] = flex->Decode.capcode; flex->GroupHandler.GroupFrame[groupbit] = iAssignedFrame; + // Ok, so the cycle and frame can be used to make sure we haven't missed the message frame. + // but the cycle is 0 - 15 and the frame is 0 - 127 + if(iAssignedFrame > flex->FIW.frameno) + { + flex->GroupHandler.GroupCycle[groupbit] = (int)flex->FIW.cycleno; + verbprintf(4, "FLEX: Message frame is in this cycle: %i\n", flex->GroupHandler.GroupCycle[groupbit]); + + } + else + { + if(flex->FIW.cycleno == 15) + { + flex->GroupHandler.GroupCycle[groupbit] = 0; + } + else + { + flex->GroupHandler.GroupCycle[groupbit] = (int)flex->FIW.cycleno++; + } + verbprintf(4, "FLEX: Message frame is in the next cycle: %i\n", flex->GroupHandler.GroupCycle[groupbit]); + } + + // Nothing else to do with this word.. move on!! continue; } @@ -671,7 +804,7 @@ if (mw1 == 0 && mw2 == 0){ verbprintf(3, "FLEX: Invalid VIW\n"); - continue; // Invalid VIW + continue; // Invalid VIW } if (is_tone_page(flex)) @@ -1133,6 +1266,12 @@ Flex_Delete(flex); flex=NULL; } + + for(int g = 0; g < 17; g++) + { + flex->GroupHandler.GroupFrame[g] = -1; + flex->GroupHandler.GroupCycle[g] = -1; + } } return flex; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/multimon-ng-1.1.5+git.20180402/win32_getopt.c new/multimon-ng-1.1.5+git.20180527/win32_getopt.c --- old/multimon-ng-1.1.5+git.20180402/win32_getopt.c 2018-04-02 20:47:26.000000000 +0200 +++ new/multimon-ng-1.1.5+git.20180527/win32_getopt.c 2018-05-27 20:10:42.000000000 +0200 @@ -1,3 +1,26 @@ +/* Getopt for GNU. + NOTE: getopt is part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to [email protected] + before changing it! + Copyright (C) 1987-1996,1998-2004,2008,2009,2010 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + /* Getopt for Microsoft C This code is a modification of the Free Software Foundation, Inc. Getopt library for parsing command line argument the purpose was diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/multimon-ng-1.1.5+git.20180402/win32_getopt.h new/multimon-ng-1.1.5+git.20180527/win32_getopt.h --- old/multimon-ng-1.1.5+git.20180402/win32_getopt.h 2018-04-02 20:47:26.000000000 +0200 +++ new/multimon-ng-1.1.5+git.20180527/win32_getopt.h 2018-05-27 20:10:42.000000000 +0200 @@ -1,3 +1,23 @@ +/* Declarations for getopt. + Copyright (C) 1989-1994,1996-1999,2001,2003,2004,2009 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + /* Getopt for Microsoft C This code is a modification of the Free Software Foundation, Inc. Getopt library for parsing command line argument the purpose was
