1
1
mirror of https://github.com/theoludwig/libcproject.git synced 2024-12-11 21:13:00 +01:00

Compare commits

..

103 Commits

Author SHA1 Message Date
semantic-release-bot
d14b56904e
chore(release): 5.1.0 [skip ci] 2024-10-08 06:50:16 +00:00
b0fd3bf373
feat(date): add date_get_age
Fixes #7
2024-10-08 08:47:16 +02:00
95ad9f24f4
feat(date): add date_get_now_local
Related #7
2024-10-08 08:37:24 +02:00
ded2ca0795
feat(date): add date_get_now_utc
Related #7
2024-10-08 08:36:14 +02:00
semantic-release-bot
a7aef0b954
chore(release): 5.0.0 [skip ci] 2024-09-25 13:00:04 +00:00
336bbf6197
feat: add assert module 2024-09-25 14:57:34 +02:00
1be12c2a97
perf: allow to init array_list with initial capacity
Fixes #8
2024-09-25 14:34:33 +02:00
51d7123c8d
fix!: usage of stdint instead of int types for cross-platform compatibility
BREAKING CHANGE: Functions signatures changed.

Fixes #9
2024-09-25 14:26:15 +02:00
6ac47429e8
feat: use double instead of float for better precision
BREAKING CHANGE: Functions signatures changed
in the `mathematics` module.

BREAKING CHANGE: Renamed `MATHEMATICS_FLOAT_PRECISION` to `MATHEMATICS_DOUBLE_PRECISION`
2024-09-25 12:53:28 +02:00
semantic-release-bot
b3c17983b3
chore(release): 4.3.0 [skip ci] 2024-09-15 17:24:10 +00:00
aff8233483
feat: add date module 2024-09-15 19:21:35 +02:00
e1d9b714db
chore: update @since version 2024-09-15 18:43:39 +02:00
740aab1fcf
chore: rename master branch to main 2024-09-15 18:39:10 +02:00
fd6330c08c
build(deps): update latest 2024-09-15 18:38:21 +02:00
164ea2a7f8
docs: fix string_get_formatted_number examples 2024-09-15 18:25:01 +02:00
2fd8d102e9
feat: add mathematics_max, mathematics_min
Also add `mathematics_max_values` and
`mathematics_min_values` to check in array.
2024-09-13 15:35:19 +02:00
85ce5228ef
feat: add mathematics_opposite 2024-09-13 14:44:26 +02:00
c49d5f5421
feat: add string_zero_pad 2024-09-12 12:31:58 +02:00
35b868d0c1
feat: add string_pad_start 2024-09-12 12:22:53 +02:00
7683aa1db7
docs(license): add email address 2024-01-30 01:25:17 +01:00
semantic-release-bot
6eee39fffb
chore(release): 4.2.1 [skip ci] 2023-12-26 20:20:38 +00:00
ab9860e969
fix: markdownlint in LICENSE 2023-12-26 21:19:20 +01:00
semantic-release-bot
a50773e058
chore(release): 4.2.0 [skip ci] 2023-12-26 19:47:09 +00:00
1e0bf99ef6
feat: add string_last_position_of 2023-12-26 20:40:46 +01:00
ec6e748d24
feat: add string_position_of 2023-12-26 20:30:54 +01:00
9bb21e070f
build(deps): update latest 2023-12-26 19:42:12 +01:00
bb9c7a1668
Merge branch 'master' of github.com:theoludwig/libcproject 2023-10-23 23:02:35 +02:00
211648d29f
chore: better Prettier config for easier reviews 2023-10-23 23:02:29 +02:00
semantic-release-bot
574aeb414e
chore(release): 4.1.1 [skip ci] 2023-10-13 09:07:49 +00:00
ChepakiLeCookie
e0115dd7d9
fix: error in array_list_remove (always removed the last index and not the index given) (#6)
Co-authored-by: Maxime Rumpler <mrumpler68@gmail.com>
2023-10-13 11:04:38 +02:00
semantic-release-bot
269b1f7451
chore(release): 4.1.0 [skip ci] 2023-08-10 09:06:44 +00:00
c6df05e634
refactor: avoid usage of char*, instead use string_t 2023-08-10 00:32:49 +02:00
07e2f4db45
fix: convert numbers base to another only accept unsigned integers 2023-08-09 23:29:58 +02:00
b9ba3fbff4
docs: consistency improvements 2023-08-09 21:08:15 +02:00
7ef38fa993
chore: always use apt instead of apt-get 2023-08-09 20:29:19 +02:00
f99e4941e4
fix: correct usage of malloc and sizeof for structs 2023-08-09 20:25:03 +02:00
6505e3ba49
feat: add string_remove_character 2023-08-09 20:21:33 +02:00
f0716c2e12
docs: invalid @param for character_append 2023-08-09 20:17:54 +02:00
semantic-release-bot
78fe9ff404
chore(release): 4.0.0 [skip ci] 2023-08-08 12:24:43 +00:00
e5190818c4
perf: mutate destination string for string_concatenate
BREAKING CHANGE: Function signature changed
2023-08-07 00:42:11 +02:00
b922fd9cd3
fix: handle EXIT_FAILURE by printing error message with perror 2023-08-07 00:11:07 +02:00
72645da4b2
perf: mutate strings instead of copy when possible
BREAKING CHANGE: Most of string functions mutates the string instead of copying now.
This allows better performance when copy is not needed.
It also allows more granual control.
If copy is wanted, simply use `string_copy` before calling the function.

Impacted functions are:
`string_to_uppercase`, `string_to_lowercase`, `string_replace`,
`string_trim_start`, `string_trim_end`, `string_trim`,
`string_capitalize`, `string_reverse`
2023-08-06 23:17:07 +02:00
semantic-release-bot
01e9b71402
chore(release): 3.1.0 [skip ci] 2023-08-06 14:43:01 +00:00
5c6f4d8192
feat: improvements to filesystem_get_mimetype 2023-08-06 16:39:33 +02:00
d604288365
docs: improve usage explanations 2023-08-06 16:12:10 +02:00
dff2836bfc
feat: add filesystem_remove 2023-08-06 12:14:13 +02:00
ad0a460923
feat: add filesystem_exists 2023-08-06 12:06:43 +02:00
semantic-release-bot
be8a63ca8a
chore(release): 3.0.0 [skip ci] 2023-08-05 13:40:47 +00:00
693cab7a34
chore: only use sanitizer flags in test 2023-08-05 15:33:19 +02:00
3220c0e26b
chore: update @since version 2023-08-05 15:03:53 +02:00
06b34b115b
feat: support giving a custom character for string_trim, string_trim_start, string_trim_end
BREAKING CHANGE: Functions signatures changed.
If you want to preserve the same behavior, you should pass explictly the space character to trim:
Example: `string_trim(" Hello ")` => `string_trim(" Hello ", ' ')`
2023-08-05 14:19:44 +02:00
316dfa10e7
chore: improve Makefile to use -fsanitize=address -fsanitize=undefined gcc flags
Fixes #5
2023-08-04 19:58:41 +02:00
145dfcf546
fix: more memory issues thanks to -fsanitize=address flag
Work In Progress #5
2023-08-04 19:20:00 +02:00
d345c90ba3
style: fix linting 2023-08-04 00:02:35 +02:00
209440588d
fix: more memory issues thanks to -fsanitize=address flag
Work In Progress #5
2023-08-03 23:55:14 +02:00
a0a1310f53
feat: add hash_map_free 2023-08-03 23:17:54 +02:00
8b6f06dc6e
feat: add stack_free 2023-08-03 23:01:19 +02:00
1e475a59b1
feat: add queue_free 2023-08-03 22:57:32 +02:00
6a40df3ad1
feat: add linked_list_free 2023-08-03 19:48:02 +02:00
d231a0f055
feat: add array_list_free 2023-08-03 19:42:50 +02:00
2796dec0c7
fix: memory issues thanks to -fsanitize=address flag
Work In Progress #5
2023-08-03 19:35:44 +02:00
9717cff35a
feat: add terminal_print_array_list 2023-07-31 23:51:37 +02:00
368c07c57a
fix: char* issues with memory allocation
Work In progress #5
2023-06-26 22:32:26 +02:00
semantic-release-bot
d774ef6ad4
chore(release): 2.0.0 [skip ci] 2023-06-25 19:42:33 +00:00
e7726b8cc7
ci: install documentation tools 2023-06-25 21:39:53 +02:00
c168a7179d
ci: check all possible Makefile paths 2023-06-25 21:37:56 +02:00
c5a7bbf7c1
fix: set_version typings 2023-06-25 21:35:24 +02:00
074d9e0acb
docs: fix doxygen warnings 2023-06-25 21:32:16 +02:00
0c93355e60
chore: remove .exe file extension to be more "linux way" 2023-06-25 20:17:28 +02:00
016bfeb47f
perf: use SipHash 1-3 algorithm for hash_map 2023-06-25 20:09:07 +02:00
baea00fdac
feat!: remove dictionary data structure
Replaced by `hash_map`
2023-06-25 20:09:07 +02:00
256e9cb690
refactor: usage of hash_map instead of dictionary 2023-06-25 20:09:07 +02:00
4a11a096fa
feat: add hash_map data structure
fixes #3
2023-06-25 20:09:07 +02:00
931a0b69ce
chore: replace missing string_t 2023-06-25 20:09:07 +02:00
682997c0a5
chore: prefix all #define for includes with LIBCPROJECT 2023-06-25 20:09:07 +02:00
5f60abc759
chore: remove useless @return 2023-06-25 20:09:07 +02:00
a0140a6716
feat: add types.h 2023-06-25 20:09:07 +02:00
1ded37b106
feat!: rename types string to string_t and byte to byte_t 2023-06-25 20:08:58 +02:00
8f3ee199e5
feat: add string type 2023-06-25 15:20:38 +02:00
ce088f8ff5
feat: add byte typedef 2023-06-25 15:20:38 +02:00
eb798a619a
fix: update filesystem_read and filesystem_write signatures
BREAKING CHANGE: take a `uint8_t` for file_content instead of `char`

It makes more sense to treat files as array of "bytes", not only characters/text files.
2023-06-25 15:20:07 +02:00
b9f573bfb2
feat: support more mimetypes for filesystem_get_mimetype 2023-06-24 21:15:55 +02:00
b665e3629d
fix: handle filesystem read and write errors 2023-06-24 21:13:00 +02:00
d42ec38e36
ci: add gcc --version 2023-06-24 21:09:19 +02:00
d1b93d1da0
docs: add @since to know when a structure/function was added 2023-06-24 21:06:45 +02:00
071b645cb4
build(deps): update doxygen-awesome-css to v2.2.1 2023-06-24 20:44:48 +02:00
e5d07d73cd
ci: set dependencies version explicitly 2023-06-24 20:39:14 +02:00
d850f04069
perf: compile with -O3 gcc flag 2023-06-24 20:30:34 +02:00
20d31ba2e3
fix: update author - Théo LUDWIG 2023-06-24 20:29:30 +02:00
semantic-release-bot
f1a729c418
chore(release): 1.2.0 [skip ci] 2023-01-07 18:43:17 +00:00
Divlo
bd85171e2d
refactor: include only in header files 2023-01-07 19:41:04 +01:00
Divlo
886038a0ac
feat: add array_list data structure
fixes #2
2023-01-07 19:40:16 +01:00
Divlo
821c27c6a9
chore: minor improvements 2023-01-07 18:57:14 +01:00
semantic-release-bot
e844600214
chore(release): 1.1.2 [skip ci] 2023-01-06 17:09:41 +00:00
Divlo
ba5dddcf2f
fix: exclude release tools in documentation 2023-01-06 18:08:34 +01:00
semantic-release-bot
3b9d137df4
chore(release): 1.1.1 [skip ci] 2023-01-06 17:00:28 +00:00
Divlo
471cb862f5
fix: generate documentation after release
To have the correct version number in the documentation (version.h).
2023-01-06 17:58:15 +01:00
semantic-release-bot
892cc71391
chore(release): 1.1.0 [skip ci] 2023-01-06 16:47:43 +00:00
Divlo
86ae85f130
docs: add online documentation link 2023-01-06 17:46:23 +01:00
Divlo
3fb77f70cb
chore: add doxygen-awesome-css git submodule correctly 2023-01-06 17:42:51 +01:00
Divlo
469859001e
perf: improve Makefile to only compile changed files
fixes #4
2023-01-06 17:37:50 +01:00
Divlo
6932907f05
feat: generate documentation
fixes #1
2023-01-06 16:32:29 +01:00
Divlo
9fc4cd9139
ci: add lint-commit job 2023-01-06 14:40:15 +01:00
78 changed files with 3876 additions and 853 deletions

View File

@ -1,2 +1,2 @@
BasedOnStyle: 'Google' BasedOnStyle: "Google"
ColumnLimit: 0 ColumnLimit: 0

View File

@ -1,8 +1,8 @@
--- ---
name: '🐛 Bug Report' name: "🐛 Bug Report"
about: 'Report an unexpected problem or unintended behavior.' about: "Report an unexpected problem or unintended behavior."
title: '[Bug]' title: "[Bug]"
labels: 'bug' labels: "bug"
--- ---
<!-- <!--

View File

@ -1,8 +1,8 @@
--- ---
name: '📜 Documentation' name: "📜 Documentation"
about: 'Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...).' about: "Correct spelling errors, improvements or additions to documentation files (README, CONTRIBUTING...)."
title: '[Documentation]' title: "[Documentation]"
labels: 'documentation' labels: "documentation"
--- ---
<!-- Please make sure your issue has not already been fixed. --> <!-- Please make sure your issue has not already been fixed. -->

View File

@ -1,8 +1,8 @@
--- ---
name: '✨ Feature Request' name: "✨ Feature Request"
about: 'Suggest a new feature idea.' about: "Suggest a new feature idea."
title: '[Feature]' title: "[Feature]"
labels: 'feature request' labels: "feature request"
--- ---
<!-- Please make sure your issue has not already been fixed. --> <!-- Please make sure your issue has not already been fixed. -->

View File

@ -1,8 +1,8 @@
--- ---
name: '🔧 Improvement' name: "🔧 Improvement"
about: 'Improve structure/format/performance/refactor/tests of the code.' about: "Improve structure/format/performance/refactor/tests of the code."
title: '[Improvement]' title: "[Improvement]"
labels: 'improvement' labels: "improvement"
--- ---
<!-- Please make sure your issue has not already been fixed. --> <!-- Please make sure your issue has not already been fixed. -->

View File

@ -1,8 +1,8 @@
--- ---
name: '🙋 Question' name: "🙋 Question"
about: 'Further information is requested.' about: "Further information is requested."
title: '[Question]' title: "[Question]"
labels: 'question' labels: "question"
--- ---
### Question ### Question

View File

@ -1,6 +1,6 @@
<!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. --> <!-- Please first discuss the change you wish to make via issue before making a change. It might avoid a waste of your time. -->
## What changes this PR introduce? # What changes this PR introduce?
## List any relevant issue numbers ## List any relevant issue numbers

View File

@ -1,22 +1,40 @@
name: 'CI' name: "CI"
on: on:
push: push:
branches: [develop] branches: [develop]
pull_request: pull_request:
branches: [master, develop] branches: [main, develop]
jobs: jobs:
ci: ci:
runs-on: 'ubuntu-latest' runs-on: "ubuntu-latest"
steps: steps:
- uses: 'actions/checkout@v3.0.0' - uses: "actions/checkout@v4.1.7"
- name: 'Install Build Tools' - run: "sudo apt update"
run: 'sudo apt-get install --yes build-essential gcc make clang-format'
- run: 'make' - name: "Install Build Tools"
- run: 'make run' run: "sudo apt install --yes build-essential gcc make clang-format"
- run: 'make test'
- run: 'make lint' - name: "Install Documentation Tools"
- run: 'make clean' run: "sudo apt install --yes doxygen doxygen-gui doxygen-doc graphviz"
- run: "gcc --version"
- run: "make"
- run: "make run"
- run: "make test"
- run: "make lint"
- run: "make documentation"
- run: "make set_version"
- run: "make clean"
lint-commit:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v4.1.7"
with:
fetch-depth: 0
- uses: "wagoid/commitlint-github-action@v6.1.2"

View File

@ -1,43 +1,59 @@
name: 'Release' name: "Release"
on: on:
push: push:
branches: [master] branches: [main]
jobs: jobs:
release: release:
runs-on: 'ubuntu-latest' runs-on: "ubuntu-latest"
steps: steps:
- uses: 'actions/checkout@v3.1.0' - uses: "actions/checkout@v4.1.7"
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
submodules: "recursive"
- name: 'Import GPG key' - name: "Import GPG key"
uses: 'crazy-max/ghaction-import-gpg@v4' uses: "crazy-max/ghaction-import-gpg@v6.1.0"
with: with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
git_user_signingkey: true git_user_signingkey: true
git_commit_gpgsign: true git_commit_gpgsign: true
- name: 'Install Build Tools' - run: "sudo apt update"
run: 'sudo apt-get install --yes build-essential gcc make clang-format'
- run: 'make set_version' - name: "Install Build Tools"
run: "sudo apt install --yes build-essential gcc make clang-format"
- name: 'Use Node.js' - name: "Install Documentation Tools"
uses: 'actions/setup-node@v3.1.0' run: "sudo apt install --yes doxygen doxygen-gui doxygen-doc graphviz"
- run: "make set_version"
- name: "Use Node.js"
uses: "actions/setup-node@v4.0.3"
with: with:
node-version: 'lts/*' node-version: "20.17.0"
- name: 'Install Release Tools' - name: "Install Release Tools"
run: 'npm install --save-dev semantic-release @commitlint/cli @commitlint/config-conventional @semantic-release/git @semantic-release/exec @saithodev/semantic-release-backmerge' run: "npm install --save-dev semantic-release@23.1.1 @commitlint/cli@19.5.0 @commitlint/config-conventional@19.5.0 @semantic-release/git@10.0.1 @semantic-release/exec@6.0.3 @saithodev/semantic-release-backmerge@4.0.1 vercel@37.4.2"
- run: 'rm --force package.json package-lock.json' - run: "rm --force package.json package-lock.json"
- name: 'Release' - name: "Release"
run: 'npx semantic-release' run: "npx semantic-release"
env: env:
GH_TOKEN: ${{ secrets.GH_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN }}
GIT_COMMITTER_NAME: ${{ secrets.GIT_NAME }} GIT_COMMITTER_NAME: ${{ secrets.GIT_NAME }}
GIT_COMMITTER_EMAIL: ${{ secrets.GIT_EMAIL }} GIT_COMMITTER_EMAIL: ${{ secrets.GIT_EMAIL }}
- name: "Generate Documentation"
run: "make documentation"
- name: "Deploy to Vercel"
run: 'npx vercel ./documentation/html --token="${VERCEL_TOKEN}" --prod'
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}

4
.gitignore vendored
View File

@ -1,8 +1,10 @@
build build
bin bin
documentation
.vscode .vscode
*.out *.out
*.o *.o
*.exe
*.a *.a
node_modules node_modules
package.json
package-lock.json

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "doxygen-awesome-css"]
path = doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git

View File

@ -1,5 +1,5 @@
{ {
"branches": ["master"], "branches": ["main"],
"plugins": [ "plugins": [
[ [
"@semantic-release/commit-analyzer", "@semantic-release/commit-analyzer",
@ -16,7 +16,7 @@
[ [
"@semantic-release/exec", "@semantic-release/exec",
{ {
"prepareCmd": "make set_version && ./bin/set_version.exe ${nextRelease.version}" "prepareCmd": "make set_version && ./bin/set_version ${nextRelease.version}"
} }
], ],
[ [
@ -30,7 +30,7 @@
[ [
"@saithodev/semantic-release-backmerge", "@saithodev/semantic-release-backmerge",
{ {
"branches": [{ "from": "master", "to": "develop" }], "branches": [{ "from": "main", "to": "develop" }],
"backmergeStrategy": "merge" "backmergeStrategy": "merge"
} }
] ]

View File

@ -60,7 +60,7 @@ representative at an online or offline event.
Instances of abusive, harassing, or otherwise unacceptable behavior may be Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at reported to the community leaders responsible for enforcement at
contact@divlo.fr. <contact@theoludwig.fr>.
All complaints will be reviewed and investigated promptly and fairly. All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the All community leaders are obligated to respect the privacy and security of the

View File

@ -2,6 +2,14 @@
Thanks a lot for your interest in contributing to **libcproject**! 🎉 Thanks a lot for your interest in contributing to **libcproject**! 🎉
## Code of Conduct
**libcproject** adopted the [Contributor Covenant](https://www.contributor-covenant.org/) as its Code of Conduct, and we expect project participants to adhere to it. Please read [the full text](./CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated.
## Open Development
All work on **libcproject** happens directly on this repository. Both core team members and external contributors send pull requests which go through the same review process.
## Types of contributions ## Types of contributions
- Reporting a bug. - Reporting a bug.
@ -11,7 +19,7 @@ Thanks a lot for your interest in contributing to **libcproject**! 🎉
## Pull Requests ## Pull Requests
- **Please first discuss** the change you wish to make via [issue](https://github.com/Divlo/libcproject/issues) before making a change. It might avoid a waste of your time. - **Please first discuss** the change you wish to make via [issue](https://github.com/theoludwig/libcproject/issues) before making a change. It might avoid a waste of your time.
- Ensure your code respect linting. - Ensure your code respect linting.
@ -21,26 +29,19 @@ If you're adding new features to **libcproject**, please include tests.
## Commits ## Commits
The commit message guidelines respect [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) and [Semantic Versioning](https://semver.org/) for releases. The commit message guidelines adheres to [Conventional Commits](https://www.conventionalcommits.org/) and [Semantic Versioning](https://semver.org/) for releases.
### Types ## Git Submodules
Types define which kind of changes you made to the project. To get the submodule:
| Types | Description | ```sh
| -------- | ------------------------------------------------------------------------------------------------------------ | git submodule update --init --recursive
| feat | A new feature. | ```
| fix | A bug fix. |
| docs | Documentation only changes. |
| style | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc). |
| refactor | A code change that neither fixes a bug nor adds a feature. |
| perf | A code change that improves performance. |
| test | Adding missing tests or correcting existing tests. |
| build | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm). |
| ci | Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs). |
| chore | Other changes that don't modify src or test files. |
| revert | Reverts a previous commit. |
### Scopes To update the version:
Scopes define what part of the code changed. ```sh
cd doxygen-awesome-css
git checkout v2.3.3
```

31
Doxyfile Normal file
View File

@ -0,0 +1,31 @@
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = libcproject
PROJECT_BRIEF = "C static library easier to use than libc (C standard library)."
OUTPUT_DIRECTORY = documentation
OUTPUT_LANGUAGE = English
OPTIMIZE_OUTPUT_FOR_C = YES
INPUT = ./
INPUT_ENCODING = UTF-8
USE_MDFILE_AS_MAINPAGE = README.md
FILE_PATTERNS = *.h \
README.md \
CODE_OF_CONDUCT.md \
CONTRIBUTING.md \
LICENSE
HTML_EXTRA_STYLESHEET = doxygen-awesome-css/doxygen-awesome.css
RECURSIVE = YES
EXCLUDE = test doxygen-awesome-css node_modules
GENERATE_LATEX = NO
GENERATE_TREEVIEW = YES
EXAMPLE_PATTERNS = *
SOURCE_BROWSER = YES
INLINE_SIMPLE_STRUCTS = YES
EXTRACT_ALL = YES
EXTRACT_STATIC = YES
SORT_MEMBER_DOCS = NO
FULL_SIDEBAR = NO
DISABLE_INDEX = NO
INLINE_SOURCES = YES
LAYOUT_FILE = DoxygenLayout.xml
HTML_INDEX_NUM_ENTRIES = 1

57
DoxygenLayout.xml Normal file
View File

@ -0,0 +1,57 @@
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.9.1 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title=""/>
<tab type="pages" visible="yes" title="" intro=""/>
<tab type="filelist" visible="yes" title="" intro=""/>
</navindex>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<interfaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<structs visible="yes" title=""/>
<exceptions visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<sequences title=""/>
<dictionaries title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>

View File

@ -1,6 +1,6 @@
MIT License # MIT License
Copyright (c) Divlo Copyright (c) Théo LUDWIG <contact@theoludwig.fr>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,44 +1,59 @@
LIBRARY_NAME = libcproject LIBRARY_NAME = libcproject
CC = gcc CC = gcc
CC_FLAGS = -Wall -Wextra -Wfloat-equal -Wundef -Werror -std=c17 -pedantic -pedantic-errors -I./ CC_FLAGS = -Wall -Wextra -Wfloat-equal -Wundef -Werror -std=c17 -pedantic -pedantic-errors -O3 -I./
CC_SANITIZER_FLAGS = -fsanitize=address -fsanitize=undefined
LIB = ./build/${LIBRARY_NAME}.a LIB = ./build/${LIBRARY_NAME}.a
LIB_CC_FLAGS = -L. -l:${LIB} LIB_CC_FLAGS = -L. -l:${LIB}
LIB_SOURCES = $(wildcard lib/*.c) LIB_SOURCES = $(wildcard lib/*.c)
LIB_OBJECTS = $(patsubst %.c, %.o, $(LIB_SOURCES))
TEST_SOURCES = $(wildcard test/*.c) TEST_SOURCES = $(wildcard test/*.c)
TEST_OBJECTS = $(patsubst %.c, %.o, $(TEST_SOURCES))
HEADER_FILES = $(wildcard lib/*.h) $(wildcard test/*.h) ./${LIBRARY_NAME}.h HEADER_FILES = $(wildcard lib/*.h) $(wildcard test/*.h) ./${LIBRARY_NAME}.h
MAIN_EXECUTABLE = bin/main.exe MAIN_EXECUTABLE = bin/main
SET_VERSION_EXECUTABLE = bin/set_version.exe SET_VERSION_EXECUTABLE = bin/set_version
TEST_EXECUTABLE = bin/test.exe TEST_EXECUTABLE = bin/test
.PHONY: all ${LIB}: $(addprefix build/, ${LIB_OBJECTS})
all: ${LIB_SOURCES}
mkdir --parents ./build
${CC} ${CC_FLAGS} -c ${LIB_SOURCES}
rm --force ${LIB} rm --force ${LIB}
ar -rcs ${LIB} *.o ar -rcs ${LIB} $(addprefix build/, ${LIB_OBJECTS})
rm --recursive --force *.o
build/lib:
mkdir --parents ./build/lib
build/test:
mkdir --parents ./build/test
build/lib/%.o: lib/%.c ${HEADER_FILES} | build/lib
${CC} ${CC_FLAGS} -c $< -o $@
build/test/%.o: test/%.c ${HEADER_FILES} | build/test
${CC} ${CC_FLAGS} -c $< -o $@
.PHONY: run .PHONY: run
run: all ./main.c run: ${LIB} ./main.c
mkdir --parents ./bin mkdir --parents ./bin
${CC} ${CC_FLAGS} -o ${MAIN_EXECUTABLE} ./main.c ${LIB_CC_FLAGS} ${CC} ${CC_FLAGS} ${CC_SANITIZER_FLAGS} -o ${MAIN_EXECUTABLE} ./main.c ${LIB_CC_FLAGS}
./${MAIN_EXECUTABLE} ${ARGS} ./${MAIN_EXECUTABLE} ${ARGS}
.PHONY: set_version .PHONY: set_version
set_version: all ./set_version.c set_version: ${LIB} ./set_version.c
mkdir --parents ./bin mkdir --parents ./bin
${CC} ${CC_FLAGS} -o ${SET_VERSION_EXECUTABLE} ./set_version.c ${LIB_CC_FLAGS} ${CC} ${CC_FLAGS} ${CC_SANITIZER_FLAGS} -o ${SET_VERSION_EXECUTABLE} ./set_version.c ${LIB_CC_FLAGS}
.PHONY: test .PHONY: test
test: all ${TEST_SOURCES} test: ${LIB} $(addprefix build/, ${TEST_OBJECTS})
mkdir --parents ./bin mkdir --parents ./bin
${CC} ${CC_FLAGS} -o ${TEST_EXECUTABLE} ${TEST_SOURCES} ${LIB_CC_FLAGS} ${CC} ${CC_FLAGS} ${CC_SANITIZER_FLAGS} -o ${TEST_EXECUTABLE} $(addprefix build/, ${TEST_OBJECTS}) ${LIB_CC_FLAGS}
./${TEST_EXECUTABLE} ./${TEST_EXECUTABLE} ${ARGS}
.PHONY: lint .PHONY: lint
lint: lint:
clang-format --Werror --dry-run ${LIB_SOURCES} ${TEST_SOURCES} ${HEADER_FILES} ./main.c clang-format --Werror --dry-run ${LIB_SOURCES} ${TEST_SOURCES} ${HEADER_FILES} ./main.c
.PHONY: documentation
documentation:
doxygen ./Doxyfile
.PHONY: clean .PHONY: clean
clean: clean:
rm --recursive --force ./build ./bin *.out *.o *.exe *.a rm --recursive --force ./build ./bin ./documentation

View File

@ -5,11 +5,11 @@
</p> </p>
<p align="center"> <p align="center">
<a href="./CONTRIBUTING.md"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" /></a> <a href="./CONTRIBUTING.md"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat" alt="Contributing" /></a>
<a href="./LICENSE"><img src="https://img.shields.io/badge/licence-MIT-blue.svg" alt="Licence MIT"/></a> <a href="./LICENSE"><img src="https://img.shields.io/badge/licence-MIT-blue.svg" alt="Licence MIT"/></a>
<a href="./CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg" alt="Contributor Covenant" /></a> <a href="./CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg" alt="Contributor Covenant" /></a>
<br /> <br />
<a href="https://github.com/Divlo/libcproject/actions/workflows/ci.yml"><img src="https://github.com/Divlo/libcproject/actions/workflows/ci.yml/badge.svg?branch=develop" /></a> <a href="https://github.com/theoludwig/libcproject/actions/workflows/ci.yml"><img src="https://github.com/theoludwig/libcproject/actions/workflows/ci.yml/badge.svg?branch=develop" alt="CI" /></a>
<a href="https://conventionalcommits.org"><img src="https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg" alt="Conventional Commits" /></a> <a href="https://conventionalcommits.org"><img src="https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg" alt="Conventional Commits" /></a>
<a href="https://github.com/semantic-release/semantic-release"><img src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg" alt="semantic-release" /></a> <a href="https://github.com/semantic-release/semantic-release"><img src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg" alt="semantic-release" /></a>
</p> </p>
@ -20,7 +20,9 @@
C is a low-level programming language and we often end up reinventing the wheel as the C standard library (`libc`) is quite small and in my humble opinion, not well designed. C is a low-level programming language and we often end up reinventing the wheel as the C standard library (`libc`) is quite small and in my humble opinion, not well designed.
**libcproject** solve this by providing common functions or data structures (`dictionary`, `linked_list`, `queue`, `stack`, etc.) we might need in our C projects. **libcproject** solve this by providing common functions or data structures (`hash_map`, `array_list`, `linked_list`, `queue`, `stack`, etc.), we might need in our C projects.
[Online documentation](https://libcproject.vercel.app/).
## Prerequisites ## Prerequisites
@ -28,12 +30,17 @@ C is a low-level programming language and we often end up reinventing the wheel
- [GNU binutils](https://www.gnu.org/software/binutils/) - [GNU binutils](https://www.gnu.org/software/binutils/)
- [GNU gcc](https://gcc.gnu.org/) - [GNU gcc](https://gcc.gnu.org/)
- [GNU make](https://www.gnu.org/software/make/) - [GNU make](https://www.gnu.org/software/make/)
- [clang-format](https://clang.llvm.org/docs/ClangFormat.html) - [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html)
- [Doxygen](https://www.doxygen.nl/)
For example on GNU/Linux Ubuntu: For example on GNU/Linux Ubuntu:
```sh ```sh
sudo apt-get install build-essential gcc make clang-format # Install Build Tools
sudo apt install build-essential gcc make clang-format
# Install Documentation Tools
sudo apt install doxygen doxygen-gui doxygen-doc graphviz
``` ```
## Usage ## Usage
@ -43,6 +50,7 @@ make # to compile
make run # to run main make run # to run main
make test # to run unit tests make test # to run unit tests
make lint # to lint the code make lint # to lint the code
make documentation # to generate the documentation
make clean # to clean up make clean # to clean up
nm ./build/libcproject.a # to see the symbols nm ./build/libcproject.a # to see the symbols
@ -50,31 +58,30 @@ nm ./build/libcproject.a # to see the symbols
Steps to create a new C project that uses `libcproject`: Steps to create a new C project that uses `libcproject`:
### Step 1: Compile `libcproject` ### Step 1: Create a new project
```sh
make
```
### Step 2: Create a new project
```sh ```sh
mkdir my-project mkdir my-project
cd my-project cd my-project
``` ```
### Step 3: Install `libcproject` in the project ### Step 2: Install and Compile `libcproject` in the project
```sh ```sh
mkdir libcproject # Clone the repository
cp --recursive <path-to-libcproject> ./ # copy git clone git@github.com:theoludwig/libcproject.git
# or
ln -s <path-to-libcproject> ./ # symbolic link # Go to libcproject directory
cd libcproject
# Compile the library
make
``` ```
### Step 4: Create a new C file ### Step 3: Create a new C file
```sh ```sh
cd ..
touch main.c touch main.c
``` ```
@ -85,17 +92,17 @@ touch main.c
#include "libcproject/libcproject.h" #include "libcproject/libcproject.h"
int main() { int main() {
char* string = "Hello, world!"; string_t string = "Hello, world!"; // `string_t` is a typedef from `libcproject`
printf("%s\n", string); printf("%s\n", string);
printf("string_length = %ld\n", string_get_length(string)); // `string_get_length` is a function from `libcproject` printf("string_length = %ld\n", string_get_length(string)); // `string_get_length` is a function from `libcproject`
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
``` ```
### Step 5: Compile your project and link it with the library ### Step 4: Compile your project and link it with the library
```sh ```sh
gcc -o ./main.exe ./main.c -L. -l:./libcproject/build/libcproject.a gcc -o ./main ./main.c -L. -l:./libcproject/build/libcproject.a
``` ```
## 💡 Contributing ## 💡 Contributing

1
doxygen-awesome-css Submodule

@ -0,0 +1 @@
Subproject commit 40e9b25b6174dd3b472d8868f63323a870dfeeb8

61
lib/array_list.c Normal file
View File

@ -0,0 +1,61 @@
#include "array_list.h"
struct array_list* array_list_initialization() {
return array_list_initialization_with_capacity(ARRAY_LIST_INITIAL_CAPACITY);
}
struct array_list* array_list_initialization_with_capacity(size_t capacity) {
struct array_list* list = malloc(sizeof(struct array_list));
if (list == NULL) {
perror("Error (array_list_initialization)");
exit(EXIT_FAILURE);
}
list->size = 0;
list->capacity = capacity;
list->capacity_step = capacity;
list->data = malloc(sizeof(void*) * list->capacity);
if (list->data == NULL) {
perror("Error (array_list_initialization)");
exit(EXIT_FAILURE);
}
return list;
}
void array_list_add(struct array_list* list, void* element) {
if (list->size >= list->capacity) {
size_t previous_capacity = list->capacity;
list->capacity += list->capacity_step;
list->data = realloc(list->data, sizeof(void*) * list->capacity);
if (list->data == NULL) {
perror("Error (array_list_add)");
exit(EXIT_FAILURE);
}
for (size_t index = previous_capacity; index < list->capacity; index++) {
list->data[index] = NULL;
}
}
list->data[list->size] = element;
list->size++;
}
void array_list_remove(struct array_list* list, size_t index) {
if (index >= list->size) {
return;
}
for (size_t i = index; i < list->size - 1; i++) {
list->data[i] = list->data[i + 1];
}
list->size--;
}
void* array_list_get(struct array_list* list, size_t index) {
if (index >= list->size) {
return NULL;
}
return list->data[index];
}
void array_list_free(struct array_list* list) {
free(list->data);
free(list);
}

72
lib/array_list.h Normal file
View File

@ -0,0 +1,72 @@
#ifndef __LIBCPROJECT_ARRAY_LIST__
#define __LIBCPROJECT_ARRAY_LIST__
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "types.h"
#define ARRAY_LIST_INITIAL_CAPACITY 10
/**
* @brief A dynamic array implementation.
* @since v1.2.0
*/
struct array_list {
void** data;
size_t size;
size_t capacity;
size_t capacity_step;
};
/**
* @brief Initializes a new array list.
* @since v1.2.0
*/
struct array_list* array_list_initialization();
/**
* @brief Initializes a new array list with a capacity.
* @since v5.0.0
*/
struct array_list* array_list_initialization_with_capacity(size_t capacity);
/**
* @brief Adds an element to the end of the array list.
*
* @param list
* @param element
* @since v1.2.0
*/
void array_list_add(struct array_list* list, void* element);
/**
* @brief Removes an element from the array list.
*
* @param list
* @param index
* @since v1.2.0
*/
void array_list_remove(struct array_list* list, size_t index);
/**
* @brief Gets an element from the array list.
*
* @param list
* @param index
* @return void*
* @since v1.2.0
*/
void* array_list_get(struct array_list* list, size_t index);
/**
* @brief Frees the array list.
*
* @param list
* @since v3.0.0
*/
void array_list_free(struct array_list* list);
#endif

17
lib/assert.c Normal file
View File

@ -0,0 +1,17 @@
#include "assert.h"
bool assert_string_equal(const string_t actual, const string_t expected) {
if (!string_equals(actual, expected)) {
printf("FAIL: expected = \"%s\" ; actual = \"%s\"\n", expected, actual);
return false;
}
return true;
}
bool assert_string_not_equal(const string_t actual, const string_t expected) {
if (string_equals(actual, expected)) {
printf("FAIL: expected = \"%s\" ; actual = \"%s\"\n", expected, actual);
return false;
}
return true;
}

30
lib/assert.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef __LIBCPROJECT_ASSERT__
#define __LIBCPROJECT_ASSERT__
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include "string.h"
#include "types.h"
/**
* @brief Check if the two strings are equal. If they are not equal, print the expected and actual strings.
*
* @param character
* @return bool
* @since v5.0.0
*/
bool assert_string_equal(const string_t actual, const string_t expected);
/**
* @brief Check if the two strings are not equal. If they are equal, print the expected and actual strings.
*
* @param character
* @return bool
* @since v5.0.0
*/
bool assert_string_not_equal(const string_t actual, const string_t expected);
#endif

View File

@ -1,16 +1,11 @@
#include "character.h" #include "character.h"
#include <stdbool.h> void character_append(string_t string, const char character) {
#include <stdlib.h>
#include "string.h"
void character_append(char* string, const char character) {
size_t length = string_get_length(string); size_t length = string_get_length(string);
character_append_at(string, character, length); character_append_at(string, character, length);
} }
void character_append_at(char* string, const char character, const size_t index) { void character_append_at(string_t string, const char character, const size_t index) {
size_t length = string_get_length(string); size_t length = string_get_length(string);
for (size_t index_string = length; index_string > index; index_string--) { for (size_t index_string = length; index_string > index; index_string--) {
string[index_string] = string[index_string - 1]; string[index_string] = string[index_string - 1];
@ -37,9 +32,9 @@ bool character_get_is_digit(const char character) {
return character >= '0' && character <= '9'; return character >= '0' && character <= '9';
} }
unsigned char character_get_alphabet_position(const char character) { uint8_t character_get_alphabet_position(const char character) {
const char letter = character_to_lower(character); const char letter = character_to_lower(character);
unsigned char position = 0; uint8_t position = 0;
if (letter >= 'a' && letter <= 'z') { if (letter >= 'a' && letter <= 'z') {
position = (letter - 'a') + 1; position = (letter - 'a') + 1;
} }

View File

@ -1,17 +1,22 @@
#ifndef __CHARACTER__ #ifndef __LIBCPROJECT_CHARACTER__
#define __CHARACTER__ #define __LIBCPROJECT_CHARACTER__
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#include "string.h"
#include "types.h"
/** /**
* @brief Append a character to a string, assuming string points to an array * @brief Append a character to a string, assuming string points to an array
* with enough space. * with enough space.
* *
* @param string * @param string
* @param character * @param character
* @since v1.0.0
*/ */
void character_append(char* string, char character); void character_append(string_t string, char character);
/** /**
* @brief Append a character to a string at a specific index, assuming string points to an array with enough space. * @brief Append a character to a string at a specific index, assuming string points to an array with enough space.
@ -19,14 +24,15 @@ void character_append(char* string, char character);
* @param string * @param string
* @param character * @param character
* @param index * @param index
* @since v1.0.0
*/ */
void character_append_at(char* string, const char character, const size_t index); void character_append_at(string_t string, const char character, const size_t index);
/** /**
* @brief Converts the character to uppercase. * @brief Converts the character to uppercase.
* *
* @param character * @param character
* @return const char * @since v1.0.0
*/ */
char character_to_upper(const char character); char character_to_upper(const char character);
@ -34,16 +40,16 @@ char character_to_upper(const char character);
* @brief Converts the character to lowercase. * @brief Converts the character to lowercase.
* *
* @param character * @param character
* @return const char * @since v1.0.0
*/ */
char character_to_lower(const char character); char character_to_lower(const char character);
/** /**
* @brief Check if the character is a digit ('0', '1', '2', '3', '4', '5', '6', '7, '8' or '9'). * @brief Check if the character is a digit ('0', '1', '2', '3', '4', '5', '6', '7, '8' or '9').
* *
* @param string1 * @param character
* @param string2 * @return bool
* @return true if the character is a digit, false otherwise * @since v1.0.0
*/ */
bool character_get_is_digit(const char character); bool character_get_is_digit(const char character);
@ -52,8 +58,9 @@ bool character_get_is_digit(const char character);
* Return 0 if the character is not a letter. * Return 0 if the character is not a letter.
* *
* @param character * @param character
* @return char * @return uint8_t
* @since v1.0.0
*/ */
unsigned char character_get_alphabet_position(const char character); uint8_t character_get_alphabet_position(const char character);
#endif #endif

View File

@ -1,19 +1,13 @@
#include "convert.h" #include "convert.h"
#include <stdio.h> string_t convert_character_to_string(const char character) {
#include <stdlib.h> string_t string = malloc(sizeof(char) * 2);
#include "character.h"
#include "mathematics.h"
#include "stdbool.h"
#include "string.h"
char* convert_character_to_string(const char character) {
char* string = malloc(sizeof(char*) * 2);
if (string == NULL) { if (string == NULL) {
perror("Error (convert_character_to_string)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
character_append(string, character); string[0] = character;
string[1] = '\0';
return string; return string;
} }
@ -25,9 +19,9 @@ char convert_digit_to_character(const char digit) {
return digit + '0'; return digit + '0';
} }
long long convert_string_to_number(const char* string) { int64_t convert_string_to_number(const string_t string) {
bool is_negative = string[0] == '-'; bool is_negative = string[0] == '-';
long long integer = 0; int64_t integer = 0;
size_t length = string_get_length(string); size_t length = string_get_length(string);
for (size_t index = is_negative ? 1 : 0; index < length; index++) { for (size_t index = is_negative ? 1 : 0; index < length; index++) {
integer = integer * 10 + convert_character_to_digit(string[index]); integer = integer * 10 + convert_character_to_digit(string[index]);
@ -35,46 +29,54 @@ long long convert_string_to_number(const char* string) {
return is_negative ? integer * -1 : integer; return is_negative ? integer * -1 : integer;
} }
char* convert_number_to_string(const long long integer) { string_t convert_number_to_string(const int64_t integer) {
if (integer == 0) { if (integer == 0) {
return convert_character_to_string('0'); return convert_character_to_string('0');
} }
bool is_negative = integer < 0; bool is_negative = integer < 0;
size_t length = 1; size_t length = 1;
char* string = malloc(sizeof(char*) * length); int64_t current = mathematics_absolute_value(integer);
if (string == NULL) {
exit(EXIT_FAILURE);
}
long long current = mathematics_absolute_value(integer);
while (current != 0) { while (current != 0) {
character_append(string, convert_digit_to_character(current % 10));
current = current / 10; current = current / 10;
length++; length++;
string = realloc(string, sizeof(char*) * length);
} }
if (is_negative) { if (is_negative) {
character_append(string, '-');
length++; length++;
string = realloc(string, sizeof(char*) * length);
} }
return string_reverse(string); string_t string = malloc(sizeof(char) * length);
if (string == NULL) {
perror("Error (convert_number_to_string)");
exit(EXIT_FAILURE);
}
current = mathematics_absolute_value(integer);
size_t index = 0;
while (current != 0) {
string[index++] = convert_digit_to_character(current % 10);
current = current / 10;
}
if (is_negative) {
string[index++] = '-';
}
string[index] = '\0';
string_reverse(string);
return string;
} }
char* convert_number_from_base_10_to_base(unsigned long long number, unsigned int base) { string_t convert_number_from_base_10_to_base(uint64_t number, uint64_t base) {
if (number == 0) { if (number == 0) {
return "0"; return "0";
} }
int remainders[64]; int64_t remainders[64];
int index = 0; int64_t index = 0;
while (number > 0) { while (number > 0) {
remainders[index] = number % base; remainders[index] = number % base;
number = number / base; number = number / base;
index++; index++;
} }
char* result = malloc(sizeof(char) * (index + 1)); string_t result = malloc(sizeof(char) * (index + 1));
int index_result = 0; int64_t index_result = 0;
for (int iteration = index - 1; iteration >= 0; iteration--) { for (int64_t iteration = index - 1; iteration >= 0; iteration--) {
int remainder = remainders[iteration]; int64_t remainder = remainders[iteration];
if (remainder >= 10) { if (remainder >= 10) {
result[index_result] = (char)((remainder - 10) + 'A'); result[index_result] = (char)((remainder - 10) + 'A');
} else { } else {
@ -82,20 +84,21 @@ char* convert_number_from_base_10_to_base(unsigned long long number, unsigned in
} }
index_result++; index_result++;
} }
result[index_result] = '\0';
return result; return result;
} }
int convert_number_from_base_to_base_10(char* number, unsigned int base) { uint64_t convert_number_from_base_to_base_10(string_t number, uint64_t base) {
int length = string_get_length(number); size_t length = string_get_length(number);
int exponent = length - 1; int64_t exponent = length - 1;
int result = 0; uint64_t result = 0;
int index = 0; int64_t index = 0;
while (exponent >= 0) { while (exponent >= 0) {
int current_number = (int)(number[index] - '0'); int64_t current_number = (int64_t)(number[index] - '0');
if (current_number >= 10) { if (current_number >= 10) {
current_number = (int)(number[index] - 'A') + 10; current_number = (int64_t)(number[index] - 'A') + 10;
} else { } else {
current_number = (int)(number[index] - '0'); current_number = (int64_t)(number[index] - '0');
} }
result = result + current_number * mathematics_pow(base, exponent); result = result + current_number * mathematics_pow(base, exponent);
exponent--; exponent--;
@ -104,6 +107,6 @@ int convert_number_from_base_to_base_10(char* number, unsigned int base) {
return result; return result;
} }
char* convert_number_from_base_to_another(char* number, int base_from, int base_target) { string_t convert_number_from_base_to_another(string_t number, uint64_t base_from, uint64_t base_target) {
return convert_number_from_base_10_to_base(convert_number_from_base_to_base_10(number, base_from), base_target); return convert_number_from_base_10_to_base(convert_number_from_base_to_base_10(number, base_from), base_target);
} }

View File

@ -1,20 +1,90 @@
#ifndef __CONVERT__ #ifndef __LIBCPROJECT_CONVERT__
#define __CONVERT__ #define __LIBCPROJECT_CONVERT__
char* convert_character_to_string(const char character); #include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "character.h"
#include "mathematics.h"
#include "stdbool.h"
#include "string.h"
#include "types.h"
/**
* @brief Convert a character to a string.
*
* @param character
* @return string_t
* @since v1.0.0
*/
string_t convert_character_to_string(const char character);
/**
* @brief Convert a character to a digit.
*
* @param character
* @return char
* @since v1.0.0
*/
char convert_character_to_digit(const char character); char convert_character_to_digit(const char character);
/**
* @brief Convert a digit to a character.
*
* @param digit
* @return char
* @since v1.0.0
*/
char convert_digit_to_character(const char digit); char convert_digit_to_character(const char digit);
long long convert_string_to_number(const char* string); /**
* @brief Convert a string to a number.
*
* @param string
* @return int64_t
* @since v1.0.0
*/
int64_t convert_string_to_number(const string_t string);
char* convert_number_to_string(const long long integer); /**
* @brief Convert a number to a string.
*
* @param integer
* @return string_t
* @since v1.0.0
*/
string_t convert_number_to_string(const int64_t integer);
char* convert_number_from_base_10_to_base(unsigned long long number, unsigned int base); /**
* @brief Convert a number (base 10) to a string with a specific base.
*
* @param number
* @param base
* @return string_t
* @since v1.0.0
*/
string_t convert_number_from_base_10_to_base(uint64_t number, uint64_t base);
int convert_number_from_base_to_base_10(char* number, unsigned int base); /**
* @brief Convert a number with a specific base to a number base 10.
*
* @param number
* @param base
* @return uint64_t
* @since v1.0.0
*/
uint64_t convert_number_from_base_to_base_10(string_t number, uint64_t base);
char* convert_number_from_base_to_another(char* number, int base_from, int base_target); /**
* @brief Convert a number with a specific base to a number of specific base.
*
* @param number
* @param base_from
* @param base_target
* @return string_t
* @since v1.0.0
*/
string_t convert_number_from_base_to_another(string_t number, uint64_t base_from, uint64_t base_target);
#endif #endif

339
lib/date.c Normal file
View File

@ -0,0 +1,339 @@
#include "date.h"
struct date *date_copy(struct date *date_to_copy) {
struct date *date = malloc(sizeof(struct date));
if (date == NULL) {
perror("Error (date_copy)");
exit(EXIT_FAILURE);
}
date->year = date_to_copy->year;
date->month = date_to_copy->month;
date->day = date_to_copy->day;
date->hours = date_to_copy->hours;
date->minutes = date_to_copy->minutes;
date->seconds = date_to_copy->seconds;
date->milliseconds = date_to_copy->milliseconds;
date->timezone_utc_offset = date_to_copy->timezone_utc_offset;
return date;
}
bool date_get_is_valid_year(uint16_t year) {
return year <= 9999;
}
bool date_get_is_valid_month(uint8_t month) {
return month >= 1 && month <= 12;
}
bool date_get_is_valid_day(uint8_t day) {
return day >= 1 && day <= 31;
}
bool date_get_is_valid_hours(uint8_t hours) {
return hours <= 23;
}
bool date_get_is_valid_minutes(uint8_t minutes) {
return minutes <= 59;
}
bool date_get_is_valid_seconds(uint8_t seconds) {
return seconds <= 59;
}
bool date_get_is_valid_milliseconds(uint16_t milliseconds) {
return milliseconds <= 999;
}
bool date_get_is_valid_timezone_utc_offset(int8_t timezone_utc_offset) {
return timezone_utc_offset >= -12 && timezone_utc_offset <= 14;
}
bool date_get_is_valid(struct date *date) {
size_t date_days_of_month = date_get_days_of_month(date->month, date->year);
return (date_get_is_valid_month(date->month) &&
date_get_is_valid_day(date->day) &&
date->day <= date_days_of_month &&
date_get_is_valid_hours(date->hours) &&
date_get_is_valid_minutes(date->minutes) &&
date_get_is_valid_seconds(date->seconds) &&
date_get_is_valid_milliseconds(date->milliseconds) &&
date_get_is_valid_timezone_utc_offset(date->timezone_utc_offset));
}
string_t date_to_iso_string(struct date *date_original) {
struct date *date = date_copy(date_original);
date_to_utc(date);
size_t iso_string_length = 24;
string_t result = malloc(sizeof(char) * (iso_string_length + 1));
string_t year_string = string_zero_pad(date->year, 4);
string_t month_string = string_zero_pad(date->month, 2);
string_t day_string = string_zero_pad(date->day, 2);
string_t hours_string = string_zero_pad(date->hours, 2);
string_t minutes_string = string_zero_pad(date->minutes, 2);
string_t seconds_string = string_zero_pad(date->seconds, 2);
string_t milliseconds_string = string_zero_pad(date->milliseconds, 3);
sprintf(result, "%s-%s-%sT%s:%s:%s.%sZ", year_string, month_string, day_string, hours_string, minutes_string, seconds_string, milliseconds_string);
free(year_string);
free(month_string);
free(day_string);
free(hours_string);
free(minutes_string);
free(seconds_string);
free(milliseconds_string);
free(date);
return result;
}
string_t date_to_iso_string_without_time(struct date *date) {
size_t iso_string_length = 10;
string_t result = malloc(sizeof(char) * (iso_string_length + 1));
if (result == NULL) {
perror("Error (date_to_iso_string_without_time)");
exit(EXIT_FAILURE);
}
string_t year_string = string_zero_pad(date->year, 4);
string_t month_string = string_zero_pad(date->month, 2);
string_t day_string = string_zero_pad(date->day, 2);
sprintf(result, "%s-%s-%s", year_string, month_string, day_string);
free(year_string);
free(month_string);
free(day_string);
return result;
}
struct date *date_from_iso_string(string_t iso_string) {
struct date *date = malloc(sizeof(struct date));
if (date == NULL) {
perror("Error (date_from_iso_string)");
exit(EXIT_FAILURE);
}
string_t year_string = string_substring(iso_string, 0, 3);
date->year = (uint16_t)convert_string_to_number(year_string);
free(year_string);
string_t month_string = string_substring(iso_string, 5, 6);
date->month = (uint8_t)convert_string_to_number(month_string);
free(month_string);
string_t day_string = string_substring(iso_string, 8, 9);
date->day = (uint8_t)convert_string_to_number(day_string);
free(day_string);
string_t hours_string = string_substring(iso_string, 11, 12);
date->hours = (uint8_t)convert_string_to_number(hours_string);
free(hours_string);
string_t minutes_string = string_substring(iso_string, 14, 15);
date->minutes = (uint8_t)convert_string_to_number(minutes_string);
free(minutes_string);
string_t seconds_string = string_substring(iso_string, 17, 18);
date->seconds = (uint8_t)convert_string_to_number(seconds_string);
free(seconds_string);
string_t milliseconds_string = string_substring(iso_string, 20, 22);
date->milliseconds = (uint16_t)convert_string_to_number(milliseconds_string);
free(milliseconds_string);
date->timezone_utc_offset = 0;
return date;
}
uint8_t date_get_days_of_month(uint8_t month, uint16_t year) {
switch (month) {
case 1:
return 31;
case 2:
return date_get_is_leap_year(year) ? 29 : 28;
case 3:
return 31;
case 4:
return 30;
case 5:
return 31;
case 6:
return 30;
case 7:
return 31;
case 8:
return 31;
case 9:
return 30;
case 10:
return 31;
case 11:
return 30;
case 12:
return 31;
default:
return 0;
}
}
bool date_get_is_leap_year(uint16_t year) {
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
uint64_t date_convert_milliseconds_to_seconds(uint16_t milliseconds) {
return milliseconds / MILLISECONDS_PER_SECOND;
}
uint64_t date_convert_seconds_to_milliseconds(uint64_t seconds) {
return seconds * MILLISECONDS_PER_SECOND;
}
uint64_t date_convert_days_to_seconds(uint64_t days) {
return days * SECONDS_PER_DAY;
}
uint64_t date_convert_hms_to_seconds(uint8_t hours, uint8_t minutes, uint8_t seconds) {
return (hours * SECONDS_PER_HOUR) + (minutes * SECONDS_PER_MINUTE) + seconds;
}
uint64_t date_to_total_seconds(struct date *date) {
uint64_t total_seconds = 0;
for (uint16_t year = 0; year < date->year; year++) {
total_seconds += 365 * SECONDS_PER_DAY;
if (date_get_is_leap_year(year)) {
total_seconds += SECONDS_PER_DAY;
}
}
for (uint8_t month = 1; month < date->month; month++) {
total_seconds += date_convert_days_to_seconds(date_get_days_of_month(month, date->year));
}
total_seconds += date_convert_days_to_seconds(date->day - 1);
total_seconds += date_convert_hms_to_seconds(date->hours, date->minutes, date->seconds);
return total_seconds;
}
uint64_t date_duration_seconds_between_2_dates(struct date *date1, struct date *date2) {
struct date *utc_date1 = date_copy(date1);
struct date *utc_date2 = date_copy(date2);
date_to_utc(utc_date1);
date_to_utc(utc_date2);
uint64_t total_seconds_date1 = date_to_total_seconds(utc_date1);
uint64_t total_seconds_date2 = date_to_total_seconds(utc_date2);
free(utc_date1);
free(utc_date2);
return total_seconds_date1 > total_seconds_date2 ? total_seconds_date1 - total_seconds_date2 : total_seconds_date2 - total_seconds_date1;
}
void date_add_hours(struct date *date, int64_t hours) {
if (hours == 0) {
return;
}
int64_t total_hours = date->hours + hours;
int64_t additional_days = total_hours / 24;
int64_t new_hours = total_hours % 24;
if (new_hours < 0) {
new_hours += 24;
additional_days -= 1;
}
date->hours = (uint8_t)new_hours;
if (additional_days != 0) {
date->day += additional_days;
while (date->day > date_get_days_of_month(date->month, date->year)) {
date->day -= date_get_days_of_month(date->month, date->year);
date->month++;
if (date->month > 12) {
date->month = 1;
date->year++;
}
}
while (date->day < 1) {
date->month--;
if (date->month < 1) {
date->month = 12;
date->year--;
}
date->day += date_get_days_of_month(date->month, date->year);
}
}
}
void date_add_days(struct date *date, int64_t days) {
date_add_hours(date, days * 24);
}
void date_to_utc(struct date *date) {
if (date->timezone_utc_offset == 0) {
return;
}
int8_t timezone_utc_offset = date->timezone_utc_offset;
date->timezone_utc_offset = 0;
date_add_hours(date, mathematics_opposite(timezone_utc_offset));
}
struct date *date_get_now_utc() {
struct date *date = malloc(sizeof(struct date));
if (date == NULL) {
perror("Error (date_get_now_utc)");
exit(EXIT_FAILURE);
}
time_t current_time = time(NULL);
struct tm *current_time_tm = gmtime(&current_time);
date->year = (uint16_t)(current_time_tm->tm_year + 1900);
date->month = (uint8_t)(current_time_tm->tm_mon + 1);
date->day = (uint8_t)current_time_tm->tm_mday;
date->hours = (uint8_t)current_time_tm->tm_hour;
date->minutes = (uint8_t)current_time_tm->tm_min;
date->seconds = (uint8_t)current_time_tm->tm_sec;
date->milliseconds = 0;
date->timezone_utc_offset = 0;
return date;
}
struct date *date_get_now_local() {
struct date *date = malloc(sizeof(struct date));
if (date == NULL) {
perror("Error (date_get_now_local)");
exit(EXIT_FAILURE);
}
time_t current_time = time(NULL);
struct tm *current_time_tm = localtime(&current_time);
date->year = (uint16_t)(current_time_tm->tm_year + 1900);
date->month = (uint8_t)(current_time_tm->tm_mon + 1);
date->day = (uint8_t)current_time_tm->tm_mday;
date->hours = (uint8_t)current_time_tm->tm_hour;
date->minutes = (uint8_t)current_time_tm->tm_min;
date->seconds = (uint8_t)current_time_tm->tm_sec;
date->milliseconds = 0;
date->timezone_utc_offset = 0;
return date;
}
uint16_t date_get_age(struct date *birth_date, struct date *current_date) {
uint16_t age = current_date->year - birth_date->year;
if (current_date->month < birth_date->month || (current_date->month == birth_date->month && current_date->day < birth_date->day)) {
age--;
}
return age;
}

350
lib/date.h Normal file
View File

@ -0,0 +1,350 @@
#ifndef __LIBCPROJECT_DATE__
#define __LIBCPROJECT_DATE__
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "convert.h"
#include "mathematics.h"
#include "string.h"
#include "types.h"
#define SECONDS_PER_MINUTE 60
#define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE)
#define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR)
#define MILLISECONDS_PER_SECOND 1000
/**
* @brief Date object representing a single moment in time.
* @since v4.3.0
*/
struct date {
/**
* Year.
* Between [0, 9999] (inclusive).
* As per ISO 8601, a four-digit year [YYYY] and represents years from 0000 to 9999, year 0000 being equal to 1 BC and all others AD.
*/
uint16_t year;
/**
* Month.
* Between [1, 12] (inclusive).
*/
uint8_t month;
/**
* Day.
* Between [1, 31] (inclusive).
*/
uint8_t day;
/**
* Hours.
* Between [0, 23] (inclusive).
*/
uint8_t hours;
/**
* Minutes.
* Between [0, 59] (inclusive).
*/
uint8_t minutes;
/**
* Seconds.
* Between [0, 59] (inclusive).
*/
uint8_t seconds;
/**
* Milliseconds.
* Between [0, 999] (inclusive).
*/
uint16_t milliseconds;
/**
* Timezone UTC offset.
* Between [-12, 14]
*/
int8_t timezone_utc_offset;
};
/**
* @brief Return the copy of a date.
*
* @param date
* @return struct date*
* @since v4.3.0
*/
struct date *date_copy(struct date *date_to_copy);
/**
* @brief Check if a year is valid, between [0, 9999] (inclusive).
*
* @param year
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid_year(uint16_t year);
/**
* @brief Check if a month is valid, between [1, 12] (inclusive).
*
* @param month
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid_month(uint8_t month);
/**
* @brief Check if a day is valid, between [1, 31] (inclusive).
*
* @param day
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid_day(uint8_t day);
/**
* @brief Check if hours are valid, between [0, 23] (inclusive).
*
* @param hours
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid_hours(uint8_t hours);
/**
* @brief Check if minutes are valid, between [0, 59] (inclusive).
*
* @param minutes
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid_minutes(uint8_t minutes);
/**
* @brief Check if seconds are valid, between [0, 59] (inclusive).
*
* @param seconds
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid_seconds(uint8_t seconds);
/**
* @brief Check if milliseconds are valid, between [0, 999] (inclusive).
*
* @param milliseconds
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid_milliseconds(uint16_t milliseconds);
/**
* @brief Check if the timezone UTC offset is valid, between [-12, 14] (inclusive).
*
* @param timezone_utc_offset
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid_timezone_utc_offset(int8_t timezone_utc_offset);
/**
* @brief Check if the date is valid (all fields are possible).
*
* @param date
* @return bool
* @since v4.3.0
*/
bool date_get_is_valid(struct date *date);
/**
* @brief String representing the date in the date time string format, a simplified format based on ISO 8601, which is always 24 characters long (`YYYY-MM-DDTHH:mm:ss.sssZ`). The timezone is always UTC, as denoted by the suffix `Z`.
*
* @param date
* @return string_t
*
* @code
* date_to_iso_string() // "2024-09-11T09:39:18.203Z"
* @endcode
*
* @since v4.3.0
*/
string_t date_to_iso_string(struct date *date);
/**
* @brief String representing the date in the ISO 8601 format, without time information (`YYYY-MM-DD`).
*
* @param date
* @return string_t
*
* @code
* date_to_iso_string_without_time() // "2024-09-11"
* @endcode
*
* @since v4.3.0
*/
string_t date_to_iso_string_without_time(struct date *date);
/**
* @brief Create a date from an ISO 8601 string, with the format `YYYY-MM-DDTHH:mm:ss.sssZ`.
*
* The timezone is always UTC, as denoted by the suffix `Z`.
*
* @param iso_string
* @return struct date*
* @since v4.3.0
*/
struct date *date_from_iso_string(string_t iso_string);
/**
* @brief Get number of days in one month [1, 12].
*
* @param month
* @return uint8_t
* @since v4.3.0
*/
uint8_t date_get_days_of_month(uint8_t month, uint16_t year);
/**
* @brief Determine if a year is a leap year.
*
* @param year
* @return bool
*
* @code
* date_is_leap_year(2020) // true
*
* date_is_leap_year(2021) // false
*
* date_is_leap_year(2022) // false
*
* date_is_leap_year(2023) // false
*
* date_is_leap_year(2024) // true
* @endcode
*
* @since v4.3.0
*/
bool date_get_is_leap_year(uint16_t year);
/**
* @brief Convert milliseconds to seconds.
*
* @param milliseconds
* @return uint64_t
* @since v4.3.0
*/
uint64_t date_convert_milliseconds_to_seconds(uint16_t milliseconds);
/**
* @brief Convert seconds to milliseconds.
*
* @param seconds
* @return uint64_t
* @since v4.3.0
*/
uint64_t date_convert_seconds_to_milliseconds(uint64_t seconds);
/**
* @brief Convert days to seconds.
*
* @param days
* @return uint64_t
* @since v4.3.0
*/
uint64_t date_convert_days_to_seconds(uint64_t days);
/**
* @brief Convert hours, minutes, and seconds to seconds.
*
* @param hours
* @param minutes
* @param seconds
* @return uint64_t
* @since v4.3.0
*/
uint64_t date_convert_hms_to_seconds(uint8_t hours, uint8_t minutes, uint8_t seconds);
/**
* @brief Convert a date to total seconds.
*
* @param date
* @return uint64_t
* @since v4.3.0
*/
uint64_t date_to_total_seconds(struct date *date);
/**
* @brief Calculate the duration in seconds between 2 dates.
*
* @param date1
* @param date2
* @return uint64_t
* @since v4.3.0
*/
uint64_t date_duration_seconds_between_2_dates(struct date *date1, struct date *date2);
/**
* @brief Add hours to the date, managing the day, month, year changes if necessary.
*
* NOTE: Mutates the date.
*
* @param date
* @param hours
* @since v4.3.0
*/
void date_add_hours(struct date *date, int64_t hours);
/**
* @brief Adds days to the date, managing month and year changes as needed.
*
* NOTE: Mutates the date.
*
* @param date The date to which days are being added.
* @param days The number of days to add.
* @since v4.3.0
*/
void date_add_days(struct date *date, int64_t days);
/**
* @brief Transform the date with a Timezone UTC Offset to UTC (timezone_utc_offset = 0).
*
* NOTE: Mutates the date.
*
* @param date
* @since v4.3.0
*/
void date_to_utc(struct date *date);
/**
* @brief Get the current date in UTC.
*
* @return struct date*
* @since v5.1.0
*/
struct date *date_get_now_utc();
/**
* @brief Get the current date in local time.
*
* @return struct date*
* @since v5.1.0
*/
struct date *date_get_now_local();
/**
* @brief Calculates the age of a person based on their birth date.
*
* @param birth_date
* @return uint16_t
* @since v5.1.0
*/
uint16_t date_get_age(struct date *birth_date, struct date *current_date);
#endif

View File

@ -1,68 +0,0 @@
#include "dictionary.h"
#include <stdlib.h>
#include "string.h"
struct dictionary *dictionary_initialization() {
struct dictionary *dictionary = malloc(sizeof(struct dictionary));
dictionary->items = malloc(sizeof(struct dictionary_item *) * DICTIONARY_INITIAL_CAPACITY);
dictionary->length = 0;
dictionary->capacity = DICTIONARY_INITIAL_CAPACITY;
for (size_t index = 0; index < dictionary->capacity; index++) {
dictionary->items[index] = NULL;
}
return dictionary;
}
void dictionary_add(struct dictionary *dictionary, char *key, void *data) {
if (dictionary->length == dictionary->capacity) {
size_t previous_capacity = dictionary->capacity;
dictionary->capacity += DICTIONARY_INITIAL_CAPACITY;
dictionary->items = realloc(dictionary->items, sizeof(struct dictionary_item *) * dictionary->capacity);
for (size_t index = previous_capacity; index < dictionary->capacity; index++) {
dictionary->items[index] = NULL;
}
}
struct dictionary_item *item = NULL;
for (size_t index = 0; index < dictionary->length && item == NULL; index++) {
if (string_equals(key, dictionary->items[index]->key)) {
item = dictionary->items[index];
}
}
if (item == NULL) {
item = malloc(sizeof(struct dictionary_item));
item->key = key;
item->data = data;
dictionary->items[dictionary->length] = item;
dictionary->length++;
} else {
item->data = data;
}
}
void dictionary_remove(struct dictionary *dictionary, char *key) {
bool found = false;
for (size_t index = 0; index < dictionary->length && !found; index++) {
if (string_equals(key, dictionary->items[index]->key)) {
free(dictionary->items[index]);
dictionary->items[index] = dictionary->items[dictionary->length - 1];
dictionary->length--;
found = true;
}
}
}
struct dictionary_item *dictionary_get(struct dictionary *dictionary, char *key) {
for (size_t index = 0; index < dictionary->length; index++) {
struct dictionary_item *item = dictionary->items[index];
if (string_equals(key, item->key)) {
return item;
}
}
return NULL;
}
bool dictionary_contains_key(struct dictionary *dictionary, char *key) {
return dictionary_get(dictionary, key) != NULL;
}

View File

@ -1,34 +0,0 @@
#ifndef __DICTIONARY__
#define __DICTIONARY__
#include <stdbool.h>
#include <stdlib.h>
#include "linked_list.h"
#define DICTIONARY_INITIAL_CAPACITY 10
// Dictionary implementation with O(n) lookup complexity.
struct dictionary {
struct dictionary_item **items;
size_t length;
size_t capacity;
};
struct dictionary_item {
void *data;
char *key;
};
struct dictionary *dictionary_initialization();
void dictionary_add(struct dictionary *dictionary, char *key, void *data);
void dictionary_remove(struct dictionary *dictionary, char *key);
struct dictionary_item *dictionary_get(struct dictionary *dictionary, char *key);
bool dictionary_contains_key(struct dictionary *dictionary, char *key);
#endif

View File

@ -1,17 +1,6 @@
#include "filesystem.h" #include "filesystem.h"
#include <dirent.h> int filesystem_read(string_t path, byte_t **file_content, size_t *file_size) {
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "string.h"
int filesystem_read(char *path, char **file_content, off_t *file_size) {
int file_descriptor = open(path, O_RDONLY); int file_descriptor = open(path, O_RDONLY);
if (file_descriptor == -1) { if (file_descriptor == -1) {
return -1; return -1;
@ -19,39 +8,243 @@ int filesystem_read(char *path, char **file_content, off_t *file_size) {
(*file_size) = lseek(file_descriptor, 0, SEEK_END); (*file_size) = lseek(file_descriptor, 0, SEEK_END);
lseek(file_descriptor, 0, SEEK_SET); lseek(file_descriptor, 0, SEEK_SET);
(*file_content) = malloc(*file_size); (*file_content) = malloc(*file_size);
read(file_descriptor, *file_content, *file_size); if (read(file_descriptor, *file_content, *file_size) == -1) {
return -1;
}
close(file_descriptor); close(file_descriptor);
return 0; return 0;
} }
int filesystem_write(char *path, char *file_content, off_t file_size) { int filesystem_write(string_t path, byte_t *file_content, size_t file_size) {
int file_descriptor = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); int file_descriptor = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (file_descriptor == -1) { if (file_descriptor == -1) {
return -1; return -1;
} }
write(file_descriptor, file_content, file_size); if (write(file_descriptor, file_content, file_size) == -1) {
return -1;
}
close(file_descriptor); close(file_descriptor);
return 0; return 0;
} }
char *filesystem_get_mimetype(char *path) { bool filesystem_exists(string_t path) {
if (string_ends_with(path, ".html")) { return access(path, F_OK) == 0;
return "text/html"; }
int filesystem_remove(string_t path) {
return remove(path);
}
string_t filesystem_get_mimetype(string_t path) {
if (string_ends_with(path, ".aac")) {
return "audio/aac";
}
if (string_ends_with(path, ".abw")) {
return "application/x-abiword";
}
if (string_ends_with(path, ".arc")) {
return "application/x-freearc";
}
if (string_ends_with(path, ".avif")) {
return "image/avif";
}
if (string_ends_with(path, ".avi")) {
return "video/x-msvideo";
}
if (string_ends_with(path, ".azw")) {
return "application/vnd.amazon.ebook";
}
if (string_ends_with(path, ".bin")) {
return "application/octet-stream";
}
if (string_ends_with(path, ".bmp")) {
return "image/bmp";
}
if (string_ends_with(path, ".bz")) {
return "application/x-bzip";
}
if (string_ends_with(path, ".bz2")) {
return "application/x-bzip2";
}
if (string_ends_with(path, ".cda")) {
return "application/x-cdf";
}
if (string_ends_with(path, ".csh")) {
return "application/x-csh";
} }
if (string_ends_with(path, ".css")) { if (string_ends_with(path, ".css")) {
return "text/css"; return "text/css";
} }
if (string_ends_with(path, ".js")) { if (string_ends_with(path, ".csv")) {
return "text/javascript"; return "text/csv";
} }
if (string_ends_with(path, ".png")) { if (string_ends_with(path, ".doc")) {
return "image/png"; return "application/msword";
} }
if (string_ends_with(path, ".jpg") || string_ends_with(path, ".jpeg")) { if (string_ends_with(path, ".docx")) {
return "image/jpeg"; return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
}
if (string_ends_with(path, ".eot")) {
return "application/vnd.ms-fontobject";
}
if (string_ends_with(path, ".epub")) {
return "application/epub+zip";
}
if (string_ends_with(path, ".gz")) {
return "application/gzip";
} }
if (string_ends_with(path, ".gif")) { if (string_ends_with(path, ".gif")) {
return "image/gif"; return "image/gif";
} }
return "text/plain"; if (string_ends_with(path, ".htm") || string_ends_with(path, ".html")) {
return "text/html";
}
if (string_ends_with(path, ".ico")) {
return "image/vnd.microsoft.icon";
}
if (string_ends_with(path, ".ics")) {
return "text/calendar";
}
if (string_ends_with(path, ".jar")) {
return "application/java-archive";
}
if (string_ends_with(path, ".jpg") || string_ends_with(path, ".jpeg") || string_ends_with(path, ".jpe") || string_ends_with(path, ".jif") || string_ends_with(path, ".jfif") || string_ends_with(path, ".jfi")) {
return "image/jpeg";
}
if (string_ends_with(path, ".js") || string_ends_with(path, ".mjs") || string_ends_with(path, ".cjs")) {
return "text/javascript";
}
if (string_ends_with(path, ".json")) {
return "application/json";
}
if (string_ends_with(path, ".jsonld")) {
return "application/ld+json";
}
if (string_ends_with(path, ".mid") || string_ends_with(path, ".midi")) {
return "audio/midi";
}
if (string_ends_with(path, ".mp3")) {
return "audio/mpeg";
}
if (string_ends_with(path, ".mp4")) {
return "video/mp4";
}
if (string_ends_with(path, ".mpeg")) {
return "video/mpeg";
}
if (string_ends_with(path, ".mpkg")) {
return "application/vnd.apple.installer+xml";
}
if (string_ends_with(path, ".odp")) {
return "application/vnd.oasis.opendocument.presentation";
}
if (string_ends_with(path, ".ods")) {
return "application/vnd.oasis.opendocument.spreadsheet";
}
if (string_ends_with(path, ".odt")) {
return "application/vnd.oasis.opendocument.text";
}
if (string_ends_with(path, ".oga")) {
return "audio/ogg";
}
if (string_ends_with(path, ".ogv")) {
return "video/ogg";
}
if (string_ends_with(path, ".ogx")) {
return "application/ogg";
}
if (string_ends_with(path, ".opus")) {
return "audio/opus";
}
if (string_ends_with(path, ".otf")) {
return "font/otf";
}
if (string_ends_with(path, ".png")) {
return "image/png";
}
if (string_ends_with(path, ".pdf")) {
return "application/pdf";
}
if (string_ends_with(path, ".php")) {
return "application/x-httpd-php";
}
if (string_ends_with(path, ".ppt")) {
return "application/vnd.ms-powerpoint";
}
if (string_ends_with(path, ".pptx")) {
return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
}
if (string_ends_with(path, ".rar")) {
return "application/vnd.rar";
}
if (string_ends_with(path, ".rtf")) {
return "application/rtf";
}
if (string_ends_with(path, ".sh")) {
return "application/x-sh";
}
if (string_ends_with(path, ".svg")) {
return "image/svg+xml";
}
if (string_ends_with(path, ".tar")) {
return "application/x-tar";
}
if (string_ends_with(path, ".tif") || string_ends_with(path, ".tiff")) {
return "image/tiff";
}
if (string_ends_with(path, ".ts")) {
return "application/typescript";
}
if (string_ends_with(path, ".ttf")) {
return "font/ttf";
}
if (string_ends_with(path, ".txt")) {
return "text/plain";
}
if (string_ends_with(path, ".vsd")) {
return "application/vnd.visio";
}
if (string_ends_with(path, ".wav")) {
return "audio/wav";
}
if (string_ends_with(path, ".weba") || string_ends_with(path, ".webm")) {
return "audio/webm";
}
if (string_ends_with(path, ".webp")) {
return "image/webp";
}
if (string_ends_with(path, ".woff")) {
return "font/woff";
}
if (string_ends_with(path, ".woff2")) {
return "font/woff2";
}
if (string_ends_with(path, ".xhtml")) {
return "application/xhtml+xml";
}
if (string_ends_with(path, ".xls")) {
return "application/vnd.ms-excel";
}
if (string_ends_with(path, ".xlsx")) {
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
}
if (string_ends_with(path, ".xml")) {
return "application/xml";
}
if (string_ends_with(path, ".xul")) {
return "application/vnd.mozilla.xul+xml";
}
if (string_ends_with(path, ".zip")) {
return "application/zip";
}
if (string_ends_with(path, ".3gp")) {
return "video/3gpp";
}
if (string_ends_with(path, ".3g2")) {
return "video/3gpp2";
}
if (string_ends_with(path, ".7z")) {
return "application/x-7z-compressed";
}
return "application/octet-stream";
} }

View File

@ -1,19 +1,30 @@
#ifndef __FILESYSTEM__ #ifndef __LIBCPROJECT_FILESYSTEM__
#define __FILESYSTEM__ #define __LIBCPROJECT_FILESYSTEM__
#include <dirent.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "string.h"
#include "types.h"
/** /**
* @brief Read the content of a file. * @brief Read the content of a file.
* *
* @param path * @param path
* @param file_content * @param file_content
* @param file_size * @param file_size The size of the file that was read (mutated by the function).
* @retval -1 if the file does not exist or if there is an error.
* @retval 0 for success.
* @return int * @return int
* @retval -1 if the file does not exist * @since v1.0.0
* @retval 0 for success
*/ */
int filesystem_read(char *path, char **file_content, off_t *file_size); int filesystem_read(string_t path, byte_t **file_content, size_t *file_size);
/** /**
* @brief Write the content to a file. * @brief Write the content to a file.
@ -21,18 +32,43 @@ int filesystem_read(char *path, char **file_content, off_t *file_size);
* @param path * @param path
* @param file_content * @param file_content
* @param file_size * @param file_size
* @retval -1 if there is an error.
* @retval 0 for success.
* @return int * @return int
* @retval -1 if errors * @since v1.0.0
* @retval 0 for success
*/ */
int filesystem_write(char *path, char *file_content, off_t file_size); int filesystem_write(string_t path, byte_t *file_content, size_t file_size);
/** /**
* @brief Get the mimetype of a file. * @brief Check if a path exists.
* *
* @param path * @param path
* @return char* * @return bool
* @since v3.1.0
*/ */
char *filesystem_get_mimetype(char *path); bool filesystem_exists(string_t path);
/**
* @brief Removes a path.
*
* @param path
* @return int
* @retval -1 if there is an error.
* @retval 0 for success.
* @return int
* @since v3.1.0
*/
int filesystem_remove(string_t path);
/**
* @brief Get the mimetype of a file based on its extension.
*
* @param path
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
* @see https://www.iana.org/assignments/media-types/media-types.xhtml
* @return string_t
* @since v1.0.0
*/
string_t filesystem_get_mimetype(string_t path);
#endif #endif

244
lib/hash_map.c Normal file
View File

@ -0,0 +1,244 @@
#include "hash_map.h"
#define ROTATE_LEFT(x, b) (((x) << (b)) | ((x) >> (64 - (b))))
uint64_t sip_round(uint64_t v0, uint64_t v1, uint64_t v2, uint64_t v3) {
v0 += v1;
v2 += v3;
v1 = ROTATE_LEFT(v1, 13);
v3 = ROTATE_LEFT(v3, 16);
v1 ^= v0;
v3 ^= v2;
v0 = ROTATE_LEFT(v0, 32);
v2 += v1;
v0 += v3;
v1 = ROTATE_LEFT(v1, 17);
v3 = ROTATE_LEFT(v3, 21);
v1 ^= v2;
v3 ^= v0;
v2 = ROTATE_LEFT(v2, 32);
return v0;
}
uint64_t hash(string_t key, size_t capacity) {
size_t key_length = string_get_length(key);
const uint64_t c = 0x736f6d6570736575;
uint64_t v0 = c ^ 0x736f6d6570736575;
uint64_t v1 = c ^ 0x646f72616e646f6d;
uint64_t v2 = c ^ 0x6c7967656e657261;
uint64_t v3 = c ^ 0x7465646279746573;
uint64_t m;
uint64_t hash;
uint8_t *message = (uint8_t *)key;
size_t remaining = key_length;
size_t offset = 0;
while (remaining >= 8) {
memcpy(&m, message + offset, sizeof(uint64_t));
v3 ^= m;
for (uint8_t i = 0; i < 2; i++) {
v0 = sip_round(v0, v1, v2, v3);
v1 = ROTATE_LEFT(v1, 13);
v2 = ROTATE_LEFT(v2, 16);
v3 = ROTATE_LEFT(v3, 32);
v0 ^= m;
}
v2 ^= 0xff;
for (uint8_t i = 0; i < 4; i++) {
v0 = sip_round(v0, v1, v2, v3);
v1 = ROTATE_LEFT(v1, 13);
v2 = ROTATE_LEFT(v2, 16);
v3 = ROTATE_LEFT(v3, 32);
}
hash = v0 ^ v1 ^ v2 ^ v3;
remaining -= sizeof(uint64_t);
offset += sizeof(uint64_t);
}
m = (uint64_t)remaining << 56;
switch (remaining) {
case 7:
m |= (uint64_t)message[offset + 6] << 48;
break;
case 6:
m |= (uint64_t)message[offset + 5] << 40;
break;
case 5:
m |= (uint64_t)message[offset + 4] << 32;
break;
case 4:
m |= (uint64_t)message[offset + 3] << 24;
break;
case 3:
m |= (uint64_t)message[offset + 2] << 16;
break;
case 2:
m |= (uint64_t)message[offset + 1] << 8;
break;
case 1:
m |= (uint64_t)message[offset];
break;
default:
break;
}
v3 ^= m;
for (uint8_t i = 0; i < 2; i++) {
v0 = sip_round(v0, v1, v2, v3);
v1 = ROTATE_LEFT(v1, 13);
v2 = ROTATE_LEFT(v2, 16);
v3 = ROTATE_LEFT(v3, 32);
}
v0 ^= m;
v2 ^= 0xff;
for (uint8_t i = 0; i < 4; i++) {
v0 = sip_round(v0, v1, v2, v3);
v1 = ROTATE_LEFT(v1, 13);
v2 = ROTATE_LEFT(v2, 16);
v3 = ROTATE_LEFT(v3, 32);
}
hash = v0 ^ v1 ^ v2 ^ v3;
return hash % capacity;
}
struct hash_map *hash_map_initialization() {
struct hash_map *hash_map = malloc(sizeof(struct hash_map));
hash_map->items = malloc(sizeof(struct linked_list *) * HASH_MAP_INITIAL_CAPACITY);
hash_map->length = 0;
hash_map->capacity = HASH_MAP_INITIAL_CAPACITY;
for (size_t index = 0; index < hash_map->capacity; index++) {
hash_map->items[index] = NULL;
}
return hash_map;
}
void hash_map_add(struct hash_map *hash_map, string_t key_value, void *data) {
if (hash_map->length == hash_map->capacity) {
size_t previous_capacity = hash_map->capacity;
hash_map->capacity += HASH_MAP_INITIAL_CAPACITY;
hash_map->items = realloc(hash_map->items, sizeof(struct linked_list *) * hash_map->capacity);
for (size_t index = previous_capacity; index < hash_map->capacity; index++) {
hash_map->items[index] = NULL;
}
}
string_t key = string_copy(key_value);
uint64_t hash_value = hash(key, hash_map->capacity);
struct linked_list *list = hash_map->items[hash_value];
struct hash_map_item *item = malloc(sizeof(struct hash_map_item));
item->key = key;
item->data = data;
if (list == NULL) {
list = linked_list_initialization();
hash_map->items[hash_value] = list;
linked_list_add_in_head(list, (void *)item);
hash_map->length++;
} else {
struct linked_list_node *node = list->head;
bool found = false;
while (node != NULL && !found) {
struct hash_map_item *item = (struct hash_map_item *)node->data;
if (string_equals(key, item->key)) {
item->data = data;
found = true;
}
node = node->next;
}
if (!found) {
linked_list_add_in_head(list, (void *)item);
hash_map->length++;
} else {
free(key);
free(item);
}
}
}
void hash_map_remove(struct hash_map *hash_map, string_t key) {
uint64_t hash_value = hash(key, hash_map->capacity);
struct linked_list *list = hash_map->items[hash_value];
if (list == NULL) {
return;
}
struct linked_list *new_list = linked_list_initialization();
struct linked_list_node *node = list->head;
while (node != NULL) {
struct hash_map_item *item = (struct hash_map_item *)node->data;
if (!string_equals(key, item->key)) {
linked_list_add_in_head(new_list, item);
} else {
free(item->key);
free(item);
}
node = node->next;
}
linked_list_free(list);
hash_map->items[hash_value] = new_list;
hash_map->length--;
}
void *hash_map_get(struct hash_map *hash_map, string_t key) {
uint64_t hash_value = hash(key, hash_map->capacity);
struct linked_list *list = hash_map->items[hash_value];
if (list == NULL) {
return NULL;
}
struct linked_list_node *node = list->head;
while (node != NULL) {
struct hash_map_item *item = (struct hash_map_item *)node->data;
if (string_equals(key, item->key)) {
return item->data;
}
node = node->next;
}
return NULL;
}
bool hash_map_contains_key(struct hash_map *hash_map, string_t key) {
return hash_map_get(hash_map, key) != NULL;
}
string_t *hash_map_get_keys(struct hash_map *hash_map) {
string_t *keys = malloc(sizeof(string_t) * hash_map->length);
size_t index = 0;
for (size_t hash_value = 0; hash_value < hash_map->capacity; hash_value++) {
struct linked_list *list = hash_map->items[hash_value];
if (list != NULL) {
struct linked_list_node *node = list->head;
while (node != NULL) {
struct hash_map_item *item = (struct hash_map_item *)node->data;
keys[index++] = item->key;
node = node->next;
}
}
}
return keys;
}
void hash_map_free(struct hash_map *hash_map) {
for (size_t index = 0; index < hash_map->capacity; index++) {
struct linked_list *list = hash_map->items[index];
if (list != NULL) {
struct linked_list_node *node = list->head;
while (node != NULL) {
struct hash_map_item *item = (struct hash_map_item *)node->data;
free(item->key);
free(item);
node = node->next;
}
linked_list_free(list);
}
}
free(hash_map->items);
free(hash_map);
}

110
lib/hash_map.h Normal file
View File

@ -0,0 +1,110 @@
#ifndef __LIBCPROJECT_HASH_MAP__
#define __LIBCPROJECT_HASH_MAP__
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "linked_list.h"
#include "string.h"
#include "types.h"
#define HASH_MAP_INITIAL_CAPACITY 10
/**
* @brief Hash map data structure.
* @since v2.0.0
*/
struct hash_map {
struct linked_list **items;
size_t length;
size_t capacity;
};
/**
* @brief Hash map item data structure.
* @since v2.0.0
*/
struct hash_map_item {
void *data;
string_t key;
};
/**
* @brief Hash function (using SipHash 1-3 algorithm).
* @see https://en.wikipedia.org/wiki/SipHash
* @see https://github.com/veorq/SipHash
*
* @param key
* @param capacity
* @return uint64_t
* @since v2.0.0
*/
uint64_t hash(string_t key, size_t capacity);
/**
* @brief Hash map initialization.
*
* @return struct hash_map*
* @since v2.0.0
*/
struct hash_map *hash_map_initialization();
/**
* @brief Add an item to the hash map.
*
* @param hash_map
* @param key
* @param data
* @since v2.0.0
*/
void hash_map_add(struct hash_map *hash_map, string_t key, void *data);
/**
* @brief Remove an item from the hash map.
* @param hash_map
* @param key
* @since v2.0.0
*/
void hash_map_remove(struct hash_map *hash_map, string_t key);
/**
* @brief Get an item from the hash map.
* @param hash_map
* @param key
* @return void*
* @since v2.0.0
*/
void *hash_map_get(struct hash_map *hash_map, string_t key);
/**
* @brief Check if the hash map contains a key.
*
* @param hash_map
* @param key
* @return bool
* @since v2.0.0
*/
bool hash_map_contains_key(struct hash_map *hash_map, string_t key);
/**
* @brief Get the hash map keys.
*
* @param hash_map
* @return string_t*
* @since v2.0.0
*/
string_t *hash_map_get_keys(struct hash_map *hash_map);
/**
* @brief Frees the hash map.
*
* @param hash_map
* @since v3.0.0
*/
void hash_map_free(struct hash_map *hash_map);
#endif

View File

@ -1,13 +1,9 @@
#include "linked_list.h" #include "linked_list.h"
#include <stdbool.h>
#include <stdlib.h>
#include "stack.h"
struct linked_list *linked_list_initialization() { struct linked_list *linked_list_initialization() {
struct linked_list *list = malloc(sizeof(*list)); struct linked_list *list = malloc(sizeof(struct linked_list));
if (list == NULL) { if (list == NULL) {
perror("Error (linked_list_initialization)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
list->head = NULL; list->head = NULL;
@ -16,8 +12,14 @@ struct linked_list *linked_list_initialization() {
} }
struct linked_list_node *linked_list_add_in_head(struct linked_list *list, void *new_data) { struct linked_list_node *linked_list_add_in_head(struct linked_list *list, void *new_data) {
struct linked_list_node *node_new = malloc(sizeof(*node_new)); if (list == NULL) {
if (list == NULL || node_new == NULL) { errno = EINVAL;
perror("Error (linked_list_add_in_head)");
exit(EXIT_FAILURE);
}
struct linked_list_node *node_new = malloc(sizeof(struct linked_list_node));
if (node_new == NULL) {
perror("Error (linked_list_add_in_head)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
node_new->data = new_data; node_new->data = new_data;
@ -29,6 +31,8 @@ struct linked_list_node *linked_list_add_in_head(struct linked_list *list, void
void linked_list_delete_in_head(struct linked_list *list) { void linked_list_delete_in_head(struct linked_list *list) {
if (list == NULL) { if (list == NULL) {
errno = EINVAL;
perror("Error (linked_list_delete_in_head)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (list->head != NULL) { if (list->head != NULL) {
@ -40,11 +44,17 @@ void linked_list_delete_in_head(struct linked_list *list) {
} }
struct linked_list_node *linked_list_add_after_last(struct linked_list *list, void *new_data) { struct linked_list_node *linked_list_add_after_last(struct linked_list *list, void *new_data) {
if (list == NULL) {
errno = EINVAL;
perror("Error (linked_list_add_after_last)");
exit(EXIT_FAILURE);
}
if (list->head == NULL) { if (list->head == NULL) {
return linked_list_add_in_head(list, new_data); return linked_list_add_in_head(list, new_data);
} }
struct linked_list_node *node_new = malloc(sizeof(*node_new)); struct linked_list_node *node_new = malloc(sizeof(struct linked_list_node));
if (list == NULL || node_new == NULL) { if (node_new == NULL) {
perror("Error (linked_list_add_after_last)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
node_new->data = new_data; node_new->data = new_data;
@ -73,6 +83,7 @@ struct linked_list *linked_list_reverse(struct linked_list *list) {
linked_list_add_after_last(linked_list_reversed, stack_node_current->data); linked_list_add_after_last(linked_list_reversed, stack_node_current->data);
stack_node_current = stack_node_current->next; stack_node_current = stack_node_current->next;
} }
stack_free(stack);
return linked_list_reversed; return linked_list_reversed;
} }
@ -89,3 +100,14 @@ void linked_list_reverse_mutate(struct linked_list *list) {
(*current) = temporary_current; (*current) = temporary_current;
} }
} }
void linked_list_free(struct linked_list *list) {
struct linked_list_node *node_current = list->head;
while (node_current != NULL) {
struct linked_list_node *node_to_remove = node_current;
node_current = node_current->next;
free(node_to_remove);
}
list->head = NULL;
free(list);
}

View File

@ -1,30 +1,90 @@
#ifndef __LINKED_LIST__ #ifndef __LIBCPROJECT_LINKED_LIST__
#define __LINKED_LIST__ #define __LIBCPROJECT_LINKED_LIST__
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
struct linked_list { #include "stack.h"
// first node of the list #include "types.h"
struct linked_list_node *head;
/**
* @brief Linked list data structure.
* @since v1.0.0
*/
struct linked_list {
struct linked_list_node *head;
size_t length; size_t length;
}; };
/**
* @brief Linked list node data structure.
* @since v1.0.0
*/
struct linked_list_node { struct linked_list_node {
void *data; void *data;
struct linked_list_node *next; struct linked_list_node *next;
}; };
/**
* @brief Linked list initialization.
*
* @return struct linked_list*
* @since v1.0.0
*/
struct linked_list *linked_list_initialization(); struct linked_list *linked_list_initialization();
/**
* @brief Add a new node in the head of the linked list.
*
* @param list
* @param new_value
* @return struct linked_list_node*
* @since v1.0.0
*/
struct linked_list_node *linked_list_add_in_head(struct linked_list *list, void *new_value); struct linked_list_node *linked_list_add_in_head(struct linked_list *list, void *new_value);
/**
* @brief Delete node in the head of the linked list.
*
* @param list
* @since v1.0.0
*/
void linked_list_delete_in_head(struct linked_list *list); void linked_list_delete_in_head(struct linked_list *list);
/**
* @brief Add a new node in the tail of the linked list.
*
* @param list
* @param new_data
* @return struct linked_list_node*
* @since v1.0.0
*/
struct linked_list_node *linked_list_add_after_last(struct linked_list *list, void *new_data); struct linked_list_node *linked_list_add_after_last(struct linked_list *list, void *new_data);
/**
* @brief Reverse the linked list by creating a new one.
*
* @param list
* @return struct linked_list*
* @since v1.0.0
*/
struct linked_list *linked_list_reverse(struct linked_list *list); struct linked_list *linked_list_reverse(struct linked_list *list);
/**
* @brief Reverse the linked list by mutating it.
*
* @param list
* @since v1.0.0
*/
void linked_list_reverse_mutate(struct linked_list *list); void linked_list_reverse_mutate(struct linked_list *list);
/**
* @brief Frees the linked list.
*
* @param list
* @since v3.0.0
*/
void linked_list_free(struct linked_list *list);
#endif #endif

View File

@ -1,25 +1,23 @@
#include "mathematics.h" #include "mathematics.h"
#include <stdbool.h> bool mathematics_equals(const float64_t number1, const float64_t number2) {
return (number1 - number2) < MATHEMATICS_DOUBLE_PRECISION;
bool mathematics_equals(const float number1, const float number2) {
return (number1 - number2) < MATHEMATICS_FLOAT_PRECISION;
} }
unsigned long long mathematics_absolute_value(const long long number) { uint64_t mathematics_absolute_value(const int64_t number) {
if (number >= 0) { if (number >= 0) {
return number; return number;
} }
return -number; return -number;
} }
unsigned long long mathematics_pow(unsigned long long base, unsigned long long exponent) { uint64_t mathematics_pow(uint64_t base, uint64_t exponent) {
return exponent == 0 ? 1 : base * mathematics_pow(base, exponent - 1); return exponent == 0 ? 1 : base * mathematics_pow(base, exponent - 1);
} }
float mathematics_root(float number, unsigned int nth_root) { float64_t mathematics_root(float64_t number, uint64_t nth_root) {
float result = number; float64_t result = number;
float previous_result = 0; float64_t previous_result = 0;
while (!mathematics_equals(result, previous_result)) { while (!mathematics_equals(result, previous_result)) {
result = (((nth_root - 1) * previous_result) + (number / mathematics_pow(result, nth_root - 1))) / nth_root; result = (((nth_root - 1) * previous_result) + (number / mathematics_pow(result, nth_root - 1))) / nth_root;
previous_result = result; previous_result = result;
@ -27,10 +25,46 @@ float mathematics_root(float number, unsigned int nth_root) {
return result; return result;
} }
float mathematics_square_root(float number) { float64_t mathematics_square_root(float64_t number) {
return mathematics_root(number, 2); return mathematics_root(number, 2);
} }
unsigned long long mathematics_factorial(unsigned long long number) { uint64_t mathematics_factorial(uint64_t number) {
return number == 0 ? 1 : number * mathematics_factorial(number - 1); return number == 0 ? 1 : number * mathematics_factorial(number - 1);
} }
int64_t mathematics_opposite(int64_t number) {
return number * -1;
}
int64_t mathematics_max(int64_t number1, int64_t number2) {
return number1 > number2 ? number1 : number2;
}
int64_t mathematics_max_values(int64_t *values, size_t values_length) {
int64_t max = 0;
if (values_length <= 0) {
return max;
}
max = values[0];
for (size_t index = 1; index < values_length; index++) {
max = mathematics_max(max, values[index]);
}
return max;
}
int64_t mathematics_min(int64_t number1, int64_t number2) {
return number1 > number2 ? number2 : number1;
}
int64_t mathematics_min_values(int64_t *values, size_t values_length) {
int64_t min = 0;
if (values_length <= 0) {
return min;
}
min = values[0];
for (size_t index = 1; index < values_length; index++) {
min = mathematics_min(min, values[index]);
}
return min;
}

View File

@ -1,27 +1,124 @@
#ifndef __MATHEMATICS__ #ifndef __LIBCPROJECT_MATHEMATICS__
#define __MATHEMATICS__ #define __LIBCPROJECT_MATHEMATICS__
#define MATHEMATICS_FLOAT_PRECISION 0.00000001 #define MATHEMATICS_DOUBLE_PRECISION 0.0000000001
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
bool mathematics_equals(const float number1, const float number2); #include "types.h"
unsigned long long mathematics_absolute_value(const long long number);
unsigned long long mathematics_pow(unsigned long long base, unsigned long long exponent);
/** /**
* @brief Calculates the nth root of a number using Heron's method. * @brief Verify that 2 numbers are equal.
*
* @param number1
* @param number2
* @return bool
* @since v1.0.0
*/
bool mathematics_equals(const float64_t number1, const float64_t number2);
/**
* @brief Get the absolute value of a number.
*
* @param number
* @return uint64_t
* @since v1.0.0
*/
uint64_t mathematics_absolute_value(const int64_t number);
/**
* @brief Calculates the power of a number.
*
* @param base
* @param exponent
* @return uint64_t
* @since v1.0.0
*/
uint64_t mathematics_pow(uint64_t base, uint64_t exponent);
/**
* @brief Calculates the nth root of a number.
* *
* @param number * @param number
* @param nth_root * @param nth_root
* @return float * @return float64_t
* @since v1.0.0
*/ */
float mathematics_root(float number, unsigned int nth_root); float64_t mathematics_root(float64_t number, uint64_t nth_root);
float mathematics_square_root(float number); /**
* @brief Calculates the square root of a number using Heron's method.
*
* @param number
* @return float64_t
* @since v1.0.0
*/
float64_t mathematics_square_root(float64_t number);
unsigned long long mathematics_factorial(unsigned long long number); /**
* @brief Calculates the factorial of a number.
*
* @param number
* @return uint64_t
* @since v1.0.0
*/
uint64_t mathematics_factorial(uint64_t number);
/**
* @brief Calulcates the opposite number (additive inverse).
*
* @param number
* @return int64_t
*
* @code
* mathematics_opposite(7) // -7
*
* mathematics_opposite(-7) // 7
* @endcode
* @since v4.3.0
*/
int64_t mathematics_opposite(int64_t number);
/**
* @brief Returns the largest number between 2 numbers.
*
* @param number1
* @param number2
* @return int64_t
* @since v4.3.0
*/
int64_t mathematics_max(int64_t number1, int64_t number2);
/**
* @brief Returns the largest number between multiple numbers. If the array is empty, returns 0.
*
* @param values
* @param values_length
* @return int64_t
* @since v4.3.0
*/
int64_t mathematics_max_values(int64_t *values, size_t values_length);
/**
* @brief Returns the smallest number between 2 numbers.
*
* @param number1
* @param number2
* @return int64_t
* @since v4.3.0
*/
int64_t mathematics_min(int64_t number1, int64_t number2);
/**
* @brief Returns the smallest number between multiple numbers. If the array is empty, returns 0.
*
* @param values
* @param values_length
* @return int64_t
* @since v4.3.0
*/
int64_t mathematics_min_values(int64_t *values, size_t values_length);
#endif #endif

View File

@ -1,11 +1,9 @@
#include "queue.h" #include "queue.h"
#include <stdio.h>
#include <stdlib.h>
struct queue *queue_initialization() { struct queue *queue_initialization() {
struct queue *queue = malloc(sizeof(*queue)); struct queue *queue = malloc(sizeof(struct queue));
if (queue == NULL) { if (queue == NULL) {
perror("Error (queue_initialization)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
queue->first = NULL; queue->first = NULL;
@ -14,8 +12,14 @@ struct queue *queue_initialization() {
} }
void queue_push(struct queue *queue, void *data) { void queue_push(struct queue *queue, void *data) {
struct queue_node *node_new = malloc(sizeof(*node_new)); if (queue == NULL) {
if (queue == NULL || node_new == NULL) { errno = EINVAL;
perror("Error (queue_push)");
exit(EXIT_FAILURE);
}
struct queue_node *node_new = malloc(sizeof(struct queue_node));
if (node_new == NULL) {
perror("Error (queue_push)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
node_new->data = data; node_new->data = data;
@ -34,6 +38,8 @@ void queue_push(struct queue *queue, void *data) {
void *queue_pop(struct queue *queue) { void *queue_pop(struct queue *queue) {
if (queue == NULL) { if (queue == NULL) {
errno = EINVAL;
perror("Error (queue_pop)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct queue_node *node = queue->first; struct queue_node *node = queue->first;
@ -46,3 +52,18 @@ void *queue_pop(struct queue *queue) {
queue->length = queue->length - 1; queue->length = queue->length - 1;
return data; return data;
} }
void queue_free(struct queue *queue) {
if (queue == NULL) {
errno = EINVAL;
perror("Error (queue_free)");
exit(EXIT_FAILURE);
}
struct queue_node *node = queue->first;
while (node != NULL) {
struct queue_node *node_next = node->next;
free(node);
node = node_next;
}
free(queue);
}

View File

@ -1,23 +1,62 @@
#ifndef __QUEUE__ #ifndef __LIBCPROJECT_QUEUE__
#define __QUEUE__ #define __LIBCPROJECT_QUEUE__
#include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
// FIFO = First In First Out #include "types.h"
/**
* @brief Queue structure => FIFO (First In First Out).
* @since v1.0.0
*/
struct queue { struct queue {
struct queue_node *first; struct queue_node *first;
size_t length; size_t length;
}; };
/**
* @brief Queue node structure.
* @since v1.0.0
*/
struct queue_node { struct queue_node {
void *data; void *data;
struct queue_node *next; struct queue_node *next;
}; };
/**
* @brief Queue initialization.
*
* @return struct queue*
* @since v1.0.0
*/
struct queue *queue_initialization(); struct queue *queue_initialization();
/**
* @brief Push data to queue.
*
* @param queue
* @param data
* @since v1.0.0
*/
void queue_push(struct queue *queue, void *data); void queue_push(struct queue *queue, void *data);
/**
* @brief Pop data from queue.
*
* @param queue
* @return void*
* @since v1.0.0
*/
void *queue_pop(struct queue *queue); void *queue_pop(struct queue *queue);
/**
* @brief Frees the queue.
*
* @param queue
* @since v3.0.0
*/
void queue_free(struct queue *queue);
#endif #endif

View File

@ -1,11 +1,9 @@
#include "stack.h" #include "stack.h"
#include <stdio.h>
#include <stdlib.h>
struct stack *stack_initialization() { struct stack *stack_initialization() {
struct stack *stack = malloc(sizeof(*stack)); struct stack *stack = malloc(sizeof(struct stack));
if (stack == NULL) { if (stack == NULL) {
perror("Error (stack_initialization)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
stack->first = NULL; stack->first = NULL;
@ -14,8 +12,14 @@ struct stack *stack_initialization() {
} }
void stack_push(struct stack *stack, void *data) { void stack_push(struct stack *stack, void *data) {
struct stack_node *node_new = malloc(sizeof(*node_new)); if (stack == NULL) {
if (stack == NULL || data == NULL) { errno = EINVAL;
perror("Error (stack_push)");
exit(EXIT_FAILURE);
}
struct stack_node *node_new = malloc(sizeof(struct stack_node));
if (data == NULL) {
perror("Error (stack_push)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
node_new->data = data; node_new->data = data;
@ -26,6 +30,8 @@ void stack_push(struct stack *stack, void *data) {
void *stack_pop(struct stack *stack) { void *stack_pop(struct stack *stack) {
if (stack == NULL) { if (stack == NULL) {
errno = EINVAL;
perror("Error (stack_pop)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct stack_node *node = stack->first; struct stack_node *node = stack->first;
@ -38,3 +44,18 @@ void *stack_pop(struct stack *stack) {
stack->length = stack->length - 1; stack->length = stack->length - 1;
return data; return data;
} }
void stack_free(struct stack *stack) {
if (stack == NULL) {
errno = EINVAL;
perror("Error (stack_free)");
exit(EXIT_FAILURE);
}
struct stack_node *node = stack->first;
while (node != NULL) {
struct stack_node *node_next = node->next;
free(node);
node = node_next;
}
free(stack);
}

View File

@ -1,23 +1,62 @@
#ifndef __STACK__ #ifndef __LIBCPROJECT_STACK__
#define __STACK__ #define __LIBCPROJECT_STACK__
#include <errno.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
// LIFO = Last In First Out #include "types.h"
/**
* @brief Stack structure => LIFO (Last In First Out).
* @since v1.0.0
*/
struct stack { struct stack {
struct stack_node *first; struct stack_node *first;
size_t length; size_t length;
}; };
/**
* @brief Stack node structure.
* @since v1.0.0
*/
struct stack_node { struct stack_node {
void *data; void *data;
struct stack_node *next; struct stack_node *next;
}; };
/**
* @brief Stack initialization.
*
* @return struct stack*
* @since v1.0.0
*/
struct stack *stack_initialization(); struct stack *stack_initialization();
/**
* @brief Push data to stack.
*
* @param stack
* @param data
* @since v1.0.0
*/
void stack_push(struct stack *stack, void *data); void stack_push(struct stack *stack, void *data);
/**
* @brief Pop data from stack.
*
* @param stack
* @return void*
* @since v1.0.0
*/
void *stack_pop(struct stack *stack); void *stack_pop(struct stack *stack);
/**
* @brief Frees the stack.
*
* @param stack
* @since v3.0.0
*/
void stack_free(struct stack *stack);
#endif #endif

View File

@ -1,14 +1,6 @@
#include "string.h" #include "string.h"
#include <stdbool.h> size_t string_get_length(const string_t string) {
#include <stdio.h>
#include <stdlib.h>
#include "character.h"
#include "convert.h"
#include "dictionary.h"
size_t string_get_length(const char* string) {
size_t length = 0; size_t length = 0;
while (string[length] != '\0') { while (string[length] != '\0') {
length++; length++;
@ -16,107 +8,99 @@ size_t string_get_length(const char* string) {
return length; return length;
} }
char* string_to_uppercase(char* string) { void string_to_uppercase(string_t string) {
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
char* result = malloc(sizeof(char*) * string_length);
if (result == NULL) {
exit(EXIT_FAILURE);
}
for (size_t index = 0; index < string_length; index++) { for (size_t index = 0; index < string_length; index++) {
character_append(result, character_to_upper(string[index])); string[index] = character_to_upper(string[index]);
} }
return result; string[string_length] = '\0';
} }
char* string_to_lowercase(char* string) { void string_to_lowercase(string_t string) {
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
char* result = malloc(sizeof(char*) * string_length);
if (result == NULL) {
exit(EXIT_FAILURE);
}
for (size_t index = 0; index < string_length; index++) { for (size_t index = 0; index < string_length; index++) {
character_append(result, character_to_lower(string[index])); string[index] = character_to_lower(string[index]);
} }
return result; string[string_length] = '\0';
} }
char* string_replace(char* string, char search, char replace) { void string_replace(string_t string, char search, char replace) {
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
char* result = malloc(sizeof(char*) * string_length);
if (result == NULL) {
exit(EXIT_FAILURE);
}
for (size_t index = 0; index < string_length; index++) { for (size_t index = 0; index < string_length; index++) {
bool is_search_value = search == string[index]; bool is_search_value = search == string[index];
if (is_search_value) { if (is_search_value) {
character_append(result, replace); string[index] = replace;
} else { } else {
character_append(result, string[index]); string[index] = string[index];
} }
} }
return result; string[string_length] = '\0';
} }
char* string_trim_start(char* string) { void string_remove_character(string_t string, char search) {
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
char* result = malloc(sizeof(char*) * string_length); for (size_t index = 0; index < string_length; index++) {
if (result == NULL) { if (string[index] == search) {
exit(EXIT_FAILURE); for (size_t index_string = index; index_string < string_length; index_string++) {
string[index_string] = string[index_string + 1];
}
string_length--;
index--;
}
} }
string[string_length] = '\0';
}
void string_trim_start(string_t string, char character) {
size_t string_length = string_get_length(string);
size_t index_space = 0; size_t index_space = 0;
while (string[index_space] == ' ') { while (string[index_space] == character) {
index_space++; index_space++;
} }
for (size_t index = index_space; index < string_length; index++) { for (size_t index = 0; index < string_length - index_space; index++) {
character_append(result, string[index]); string[index] = string[index + index_space];
} }
return result; string[string_length - index_space] = '\0';
} }
char* string_trim_end(char* string) { void string_trim_end(string_t string, char character) {
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
char* result = malloc(sizeof(char*) * string_length);
if (result == NULL) {
exit(EXIT_FAILURE);
}
size_t index_space = string_length - 1; size_t index_space = string_length - 1;
while (string[index_space] == ' ') { while (string[index_space] == character) {
index_space--; index_space--;
} }
for (size_t index = 0; index < index_space + 1; index++) { string[index_space + 1] = '\0';
character_append(result, string[index]);
}
return result;
} }
char* string_trim(char* string) { void string_trim(string_t string, char character) {
char* result = string_trim_start(string); string_trim_start(string, character);
result = string_trim_end(result); string_trim_end(string, character);
return result;
} }
char* string_copy(const char* string) { string_t string_copy(const string_t string) {
return string_substring(string, 0, string_get_length(string)); size_t source_length = string_get_length(string);
} string_t copy = malloc(sizeof(char) * (source_length + 1));
if (copy == NULL) {
char* string_capitalize(char* string) { perror("Error (string_copy)");
size_t string_length = string_get_length(string);
char* result = malloc(sizeof(char*) * string_length);
if (result == NULL) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
for (size_t index = 0; index < string_length; index++) { size_t index;
bool is_first_character = index == 0; for (index = 0; index < source_length; index++) {
if (is_first_character) { copy[index] = string[index];
character_append(result, character_to_upper(string[index]));
} else {
character_append(result, string[index]);
}
} }
return result; copy[index] = '\0';
return copy;
} }
size_t string_total_occurrences_of_character(char* string, char character) { void string_capitalize(string_t string) {
size_t string_length = string_get_length(string);
if (string_length == 0) {
return;
}
string[0] = character_to_upper(string[0]);
}
size_t string_total_occurrences_of_character(string_t string, char character) {
size_t result = 0; size_t result = 0;
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
for (size_t index = 0; index < string_length; index++) { for (size_t index = 0; index < string_length; index++) {
@ -128,21 +112,20 @@ size_t string_total_occurrences_of_character(char* string, char character) {
return result; return result;
} }
char* string_reverse(const char* string) { void string_reverse(const string_t string) {
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
size_t index = 0; size_t index_start = 0;
char* result = malloc(sizeof(char*) * string_length); size_t index_end = string_length - 1;
if (result == NULL) { while (index_start < index_end) {
exit(EXIT_FAILURE); char temporary = string[index_start];
string[index_start] = string[index_end];
string[index_end] = temporary;
index_start++;
index_end--;
} }
for (index = string_length - 1; index > 0; index--) {
character_append(result, string[index]);
}
character_append(result, string[index]);
return result;
} }
bool string_equals(const char* string1, const char* string2) { bool string_equals(const string_t string1, const string_t string2) {
size_t string1_length = string_get_length(string1); size_t string1_length = string_get_length(string1);
size_t string2_length = string_get_length(string2); size_t string2_length = string_get_length(string2);
bool is_equal = string1_length == string2_length; bool is_equal = string1_length == string2_length;
@ -154,7 +137,7 @@ bool string_equals(const char* string1, const char* string2) {
return is_equal; return is_equal;
} }
bool string_get_is_integer(const char* string) { bool string_get_is_integer(const string_t string) {
size_t index = 0; size_t index = 0;
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
bool is_integer = string_length >= 1; bool is_integer = string_length >= 1;
@ -174,106 +157,130 @@ bool string_get_is_integer(const char* string) {
return is_integer; return is_integer;
} }
char** string_split(const char* string, char separator, size_t* result_size) { string_t* string_split(const string_t string, char separator, size_t* result_size) {
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
size_t index_string = 0; size_t index_string = 0;
size_t index_current = 0; size_t index_current = 0;
size_t index_result = 0; size_t index_result = 0;
char* current = malloc(sizeof(char*) * string_length); string_t current = malloc(sizeof(char) * (string_length + 1));
char** result = malloc(sizeof(char**) * index_result); string_t* result = NULL;
if (result == NULL || current == NULL) { if (current == NULL) {
perror("Error (string_split)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
while (index_string < string_length) { while (index_string < string_length) {
if (string[index_string] == separator) { if (string[index_string] == separator) {
result[index_result] = string_copy(current); current[index_current] = '\0';
index_result++; result = realloc(result, sizeof(string_t) * (index_result + 1));
result = realloc(result, sizeof(char*) * index_result);
if (result == NULL) { if (result == NULL) {
perror("Error (string_split)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
result[index_result] = string_copy(current);
index_result++;
index_current = 0; index_current = 0;
current = string_copy("");
} else { } else {
character_append(current, string[index_string]); current[index_current] = string[index_string];
index_current++; index_current++;
} }
index_string++; index_string++;
} }
current[index_current] = '\0';
result = realloc(result, sizeof(string_t) * (index_result + 1));
if (result == NULL) {
perror("Error (string_split)");
exit(EXIT_FAILURE);
}
result[index_result] = string_copy(current); result[index_result] = string_copy(current);
free(current); free(current);
*result_size = index_result + 1; *result_size = index_result + 1;
return result; return result;
} }
char* string_join(char** array, const char separator, size_t array_length) { string_t string_join(string_t* array, const char separator, size_t array_length) {
size_t string_length = array_length; size_t total_length = 0;
char* string = malloc(sizeof(char*) * string_length); for (size_t index_array = 0; index_array < array_length; index_array++) {
total_length += string_get_length(array[index_array]);
}
size_t string_length = total_length + (array_length - 1);
string_t string = malloc(sizeof(char) * (string_length + 1));
if (string == NULL) { if (string == NULL) {
perror("Error (string_join)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
size_t current_index = 0;
for (size_t index_array = 0; index_array < array_length; index_array++) { for (size_t index_array = 0; index_array < array_length; index_array++) {
char* substring = array[index_array]; string_t substring = array[index_array];
size_t substring_length = string_get_length(substring); size_t substring_length = string_get_length(substring);
string_length += substring_length;
string = realloc(string, sizeof(char*) * string_length);
if (string == NULL) {
exit(EXIT_FAILURE);
}
for (size_t index_substring = 0; index_substring < substring_length; index_substring++) { for (size_t index_substring = 0; index_substring < substring_length; index_substring++) {
character_append(string, substring[index_substring]); string[current_index] = substring[index_substring];
current_index++;
} }
bool is_last_character = index_array == (array_length - 1); bool is_last_character = index_array == (array_length - 1);
if (!is_last_character) { if (!is_last_character) {
character_append(string, separator); string[current_index] = separator;
current_index++;
} }
} }
string[string_length] = '\0';
return string; return string;
} }
char* string_concatenate(char* string1, char* string2) { void string_concatenate(string_t* destination, string_t source) {
size_t string1_length = string_get_length(string1); size_t destination_length = string_get_length(*destination);
size_t string2_length = string_get_length(string2); size_t source_length = string_get_length(source);
size_t result_length = string1_length + string2_length; size_t new_length = destination_length + source_length;
char* result = malloc(sizeof(char*) * result_length); *destination = realloc(*destination, sizeof(char) * (new_length + 1));
if (result == NULL) { if (*destination == NULL) {
perror("Error (string_concatenate)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
for (size_t index_string1 = 0; index_string1 < string1_length; index_string1++) { size_t index_destination = destination_length;
character_append(result, string1[index_string1]); for (size_t index_source = 0; index_source < source_length; index_source++) {
(*destination)[index_destination++] = source[index_source];
} }
for (size_t index_string2 = 0; index_string2 < string2_length; index_string2++) { (*destination)[index_destination] = '\0';
character_append(result, string2[index_string2]);
}
return result;
} }
bool string_get_has_unique_characters(const char* string) { bool string_get_has_unique_characters(const string_t string) {
bool has_unique = true; bool has_unique = true;
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
struct dictionary* characters_already_seen = dictionary_initialization(); struct hash_map* characters_already_seen = hash_map_initialization();
string_t* keys = malloc(sizeof(string_t) * string_length);
for (size_t index = 0; index < string_length; index++) {
keys[index] = NULL;
}
for (size_t index = 0; index < string_length && has_unique; index++) { for (size_t index = 0; index < string_length && has_unique; index++) {
char character = string[index]; char character = string[index];
char* key = convert_character_to_string(character); keys[index] = convert_character_to_string(character);
if (dictionary_contains_key(characters_already_seen, key)) { string_t key = keys[index];
if (hash_map_contains_key(characters_already_seen, key)) {
has_unique = false; has_unique = false;
} else { } else {
dictionary_add(characters_already_seen, key, (void*)true); hash_map_add(characters_already_seen, key, (void*)true);
} }
} }
for (size_t index = 0; index < string_length; index++) {
if (keys[index] != NULL) {
free(keys[index]);
}
}
free(keys);
hash_map_free(characters_already_seen);
return has_unique; return has_unique;
} }
char* string_substring(const char* string, size_t index_start, size_t index_end) { string_t string_substring(const string_t string, size_t index_start, size_t index_end) {
size_t string_length = string_get_length(string); size_t substring_length = index_end - index_start + 1;
char* result = malloc(sizeof(char*) * string_length); string_t result = malloc(sizeof(char) * (substring_length + 1));
for (size_t index = index_start; index <= index_end; index++) { for (size_t index = 0; index < substring_length; index++) {
character_append(result, string[index]); result[index] = string[index_start + index];
} }
result[substring_length] = '\0';
return result; return result;
} }
bool string_get_is_substring(const char* string, const char* substring) { bool string_get_is_substring(const string_t string, const string_t substring) {
bool is_substring = false; bool is_substring = false;
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
size_t substring_length = string_get_length(substring); size_t substring_length = string_get_length(substring);
@ -289,57 +296,73 @@ bool string_get_is_substring(const char* string, const char* substring) {
return is_substring; return is_substring;
} }
char* string_get_formatted_number(const long long number, char* separator) { string_t string_get_formatted_number(const int64_t number, string_t separator) {
char* number_string = convert_number_to_string(number); string_t number_string_temp = convert_number_to_string(number);
bool is_negative = number_string[0] == '-'; string_t number_string = number_string_temp;
bool is_negative = number_string_temp[0] == '-';
if (is_negative) { if (is_negative) {
number_string = string_substring(number_string, 1, string_get_length(number_string)); number_string = string_substring(number_string_temp, 1, string_get_length(number_string_temp));
free(number_string_temp);
} }
size_t number_string_length = string_get_length(number_string); size_t number_string_length = string_get_length(number_string);
char* result = malloc(sizeof(char*) * number_string_length); size_t formatted_length = number_string_length + (number_string_length - 1) / 3;
string_t result = malloc(sizeof(char) * (formatted_length + 1));
if (result == NULL) { if (result == NULL) {
perror("Error (string_get_formatted_number)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
size_t count = 0; size_t count = 0;
size_t result_index = 0;
for (size_t index = 0; index < number_string_length; index++) { for (size_t index = 0; index < number_string_length; index++) {
size_t index_reversed = number_string_length - index - 1; size_t index_reversed = number_string_length - index - 1;
result[result_index] = number_string[index_reversed];
count++; count++;
result = string_concatenate(result, convert_character_to_string(number_string[index_reversed])); result_index++;
if (count == 3) { if (count == 3 && index != number_string_length - 1) {
result = string_concatenate(result, separator); for (size_t sep_index = 0; sep_index < string_get_length(separator); sep_index++) {
result[result_index] = separator[sep_index];
result_index++;
}
count = 0; count = 0;
} }
} }
result = string_reverse(result); free(number_string);
size_t result_length = string_get_length(result); result[formatted_length] = '\0';
if (result_length % 4 == 0) { string_reverse(result);
result = string_substring(result, 1, result_length);
}
if (is_negative) { if (is_negative) {
result = string_concatenate(convert_character_to_string('-'), result); string_t negative_result = convert_character_to_string('-');
string_concatenate(&negative_result, result);
free(result);
return negative_result;
} }
return result; return result;
} }
char* string_get_last_occurence_of_character(const char* string, char character) { string_t string_get_last_occurence_of_character(const string_t string, char character) {
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
char* result = malloc(sizeof(char*) * string_length); size_t index_last_occurrence = SIZE_MAX;
for (size_t index = 0; index < string_length; index++) {
if (string[index] == character) {
index_last_occurrence = index;
}
}
if (index_last_occurrence == SIZE_MAX) {
return "";
}
string_t result = malloc(sizeof(char) * (string_length - index_last_occurrence + 1));
if (result == NULL) { if (result == NULL) {
perror("Error (string_get_last_occurence_of_character)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
size_t index_result = 0; size_t index_result = 0;
for (size_t index = 0; index < string_length; index++) { for (size_t index = index_last_occurrence; index < string_length; index++) {
if (string[index] == character) { result[index_result++] = string[index];
index_result = 0;
result = string_copy("");
}
character_append(result, string[index]);
index_result++;
} }
result[index_result] = '\0';
return result; return result;
} }
bool string_starts_with(const char* string, const char* prefix) { bool string_starts_with(const string_t string, const string_t prefix) {
bool starts_with = true; bool starts_with = true;
size_t prefix_length = string_get_length(prefix); size_t prefix_length = string_get_length(prefix);
for (size_t index = 0; index < prefix_length && starts_with; index++) { for (size_t index = 0; index < prefix_length && starts_with; index++) {
@ -348,7 +371,7 @@ bool string_starts_with(const char* string, const char* prefix) {
return starts_with; return starts_with;
} }
bool string_ends_with(const char* string, const char* prefix) { bool string_ends_with(const string_t string, const string_t prefix) {
bool ends_with = true; bool ends_with = true;
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
size_t prefix_length = string_get_length(prefix); size_t prefix_length = string_get_length(prefix);
@ -361,3 +384,59 @@ bool string_ends_with(const char* string, const char* prefix) {
} }
return ends_with; return ends_with;
} }
size_t string_position_of(const string_t string, const char character) {
size_t position_found = 0;
size_t string_length = string_get_length(string);
for (size_t index = 0; index < string_length && position_found == 0; index++) {
if (string[index] == character) {
position_found = index + 1;
}
}
return position_found;
}
size_t string_last_position_of(const string_t string, const char character) {
size_t position_found = 0;
size_t string_length = string_get_length(string);
while (string_length > 0 && position_found == 0) {
if (string[string_length - 1] == character) {
position_found = string_length;
}
string_length--;
}
return position_found;
}
string_t string_pad_start(const string_t string, const string_t pad_string, size_t target_length) {
string_t result = malloc(sizeof(char) * (target_length + 1));
size_t initial_length = string_get_length(string);
size_t left_length = target_length - initial_length;
if (target_length <= initial_length) {
left_length = 0;
}
size_t pad_length = string_get_length(pad_string);
size_t count_pad_string = 0;
size_t index_initial_string = 0;
for (size_t index = 0; index < target_length; index++) {
if (index < left_length) {
size_t index_pad_string = count_pad_string % pad_length;
result[index] = pad_string[index_pad_string];
count_pad_string += 1;
} else {
result[index] = string[index_initial_string];
index_initial_string += 1;
}
}
result[target_length] = '\0';
return result;
}
string_t string_zero_pad(uint64_t number, size_t places) {
string_t number_string = convert_number_to_string((int64_t)number);
string_t pad_string = string_copy("0");
string_t result = string_pad_start(number_string, pad_string, places);
free(pad_string);
free(number_string);
return result;
}

View File

@ -1,82 +1,116 @@
#ifndef __STRING__ #ifndef __LIBCPROJECT_STRING__
#define __STRING__ #define __LIBCPROJECT_STRING__
#include <errno.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "character.h"
#include "convert.h"
#include "hash_map.h"
#include "types.h"
/** /**
* @brief Return the length of a string (excluding '\0'). * @brief Return the length of a string (excluding '\0').
* *
* @param string * @param string
* @return size_t * @return size_t
* @since v1.0.0
*/ */
size_t string_get_length(const char* string); size_t string_get_length(const string_t string);
/** /**
* @brief Converts all the alphabetic characters in a string to uppercase. * @brief Converts all the alphabetic characters in a string to uppercase.
* *
* NOTE: Mutates the string.
*
* @param string * @param string
* @return char* * @since v1.0.0
*/ */
char* string_to_uppercase(char* string); void string_to_uppercase(string_t string);
/** /**
* @brief Converts all the alphabetic characters in a string to lowercase. * @brief Converts all the alphabetic characters in a string to lowercase.
* *
* NOTE: Mutates the string.
*
* @param string * @param string
* @return char* * @since v1.0.0
*/ */
char* string_to_lowercase(char* string); void string_to_lowercase(string_t string);
/** /**
* @brief Replace all the occurrences of search value into replace value in the string. * @brief Replace all the occurrences of search value into replace value in the string.
* *
* @param string * NOTE: Mutates the string.
* @param search_value A character search value.
* @param replace_value A character containing the text to replace for match.
* @return char*
*/
char* string_replace(char* string, char search, char replace);
/**
* @brief Removes all whitespace from the start of a string.
* *
* @param string * @param string
* @return char* * @param search A character search value.
* @param replace A character containing the text to replace for match.
* @since v1.0.0
*/ */
char* string_trim_start(char* string); void string_replace(string_t string, char search, char replace);
/** /**
* @brief Removes all whitespace from the end of a string. * @brief Removes all the occurrences of a character in a string.
*
* NOTE: Mutates the string.
* *
* @param string * @param string
* @return char* * @param search A character search value.
* @since v4.1.0
*/ */
char* string_trim_end(char* string); void string_remove_character(string_t string, char search);
/** /**
* @brief Removes all whitespace from the start and end of a string. * @brief Removes all `character` from the start of a string.
*
* NOTE: Mutates the string.
* *
* @param string * @param string
* @return char* * @since v1.0.0
*/ */
char* string_trim(char* string); void string_trim_start(string_t string, char character);
/**
* @brief Removes all `character` from the end of a string.
*
* NOTE: Mutates the string.
*
* @param string
* @since v1.0.0
*/
void string_trim_end(string_t string, char character);
/**
* @brief Removes all `character` from the start and end of a string.
*
* NOTE: Mutates the string.
*
* @param string
* @since v1.0.0
*/
void string_trim(string_t string, char character);
/** /**
* @brief Return the copy of a string. * @brief Return the copy of a string.
* *
* @param string * @param string
* @return char* * @return string_t
* @since v1.0.0
*/ */
char* string_copy(const char* string); string_t string_copy(const string_t string);
/** /**
* @brief Capitalizes the string. * @brief Capitalizes the string.
* *
* NOTE: Mutates the string.
*
* @param string * @param string
* @return char* * @since v1.0.0
*/ */
char* string_capitalize(char* string); void string_capitalize(string_t string);
/** /**
* @brief Returns the total number of occurrences of the given character in the string. * @brief Returns the total number of occurrences of the given character in the string.
@ -84,68 +118,83 @@ char* string_capitalize(char* string);
* @param string * @param string
* @param character * @param character
* @return size_t * @return size_t
* @since v1.0.0
*/ */
size_t string_total_occurrences_of_character(char* string, char character); size_t string_total_occurrences_of_character(string_t string, char character);
/** /**
* @brief Reverse the characters in an array. * @brief Reverse the characters in a string.
*
* NOTE: Mutates the string.
* *
* @param string * @param string
* @return char* * @since v1.0.0
*/ */
char* string_reverse(const char* string); void string_reverse(const string_t string);
/** /**
* @brief Check if two strings are equals. * @brief Check if two strings are equals.
* *
* @param string1 * @param string1
* @param string2 * @param string2
* @return true if the strings are equals, false otherwise * @return true if the strings are equals.
* @return false if the strings are not equals.
* @since v1.0.0
*/ */
bool string_equals(const char* string1, const char* string2); bool string_equals(const string_t string1, const string_t string2);
/** /**
* @brief Check if the string is a integer. * @brief Check if the string is an integer.
* *
* @param string * @param string
* @return true if the string is a integer, false otherwise * @return true if the string is an integer.
* @return false if the string is not an integer.
* @since v1.0.0
*/ */
bool string_get_is_integer(const char* string); bool string_get_is_integer(const string_t string);
/** /**
* @brief Split a string into substrings using the specified separator and return them as an array and update the pointer `result_size` to the resulting size of the created array. * @brief Split a string into substrings using the specified separator and return them as an array and update the pointer `result_size` to the resulting size of the created array.
* *
* @param string * @param string
* @param separator * @param separator
* @return char** * @param result_size
* @return string_t*
* @since v1.0.0
*/ */
char** string_split(const char* string, char separator, size_t* result_size); string_t* string_split(const string_t string, char separator, size_t* result_size);
/** /**
* @brief Adds all the elements of an array into a string, separated by the specified separator string. * @brief Adds all the elements of an array into a string, separated by the specified separator string.
* *
* @param array * @param array
* @param separator * @param separator
* @return char* * @param array_length
* @return string_t
* @since v1.0.0
*/ */
char* string_join(char** array, const char separator, size_t array_length); string_t string_join(string_t* array, const char separator, size_t array_length);
/** /**
* @brief Concatenate two strings. * @brief Concatenate two strings.
* *
* @param string1 * NOTE: Mutates the string `destination`.
* @param string2 *
* @return char* * @param destination
* @param source
* @since v1.0.0
*/ */
char* string_concatenate(char* string1, char* string2); void string_concatenate(string_t* destination, string_t source);
/** /**
* @brief Check if a string contains only unique characters. * @brief Check if a string contains only unique characters.
* *
* @param string * @param string
* @return true if string contains only unique characters, false otherwise * @return true if string contains only unique characters.
* @return false if string contains duplicate characters.
* @since v1.0.0
*/ */
bool string_get_has_unique_characters(const char* string); bool string_get_has_unique_characters(const string_t string);
/** /**
* @brief Returns the part of the string between the start and end indexes (both included). * @brief Returns the part of the string between the start and end indexes (both included).
@ -153,52 +202,127 @@ bool string_get_has_unique_characters(const char* string);
* @param string * @param string
* @param index_start * @param index_start
* @param index_end * @param index_end
* @return char* * @return string_t
* @since v1.0.0
*/ */
char* string_substring(const char* string, size_t index_start, size_t index_end); string_t string_substring(const string_t string, size_t index_start, size_t index_end);
/** /**
* @brief Check if a string contains a substring. * @brief Check if a string contains a substring.
* *
* @param string * @param string
* @param substring * @param substring
* @return true if the string contains the substring, false otherwise * @return true if the string contains the substring.
* @return false if the string does not contain the substring.
* @since v1.0.0
*/ */
bool string_get_is_substring(const char* string, const char* substring); bool string_get_is_substring(const string_t string, const string_t substring);
/** /**
* @brief Format a number to a string with specified separator. * @brief Format a number to a string with specified separator.
* *
* @param integer * @param number
* @return char* example: string_get_formatted_number(1000, " ") => "1 000" * @param separator
* @return string_t
*
* @code
* string_get_formatted_number(1000, " ") // "1 000"
*
* string_get_formatted_number(1000, ",") // "1,000"
* @endcode
* @since v1.0.0
*/ */
char* string_get_formatted_number(const long long number, char* separator); string_t string_get_formatted_number(const int64_t number, string_t separator);
/** /**
* @brief Returns a pointer to the last occurrence of character in the string. * @brief Returns a pointer to the last occurrence of character in the string.
* *
* @param string * @param string
* @param character * @param character
* @return char* * @return string_t
* @since v1.0.0
*/ */
char* string_get_last_occurence_of_character(const char* string, char character); string_t string_get_last_occurence_of_character(const string_t string, char character);
/** /**
* @brief Check if a string starts with a substring. * @brief Check if a string starts with a substring.
* *
* @param string * @param string
* @param prefix * @param prefix
* @return true if the string starts with the substring, false otherwise * @return true if the string starts with the substring.
* @return false if the string does not start with the substring.
* @since v1.0.0
*/ */
bool string_starts_with(const char* string, const char* prefix); bool string_starts_with(const string_t string, const string_t prefix);
/** /**
* @brief Check if a string ends with a substring. * @brief Check if a string ends with a substring.
* *
* @param string * @param string
* @param prefix * @param prefix
* @return true if the string ends with the substring, false otherwise * @return true if the string ends with the substring.
* @return false if the string does not end with the substring.
* @since v1.0.0
*/ */
bool string_ends_with(const char* string, const char* prefix); bool string_ends_with(const string_t string, const string_t prefix);
/**
* @brief Returns the position (index + 1) within the string of the first occurrence of the specified substring (0 if not found).
*
* @param string
* @param substring
* @return size_t
*
* @code
* string_position_of("hello world", 'e') // 2
* @endcode
* @since v4.2.0
*/
size_t string_position_of(const string_t string, const char character);
/**
* @brief Returns the position (index + 1) within the string of the last occurrence of the specified substring (0 if not found).
*
* @param string
* @param character
* @return size_t
*
* @code
* string_last_position_of("hello world", 'o') // 8
* @endcode
* @since v4.2.0
*/
size_t string_last_position_of(const string_t string, const char character);
/**
* @brief Pads a `string` with another `pad_string` (multiple times, if needed) until the resulting string reaches the `target_length`. The padding is applied from the start (left) of the string.
*
* @param string The string to pad.
* @param pad_string The string to pad the current string with, to the left.
* @param target_length
* @return string_t
*
* @code
* string_pad_start("hello", " ", 10) // " hello"
* @endcode
* @since v4.3.0
*/
string_t string_pad_start(const string_t string, const string_t pad_string, size_t target_length);
/**
* @brief Pad a number with zeros.
*
* @param number
* @param places
* @return string_t
*
* @code
* string_zero_pad(1, 2) // "01"
*
* string_zero_pad(10, 2) // "10"
* @endcode
* @since v4.3.0
*/
string_t string_zero_pad(uint64_t number, size_t places);
#endif #endif

View File

@ -1,21 +1,11 @@
#include "terminal.h" #include "terminal.h"
#include <stdbool.h> string_t terminal_input() {
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "character.h"
#include "dictionary.h"
#include "linked_list.h"
#include "queue.h"
#include "stack.h"
char* terminal_input() {
char character; char character;
size_t length = 1; size_t length = 1;
char* string = malloc(length * sizeof(char)); string_t string = malloc(length * sizeof(char));
if (string == NULL) { if (string == NULL) {
perror("Error (terminal_input)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
*string = '\0'; *string = '\0';
@ -23,6 +13,7 @@ char* terminal_input() {
length++; length++;
string = realloc(string, length * sizeof(char)); string = realloc(string, length * sizeof(char));
if (string == NULL) { if (string == NULL) {
perror("Error (terminal_input)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
character_append(string, character); character_append(string, character);
@ -30,23 +21,14 @@ char* terminal_input() {
return string; return string;
} }
void terminal_print_array(void* array, size_t array_size, size_t element_size, void (*print_element)(void*)) {
printf("[");
for (size_t index = 0; index < array_size; index++) {
void* element = (char*)array + index * element_size;
print_element(element);
bool is_last = index == array_size - 1;
if (!is_last) {
printf(", ");
}
}
printf("]\n");
}
void terminal_print_int(void* value) { void terminal_print_int(void* value) {
printf("%d", *(int*)value); printf("%d", *(int*)value);
} }
void terminal_print_bool(void* value) {
printf("%s", *(bool*)value ? "true" : "false");
}
void terminal_print_long(void* value) { void terminal_print_long(void* value) {
printf("%ld", *(long*)value); printf("%ld", *(long*)value);
} }
@ -55,23 +37,78 @@ void terminal_print_unsigned_long(void* value) {
printf("%lu", *(unsigned long*)value); printf("%lu", *(unsigned long*)value);
} }
void terminal_print_float(void* value) {
printf("%f", *(float*)value);
}
void terminal_print_double(void* value) {
printf("%f", *(double*)value);
}
void terminal_print_int8_t(void* value) {
printf("%d", *(int8_t*)value);
}
void terminal_print_int16_t(void* value) {
printf("%d", *(int16_t*)value);
}
void terminal_print_int32_t(void* value) {
printf("%d", *(int32_t*)value);
}
void terminal_print_int64_t(void* value) {
printf("%ld", *(int64_t*)value);
}
void terminal_print_uint8_t(void* value) {
printf("%u", *(uint8_t*)value);
}
void terminal_print_uint16_t(void* value) {
printf("%u", *(uint16_t*)value);
}
void terminal_print_uint32_t(void* value) {
printf("%u", *(uint32_t*)value);
}
void terminal_print_uint64_t(void* value) {
printf("%lu", *(uint64_t*)value);
}
void terminal_print_char(void* value) { void terminal_print_char(void* value) {
printf("%c", *(char*)value); printf("%c", *(string_t)value);
}
void terminal_print_array(void* array, size_t array_size, size_t element_size, void (*print_element)(void*)) {
printf("[");
for (size_t index = 0; index < array_size; index++) {
void* element = (string_t)array + index * element_size;
print_element(element);
bool is_last = index == array_size - 1;
if (!is_last) {
printf(", ");
}
}
printf("]\n");
} }
void terminal_print_string(void* value) { void terminal_print_string(void* value) {
printf("%s", (char*)value); printf("%s", (string_t)value);
} }
void terminal_print_stack(struct stack* stack, void (*print_element)(void*)) { void terminal_print_stack(struct stack* stack, void (*print_element)(void*)) {
if (stack == NULL) { if (stack == NULL) {
errno = EINVAL;
perror("Error (terminal_print_stack)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct stack_node* node_current = stack->first; struct stack_node* node_current = stack->first;
while (node_current != NULL) { while (node_current != NULL) {
printf("|\t"); printf("|\t");
void* element = (char*)node_current->data; void* element = node_current->data;
print_element(&element); print_element(element);
node_current = node_current->next; node_current = node_current->next;
printf("\t|\n"); printf("\t|\n");
} }
@ -79,13 +116,15 @@ void terminal_print_stack(struct stack* stack, void (*print_element)(void*)) {
void terminal_print_queue(struct queue* queue, void (*print_element)(void*)) { void terminal_print_queue(struct queue* queue, void (*print_element)(void*)) {
if (queue == NULL) { if (queue == NULL) {
errno = EINVAL;
perror("Error (terminal_print_queue)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct queue_node* node_current = queue->first; struct queue_node* node_current = queue->first;
while (node_current != NULL) { while (node_current != NULL) {
printf("|\t"); printf("|\t");
void* element = (char*)node_current->data; void* element = node_current->data;
print_element(&element); print_element(element);
node_current = node_current->next; node_current = node_current->next;
printf("\t|\n"); printf("\t|\n");
} }
@ -93,30 +132,49 @@ void terminal_print_queue(struct queue* queue, void (*print_element)(void*)) {
void terminal_print_linked_list(struct linked_list* linked_list, void (*print_element)(void*)) { void terminal_print_linked_list(struct linked_list* linked_list, void (*print_element)(void*)) {
if (linked_list == NULL) { if (linked_list == NULL) {
errno = EINVAL;
perror("Error (terminal_print_linked_list)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct linked_list_node* node_current = linked_list->head; struct linked_list_node* node_current = linked_list->head;
while (node_current != NULL) { while (node_current != NULL) {
void* element = (char*)node_current->data; void* element = (string_t)node_current->data;
node_current = node_current->next; node_current = node_current->next;
print_element(&element); print_element(element);
printf(" -> "); printf(" -> ");
} }
printf("NULL\n"); printf("NULL\n");
} }
void terminal_print_dictionary(struct dictionary* dictionary, void (*print_element)(void*)) { void terminal_print_hash_map(struct hash_map* hash_map, void (*print_element)(void*)) {
if (dictionary == NULL) { if (hash_map == NULL) {
errno = EINVAL;
perror("Error (terminal_print_hash_map)");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
printf("{\n"); printf("{\n");
for (size_t index = 0; index < dictionary->length; index++) { string_t* keys = hash_map_get_keys(hash_map);
struct dictionary_item* item = dictionary->items[index]; for (size_t index = 0; index < hash_map->length; index++) {
string_t key = keys[index];
void* value = hash_map_get(hash_map, key);
printf("\t\""); printf("\t\"");
terminal_print_string(item->key); terminal_print_string(key);
printf("\" -> "); printf("\" -> ");
print_element(&item->data); print_element(value);
printf("\n"); printf("\n");
} }
printf("}\n"); printf("}\n");
free(keys);
}
void terminal_print_array_list(struct array_list* list, void (*print_element)(void*)) {
printf("[");
for (size_t index = 0; index < list->size; index++) {
void* element = list->data[index];
print_element(element);
if (index < list->size - 1) {
printf(", ");
}
}
printf("]\n");
} }

View File

@ -1,38 +1,210 @@
#ifndef __TERMINAL__ #ifndef __LIBCPROJECT_TERMINAL__
#define __TERMINAL__ #define __LIBCPROJECT_TERMINAL__
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "dictionary.h" #include "array_list.h"
#include "character.h"
#include "hash_map.h"
#include "linked_list.h" #include "linked_list.h"
#include "queue.h" #include "queue.h"
#include "stack.h" #include "stack.h"
#include "types.h"
/** /**
* @brief Read a line from stdin. * @brief Read a line from stdin.
* *
* @return char* * @return string_t
* @since v1.0.0
*/ */
char* terminal_input(); string_t terminal_input();
void terminal_print_array(void* array, size_t array_size, size_t element_size, void (*print_element)(void*));
/**
* @brief Print a int.
*
* @param value
* @since v1.0.0
*/
void terminal_print_int(void* value); void terminal_print_int(void* value);
/**
* @brief Print a boolean.
*
* @param value
* @since v5.0.0
*/
void terminal_print_bool(void* value);
/**
* @brief Print a long.
*
* @param value
* @since v1.0.0
*/
void terminal_print_long(void* value); void terminal_print_long(void* value);
/**
* @brief Print a unsigned long.
*
* @param value
* @since v1.0.0
*/
void terminal_print_unsigned_long(void* value); void terminal_print_unsigned_long(void* value);
/**
* @brief Print a float.
*
* @param value
* @since v5.0.0
*/
void terminal_print_float(void* value);
/**
* @brief Print a double.
*
* @param value
* @since v5.0.0
*/
void terminal_print_double(void* value);
/**
* @brief Print a int8_t.
*
* @param value
* @since v5.0.0
*/
void terminal_print_int8_t(void* value);
/**
* @brief Print a int16_t.
*
* @param value
* @since v5.0.0
*/
void terminal_print_int16_t(void* value);
/**
* @brief Print a int32_t.
*
* @param value
* @since v5.0.0
*/
void terminal_print_int32_t(void* value);
/**
* @brief Print a int64_t.
*
* @param value
* @since v5.0.0
*/
void terminal_print_int64_t(void* value);
/**
* @brief Print a uint8_t.
*
* @param value
* @since v5.0.0
*/
void terminal_print_uint8_t(void* value);
/**
* @brief Print a uint16_t.
*
* @param value
* @since v5.0.0
*/
void terminal_print_uint16_t(void* value);
/**
* @brief Print a uint32_t.
*
* @param value
* @since v5.0.0
*/
void terminal_print_uint32_t(void* value);
/**
* @brief Print a uint64_t.
*
* @param value
* @since v5.0.0
*/
void terminal_print_uint64_t(void* value);
/**
* @brief Print a char.
*
* @param value
* @since v1.0.0
*/
void terminal_print_char(void* value); void terminal_print_char(void* value);
/**
* @brief Print an array.
*
* @param array
* @param array_size
* @param element_size
* @param print_element
* @since v1.0.0
*/
void terminal_print_array(void* array, size_t array_size, size_t element_size, void (*print_element)(void*));
/**
* @brief Print a string.
*
* @param value
* @since v1.0.0
*/
void terminal_print_string(void* value); void terminal_print_string(void* value);
/**
* @brief Print a stack.
*
* @param stack
* @param print_element
* @since v1.0.0
*/
void terminal_print_stack(struct stack* stack, void (*print_element)(void*)); void terminal_print_stack(struct stack* stack, void (*print_element)(void*));
/**
* @brief Print a queue.
*
* @param queue
* @param print_element
* @since v1.0.0
*/
void terminal_print_queue(struct queue* queue, void (*print_element)(void*)); void terminal_print_queue(struct queue* queue, void (*print_element)(void*));
/**
* @brief Print a linked list.
*
* @param linked_list
* @param print_element
* @since v1.0.0
*/
void terminal_print_linked_list(struct linked_list* linked_list, void (*print_element)(void*)); void terminal_print_linked_list(struct linked_list* linked_list, void (*print_element)(void*));
void terminal_print_dictionary(struct dictionary* dictionary, void (*print_element)(void*)); /**
* @brief Print a hash map.
*
* @param hash_map
* @param print_element
* @since v2.0.0
*/
void terminal_print_hash_map(struct hash_map* hash_map, void (*print_element)(void*));
/**
* @brief Print an array list.
*
* @param list
* @param print_element
* @since v3.0.0
*/
void terminal_print_array_list(struct array_list* list, void (*print_element)(void*));
#endif #endif

13
lib/types.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __LIBCPROJECT_TYPES__
#define __LIBCPROJECT_TYPES__
#include <stdint.h>
typedef uint8_t byte_t;
typedef char* string_t;
typedef float float32_t;
typedef double float64_t;
#endif

View File

@ -1,15 +1,20 @@
#ifndef __LIBCPROJECT__ #ifndef __LIBCPROJECT__
#define __LIBCPROJECT__ #define __LIBCPROJECT__
#include "lib/array_list.h"
#include "lib/assert.h"
#include "lib/character.h" #include "lib/character.h"
#include "lib/convert.h" #include "lib/convert.h"
#include "lib/dictionary.h" #include "lib/date.h"
#include "lib/filesystem.h" #include "lib/filesystem.h"
#include "lib/hash_map.h"
#include "lib/linked_list.h" #include "lib/linked_list.h"
#include "lib/mathematics.h" #include "lib/mathematics.h"
#include "lib/queue.h" #include "lib/queue.h"
#include "lib/stack.h" #include "lib/stack.h"
#include "lib/string.h" #include "lib/string.h"
#include "lib/terminal.h" #include "lib/terminal.h"
#include "lib/types.h"
#include "version.h"
#endif #endif

133
main.c
View File

@ -4,8 +4,135 @@
#include "libcproject.h" #include "libcproject.h"
int main() { int main() {
char* string = "Hello, world!"; int integer = 5;
printf("%s\n", string); terminal_print_int(&integer);
printf("string_length = %ld\n", string_get_length(string)); printf("\n");
bool boolean = true;
printf("terminal_print_bool: ");
terminal_print_bool(&boolean);
printf(", ");
boolean = false;
terminal_print_bool(&boolean);
printf("\n");
long integer_long = 5;
printf("terminal_print_long: ");
terminal_print_long(&integer_long);
printf("\n");
unsigned long integer_unsigned_long = 5;
printf("terminal_print_unsigned_long: ");
terminal_print_unsigned_long(&integer_unsigned_long);
printf("\n");
float floating_point = 5.5;
printf("terminal_print_float: ");
terminal_print_float(&floating_point);
printf("\n");
double floating_point_double = 5.5;
printf("terminal_print_double: ");
terminal_print_double(&floating_point_double);
printf("\n");
int8_t integer_8 = 5;
printf("terminal_print_int8_t: ");
terminal_print_int8_t(&integer_8);
printf("\n");
int16_t integer_16 = 5;
printf("terminal_print_int16_t: ");
terminal_print_int16_t(&integer_16);
printf("\n");
int32_t integer_32 = 5;
printf("terminal_print_int32_t: ");
terminal_print_int32_t(&integer_32);
printf("\n");
int64_t integer_64 = 5;
printf("terminal_print_int64_t: ");
terminal_print_int64_t(&integer_64);
printf("\n");
uint8_t integer_unsigned_8 = 5;
printf("terminal_print_uint8_t: ");
terminal_print_uint8_t(&integer_unsigned_8);
printf("\n");
uint16_t integer_unsigned_16 = 5;
printf("terminal_print_uint16_t: ");
terminal_print_uint16_t(&integer_unsigned_16);
printf("\n");
uint32_t integer_unsigned_32 = 5;
printf("terminal_print_uint32_t: ");
terminal_print_uint32_t(&integer_unsigned_32);
printf("\n");
uint64_t integer_unsigned_64 = 5;
printf("terminal_print_uint64_t: ");
terminal_print_uint64_t(&integer_unsigned_64);
printf("\n");
char character = 'c';
printf("terminal_print_char: ");
terminal_print_char(&character);
printf("\n");
int array[] = {1, 2, 3, 4, 5};
printf("terminal_print_array: ");
terminal_print_array(array, 5, sizeof(int), terminal_print_int);
string_t string = "Hello, world!";
printf("terminal_print_string: ");
terminal_print_string(string);
printf("\n");
struct stack* stack = stack_initialization();
stack_push(stack, &integer);
printf("terminal_print_stack: ");
terminal_print_stack(stack, terminal_print_int);
stack_free(stack);
struct queue* queue = queue_initialization();
queue_push(queue, &integer);
printf("terminal_print_queue: ");
terminal_print_queue(queue, terminal_print_int);
queue_free(queue);
struct linked_list* linked_list = linked_list_initialization();
linked_list_add_after_last(linked_list, string);
linked_list_add_after_last(linked_list, string);
printf("terminal_print_linked_list: ");
terminal_print_linked_list(linked_list, terminal_print_string);
linked_list_free(linked_list);
struct hash_map* hash_map = hash_map_initialization();
hash_map_add(hash_map, "key", &integer);
printf("terminal_print_hash_map: ");
terminal_print_hash_map(hash_map, terminal_print_int);
hash_map_free(hash_map);
struct array_list* array_list = array_list_initialization();
array_list_add(array_list, &integer);
array_list_add(array_list, &integer);
printf("terminal_print_array_list: ");
terminal_print_array_list(array_list, terminal_print_int);
array_list_free(array_list);
struct date* date = date_get_now_utc();
string_t iso_string = date_to_iso_string(date);
printf("date_get_now_utc = %s\n", iso_string);
free(iso_string);
free(date);
date = date_get_now_local();
iso_string = date_to_iso_string(date);
printf("date_get_now_local = %s\n", iso_string);
free(iso_string);
free(date);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -3,21 +3,23 @@
#include "libcproject.h" #include "libcproject.h"
int main(int argc, char* argv[]) { int main(int argc, string_t* argv) {
if (argc != 2) { if (argc != 2) {
fprintf(stderr, "Usage: %s <version>\n", argv[0]); fprintf(stderr, "Usage: %s <version>\n", argv[0]);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
char* content = "#ifndef __LIBCPROJECT_VERSION__\n"; string_t content = string_copy("#ifndef __LIBCPROJECT_VERSION__\n");
content = string_concatenate(content, "#define __LIBCPROJECT_VERSION__ \""); string_concatenate(&content, "#define __LIBCPROJECT_VERSION__ \"");
content = string_concatenate(content, argv[1]); string_concatenate(&content, argv[1]);
content = string_concatenate(content, "\"\n\n"); string_concatenate(&content, "\"\n\n");
content = string_concatenate(content, "#endif\n"); string_concatenate(&content, "#endif\n");
int result = filesystem_write("./version.h", content, string_get_length(content)); int result = filesystem_write("./version.h", (byte_t*)content, string_get_length(content));
if (result == -1) { if (result == -1) {
fprintf(stderr, "Error: Could not write to file.\n"); fprintf(stderr, "Error: Could not write to file.\n");
perror("Error (set_version)");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
printf("Success: Version set to %s.\n", argv[1]); printf("Success: Version set to %s.\n", argv[1]);
free(content);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

48
test/array_list_test.c Normal file
View File

@ -0,0 +1,48 @@
#include "array_list_test.h"
void array_list_test() {
struct array_list *list = array_list_initialization();
assert(list->size == 0);
array_list_add(list, (void *)'a');
array_list_add(list, (void *)'b');
array_list_add(list, (void *)'c');
array_list_add(list, (void *)'d');
array_list_add(list, (void *)'e');
array_list_add(list, (void *)'f');
assert(list->size == 6);
assert(array_list_get(list, 0) == (void *)'a');
assert(array_list_get(list, 1) == (void *)'b');
assert(array_list_get(list, 2) == (void *)'c');
assert(array_list_get(list, 3) == (void *)'d');
assert(array_list_get(list, 4) == (void *)'e');
assert(array_list_get(list, 5) == (void *)'f');
array_list_add(list, (void *)'a');
assert(array_list_get(list, 6) == (void *)'a');
assert(list->size == 7);
array_list_remove(list, 6);
assert(list->size == 6);
assert(array_list_get(list, 6) == NULL);
for (size_t index = 0; index < 100; index++) {
array_list_add(list, (void *)index);
}
assert(list->size == 106);
assert(array_list_get(list, 100) == (void *)94);
assert(array_list_get(list, 101) == (void *)95);
array_list_remove(list, 100);
assert(list->size == 105);
assert(array_list_get(list, 100) == (void *)95);
array_list_free(list);
list = array_list_initialization();
array_list_add(list, (void *)'a');
array_list_add(list, (void *)'b');
array_list_add(list, (void *)'c');
array_list_remove(list, 1);
assert(array_list_get(list, 0) == (void *)'a');
assert(array_list_get(list, 1) == (void *)'c');
assert(list->size == 2);
array_list_free(list);
}

13
test/array_list_test.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __ARRAY_LIST_TEST__
#define __ARRAY_LIST_TEST__
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
void array_list_test();
#endif

View File

@ -1,12 +1,5 @@
#include "character_test.h" #include "character_test.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
#include "test.h"
void character_test() { void character_test() {
character_append_test(); character_append_test();
character_append_at_test(); character_append_at_test();
@ -27,7 +20,7 @@ void character_append_at_test() {
character_append_at(string, 'd', 1); character_append_at(string, 'd', 1);
assert(assert_string_equal(string, "adbc")); assert(assert_string_equal(string, "adbc"));
char string2[5] = "abcd"; char string2[6] = "abcd";
character_append_at(string2, 'e', 4); character_append_at(string2, 'e', 4);
assert(assert_string_equal(string2, "abcde")); assert(assert_string_equal(string2, "abcde"));
} }

View File

@ -1,6 +1,12 @@
#ifndef __CHARACTER_TEST__ #ifndef __CHARACTER_TEST__
#define __CHARACTER_TEST__ #define __CHARACTER_TEST__
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
void character_test(); void character_test();
void character_append_test(); void character_append_test();

View File

@ -1,12 +1,5 @@
#include "convert_test.h" #include "convert_test.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
#include "test.h"
void convert_test() { void convert_test() {
convert_character_to_string_test(); convert_character_to_string_test();
convert_character_to_digit_test(); convert_character_to_digit_test();
@ -17,11 +10,25 @@ void convert_test() {
} }
void convert_character_to_string_test() { void convert_character_to_string_test() {
assert(assert_string_equal(convert_character_to_string('a'), "a")); string_t result = convert_character_to_string('a');
assert(assert_string_equal(convert_character_to_string('A'), "A")); assert(assert_string_equal(result, "a"));
assert(assert_string_equal(convert_character_to_string('0'), "0")); free(result);
assert(assert_string_equal(convert_character_to_string(' '), " "));
assert(assert_string_equal(convert_character_to_string('\0'), "")); result = convert_character_to_string('A');
assert(assert_string_equal(result, "A"));
free(result);
result = convert_character_to_string('0');
assert(assert_string_equal(result, "0"));
free(result);
result = convert_character_to_string(' ');
assert(assert_string_equal(result, " "));
free(result);
result = convert_character_to_string('\0');
assert(assert_string_equal(result, ""));
free(result);
} }
void convert_character_to_digit_test() { void convert_character_to_digit_test() {
@ -70,33 +77,109 @@ void convert_string_to_number_test() {
} }
void convert_number_to_string_test() { void convert_number_to_string_test() {
assert(assert_string_equal(convert_number_to_string(0), "0")); string_t result = convert_number_to_string(0);
assert(assert_string_equal(convert_number_to_string(1), "1")); assert(assert_string_equal(result, "0"));
assert(assert_string_equal(convert_number_to_string(2), "2")); free(result);
assert(assert_string_equal(convert_number_to_string(3), "3"));
assert(assert_string_equal(convert_number_to_string(4), "4")); result = convert_number_to_string(1);
assert(assert_string_equal(convert_number_to_string(5), "5")); assert(assert_string_equal(result, "1"));
assert(assert_string_equal(convert_number_to_string(6), "6")); free(result);
assert(assert_string_equal(convert_number_to_string(7), "7"));
assert(assert_string_equal(convert_number_to_string(8), "8")); result = convert_number_to_string(2);
assert(assert_string_equal(convert_number_to_string(9), "9")); assert(assert_string_equal(result, "2"));
assert(assert_string_equal(convert_number_to_string(10), "10")); free(result);
assert(assert_string_equal(convert_number_to_string(11), "11"));
assert(assert_string_equal(convert_number_to_string(20), "20")); result = convert_number_to_string(3);
assert(assert_string_equal(convert_number_to_string(-0), "0")); assert(assert_string_equal(result, "3"));
assert(assert_string_equal(convert_number_to_string(-1), "-1")); free(result);
assert(assert_string_equal(convert_number_to_string(-20), "-20"));
result = convert_number_to_string(4);
assert(assert_string_equal(result, "4"));
free(result);
result = convert_number_to_string(5);
assert(assert_string_equal(result, "5"));
free(result);
result = convert_number_to_string(6);
assert(assert_string_equal(result, "6"));
free(result);
result = convert_number_to_string(7);
assert(assert_string_equal(result, "7"));
free(result);
result = convert_number_to_string(8);
assert(assert_string_equal(result, "8"));
free(result);
result = convert_number_to_string(9);
assert(assert_string_equal(result, "9"));
free(result);
result = convert_number_to_string(10);
assert(assert_string_equal(result, "10"));
free(result);
result = convert_number_to_string(11);
assert(assert_string_equal(result, "11"));
free(result);
result = convert_number_to_string(20);
assert(assert_string_equal(result, "20"));
free(result);
result = convert_number_to_string(-0);
assert(assert_string_equal(result, "0"));
free(result);
result = convert_number_to_string(-1);
assert(assert_string_equal(result, "-1"));
free(result);
result = convert_number_to_string(-20);
assert(assert_string_equal(result, "-20"));
free(result);
} }
void convert_number_from_base_to_another_test() { void convert_number_from_base_to_another_test() {
assert(assert_string_equal(convert_number_from_base_to_another("15", 10, 16), "F")); string_t result = convert_number_from_base_to_another("15", 10, 16);
assert(assert_string_equal(convert_number_from_base_to_another("100000000", 2, 16), "100")); assert(assert_string_equal(result, "F"));
assert(assert_string_equal(convert_number_from_base_to_another("FFFFFF", 16, 10), "16777215")); free(result);
assert(assert_string_equal(convert_number_from_base_to_another("1D57", 17, 35), "75C"));
assert(assert_string_equal(convert_number_from_base_to_another("80E", 20, 5), "100324")); result = convert_number_from_base_to_another("100000000", 2, 16);
assert(assert_string_equal(convert_number_from_base_to_another("99", 10, 10), "99")); assert(assert_string_equal(result, "100"));
assert(assert_string_equal(convert_number_from_base_to_another("3433024", 6, 28), "8008")); free(result);
assert(assert_string_equal(convert_number_from_base_to_another("30288G3A", 17, 36), "KF12OI"));
assert(assert_string_equal(convert_number_from_base_to_another("10", 9, 9), "10")); result = convert_number_from_base_to_another("FFFFFF", 16, 10);
assert(assert_string_equal(convert_number_from_base_to_another("10E", 23, 8), "1037")); assert(assert_string_equal(result, "16777215"));
free(result);
result = convert_number_from_base_to_another("1D57", 17, 35);
assert(assert_string_equal(result, "75C"));
free(result);
result = convert_number_from_base_to_another("80E", 20, 5);
assert(assert_string_equal(result, "100324"));
free(result);
result = convert_number_from_base_to_another("99", 10, 10);
assert(assert_string_equal(result, "99"));
free(result);
result = convert_number_from_base_to_another("3433024", 6, 28);
assert(assert_string_equal(result, "8008"));
free(result);
result = convert_number_from_base_to_another("30288G3A", 17, 36);
assert(assert_string_equal(result, "KF12OI"));
free(result);
result = convert_number_from_base_to_another("10", 9, 9);
assert(assert_string_equal(result, "10"));
free(result);
result = convert_number_from_base_to_another("10E", 23, 8);
assert(assert_string_equal(result, "1037"));
free(result);
} }

View File

@ -1,6 +1,12 @@
#ifndef __CONVERT_TEST__ #ifndef __CONVERT_TEST__
#define __CONVERT_TEST__ #define __CONVERT_TEST__
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
void convert_test(); void convert_test();
void convert_character_to_string_test(); void convert_character_to_string_test();

191
test/date_test.c Normal file
View File

@ -0,0 +1,191 @@
#include "date_test.h"
void date_test() {
date_copy_test();
date_to_iso_string_test();
date_to_iso_string_without_time_test();
date_from_iso_string_test();
date_get_is_leap_year_test();
date_duration_seconds_between_2_dates_test();
date_to_utc_test();
date_get_age_test();
}
void date_copy_test() {
struct date *date = malloc(sizeof(struct date));
date->year = 2024;
date->month = 9;
date->day = 10;
date->hours = 20;
date->minutes = 34;
date->seconds = 25;
date->milliseconds = 76;
date->timezone_utc_offset = 0;
struct date *date2 = date_copy(date);
assert(date != date2);
assert(date->year == date2->year);
assert(date->month == date2->month);
assert(date->day == date2->day);
assert(date->hours == date2->hours);
assert(date->minutes == date2->minutes);
assert(date->seconds == date2->seconds);
assert(date->milliseconds == date2->milliseconds);
assert(date->timezone_utc_offset == date2->timezone_utc_offset);
date->year = 2025;
assert(date->year == 2025);
assert(date2->year == 2024);
free(date);
free(date2);
}
void date_to_iso_string_test() {
struct date *date = malloc(sizeof(struct date));
date->year = 2024;
date->month = 9;
date->day = 10;
date->hours = 20;
date->minutes = 34;
date->seconds = 25;
date->milliseconds = 76;
date->timezone_utc_offset = 0;
string_t iso_string = date_to_iso_string(date);
assert(assert_string_equal(iso_string, "2024-09-10T20:34:25.076Z"));
free(iso_string);
free(date);
}
void date_to_iso_string_without_time_test() {
struct date *date = malloc(sizeof(struct date));
date->year = 2024;
date->month = 9;
date->day = 10;
date->hours = 20;
date->minutes = 34;
date->seconds = 25;
date->milliseconds = 76;
date->timezone_utc_offset = 0;
string_t iso_string = date_to_iso_string_without_time(date);
assert(assert_string_equal(iso_string, "2024-09-10"));
free(iso_string);
free(date);
}
void date_from_iso_string_test() {
string_t iso_string = "2024-09-10T20:34:25.076Z";
struct date *date = date_from_iso_string(iso_string);
assert(date->year == 2024);
assert(date->month == 9);
assert(date->day == 10);
assert(date->hours == 20);
assert(date->minutes == 34);
assert(date->seconds == 25);
assert(date->milliseconds == 76);
assert(date->timezone_utc_offset == 0);
free(date);
}
void date_get_is_leap_year_test() {
assert(date_get_is_leap_year(2020));
assert(!date_get_is_leap_year(2021));
assert(!date_get_is_leap_year(2022));
assert(!date_get_is_leap_year(2023));
assert(date_get_is_leap_year(2024));
}
void date_duration_seconds_between_2_dates_test() {
struct date *date1 = date_from_iso_string("2024-09-10T20:34:25.076Z");
struct date *date2 = date_from_iso_string("2024-09-10T20:34:25.076Z");
assert(date_duration_seconds_between_2_dates(date1, date2) == 0);
free(date1);
free(date2);
date1 = date_from_iso_string("2024-09-10T20:34:25.076Z");
date2 = date_from_iso_string("2024-09-10T23:34:26.076Z");
assert(date_duration_seconds_between_2_dates(date1, date2) == 10801);
free(date1);
free(date2);
date1 = date_from_iso_string("2024-09-10T20:34:25.076Z");
date2 = date_from_iso_string("2024-09-10T20:48:25.076Z");
assert(date_duration_seconds_between_2_dates(date1, date2) == 840);
free(date1);
free(date2);
date1 = date_from_iso_string("2024-09-10T20:34:25.076Z");
date2 = date_from_iso_string("2024-09-10T20:34:38.076Z");
assert(date_duration_seconds_between_2_dates(date1, date2) == 13);
free(date1);
free(date2);
}
void date_to_utc_test() {
struct date *date = date_from_iso_string("2024-09-10T20:34:25.076Z");
date->timezone_utc_offset = 3;
date_to_utc(date);
assert(date->timezone_utc_offset == 0);
string_t iso_string = date_to_iso_string(date);
assert(assert_string_equal(iso_string, "2024-09-10T17:34:25.076Z"));
free(iso_string);
free(date);
date = date_from_iso_string("2024-09-10T20:34:25.076Z");
date->timezone_utc_offset = -3;
date_to_utc(date);
assert(date->timezone_utc_offset == 0);
iso_string = date_to_iso_string(date);
assert(assert_string_equal(iso_string, "2024-09-10T23:34:25.076Z"));
free(iso_string);
free(date);
date = date_from_iso_string("2024-01-01T00:00:00.000Z");
date->timezone_utc_offset = 3;
date_to_utc(date);
assert(date->timezone_utc_offset == 0);
iso_string = date_to_iso_string(date);
assert(assert_string_equal(iso_string, "2023-12-31T21:00:00.000Z"));
free(iso_string);
free(date);
date = date_from_iso_string("2023-12-31T21:00:00.000Z");
date->timezone_utc_offset = -4;
date_to_utc(date);
assert(date->timezone_utc_offset == 0);
iso_string = date_to_iso_string(date);
assert(assert_string_equal(iso_string, "2024-01-01T01:00:00.000Z"));
free(iso_string);
free(date);
}
void date_get_age_test() {
struct date *birth_date = date_from_iso_string("1980-02-20T00:00:00.000Z");
struct date *current_date = date_from_iso_string("2018-03-20T00:00:00.000Z");
assert(date_get_age(birth_date, current_date) == 38);
free(birth_date);
free(current_date);
birth_date = date_from_iso_string("1980-07-20T00:00:00.000Z");
current_date = date_from_iso_string("2018-03-20T00:00:00.000Z");
assert(date_get_age(birth_date, current_date) == 37);
free(birth_date);
free(current_date);
birth_date = date_from_iso_string("1980-03-20T00:00:00.000Z");
current_date = date_from_iso_string("2018-03-20T00:00:00.000Z");
assert(date_get_age(birth_date, current_date) == 38);
free(birth_date);
free(current_date);
birth_date = date_from_iso_string("1980-03-25T00:00:00.000Z");
current_date = date_from_iso_string("2018-03-20T00:00:00.000Z");
assert(date_get_age(birth_date, current_date) == 37);
free(birth_date);
free(current_date);
}

26
test/date_test.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __DATE_TEST__
#define __DATE_TEST__
#include <assert.h>
#include "libcproject.h"
void date_test();
void date_copy_test();
void date_to_iso_string_test();
void date_to_iso_string_without_time_test();
void date_from_iso_string_test();
void date_get_is_leap_year_test();
void date_duration_seconds_between_2_dates_test();
void date_to_utc_test();
void date_get_age_test();
#endif

View File

@ -1,33 +0,0 @@
#include "dictionary_test.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
void dictionary_test() {
struct dictionary *dictionary = dictionary_initialization();
assert(dictionary->length == 0);
dictionary_add(dictionary, "key", (void *)'a');
dictionary_add(dictionary, "key1", (void *)'b');
dictionary_add(dictionary, "key2", (void *)'c');
dictionary_add(dictionary, "key3", (void *)'d');
dictionary_add(dictionary, "key4", (void *)'e');
dictionary_add(dictionary, "key5", (void *)'f');
assert(dictionary->length == 6);
assert(dictionary_get(dictionary, "key")->data == (void *)'a');
assert(dictionary_get(dictionary, "key1")->data == (void *)'b');
assert(dictionary_get(dictionary, "key2")->data == (void *)'c');
assert(dictionary_get(dictionary, "key3")->data == (void *)'d');
assert(dictionary_get(dictionary, "key4")->data == (void *)'e');
assert(dictionary_get(dictionary, "key5")->data == (void *)'f');
dictionary_add(dictionary, "key5", (void *)'a');
assert(dictionary_get(dictionary, "key5")->data == (void *)'a');
assert(dictionary_contains_key(dictionary, "key5"));
assert(!dictionary_contains_key(dictionary, "invalid key"));
assert(dictionary_contains_key(dictionary, "key5"));
dictionary_remove(dictionary, "key5");
assert(dictionary->length == 5);
assert(!dictionary_contains_key(dictionary, "key5"));
}

View File

@ -1,6 +0,0 @@
#ifndef __DICTIONARY_TEST__
#define __DICTIONARY_TEST__
void dictionary_test();
#endif

28
test/hash_map_test.c Normal file
View File

@ -0,0 +1,28 @@
#include "hash_map_test.h"
void hash_map_test() {
struct hash_map *hash_map = hash_map_initialization();
assert(hash_map->length == 0);
hash_map_add(hash_map, "key", (void *)'a');
hash_map_add(hash_map, "key1", (void *)'b');
hash_map_add(hash_map, "key2", (void *)'c');
hash_map_add(hash_map, "key3", (void *)'d');
hash_map_add(hash_map, "key4", (void *)'e');
hash_map_add(hash_map, "key5", (void *)'f');
assert(hash_map->length == 6);
assert(hash_map_get(hash_map, "key") == (void *)'a');
assert(hash_map_get(hash_map, "key1") == (void *)'b');
assert(hash_map_get(hash_map, "key2") == (void *)'c');
assert(hash_map_get(hash_map, "key3") == (void *)'d');
assert(hash_map_get(hash_map, "key4") == (void *)'e');
assert(hash_map_get(hash_map, "key5") == (void *)'f');
hash_map_add(hash_map, "key5", (void *)'a');
assert(hash_map_get(hash_map, "key5") == (void *)'a');
assert(hash_map_contains_key(hash_map, "key5"));
assert(!hash_map_contains_key(hash_map, "invalid key"));
assert(hash_map_contains_key(hash_map, "key5"));
hash_map_remove(hash_map, "key5");
assert(hash_map->length == 5);
assert(!hash_map_contains_key(hash_map, "key5"));
hash_map_free(hash_map);
}

12
test/hash_map_test.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef __HASH_MAP_TEST__
#define __HASH_MAP_TEST__
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
void hash_map_test();
#endif

View File

@ -1,12 +1,5 @@
#include "linked_list_test.h" #include "linked_list_test.h"
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
void linked_list_test() { void linked_list_test() {
linked_list_initialization_test(); linked_list_initialization_test();
linked_list_add_in_head_test(); linked_list_add_in_head_test();
@ -20,6 +13,7 @@ void linked_list_initialization_test() {
struct linked_list *list = linked_list_initialization(); struct linked_list *list = linked_list_initialization();
assert(list->length == 0); assert(list->length == 0);
assert(list->head == NULL); assert(list->head == NULL);
linked_list_free(list);
} }
void linked_list_add_in_head_test() { void linked_list_add_in_head_test() {
@ -32,6 +26,7 @@ void linked_list_add_in_head_test() {
assert(((uintptr_t)list->head->next->data) == 8); assert(((uintptr_t)list->head->next->data) == 8);
assert(((uintptr_t)list->head->next->next->data) == 4); assert(((uintptr_t)list->head->next->next->data) == 4);
assert(list->head->next->next->next == NULL); assert(list->head->next->next->next == NULL);
linked_list_free(list);
} }
void linked_list_delete_in_head_test() { void linked_list_delete_in_head_test() {
@ -44,6 +39,7 @@ void linked_list_delete_in_head_test() {
assert(((uintptr_t)list->head->data) == 8); assert(((uintptr_t)list->head->data) == 8);
assert(((uintptr_t)list->head->next->data) == 4); assert(((uintptr_t)list->head->next->data) == 4);
assert(list->head->next->next == NULL); assert(list->head->next->next == NULL);
linked_list_free(list);
} }
void linked_list_add_after_last_test() { void linked_list_add_after_last_test() {
@ -61,6 +57,7 @@ void linked_list_add_after_last_test() {
assert(((uintptr_t)list->head->next->data) == 8); assert(((uintptr_t)list->head->next->data) == 8);
assert(((uintptr_t)list->head->next->next->data) == 4); assert(((uintptr_t)list->head->next->next->data) == 4);
assert(((uintptr_t)list->head->next->next->next->data) == 18); assert(((uintptr_t)list->head->next->next->next->data) == 18);
linked_list_free(list);
} }
void linked_list_reverse_test() { void linked_list_reverse_test() {
@ -81,6 +78,8 @@ void linked_list_reverse_test() {
assert((list_reversed->head->next->data) == (void *)'C'); assert((list_reversed->head->next->data) == (void *)'C');
assert((list_reversed->head->next->next->data) == (void *)'B'); assert((list_reversed->head->next->next->data) == (void *)'B');
assert((list_reversed->head->next->next->next->data) == (void *)'A'); assert((list_reversed->head->next->next->next->data) == (void *)'A');
linked_list_free(list);
linked_list_free(list_reversed);
} }
void linked_list_reverse_mutate_test() { void linked_list_reverse_mutate_test() {
@ -96,4 +95,5 @@ void linked_list_reverse_mutate_test() {
assert((list->head->next->data) == (void *)'C'); assert((list->head->next->data) == (void *)'C');
assert((list->head->next->next->data) == (void *)'B'); assert((list->head->next->next->data) == (void *)'B');
assert((list->head->next->next->next->data) == (void *)'A'); assert((list->head->next->next->next->data) == (void *)'A');
linked_list_free(list);
} }

View File

@ -1,6 +1,13 @@
#ifndef __LINKED_LIST_TEST__ #ifndef __LINKED_LIST_TEST__
#define __LINKED_LIST_TEST__ #define __LINKED_LIST_TEST__
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
void linked_list_test(); void linked_list_test();
void linked_list_initialization_test(); void linked_list_initialization_test();

View File

@ -1,9 +1,11 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "array_list_test.h"
#include "character_test.h" #include "character_test.h"
#include "convert_test.h" #include "convert_test.h"
#include "dictionary_test.h" #include "date_test.h"
#include "hash_map_test.h"
#include "linked_list_test.h" #include "linked_list_test.h"
#include "mathematics_test.h" #include "mathematics_test.h"
#include "queue_test.h" #include "queue_test.h"
@ -11,9 +13,11 @@
#include "string_test.h" #include "string_test.h"
int main() { int main() {
array_list_test();
character_test(); character_test();
convert_test(); convert_test();
dictionary_test(); date_test();
hash_map_test();
linked_list_test(); linked_list_test();
mathematics_test(); mathematics_test();
queue_test(); queue_test();

View File

@ -1,15 +1,16 @@
#include "mathematics_test.h" #include "mathematics_test.h"
#include <assert.h>
#include "libcproject.h"
void mathematics_test() { void mathematics_test() {
mathematics_absolute_value_test(); mathematics_absolute_value_test();
mathematics_pow_test(); mathematics_pow_test();
mathematics_root_test(); mathematics_root_test();
mathematics_square_root_test(); mathematics_square_root_test();
mathematics_factorial_test(); mathematics_factorial_test();
mathematics_opposite_test();
mathematics_max_test();
mathematics_max_values_test();
mathematics_min_test();
mathematics_min_values_test();
} }
void mathematics_absolute_value_test() { void mathematics_absolute_value_test() {
@ -60,3 +61,38 @@ void mathematics_factorial_test() {
assert(mathematics_factorial(9) == 362880); assert(mathematics_factorial(9) == 362880);
assert(mathematics_factorial(10) == 3628800); assert(mathematics_factorial(10) == 3628800);
} }
void mathematics_opposite_test() {
assert(mathematics_opposite(-7) == 7);
assert(mathematics_opposite(7) == -7);
}
void mathematics_max_test() {
assert(mathematics_max(0, 0) == 0);
assert(mathematics_max(0, 1) == 1);
assert(mathematics_max(2, 0) == 2);
assert(mathematics_max(54, 37) == 54);
}
void mathematics_max_values_test() {
int64_t values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
assert(mathematics_max_values(values, 10) == 9);
int64_t values2[] = {8, 6, 4, 7};
assert(mathematics_max_values(values2, 4) == 8);
}
void mathematics_min_test() {
assert(mathematics_min(0, 0) == 0);
assert(mathematics_min(3, 5) == 3);
assert(mathematics_min(2, 1) == 1);
assert(mathematics_min(54, 37) == 37);
}
void mathematics_min_values_test() {
int64_t values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
assert(mathematics_min_values(values, 10) == 0);
int64_t values2[] = {9, 6, 8, 7};
assert(mathematics_min_values(values2, 4) == 6);
}

View File

@ -1,6 +1,10 @@
#ifndef __MATHEMATICS_TEST__ #ifndef __MATHEMATICS_TEST__
#define __MATHEMATICS_TEST__ #define __MATHEMATICS_TEST__
#include <assert.h>
#include "libcproject.h"
void mathematics_test(); void mathematics_test();
void mathematics_absolute_value_test(); void mathematics_absolute_value_test();
@ -13,4 +17,14 @@ void mathematics_square_root_test();
void mathematics_factorial_test(); void mathematics_factorial_test();
void mathematics_opposite_test();
void mathematics_max_test();
void mathematics_max_values_test();
void mathematics_min_test();
void mathematics_min_values_test();
#endif #endif

View File

@ -1,11 +1,5 @@
#include "queue_test.h" #include "queue_test.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "libcproject.h"
void queue_test() { void queue_test() {
queue_initialization_test(); queue_initialization_test();
queue_push_test(); queue_push_test();
@ -16,6 +10,7 @@ void queue_initialization_test() {
struct queue *queue = queue_initialization(); struct queue *queue = queue_initialization();
assert(queue->length == 0); assert(queue->length == 0);
assert(queue->first == NULL); assert(queue->first == NULL);
queue_free(queue);
} }
void queue_push_test() { void queue_push_test() {
@ -28,6 +23,7 @@ void queue_push_test() {
assert(((uintptr_t)queue->first->next->data) == 8); assert(((uintptr_t)queue->first->next->data) == 8);
assert(((uintptr_t)queue->first->next->next->data) == 15); assert(((uintptr_t)queue->first->next->next->data) == 15);
assert(queue->first->next->next->next == NULL); assert(queue->first->next->next->next == NULL);
queue_free(queue);
} }
void queue_pop_test() { void queue_pop_test() {
@ -41,4 +37,5 @@ void queue_pop_test() {
assert(((uintptr_t)queue->first->data) == 8); assert(((uintptr_t)queue->first->data) == 8);
assert(((uintptr_t)queue->first->next->data) == 15); assert(((uintptr_t)queue->first->next->data) == 15);
assert(queue->first->next->next == NULL); assert(queue->first->next->next == NULL);
queue_free(queue);
} }

View File

@ -1,6 +1,12 @@
#ifndef __QUEUE_TEST__ #ifndef __QUEUE_TEST__
#define __QUEUE_TEST__ #define __QUEUE_TEST__
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "libcproject.h"
void queue_test(); void queue_test();
void queue_initialization_test(); void queue_initialization_test();

View File

@ -1,11 +1,5 @@
#include "stack_test.h" #include "stack_test.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "libcproject.h"
void stack_test() { void stack_test() {
stack_initialization_test(); stack_initialization_test();
stack_push_test(); stack_push_test();
@ -16,6 +10,7 @@ void stack_initialization_test() {
struct stack *stack = stack_initialization(); struct stack *stack = stack_initialization();
assert(stack->length == 0); assert(stack->length == 0);
assert(stack->first == NULL); assert(stack->first == NULL);
stack_free(stack);
} }
void stack_push_test() { void stack_push_test() {
@ -28,6 +23,7 @@ void stack_push_test() {
assert(((uintptr_t)stack->first->next->data) == 8); assert(((uintptr_t)stack->first->next->data) == 8);
assert(((uintptr_t)stack->first->next->next->data) == 4); assert(((uintptr_t)stack->first->next->next->data) == 4);
assert(stack->first->next->next->next == NULL); assert(stack->first->next->next->next == NULL);
stack_free(stack);
} }
void stack_pop_test() { void stack_pop_test() {
@ -41,4 +37,5 @@ void stack_pop_test() {
assert(((uintptr_t)stack->first->data) == 8); assert(((uintptr_t)stack->first->data) == 8);
assert(((uintptr_t)stack->first->next->data) == 4); assert(((uintptr_t)stack->first->next->data) == 4);
assert(stack->first->next->next == NULL); assert(stack->first->next->next == NULL);
stack_free(stack);
} }

View File

@ -1,6 +1,12 @@
#ifndef __STACK_TEST__ #ifndef __STACK_TEST__
#define __STACK_TEST__ #define __STACK_TEST__
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include "libcproject.h"
void stack_test(); void stack_test();
void stack_initialization_test(); void stack_initialization_test();

View File

@ -1,17 +1,11 @@
#include "string_test.h" #include "string_test.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
#include "test.h"
void string_test() { void string_test() {
string_get_length_test(); string_get_length_test();
string_to_uppercase_test(); string_to_uppercase_test();
string_to_lowercase_test(); string_to_lowercase_test();
string_replace_test(); string_replace_test();
string_remove_character_test();
string_trim_start_test(); string_trim_start_test();
string_trim_end_test(); string_trim_end_test();
string_trim_test(); string_trim_test();
@ -31,81 +25,102 @@ void string_test() {
string_get_last_occurence_of_character_test(); string_get_last_occurence_of_character_test();
string_starts_with_test(); string_starts_with_test();
string_ends_with_test(); string_ends_with_test();
string_position_of_test();
string_last_position_of_test();
string_pad_start_test();
string_zero_pad_test();
} }
void string_get_length_test() { void string_get_length_test() {
char *string = "Hello World!"; string_t string = "Hello World!";
size_t string_length = string_get_length(string); size_t string_length = string_get_length(string);
assert(string_length == 12); assert(string_length == 12);
assert(strlen(string) == string_length);
} }
void string_to_uppercase_test() { void string_to_uppercase_test() {
char *string = "heLlO world"; string_t string = string_copy("heLlO world");
string = string_to_uppercase(string); string_to_uppercase(string);
assert(assert_string_equal(string, "HELLO WORLD")); assert(assert_string_equal(string, "HELLO WORLD"));
free(string);
} }
void string_to_lowercase_test() { void string_to_lowercase_test() {
char *string = "HellO WoRLd"; string_t string = string_copy("HellO WoRLd");
string = string_to_lowercase(string); string_to_lowercase(string);
assert(assert_string_equal(string, "hello world")); assert(assert_string_equal(string, "hello world"));
free(string);
} }
void string_replace_test() { void string_replace_test() {
char *string = "hello world"; string_t string = string_copy("hello world");
string = string_replace(string, 'l', 'z'); string_replace(string, 'l', 'z');
assert(assert_string_equal(string, "hezzo worzd")); assert(assert_string_equal(string, "hezzo worzd"));
free(string);
}
void string_remove_character_test() {
string_t string = string_copy("hello world");
string_remove_character(string, 'l');
assert(assert_string_equal(string, "heo word"));
free(string);
} }
void string_trim_start_test() { void string_trim_start_test() {
char *string = " hello world "; string_t string = string_copy(" hello world ");
string = string_trim_start(string); string_trim_start(string, ' ');
assert(assert_string_equal(string, "hello world ")); assert(assert_string_equal(string, "hello world "));
free(string);
} }
void string_trim_end_test() { void string_trim_end_test() {
char *string = " hello world "; string_t string = string_copy(" hello world ");
string = string_trim_end(string); string_trim_end(string, ' ');
assert(assert_string_equal(string, " hello world")); assert(assert_string_equal(string, " hello world"));
free(string);
} }
void string_trim_test() { void string_trim_test() {
char *string = " hello world "; string_t string = string_copy(" hello world ");
string = string_trim(string); string_trim(string, ' ');
assert(assert_string_equal(string, "hello world")); assert(assert_string_equal(string, "hello world"));
free(string);
} }
void string_copy_test() { void string_copy_test() {
char *string = "hello world"; string_t string = "hello world";
char *string2 = string_copy(string); string_t string2 = string_copy(string);
assert(assert_string_equal(string, string2)); assert(assert_string_equal(string, string2));
string2[0] = 'a'; string2[0] = 'a';
assert(assert_string_not_equal(string, string2)); assert(assert_string_not_equal(string, string2));
assert(assert_string_equal(string, "hello world")); assert(assert_string_equal(string, "hello world"));
assert(assert_string_equal(string2, "aello world")); assert(assert_string_equal(string2, "aello world"));
free(string2);
} }
void string_capitalize_test() { void string_capitalize_test() {
char *string = "hello world"; string_t string = string_copy("hello world");
string = string_capitalize(string); string_capitalize(string);
assert(assert_string_equal(string, "Hello world")); assert(assert_string_equal(string, "Hello world"));
free(string);
} }
void string_total_occurrences_of_character_test() { void string_total_occurrences_of_character_test() {
char *string = "hello world"; string_t string = "hello world";
assert(string_total_occurrences_of_character(string, 'l') == 3); assert(string_total_occurrences_of_character(string, 'l') == 3);
} }
void string_reverse_test() { void string_reverse_test() {
char *string = "hello world"; string_t string = string_copy("hello world");
string = string_reverse(string); string_reverse(string);
assert(assert_string_equal(string, "dlrow olleh")); assert(assert_string_equal(string, "dlrow olleh"));
free(string);
} }
void string_equals_test() { void string_equals_test() {
char *string1 = "hello world"; string_t string1 = "hello world";
char *string2 = "dlrow olleh"; string_t string2 = "dlrow olleh";
char *string3 = "dlrow olleh"; string_t string3 = "dlrow olleh";
assert(!string_equals(string1, string2)); assert(!string_equals(string1, string2));
assert(string_equals(string1, string1)); assert(string_equals(string1, string1));
assert(string_equals(string2, string3)); assert(string_equals(string2, string3));
@ -124,29 +139,46 @@ void string_get_is_integer_test() {
} }
void string_split_test() { void string_split_test() {
char *string = "abc def ghij kl"; string_t string = "abc def ghij kl";
size_t result_length = 0; size_t result_length = 0;
char **result = string_split(string, ' ', &result_length); string_t* result = string_split(string, ' ', &result_length);
assert(result_length == 4); assert(result_length == 4);
assert(assert_string_equal(result[0], "abc")); assert(assert_string_equal(result[0], "abc"));
assert(assert_string_equal(result[1], "def")); assert(assert_string_equal(result[1], "def"));
assert(assert_string_equal(result[2], "ghij")); assert(assert_string_equal(result[2], "ghij"));
assert(assert_string_equal(result[3], "kl")); assert(assert_string_equal(result[3], "kl"));
for (size_t index = 0; index < result_length; index++) {
free(result[index]);
}
free(result);
} }
void string_join_test() { void string_join_test() {
char *string = "abc def ghij kl"; string_t string = "abc def ghij kl";
size_t result_length = 0; size_t result_length = 0;
char **result = string_split(string, ' ', &result_length); string_t* result = string_split(string, ' ', &result_length);
char *new_string = string_join(result, ' ', result_length); string_t new_string = string_join(result, ' ', result_length);
char *new_string2 = string_join(result, '+', result_length); string_t new_string2 = string_join(result, '+', result_length);
assert(assert_string_equal(new_string, string)); assert(assert_string_equal(new_string, string));
assert(assert_string_equal(new_string2, "abc+def+ghij+kl")); assert(assert_string_equal(new_string2, "abc+def+ghij+kl"));
free(new_string);
free(new_string2);
for (size_t index = 0; index < result_length; index++) {
free(result[index]);
}
free(result);
} }
void string_concatenate_test() { void string_concatenate_test() {
assert(assert_string_equal(string_concatenate("abc", "def"), "abcdef")); string_t result = string_copy("abc");
assert(assert_string_equal(string_concatenate("abc ", " defghi"), "abc defghi")); string_concatenate(&result, "def");
assert(assert_string_equal(result, "abcdef"));
free(result);
result = string_copy("abcz");
string_concatenate(&result, " defghi");
assert(assert_string_equal(result, "abcz defghi"));
free(result);
} }
void string_get_has_unique_characters_test() { void string_get_has_unique_characters_test() {
@ -156,13 +188,14 @@ void string_get_has_unique_characters_test() {
} }
void string_substring_test() { void string_substring_test() {
char *string = "abcdef"; string_t string = "abcdef";
char *substring = string_substring(string, 1, 3); string_t substring = string_substring(string, 1, 3);
assert(assert_string_equal(substring, "bcd")); assert(assert_string_equal(substring, "bcd"));
free(substring);
} }
void string_get_is_substring_test() { void string_get_is_substring_test() {
char *string = "abcdef"; string_t string = "abcdef";
assert(string_get_is_substring(string, "abc")); assert(string_get_is_substring(string, "abc"));
assert(string_get_is_substring(string, "bcd")); assert(string_get_is_substring(string, "bcd"));
assert(string_get_is_substring(string, "de")); assert(string_get_is_substring(string, "de"));
@ -174,33 +207,61 @@ void string_get_is_substring_test() {
} }
void string_get_formatted_number_test() { void string_get_formatted_number_test() {
assert(assert_string_equal(string_get_formatted_number(1000, " "), "1 000")); string_t result = string_get_formatted_number(1000, " ");
assert(assert_string_equal(string_get_formatted_number(123, ","), "123")); assert(assert_string_equal(result, "1 000"));
assert(assert_string_equal(string_get_formatted_number(1234, ","), "1,234")); free(result);
assert(assert_string_equal(string_get_formatted_number(12345, ","), "12,345"));
assert(assert_string_equal(string_get_formatted_number(123456, ","), "123,456")); result = string_get_formatted_number(123, ",");
assert(assert_string_equal(string_get_formatted_number(1234567, ","), "1,234,567")); assert(assert_string_equal(result, "123"));
assert(assert_string_equal(string_get_formatted_number(12345678, ","), "12,345,678")); free(result);
assert(assert_string_equal(string_get_formatted_number(123456789, ","), "123,456,789"));
assert(assert_string_equal(string_get_formatted_number(1234567890, ","), "1,234,567,890")); result = string_get_formatted_number(1234, ",");
assert(assert_string_equal(string_get_formatted_number(-123, ","), "-123")); assert(assert_string_equal(result, "1,234"));
assert(assert_string_equal(string_get_formatted_number(-1234, ","), "-1,234")); free(result);
assert(assert_string_equal(string_get_formatted_number(-12345, ","), "-12,345"));
assert(assert_string_equal(string_get_formatted_number(-123456, ","), "-123,456")); result = string_get_formatted_number(12345, ",");
assert(assert_string_equal(string_get_formatted_number(-1234567, ","), "-1,234,567")); assert(assert_string_equal(result, "12,345"));
assert(assert_string_equal(string_get_formatted_number(-12345678, ","), "-12,345,678")); free(result);
assert(assert_string_equal(string_get_formatted_number(-123456789, ","), "-123,456,789"));
assert(assert_string_equal(string_get_formatted_number(-1234567890, ","), "-1,234,567,890")); result = string_get_formatted_number(-123, ",");
assert(assert_string_equal(result, "-123"));
free(result);
result = string_get_formatted_number(-1234, ",");
assert(assert_string_equal(result, "-1,234"));
free(result);
result = string_get_formatted_number(-1234567890, ",");
assert(assert_string_equal(result, "-1,234,567,890"));
free(result);
} }
void string_get_last_occurence_of_character_test() { void string_get_last_occurence_of_character_test() {
char *string = "abcdef"; string_t string = "abcdef";
assert(assert_string_equal(string_get_last_occurence_of_character(string, 'a'), "abcdef"));
assert(assert_string_equal(string_get_last_occurence_of_character(string, 'b'), "bcdef")); string_t result = string_get_last_occurence_of_character(string, 'a');
assert(assert_string_equal(string_get_last_occurence_of_character(string, 'c'), "cdef")); assert(assert_string_equal(result, "abcdef"));
assert(assert_string_equal(string_get_last_occurence_of_character(string, 'd'), "def")); free(result);
assert(assert_string_equal(string_get_last_occurence_of_character(string, 'e'), "ef"));
assert(assert_string_equal(string_get_last_occurence_of_character(string, 'f'), "f")); result = string_get_last_occurence_of_character(string, 'b');
assert(assert_string_equal(result, "bcdef"));
free(result);
result = string_get_last_occurence_of_character(string, 'c');
assert(assert_string_equal(result, "cdef"));
free(result);
result = string_get_last_occurence_of_character(string, 'd');
assert(assert_string_equal(result, "def"));
free(result);
result = string_get_last_occurence_of_character(string, 'e');
assert(assert_string_equal(result, "ef"));
free(result);
result = string_get_last_occurence_of_character(string, 'f');
assert(assert_string_equal(result, "f"));
free(result);
} }
void string_starts_with_test() { void string_starts_with_test() {
@ -220,3 +281,55 @@ void string_ends_with_test() {
assert(!string_ends_with("abcdef", "bcd")); assert(!string_ends_with("abcdef", "bcd"));
assert(!string_ends_with("abcdef", "abcdefg")); assert(!string_ends_with("abcdef", "abcdefg"));
} }
void string_position_of_test() {
assert(string_position_of("hello world", 'e') == 2);
assert(string_position_of("hello world", 'o') == 5);
assert(string_position_of("abcdef", 'a') == 1);
assert(string_position_of("abcdef", 'b') == 2);
assert(string_position_of("abcdef", 'c') == 3);
assert(string_position_of("abcdef", 'd') == 4);
assert(string_position_of("abcdef", 'e') == 5);
assert(string_position_of("abcdef", 'f') == 6);
assert(string_position_of("abcdef", 'g') == 0);
}
void string_last_position_of_test() {
assert(string_last_position_of("hello world", 'e') == 2);
assert(string_last_position_of("hello world", 'o') == 8);
assert(string_last_position_of("abcdef", 'a') == 1);
assert(string_last_position_of("abcdef", 'b') == 2);
assert(string_last_position_of("abcdef", 'c') == 3);
assert(string_last_position_of("abcdef", 'd') == 4);
assert(string_last_position_of("abcdef", 'e') == 5);
assert(string_last_position_of("abcdef", 'f') == 6);
assert(string_last_position_of("abcdef", 'g') == 0);
}
void string_pad_start_test() {
string_t result = string_pad_start("hello", "ab", 10);
assert(assert_string_equal(result, "ababahello"));
free(result);
result = string_pad_start("hello", "ab", 4);
assert(assert_string_equal(result, "hell"));
free(result);
result = string_pad_start("hello", "ab", 5);
assert(assert_string_equal(result, "hello"));
free(result);
result = string_pad_start("hello", "ab", 6);
assert(assert_string_equal(result, "ahello"));
free(result);
}
void string_zero_pad_test() {
string_t result = string_zero_pad(1, 2);
assert(assert_string_equal(result, "01"));
free(result);
result = string_zero_pad(10, 2);
assert(assert_string_equal(result, "10"));
free(result);
}

View File

@ -1,6 +1,12 @@
#ifndef __STRING_TEST__ #ifndef __STRING_TEST__
#define __STRING_TEST__ #define __STRING_TEST__
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "libcproject.h"
void string_test(); void string_test();
void string_get_length_test(); void string_get_length_test();
@ -11,6 +17,8 @@ void string_to_lowercase_test();
void string_replace_test(); void string_replace_test();
void string_remove_character_test();
void string_trim_start_test(); void string_trim_start_test();
void string_trim_end_test(); void string_trim_end_test();
@ -49,4 +57,12 @@ void string_starts_with_test();
void string_ends_with_test(); void string_ends_with_test();
void string_position_of_test();
void string_last_position_of_test();
void string_pad_start_test();
void string_zero_pad_test();
#endif #endif

View File

@ -1,19 +0,0 @@
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
bool assert_string_equal(const char *actual, const char *expected) {
if (strcmp(expected, actual) != 0) {
printf("FAIL: expected = \"%s\" ; actual = \"%s\"\n", expected, actual);
return false;
}
return true;
}
bool assert_string_not_equal(const char *actual, const char *expected) {
if (strcmp(expected, actual) == 0) {
printf("FAIL: expected = \"%s\" ; actual = \"%s\"\n", expected, actual);
return false;
}
return true;
}

View File

@ -1,10 +0,0 @@
#ifndef __TEST__
#define __TEST__
#include <stdbool.h>
bool assert_string_equal(const char *actual, const char *expected);
bool assert_string_not_equal(const char *actual, const char *expected);
#endif

View File

@ -1,4 +1,4 @@
#ifndef __LIBCPROJECT_VERSION__ #ifndef __LIBCPROJECT_VERSION__
#define __LIBCPROJECT_VERSION__ "1.0.0" #define __LIBCPROJECT_VERSION__ "5.1.0"
#endif #endif