Compare commits

...

3 Commits

Author SHA1 Message Date
33cc1343cb C: change phone-number to exercism V3 2021-09-03 15:51:40 +02:00
77a8072c73 C: change phone-number to exercism V3 2021-09-03 15:50:08 +02:00
215629a19c C: create my own include file 2021-09-03 15:17:18 +02:00
12 changed files with 459 additions and 139 deletions

View File

@@ -27,6 +27,10 @@
default: all
ALLSOURCES=$(wildcard ./*.c)
TESTSOURCES=$(wildcard ./test_*.c)
SRC=$(filter-out $(TESTSOURCES),$(ALLSOURCES))
include makefile
all: CFLAGS+=-DTESTALL
@@ -48,5 +52,6 @@ unitdebug: CFLAGS+=-DDEBUG
unitdebug: clean unit
unit: CFLAGS+=-DUNIT_TEST
unit: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o tests.out $(LIBS)
unit: SOURCES=$(wildcard ./*.c)
unit: *.c *.h
$(CC) $(CFLAGS) $(SRC) -o tests.out $(LIBS)

63
c/phone-number/HELP.md Normal file
View 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/

View File

@@ -1,5 +1,10 @@
# Phone Number
Welcome to Phone Number on Exercism's C Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
## Instructions
Clean up user-entered phone numbers so that they can be sent SMS messages.
The **North American Numbering Plan (NANP)** is a telephone numbering system used by many countries in North America like the United States, Canada or Bermuda. All NANP-countries share the same international country code: `1`.
@@ -28,40 +33,24 @@ should all produce the output
**Note:** As this exercise only deals with telephone numbers used in NANP-countries, only 1 is considered a valid country code.
## Getting Started
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.
## Passing 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.
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.
## Source
Event Manager by JumpstartLab [http://tutorials.jumpstartlab.com/projects/eventmanager.html](http://tutorials.jumpstartlab.com/projects/eventmanager.html)
### Created by
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
- @RealBarrettBrown
[c-track]: https://exercism.io/my/tracks/c
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
### Contributed to by
- @bcc32
- @Gamecock
- @gea-migration
- @h-3-0
- @mikewalker
- @patricksjackson
- @QLaille
- @ryanplusplus
- @wolf99
### Based on
Event Manager by JumpstartLab - http://tutorials.jumpstartlab.com/projects/eventmanager.html

View 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 */

View File

@@ -22,9 +22,9 @@ test: tests.out
@./tests.out
.PHONY: memcheck
memcheck: test/*.c src/*.c src/*.h
memcheck: ./*.c ./*.h
@echo Compiling $@
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
@$(CC) $(ASANFLAGS) $(CFLAGS) test-framework/unity.c ./*.c -o memcheck.out $(LIBS)
@./memcheck.out
@echo "Memory check passed"
@@ -32,6 +32,6 @@ memcheck: test/*.c src/*.c src/*.h
clean:
rm -rf *.o *.out *.out.dSYM
tests.out: test/*.c src/*.c src/*.h
tests.out: ./*.c ./*.h
@echo Compiling $@
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
@$(CC) $(CFLAGS) test-framework/unity.c ./*.c -o tests.out $(LIBS)

View File

@@ -1,4 +1,3 @@
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
@@ -10,15 +9,15 @@
#define LPAREN '('
/* this version is likely not very stable, due to poor scanf() capabilities
* I made it to offer an option to traditional strtok() of manual string
* 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];
int64_t num[4];
int64_t *p = &num[0];
uint64_t num[4];
uint64_t *p = &num[0];
int nmatch;
char *res;
@@ -30,7 +29,7 @@ char *phone_number_clean(const char *input)
nmatch = sscanf(input, scan, &sn[0], &sn[1], &sn[2], &sn[3]);
for (int i=0; i<nmatch; ++i) {
num[i] = atol(*sn[i] == LPAREN? sn[i]+1: sn[i]);
*(p+i) = atol(*sn[i] == LPAREN? sn[i]+1: sn[i]);
free(sn[i]);
}
@@ -39,19 +38,21 @@ char *phone_number_clean(const char *input)
case 0:
return res;
case 1:
if (num[0] > 10000000000)
num[0] -= 10000000000;
if (num[0] > 9999999999 || num[0] < 2000000000)
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 (num[0] != 1)
if (*p != 1)
return res;
p++;
fallthrough;
fallthrough; /* only gcc>=7 & clang>=12 */
case 3: /* last 3 numbers */
if (p[0] < 200 || p[0] > 999 || p[1] < 200 || p[1] > 999 ||
p[2] < 0 || p[2] > 9999)
if (*p < 200 || *p > 999 ||
*(p+1) < 200 || *(p+1) > 999 ||
*(p+2) > 9999)
return res;
break;
}

View 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

View File

@@ -1,32 +0,0 @@
#ifndef PHONE_NUMBER_H
#define PHONE_NUMBER_H
#define NUMBER_LENGTH 10
char *phone_number_clean(const char *input);
/* from :
* https://github.com/torvalds/linux/blob/master/include/linux/compiler_attributes.h
* around line 200
* should work with recent gcc/clang
*/
#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

View 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();
}

View File

@@ -1,52 +0,0 @@
# The original 'makefile' has a flaw:
# 1) it overrides CFLAGS
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
#
# It means :
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
# not practical at all.
# - Also, it does not allow to run all tests without editing the test source
# code.
#
# To use this makefile (GNU make only):
# 1) copy it into exercise directory
# 2) add ex.h to exercise include file
# 3) add ex.c to exercise source code, and create a suitable main function
# 4) use make with one of the following targets :
# all: compile and run all predefined tests.
# nowarn: compile with no -Werror, and run all predefined tests
# debug: compile with -DDEBUG and run all predefined tests
# mem: perform memcheck with all tests enabled
# unit: build standalone (unit) bimary
# unitnowarn: build standalone (unit) binary with -Werror disabled
# unitdebug: build standalone binary with -DDEBUG
#
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
.PHONY: default all nowarn debug mem unit unitnowarn unitdebug standalone
default: all
include makefile
all: CFLAGS+=-DTESTALL
all: clean test
nowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
nowarn: clean all
debug: CFLAGS+=-DDEBUG
debug: all
mem: CFLAGS+=-DTESTALL
mem: clean memcheck
unitnowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
unitnowarn: clean unit
unitdebug: CFLAGS+=-DDEBUG
unitdebug: clean unit
unit: CFLAGS+=-DUNIT_TEST
unit: src/*.c src/*.h
$(CC) $(CFLAGS) src/*.c -o tests.out $(LIBS)

45
c/templates/br-common.h Normal file
View 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 */

View File

@@ -2,11 +2,11 @@
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
*/
#if defined UNIT_TEST || defined DEBUG
#include <stdio.h>
#include <stdlib.h>
# include <stdio.h>
# include <stdlib.h>
#endif
#ifdef TESTALL
#undef TEST_IGNORE
#define TEST_IGNORE() {}
# undef TEST_IGNORE
# define TEST_IGNORE() {}
#endif