Προς το περιεχόμενο

Πρόγραμμα σε C


geodark

Προτεινόμενες αναρτήσεις

 

Σε παρακαλώ σημασια έχει MONO ο αλγοριθμος  :P

 

ασχετα αμα αυτος που ανοιξε το θεμα το ζητησε σε C. Και ο φιλος του προτεινε συναρτηση η οποια δεν ειναι portable.

 

Ρε μάθε πρώτα να προγραμματίζεις, που απαντάς ότι νάναι... δες τι απαντήσεις έδωσες στην αρχή.... άσχετος τελείως. Πραγματικά δεν ξέρεις να προγραμματίζεις. Και αυτό δεν είναι κακό. Κακό είναι που κάνεις ότι ξέρεις.

 

@mig

Πρώτον συνήθως θες 4-5 custom inputs.

String (για name, email, passwords και άλλα)

Time

Date

Integer (για ηλικίες, διάφορα αριθμητικά δεδομένα)

Float (για λεφτά και δεκαδικά μεγέθη).

Αυτά τα κάνεις μία φορά και τα έχεις στην βιβλιοθήκη σου.

 

Δεύτερον ναι θα το φτιάξεις για 1-2 πλατφόρμες να είναι user friendly παρά να παίζει και στο τελευταίο λειτουργικό.

Δεν ζούμε στις ταινίες του 80 που scrollaroun πράσινα γραμματάκια.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Απαντ. 66
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

...

Δεύτερον ναι θα το φτιάξεις για 1-2 πλατφόρμες να είναι user friendly παρά να παίζει και στο τελευταίο λειτουργικό.

Δεν ζούμε στις ταινίες του 80 που scrollaroun πράσινα γραμματάκια.

Δίνεις ως απάντηση στον topic starter non-portable κώδικα που παρσάρει το input ανά χαρακτήρα με 5-6 if στον ΚΑΘΕ χαρακτήρα (συμπεριλαμβανομένου και του μετρητή της λούπας... φαντάσου να ήθελε να διαβάσει 100 χαρακτήρες δηλαδή), και μετά με αφορμή τον δικό μου πολύ πιο generic και fully portable κώδικα μου μιλάς για πράσινα γραμματάκια και για 2013;

 

Sorry, αλλά δεν προτίθεμαι να αντιπαρατεθώ περαιτέρω για τα αυτονόητα!

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δίνεις ως απάντηση στον topic starter non-portable κώδικα που παρσάρει το input ανά χαρακτήρα με 5-6 if στον ΚΑΘΕ χαρακτήρα (συμπεριλαμβανομένου και του μετρητή της λούπας... φαντάσου να ήθελε να διαβάσει 100 χαρακτήρες δηλαδή), και μετά με αφορμή τον δικό μου πολύ πιο generic και fully portable κώδικα μου μιλάς για πράσινα γραμματάκια και για 2013;

 

Sorry, αλλά δεν προτίθεμαι να αντιπαρατεθώ περαιτέρω για τα αυτονόητα!

 

Να μην προτίθεσαι γιατι ειναι ηλίθιος. Οποτε Λήξις συζήτησης. Ετσι εκτελείς κάτι τέτοιους δεν ειναι για πολλες κουβέντες.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

 

 

 

Ρε μάθε πρώτα να προγραμματίζεις, που απαντάς ότι νάναι... δες τι απαντήσεις έδωσες στην αρχή.... άσχετος τελείως. Πραγματικά δεν ξέρεις να προγραμματίζεις. Και αυτό δεν είναι κακό. Κακό είναι που κάνεις ότι ξέρεις.

 

@mig

Πρώτον συνήθως θες 4-5 custom inputs.

String (για name, email, passwords και άλλα)

Time

Date

Integer (για ηλικίες, διάφορα αριθμητικά δεδομένα)

Float (για λεφτά και δεκαδικά μεγέθη).

Αυτά τα κάνεις μία φορά και τα έχεις στην βιβλιοθήκη σου.

 

Δεύτερον ναι θα το φτιάξεις για 1-2 πλατφόρμες να είναι user friendly παρά να παίζει και στο τελευταίο λειτουργικό.

Δεν ζούμε στις ταινίες του 80 που scrollaroun πράσινα γραμματάκια.

 

 

Δεν χρειάστηκα καν εγώ. Σε ξεφτιλισε ο migf1 :D

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δίνεις ως απάντηση στον topic starter non-portable κώδικα που παρσάρει το input ανά χαρακτήρα με 5-6 if στον ΚΑΘΕ χαρακτήρα (συμπεριλαμβανομένου και του μετρητή της λούπας... φαντάσου να ήθελε να διαβάσει 100 χαρακτήρες δηλαδή), και μετά με αφορμή τον δικό μου πολύ πιο generic και fully portable κώδικα μου μιλάς για πράσινα γραμματάκια και για 2013;

 

Sorry, αλλά δεν προτίθεμαι να αντιπαρατεθώ περαιτέρω για τα αυτονόητα!

 

Πες μου ότι μου κάνεις πλάκα. Ότι κοιτάς το performance όταν πατάει το κουμπί λες και έχεις να κάνεις με decoding video.

 

Παρα ταύτα έχω μέχρι 11 συνθήκες έγω (δεν ελέγχονται όλες μετά το &&) που γίνονται για κάθε πλήκτρο και εσύ 8 χωρίς καν να βάλουμε το parsing που θα κάνει εσωτερικά η sscanf(buffer, "%d:%d", &h, &m).

 

Αλλά παρόλαυτα το θεωρώ πραγματικά άκυρο να μιλάμε για performance σε αυτή την περίπτωση.

Και όπως σου είπα δεν έχω καν c compiler. Δεν μπορώ να ελέγξω αν τρέχει σωστά ή να το γράψω πολύ καλύτερα ή να βάλω ένα table με τους χαρακτήρες που επιτρέπονται ανά θέση ώστε να έχει λιγότερα if.

 

EDIT: (Μετά την διορθωσή είδα ότι το λες για το μέγεθος). Όπως σου είπα μπορείς να κάνεις ένα table για το τι χαρακτήρες επιτρεπονται. Και επίσης αναλόγως με το τι θα φτιάξεις κάνεις και το αντίστοιχο πρόγραμμα. Όχι δεν θα έκανα 100 if αλλά εδώ μπορώ να βάλω 4-5 if. Και όπως σου είπα συνήθως θες 4-5 custom inputs.

 

Δεν χρειάστηκα καν εγώ. Σε ξεφτιλισε ο migf1 :D

 

Αφού είσαι άσχετος και αμφιβάλλω αν καταλαβαίνεις κάν τι λέμε.

Ασε που μιλάς για ξεφτυλίκια και μαλακίες με βάση τον κώδικα λες και ήμαστε μικρά σπασικλάκια. Πόσο κομπλεξικός είσαι;

Και κάνε και κάτι από μόνος σου, σταμάτα να είσαι η πορδή του mig.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Είναι πολύ λιγότερο user friendly. Και η ρουτίνα είναι πιο εύκολη και λιγότερο δύσκολο να έχεις κάποιο λάθος.

Εγώ την έφτιαξα χωρίς compiler και έχοντας να γράψω c και c++ 8 χρόνια.

 

 

Το παραπάνω ποιος το έγραψε ρε χαζουλη εγω? εφοσον δεν ασχολειται με την C τι μπηκες να μας παραστησεις εδω μεσα? οτι εισαι των αλγοριθμων κτλπ? και την λες και στον migf1? λήξις λεμε. Εφυγες στον compiler για εκτέλεση. Τελος εδω. 

 

YΓ Για να μην μπω οτι μπέρδεψες την sscanf με την scanf. Κουμπώσου λεμε και αποχωρησε βγάζεις και γλώσσα.

Ούτε εγώ χρησιμοποίησα scanf()... χρησιμοποίησα συνδυασμό fgets() με sscanf(). Προσωπικά το θεωρώ πολύ πιο βατό από το να φτιάχνει από την αρχή custom command-line editing mode.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Το παραπάνω ποιος το έγραψε ρε χαζουλη εγω? εφοσον δεν ασχολειται με την C τι μπηκες να μας παραστησεις εδω μεσα? οτι εισαι των αλγοριθμων κτλπ? και την λες και στον migf1? λήξις λεμε. Εφυγες στον compiler για εκτέλεση. Τελος εδω. 

 

YΓ Για να μην μπω οτι μπέρδεψες την sscanf με την scanf. Κουμπώσου λεμε και αποχωρησε βγάζεις και γλώσσα.

 

βλακάκο, ναι είμαι των αλγόριθμων. Πράγμα που δεν είσαι εσύ. Και δυστυχώς δεν είσαι ούτε της c. Οπότε είσαι ένα τίποτα.

 

Όσον αφορά την sscanf και την scanf, δεν μπέρδεψα τίποτα. Το είπα γενικά με την εννοια ότι δεν χρησιμοποιώ functions που με οδηγούν σε αλγόριθμους που δεν με περιορίζουν στο είδος του input κατά την ώρα του data entry αλλά μετά.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

@Retromaniac: Αυτό που προσπάθησες να κάνεις ονομάζεται input masking και χρησιμοποιείται από την εποχή των λασπών, κυρίως στα GUI.

 

Στα πλαίσια αυτού νήματος είναι από τις χειρότερες προτάσεις που θα μπορούσες να κάνεις, και πολύ χειρότερο να επιχειρείς να το κάνεις χειροκίνητα και μάλιστα στο πόδι!

 

Εν έτει 2013 (ή μάλλον εδώ και τουλάχιστον καμιά 30αριά χρόνια) ΟΥΔΕΙΣ φτιάχνει χειροκίνητο input mask! Όταν κι αν το χρειάζεται το παίρνει έτοιμο με όποια γλώσσα κι αν προγραμματίζει.

 

Δεν έχουν απολύτως καμία σχέση οι επιδόσεις στη διαφωνία μας. Αν θέλεις να προτείνεις χειροκίνητο input masking, τουλάχιστον κάνε το στοιχειωδώς σωστά, με στοιχειωδώς generic κώδικα.

 

Η άποψή μου παραμένει πως πρόκειται για άστοχη απάντηση στο παρόν νήμα, μιας και δεν συμπεριλαμβάνεται στις στάνταρ συναρτήσεις της γλώσσας και η σωστή του υλοποίηση δεν είναι trivial. Aν το χρειάζεσαι, και πάλι δεν το γράφεις μόνος σου... αν δεν σε ενδιαφέρει η φορητότητα κοιτάς πρώτα αν το παρέχει ως extension ο vendor του compiler σου, αλλιώς κατεβάζεις καμιά έτοιμη βιβλιοθηκούλα.

 

Over & out!

  • Like 2
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δηλαδή τι ήθελες να του φτιάξω μία ολόκληρη βιβλιοθήκη input masking ή να του πω ποια βιβλιοθήκη να κατεβάσει; Αυτό θα ήταν στα πλαίσια του νήματος; Μήπως να του έφτιαχνα και μία βιβλιοθήκη δικιά μου regex;

 

Και δεν κατάλαβα πως η δικιά σου είναι γενική; Για κάθε περίπτωση θα πρέπει να γράψεις διαφορετικό κώδικα. Επειδή έχεις ένα standard μέρος για να ελέγχει για το overflow;

 

Αυτό που ήθελα να σου πω είναι ότι  εν έτει 2013 δεν χρησιμοποιείς scanf/sscanf για user frιendly input. Τώρα το αν έδωσα εγώ ένα μικρό κώδικα για το πως γίνεται αυτό για την ασκησή του και όχι μία ολόκληρη generic βιβλιοθήκη για input masking συγνώμη κιόλας.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Και εγώ θα συμφωνήσω με τον migf1. Αγνόησε τις τρολιές του star_light που θέλουν απλά να ρίξουν λάδι στη φωτιά και θα δεις ότι ο migf1 έχει δίκιο.

 

Τέλεια. Μια ρουτίνα που σε αφήνει να γράψεις όσο θέλεις και ότι θέλεις και μετά validate. Και όλα αυτά το 2013....

Αυτό που ήθελα να σου πω είναι ότι εν έτει 2013 δεν χρησιμοποιείς scanf/sscanf για user frιendly input. Τώρα το αν έδωσα εγώ ένα μικρό κώδικα για το πως γίνεται αυτό για την ασκησή του και όχι μία ολόκληρη generic βιβλιοθήκη για input masking συγνώμη κιόλας.

Καλώς ή κακώς όλοι οι φοιτητές διδάσκονται την scanf ως συνάρτηση εισόδου ίσως επειδή λόγω των format μπορείς εύκολα να διαβάσεις ό,τι θέλεις. Ως εκ τούτου, το 99% των ασκήσεων που βλέπουμε είναι λυμένες με scanf. Με αυτό το σκεπτικό η συνάρτηση του migf1 αποτελεί λύση γιατί διορθώνει κάποια από τα προβλήματα της scanf (δεν είδα καθόλου τον κώδικα αλλά διαβάζοντας για fgets / sscanf συμπεραίνω τι θέλει να κάνει).

 

Κάτσε να σου γράψω λίγο τον αλγόριθμο.

 

     key = getchar();

     if (key == '\8' && i > 0) // backspace

     Console.SetCursorPosition(0, 0); 

     Console.Write(time);

     Console.SetCursorPosition(i, 0); 

     fflush(stdin)

 

Χωρίς να θέλω να σε προσβάλλω, αν η scanf το 2013 είναι μία φορά γελοία, το get ένα ένα πλήκτρο και parse είναι 10 φορές γελοίο. Εννοείται πως ένας φοιτητής στο πλαίσιο μιας άσκησης δεν τον ενδιαφέρει να τρέξει ο κώδικας σε QNX αλλά ο κώδικάς σου ούτε καν στις "1-2 πλατφόρμες" που είπες ότι στοχεύεις δεν θα λειτουργήσει. Οι console.τάδε υποθέτω είναι συναρτήσεις του WinAPI ή κάτι για Windows τέλος πάντων, το fflush(stdin) θα παίξει μόνο σε windows και όχι σε *nix και η θεώρηση πως Backspace == 8 πάλι δεν θα παίξει σε *nix (Συνήθως οι terminal drivers στέλνουν για το Backspace το κωδικό 0x7F του Delete και για το Delete στέλνουν Escape Code [3~. Το 0x08 συνήθως στέλνεται πατώντας μόνο το Ctrl+H). Με λίγα λόγια ο κώδικας δεν στοχεύει τις 1-2 μεγάλες πλατφόρμες αλλά μόνο μία.

 

Χωρίς να το γνωρίζω στα σίγουρα, υποθέτω πως και στα Windows ακόμη έχουμε buffered είσοδο, οπότε λόγω της getchar δεν θα παίξει ούτε καν σε Windows μια και η getchar θα επιστρέψει αφού πατηθεί Enter. Για να γίνει αυτό που θέλεις θα πρέπει να χρησιμοποιήσεις την συνάρτηση _getch ή κάποια συνάρτηση του WinAPI που κάνει αυτή τη δουλειά.

 

Καταλαβαίνω ότι τον έγραψες στο χέρι χωρίς compiler όπως είπες αλλά ακόμη και με τις απαραίτητες αλλαγές για να τρέχει, πάλι ο κώδικας του migf1 θα είναι (ανάμεσα στους δύο) πιο εύκολος στην κατανόηση και θα ενδείκνυται περισσότερο για ένα νέο που μαθαίνει.

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δεν εχει μονο ο migf1 δικιο απλα η λυση του migf1 ηταν πιο πληρης και εκτενεστερη λογικο αφου εχει και περισσοτερη εμπειρια απο μενα τουλαχιστον. Εξαρχης ομως του ειπα οτι χρησιμοποιει μη φορητές συναρτησεις αντι να κοψει και να το παραδεχθεί αρχισε να λεει οτι ο αλγοριθμος εχει σημασια του απαντησα οτι σε θρεντ της C δεν εχει μονο ο αλγοριθμος σημασια. Και αρχισε να μου λεει οτι ειμαι εγω ασχετος οποτε το χέσιμο το έφαγε δικαιοτατα. Το τρολιες που γραφεις δεν καταλαβαινω τι σημαινει μπορεις να μου το εξηγησεις σε παρακαλω? 

 

Μονο σε εσενα ξανααπανταω τωρα δεν θα το συνεχιζα.Αν εσυ νομιζεις οτι ολα αυτα ειναι τρολιές εχεις λαθος. Τρολιες ειναι αυτα που γραφει αυτος οχι εγώ. Μλκια που τον υποστηριζεις. Πριν χρησιμοποιησεις το τρολιες για καποιον να ξερεις τι γραφεις. 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημοσ. (επεξεργασμένο)

Starlight κάποια στιγμή πρέπει να καταλάβεις ότι κρίνεσαι όχι από τις δηλώσεις σου αλλά από τη συμπεριφορά σου.

 

Σορρυ με εβρισε ο αλλος πρώτος ενω εχω δικιο. Και μπαινει ο ημιθεος και του λεει "μην παιρνεις τον αλλον στα σοβαρα ειναι τρολλ". Μια χαρα ειναι η συμπεριφορα μου.

Επεξ/σία από Star_Light
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δηλαδή τι ήθελες να του φτιάξω μία ολόκληρη βιβλιοθήκη input masking ή να του πω ποια βιβλιοθήκη να κατεβάσει; Αυτό θα ήταν στα πλαίσια του νήματος; Μήπως να του έφτιαχνα και μία βιβλιοθήκη δικιά μου regex;

 

Και δεν κατάλαβα πως η δικιά σου είναι γενική; Για κάθε περίπτωση θα πρέπει να γράψεις διαφορετικό κώδικα. Επειδή έχεις ένα standard μέρος για να ελέγχει για το overflow;

 

Αυτό που ήθελα να σου πω είναι ότι  εν έτει 2013 δεν χρησιμοποιείς scanf/sscanf για user frιendly input. Τώρα το αν έδωσα εγώ ένα μικρό κώδικα για το πως γίνεται αυτό για την άσκησή του και όχι μία ολόκληρη generic βιβλιοθήκη για input masking συγνώμη κιόλας.

Δεν ξέρω από που προκύπτει αυτή σου η σιγουριά ότι τα input masks σε command-line ισοδυναμούν με user-friendliness, αλλά εν έτει 2013 εγώ δεν ξέρω π.χ. κανένα unix/linux command-line utility, compiler toolchain utility, κλπ που να διαβάζει από τη γραμμή εντολών με input masks. Ούτε ξέρω π.χ. εν έτει 2013 κανέναν browser να διαβάζει το uri που του γράφεις στο address bar με input masks.

 

Εν κατακλείδι, εγώ ξέρω πως και εν έτει 1980 και εν έτει 2013 ο στάνταρ τρόπος να διαβάζεις από τη γραμμή εντολών (και όχι μόνο) ήταν και παραμένει να τη διαβάζεις μονοκόμματα σε ένα string και κατόπιν να την κάνεις tokenize σύμφωνα με τις εκάστοτε ανάγκες σου. Το αν θα τη διαβάσεις με getchar() char by char, με fgets(), με GNU getline() δεν έχει σημασία. Ούτε έχει σημασία αν το tokenization θα το κάνεις κατόπιν με sscanf(), με strtok() ή με custom συνάρτηση. Αυτό που έχει σημασία είναι η στανταρισμένη μεθοδολογία: first read it as a string, then tokenize it!

 

Τα input masks από την άλλη μεριά χρησιμοποιούνται κατά κανόνα σε GUI, σου παρέχονται έτοιμα από το API του GUI και σίγουρα αφορούν πολύ συγκεκριμένες περιπτώσεις οι οποίες με τίποτα δεν μπορούν να υπερκαλύψουν τη γενική περίπτωση, ιδιαίτερα σε γραμμή εντολών.

 

Το να προτείνεις σε κάποιον που τώρα ξεκινάει με C και ξέρει μονάχα την scanf() για να διαβάζει την κύρια είσοδο (topic starter) να κλείσει το line-buffering και να υλοποιήσει χειροκίνητο input-masking στη γραμμή εντολών όχι μόνο είναι του τελείως άχρηστο, αλλά είναι και πλήρως μαζοχιστικό για αυτόν.

 

Επίσης αρνούμαι ευθέως να αποδεχτώ πως είναι πιο φιλικό για τον τελικό χρήστη της γραμμής εντολών το input-masking. Από τη στιγμή που κανένα από την συντριπτική πλειοψηφία προγραμμάτων γραμμής-εντολών δεν χρησιμοποιεί input-masking, πως ακριβώς θα το χαρακτηρίσει user-friendly ο τελικός χρήστης; Αν ήταν user-friendly θα είχε καθιερωθεί.

 

Τώρα, πέρα από την ακαταλληλότητα της πρότασής σου για το συγκεκριμένο νήμα, σε ότι αφορά ειδικά τον κώδικα που έδωσες, προσωπικά τον θεωρώ επιεικώς νηπιακού επιπέδου ακόμα κι αν λειτουργούσε. Παρόλα αυτά δεν τον σχολίασα, παρά μόνο όταν μου άρχισες τις εξυπνάδες.

 

Τέλος, δεν είναι δική μου αρμοδιότητα να σου πω τι και πόσο κώδικα θα γράψεις στο φόρουμ. Εγώ απλά αμύνομαι σε αυτό το νήμα στις εξυπνάδες σου.

 

Επειδή όμως ενίοτε μου αρέσει να μοιράζομαι ολοκληρωμένο κώδικα, ειδικά όταν με τσιγκλάνε, μια πολύ πιο generic, πολύ πιο scalable και άρα πολύ πιο re-usable υλοποίηση αυτού που προσπάθησες να κάνεις, είναι η παρακάτω (παρόλο που δεν είναι αμιγώς input-masking: δεν χρησιμοποιεί masks... όπως δεν χρησιμοποίησες ούτε εσύ) ...

 

 

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <conio.h>

#define chCLEAR		'_'
#define sPLACEHOLDER	"__"

#define pressENTER()			\
do {					\
	printf( "press ENTER... " );	\
	fflush(stdout);			\
	while ( '\n' != getchar() )	\
		;	/* void */	\
}while(0)

/* beep n times */
#define BEEP( n )	nputchar( '\a', (n) )


/* -----------------------------------------------------------------------
 * Print a char n times, starting at cursor's current position.
 */
void nputchar( int c, int n )
{
	while (n-- > 0)
		putchar(c);
	fflush(stdout);
}

/* -----------------------------------------------------------------------
 * Print a char backwards n times, starting at cursor's current position.
 */
void nputchar_backwards( int c, int n )
{
	nputchar( '\b', n );
	nputchar( c, n );
	nputchar( '\b', n );
}

/* -----------------------------------------------------------------------
 * Return the count of digits of a 10-based unsigned long int.
 */
size_t count_digits_ulong10( unsigned long int n )
{
	size_t i = 0;
	while ( n ) {
		n /= 10;
		i++;
	}
	return i;
}

/* -----------------------------------------------------------------------
 * Read & validate in-place an unsigned long int, such as only digits are
 * allowed during the input. Non-digit characters are rejected interactively,
 * except for 'd' which is used as backspace for corrections. Furthermore, the
 * inputted number is validated against a given range, with inclusive limits.
 * Return the input number or ULONG_MAX on error (thus ULONG_MAX is NOT considered
 * to be a valid value).
 */
unsigned long int getinteractive_ulong_inrange(
	unsigned long int min,
	unsigned long int max,
	int               chClear,	/* clearing character for the output */
	const char        *sPlaceholder	/* outputted placeholder for the ulong */
	)
{
	char              *buf = NULL;	/* string buffer for holding input temporarily */
	size_t            i, ndigits = 0;
	unsigned long int ret = ULONG_MAX;

	/* force insignificant passing order of min & max */
	if ( min > max ) {
		unisgned long int temp = min;
		min = max;
		max = temp;
	}
	/* exclude ULONG_MAX from valid values */
	if ( ULONG_MAX == max )
		return ULONG_MAX;

	/* make sure that max fits in the outputted placeholder */
	ndigits = count_digits_ulong10( max );
	if ( sPlaceholder && ndigits > strlen(sPlaceholder) )
		return ULONG_MAX;

	/* allocate room for a temp string buffer, so max's digits can fit in it */
	buf = malloc( 1+ndigits );
	if ( !buf )
		return ULONG_MAX;

	/* interactive input */
	for (;
	{
		memset(buf, '\0', 1+ndigits);	/* reset */
		for (i=0; i < ndigits; )
		{
			int c = getch();

			/* allow 'd' as backspace for interactive corrections */
			if ( 'd' == tolower(c) ) {
				buf[i] = '\0';
				if ( 0 == i ) {		/* is cursor at start of input? */
					BEEP(1);
				}
				else {
					nputchar_backwards(chClear, 1);
					--i;
				}
				continue;
			}

			/* reject any other non-digit character */
			if ( !isdigit(c) ) {
				BEEP(1);
				printf( "%c\b", chClear );
				fflush(stdout);
				continue;
			}

			/* accept digit character */
			nputchar(c, 1);
			buf[i++] = c;
		}

		/* demand final ulong to be inside the given range */
		ret = strtoul(buf, NULL, 10);
		if ( ULONG_MAX == ret || ret < min || ret > max ) {
			BEEP(1);
			nputchar_backwards( chClear, ndigits );
			continue;
		}

		/* we are done */
		break;
	}

	free( buf );
	return ret;
}

// -----------------------------------------------------------------------
int main( void )
{
	char *timeEmpty    = "__:__";
	unsigned long int h = 0, m = 0; // hours, minutes

	puts( "Both hours & minutes are expected in 24h format (e.g.: 04:59)." );
	puts( "On any of them, you may use 'd' as backspace for corrections.\n" );

	printf( "Enter the time: %s", timeEmpty );
	nputchar( '\b', strlen(timeEmpty) );

	h = getinteractive_ulong_inrange(0,23, chCLEAR, sPLACEHOLDER);
	if ( ULONG_MAX == h )
		goto exit_failure;

	nputchar(chCLEAR, strlen(sPLACEHOLDER) - count_digits_ulong10(h));
	nputchar(':',1);

	m = getinteractive_ulong_inrange(0,59, chCLEAR, sPLACEHOLDER);
	if ( ULONG_MAX == m )
		goto exit_failure;

	printf("\n%02lu:%02lu\n", h, m );

	pressENTER();
	return 0;

exit_failure:
	puts( "*** internal error, terminating program..." );
	pressENTER();
	return 1;
}

 

Όπως βλέπεις δεν χρειαζόταν να γράψεις καμία βιβλιοθήκη και κανένα regex. Αν του βγάλεις τα σχόλια είναι δεν είναι 100 γραμμές.

 

Η μόνη λειτουργική έλλειψη συγκριτικά με τον κώδικά σου είναι πως δεν τσεκάρω in-place αν το τελευταίο ψηφίο κάνει overflow τον max, κάνω τον έλεγχο στο τέλος κι αν τον κάνει overflow τότε καθαρίζω όλο το input και ζητάω νέο. Πταίσμα μπροστά στις άλλες άπειρες βελτιώσεις.

 

Επίσης, η μόνη συνάρτηση που κάνει τον κώδικα μη φορητό είναι η getch()... που σημαίνει πως μπορείς να προσθέσεις conditional directives με διαφορετικές υλοποιήσεις της ανάλογα με το compilation platform. Σε Unix/Linux δεν είναι trivial, αν τη χρειάζεσαι όμως, πάει κάπως έτσι...

 

 

 

enum {	/* unbufferd i/o related constants & masks */

	KEYMASK_RESET		= 0x00,
	KEYMASK_BIT_ARROW	= (1 << 0),	// 0x01
	KEYMASK_BIT_FKEY	= (1 << 1),	// 0x02
	KEYMASK_BIT_UNKNOWN	= (1 << 2),	// 0x04

	KEY_NUL		= 0,
	KEY_ESCAPE	= 27,
	KEY_ENTER	= 13,
	KEY_SPACE	= 32,

	KEY_UP		= 72,
	KEY_DOWN	= 80,
	KEY_LEFT	= 75,
	KEY_RIGHT	= 77,
	KEY_INSERT	= 82,
	KEY_DELETE	= 83,
	KEY_HOME	= 71,
	KEY_END		= 79,
	KEY_PAGE_UP	= 73,
	KEY_PAGE_DOWN	= 81,

	KEY_BACKSPACE	= 8,

	KEY_F1		= 59,
	KEY_F2		= 60,
	KEY_F3		= 61,
	KEY_F4		= 62,
	KEY_F5		= 63,
	KEY_F6		= 64,
	KEY_F7		= 65,
	KEY_F8		= 66,
	KEY_F9		= 67,
	KEY_F10		= 68,
	KEY_F11		= 133,
	KEY_F12		= 134
};


#if defined( OS_WINDOWS )

	#include <conio.h>
	int getkey( unsigned int *outKeyMask )
	{
		int key;
		*outKeyMask = KEYMASK_RESET;

		/* on Windows platforms */

		key = getch();
		if ( 0 == key ) /* FunctionKey */
		{
			*outKeyMask |= KEYMASK_BIT_FKEY;
			key = getch();
		}
		else if ( 224 == key ) /* ArrowKey */
		{
			*outKeyMask |= KEYMASK_BIT_ARROW;
			key = getch();
		}
	}

#elif defined( OS_UNIX ) || defined( OS_LINUX )
	#include <sys/ioctl.h>
	#include <termios.h>
	#include <unistd.h>

	#define MAGIC_MAX_CHARS 18

	int getkey( unsigned int *outKeyMask )
	{
		int key;
		*outKeyMask = CUI_KEYMASK_RESET;
		struct termios	oldt, newt;
		unsigned char	keycodes[ MAGIC_MAX_CHARS ] = {'\0'};
		int		count;

		/* get the terminal settings for stdin */
		tcgetattr( STDIN_FILENO, &oldt );

		/* we want to keep the old setting to restore them at the end */
		newt = oldt;

		/* ? */
		newt.c_cc[ VMIN  ] = MAGIC_MAX_CHARS;
		newt.c_cc[ VTIME ] = 1;
		newt.c_iflag &= ~(IXOFF);

		/* disable canonical mode (buffered i/o) and local echo */
		newt.c_lflag &= ~(ECHO | ICANON);

		/* set the new settings */
	//	tcsetattr( STDIN_FILENO, TCSAFLUSH, &newt );
		tcsetattr( STDIN_FILENO, TCSANOW, &newt );

		count = read( fileno(stdin), keycodes, MAGIC_MAX_CHARS );
		if ( 1 == count )
		{
			key = keycodes[0];
			if ( '\r' == key || '\n' == key ) {
				key = KEY_ENTER;
			}
			else if ( '\b' == key || 127 == key ) {
				key = KEY_BACKSPACE;
			}
		}
		else
		{
			if ( '\r' == keycodes[0] || '\n' == keycodes[0] ) {
				key = KEY_ENTER;
			}

			// arrow keys
			else if (0 == memcmp(&keycodes[1], "[A", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_UP;
			}
			else if (0 == memcmp(&keycodes[1], "[B", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_DOWN;
			}
			else if (0 == memcmp(&keycodes[1], "[C", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_RIGHT;
			}
			else if (0 == memcmp(&keycodes[1], "[D", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_LEFT;
			}

			// insert & delete keys
			else if (0 == memcmp(&keycodes[1], "[2~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_INSERT;
			}
			else if (0 == memcmp(&keycodes[1], "[3~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_DELETE;
			}

			// home & end keys
			else if (0 == memcmp(&keycodes[1], "OH", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_HOME;
			}
			else if (0 == memcmp(&keycodes[1], "OF", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_END;
			}

			// page-up & page-down keys
			else if (0 == memcmp(&keycodes[1], "[5~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_PAGE_UP;
			}
			else if (0 == memcmp(&keycodes[1], "[6~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_ARROW;
				key = KEY_PAGE_DOWN;
			}

			// FKEYS
			else if (0 == memcmp(&keycodes[1], "OQ", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F2;
			}
			else if (0 == memcmp(&keycodes[1], "OR", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F3;
			}
			else if (0 == memcmp(&keycodes[1], "OS", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F4;
			}
			else if (0 == memcmp(&keycodes[1], "[15~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F5;
			}
			else if (0 == memcmp(&keycodes[1], "[17~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F6;
			}
			else if (0 == memcmp(&keycodes[1], "[18~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F7;
			}
			else if (0 == memcmp(&keycodes[1], "[19~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F8;
			}
			else if (0 == memcmp(&keycodes[1], "[20~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F9;
			}
			else if (0 == memcmp(&keycodes[1], "[24~", count-1) ) {
				*outKeyMask |= KEYMASK_BIT_FKEY;
				key = KEY_F12;
			}

			// other multi-character ANSI escape sequences
			else {
				*outKeyMask |= KEYMASK_BIT_UNKNOWN;
				key = -(int)keycodes[count-1];
			}
		}

		/* restore the former settings */
		tcsetattr ( STDIN_FILENO, TCSANOW, &oldt );

		return key;
	}
#endif

 

 

EDIT: Διόρθωση του outKeyMask που το πέρναγα ως C++ reference αντί για C pointer (άρα τώρα θέλει κι έλεγχο για != NULL αλλά... βαριέμαι :P).

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...