C: change phone-number to exercism V3
This commit is contained in:
63
c/phone-number/HELP.md
Normal file
63
c/phone-number/HELP.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test` task.
|
||||
|
||||
```console
|
||||
$ make test
|
||||
```
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the test to fail.
|
||||
Then write just enough code to get the test to pass.
|
||||
Once you've done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your implementation for readability and expressiveness and then go on to the next test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own low-level algorithms or facilities by hand.
|
||||
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit phone_number.c phone_number.h` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [C track's documentation](https://exercism.org/docs/tracks/c)
|
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
Make sure you have read the "Guides" section of the [C track][c-track] on the Exercism site.
|
||||
This covers the basic information on setting up the development environment expected by the exercises.
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
|
||||
If you are struggling with a particular exercise, it is possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
## Resources
|
||||
|
||||
To get help if having trouble, you can use the following resources:
|
||||
|
||||
- [StackOverflow][] can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
- [CPPReference][] can be used to look up information on C concepts, operators, types, standard library functions and more.
|
||||
- [TutorialsPoint][] has similar content as CPPReference in its C programming section.
|
||||
- [The C Programming][K&R] book by K&R is the original source of the language and is still useful today.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/c
|
||||
[cppreference]: https://en.cppreference.com/w/c
|
||||
[tutorialspoint]: https://www.tutorialspoint.com/cprogramming/
|
||||
[K&R]: https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628/
|
45
c/phone-number/br-common.h
Normal file
45
c/phone-number/br-common.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef __BR_COMMON_H
|
||||
#define __BR_COMMON_H
|
||||
|
||||
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 30
|
||||
*
|
||||
* __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
|
||||
* For other compilers, simple implementation (for __falltrough__ only)
|
||||
*/
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||
# define __GCC4_has_attribute___assume_aligned__ (__GNUC_MINOR__ >= 9)
|
||||
# define __GCC4_has_attribute___copy__ 0
|
||||
# define __GCC4_has_attribute___designated_init__ 0
|
||||
# define __GCC4_has_attribute___externally_visible__ 1
|
||||
# define __GCC4_has_attribute___no_caller_saved_registers__ 0
|
||||
# define __GCC4_has_attribute___noclone__ 1
|
||||
# define __GCC4_has_attribute___nonstring__ 0
|
||||
# define __GCC4_has_attribute___no_sanitize_address__ (__GNUC_MINOR__ >= 8)
|
||||
# define __GCC4_has_attribute___no_sanitize_undefined__ (__GNUC_MINOR__ >= 9)
|
||||
# define __GCC4_has_attribute___fallthrough__ 0
|
||||
# define __GCC4_has_attribute___fallthrough__ 0
|
||||
#endif
|
||||
|
||||
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 200
|
||||
*/
|
||||
#if __has_attribute(__fallthrough__)
|
||||
# define fallthrough __attribute__((__fallthrough__))
|
||||
#else
|
||||
# define fallthrough do {} while (0); /* fallthrough */
|
||||
#endif
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
# undef TEST_IGNORE
|
||||
# define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif /* __BR_COMMON_H */
|
80
c/phone-number/phone_number.c
Normal file
80
c/phone-number/phone_number.c
Normal file
@@ -0,0 +1,80 @@
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "phone_number.h"
|
||||
|
||||
#define LEN_NUM 10
|
||||
#define LPAREN '('
|
||||
|
||||
/* this version is likely not very stable, due to poor scanf() capabilities
|
||||
* I made it to offer an option to traditional strtok() or manual string
|
||||
* parsing.
|
||||
*/
|
||||
char *phone_number_clean(const char *input)
|
||||
{
|
||||
char *scan="%m[+(0-9]%*[()-. ]%m[0-9]%*[()-. ]%m[0-9]%*[-. ]%m[0-9]";
|
||||
char *sn[4];
|
||||
uint64_t num[4];
|
||||
uint64_t *p = &num[0];
|
||||
int nmatch;
|
||||
char *res;
|
||||
|
||||
if (!(res = malloc(LEN_NUM+1)))
|
||||
return NULL;
|
||||
memset(res, '0', LEN_NUM);
|
||||
*(res+LEN_NUM) = 0;
|
||||
|
||||
nmatch = sscanf(input, scan, &sn[0], &sn[1], &sn[2], &sn[3]);
|
||||
|
||||
for (int i=0; i<nmatch; ++i) {
|
||||
*(p+i) = atol(*sn[i] == LPAREN? sn[i]+1: sn[i]);
|
||||
free(sn[i]);
|
||||
}
|
||||
|
||||
switch (nmatch) {
|
||||
case 2:
|
||||
case 0:
|
||||
return res;
|
||||
case 1:
|
||||
if (*p > 10000000000) /* 1 000 000 0000 */
|
||||
*p -= 10000000000;
|
||||
if (*p > 9999999999 || /* 999 999 9999 */
|
||||
*p < 2000000000) /* 200 000 0000 */
|
||||
return res;
|
||||
break;
|
||||
case 4: /* area */
|
||||
if (*p != 1)
|
||||
return res;
|
||||
p++;
|
||||
fallthrough; /* only gcc>=7 & clang>=12 */
|
||||
case 3: /* last 3 numbers */
|
||||
if (*p < 200 || *p > 999 ||
|
||||
*(p+1) < 200 || *(p+1) > 999 ||
|
||||
*(p+2) > 9999)
|
||||
return res;
|
||||
break;
|
||||
}
|
||||
snprintf(res, LEN_NUM+1, "%ld%ld%ld", *p, *(p+1), *(p+2));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg;
|
||||
char *res;
|
||||
|
||||
for (arg=1; arg<ac; ++arg) {
|
||||
res=phone_number_clean(av[arg]);
|
||||
printf("orig = [%s]\n", av[arg]);
|
||||
printf("\t-> [%s]\n", res);
|
||||
free(res);
|
||||
}
|
||||
}
|
||||
#endif
|
10
c/phone-number/phone_number.h
Normal file
10
c/phone-number/phone_number.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef PHONE_NUMBER_H
|
||||
#define PHONE_NUMBER_H
|
||||
|
||||
#include "br-common.h"
|
||||
|
||||
#define NUMBER_LENGTH 10
|
||||
|
||||
char *phone_number_clean(const char *input);
|
||||
|
||||
#endif
|
246
c/phone-number/test_phone_number.c
Normal file
246
c/phone-number/test_phone_number.c
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "test-framework/unity.h"
|
||||
#include "phone_number.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *result = NULL;
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
static void test_cleans_the_number(void)
|
||||
{
|
||||
const char input[] = "(223) 456-7890";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_cleans_numbers_with_dots(void)
|
||||
{
|
||||
TEST_IGNORE(); // delete this line to run test
|
||||
const char input[] = "223.456.7890";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_cleans_numbers_with_multiple_spaces(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "223 456 7890 ";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_when_9_digits(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "123456789";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_when_11_digits_does_not_start_with_a_1(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "22234567890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_valid_when_11_digits_and_starting_with_1(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "12234567890";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_valid_when_11_digits_and_starting_with_1_even_with_punctuation(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "+1 (223) 456-7890";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_when_more_than_11_digits(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "321234567890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_with_letters(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "123-abc-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_with_punctuations(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "123-@:!-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_if_area_code_starts_with_0(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "(023) 456-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_if_area_code_starts_with_1(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "(123) 456-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_if_exchange_code_starts_with_0(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "(223) 056-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_if_exchange_code_starts_with_1(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "(223) 156-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_if_area_code_starts_with_0_on_valid_11_digit_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "1 (023) 456-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_if_area_code_starts_with_1_on_valid_11_digit_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "1 (123) 456-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_if_exchange_code_starts_with_0_on_valid_11_digit_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "1 (223) 056-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_if_exchange_code_starts_with_1_on_valid_11_digit_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "1 (123) 156-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UnityBegin("test_phone_number.c");
|
||||
|
||||
RUN_TEST(test_cleans_the_number);
|
||||
RUN_TEST(test_cleans_numbers_with_dots);
|
||||
RUN_TEST(test_cleans_numbers_with_multiple_spaces);
|
||||
RUN_TEST(test_invalid_when_9_digits);
|
||||
RUN_TEST(test_invalid_when_11_digits_does_not_start_with_a_1);
|
||||
RUN_TEST(test_valid_when_11_digits_and_starting_with_1);
|
||||
RUN_TEST
|
||||
(test_valid_when_11_digits_and_starting_with_1_even_with_punctuation);
|
||||
RUN_TEST(test_invalid_when_more_than_11_digits);
|
||||
RUN_TEST(test_invalid_with_letters);
|
||||
RUN_TEST(test_invalid_with_punctuations);
|
||||
RUN_TEST(test_invalid_if_area_code_starts_with_0);
|
||||
RUN_TEST(test_invalid_if_area_code_starts_with_1);
|
||||
RUN_TEST(test_invalid_if_exchange_code_starts_with_0);
|
||||
RUN_TEST(test_invalid_if_exchange_code_starts_with_1);
|
||||
RUN_TEST(test_invalid_if_area_code_starts_with_0_on_valid_11_digit_number);
|
||||
RUN_TEST(test_invalid_if_area_code_starts_with_1_on_valid_11_digit_number);
|
||||
RUN_TEST
|
||||
(test_invalid_if_exchange_code_starts_with_0_on_valid_11_digit_number);
|
||||
RUN_TEST
|
||||
(test_invalid_if_exchange_code_starts_with_1_on_valid_11_digit_number);
|
||||
|
||||
return UnityEnd();
|
||||
}
|
45
c/templates/br-common.h
Normal file
45
c/templates/br-common.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef __BR_COMMON_H
|
||||
#define __BR_COMMON_H
|
||||
|
||||
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 30
|
||||
*
|
||||
* __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
|
||||
* For other compilers, simple implementation (for __falltrough__ only)
|
||||
*/
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||
# define __GCC4_has_attribute___assume_aligned__ (__GNUC_MINOR__ >= 9)
|
||||
# define __GCC4_has_attribute___copy__ 0
|
||||
# define __GCC4_has_attribute___designated_init__ 0
|
||||
# define __GCC4_has_attribute___externally_visible__ 1
|
||||
# define __GCC4_has_attribute___no_caller_saved_registers__ 0
|
||||
# define __GCC4_has_attribute___noclone__ 1
|
||||
# define __GCC4_has_attribute___nonstring__ 0
|
||||
# define __GCC4_has_attribute___no_sanitize_address__ (__GNUC_MINOR__ >= 8)
|
||||
# define __GCC4_has_attribute___no_sanitize_undefined__ (__GNUC_MINOR__ >= 9)
|
||||
# define __GCC4_has_attribute___fallthrough__ 0
|
||||
# define __GCC4_has_attribute___fallthrough__ 0
|
||||
#endif
|
||||
|
||||
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 200
|
||||
*/
|
||||
#if __has_attribute(__fallthrough__)
|
||||
# define fallthrough __attribute__((__fallthrough__))
|
||||
#else
|
||||
# define fallthrough do {} while (0); /* fallthrough */
|
||||
#endif
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
# undef TEST_IGNORE
|
||||
# define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif /* __BR_COMMON_H */
|
Reference in New Issue
Block a user