blob: d4ac77e6650a9f3f713503c0d57e521a000229cf [file] [log] [blame]
Jakub Rzeszutko3064ca42018-11-26 17:09:56 +01001/*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6#include <ctype.h>
7#include "shell_ops.h"
8#include "shell_help.h"
9#include "shell_utils.h"
10
11/* Function prints a string on terminal screen with requested margin.
12 * It takes care to not divide words.
13 * shell Pointer to shell instance.
14 * p_str Pointer to string to be printed.
15 * terminal_offset Requested left margin.
16 * offset_first_line Add margin to the first printed line.
17 */
18static void formatted_text_print(const struct shell *shell, const char *str,
19 size_t terminal_offset, bool offset_first_line)
20{
21 size_t offset = 0;
22 size_t length;
23
24 if (str == NULL) {
25 return;
26 }
27
28 if (offset_first_line) {
29 shell_op_cursor_horiz_move(shell, terminal_offset);
30 }
31
32
33 /* Skipping whitespace. */
34 while (isspace((int) *(str + offset))) {
35 ++offset;
36 }
37
38 while (true) {
39 size_t idx = 0;
40
41 length = shell_strlen(str) - offset;
42
43 if (length <=
44 shell->ctx->vt100_ctx.cons.terminal_wid - terminal_offset) {
45 for (idx = 0; idx < length; idx++) {
46 if (*(str + offset + idx) == '\n') {
47 transport_buffer_flush(shell);
48 shell_write(shell, str + offset, idx);
49 offset += idx + 1;
50 cursor_next_line_move(shell);
51 shell_op_cursor_horiz_move(shell,
52 terminal_offset);
53 break;
54 }
55 }
56
57 /* String will fit in one line. */
58 shell_raw_fprintf(shell->fprintf_ctx, str + offset);
59
60 break;
61 }
62
63 /* String is longer than terminal line so text needs to
64 * divide in the way to not divide words.
65 */
66 length = shell->ctx->vt100_ctx.cons.terminal_wid
67 - terminal_offset;
68
69 while (true) {
70 /* Determining line break. */
71 if (isspace((int) (*(str + offset + idx)))) {
72 length = idx;
73 if (*(str + offset + idx) == '\n') {
74 break;
75 }
76 }
77
78 if ((idx + terminal_offset) >=
79 shell->ctx->vt100_ctx.cons.terminal_wid) {
80 /* End of line reached. */
81 break;
82 }
83
84 ++idx;
85 }
86
87 /* Writing one line, fprintf IO buffer must be flushed
88 * before calling shell_write.
89 */
90 transport_buffer_flush(shell);
91 shell_write(shell, str + offset, length);
92 offset += length;
93
94 /* Calculating text offset to ensure that next line will
95 * not begin with a space.
96 */
97 while (isspace((int) (*(str + offset)))) {
98 ++offset;
99 }
100
101 cursor_next_line_move(shell);
102 shell_op_cursor_horiz_move(shell, terminal_offset);
103
104 }
105 cursor_next_line_move(shell);
106}
107
108static void help_item_print(const struct shell *shell, const char *item_name,
109 u16_t item_name_width, const char *item_help)
110{
111 static const u8_t tabulator[] = " ";
112 const u16_t offset = 2 * strlen(tabulator) + item_name_width + 1;
113
114 if (item_name == NULL) {
115 return;
116 }
117
118 if (!IS_ENABLED(CONFIG_NEWLIB_LIBC) && !IS_ENABLED(CONFIG_ARCH_POSIX)) {
119 /* print option name */
120 shell_fprintf(shell, SHELL_NORMAL, "%s%-*s%s:",
121 tabulator,
122 item_name_width, item_name,
123 tabulator);
124 } else {
125 u16_t tmp = item_name_width - strlen(item_name);
126 char space = ' ';
127
128 shell_fprintf(shell, SHELL_NORMAL, "%s%s", tabulator,
129 item_name);
130 for (u16_t i = 0; i < tmp; i++) {
131 shell_write(shell, &space, 1);
132 }
133 shell_fprintf(shell, SHELL_NORMAL, "%s:", tabulator);
134 }
135
136 if (item_help == NULL) {
137 cursor_next_line_move(shell);
138 return;
139 }
140 /* print option help */
141 formatted_text_print(shell, item_help, offset, false);
142}
143
144/* Function is printing command help, its subcommands name and subcommands
145 * help string.
146 */
147void shell_help_subcmd_print(const struct shell *shell)
148{
149 const struct shell_static_entry *entry = NULL;
150 struct shell_static_entry static_entry;
151 u16_t longest_syntax = 0;
152 size_t cmd_idx = 0;
153
154 /* Checking if there are any subcommands available. */
155 if (!shell->ctx->active_cmd.subcmd) {
156 return;
157 }
158
159 /* Searching for the longest subcommand to print. */
160 do {
161 shell_cmd_get(shell->ctx->active_cmd.subcmd,
162 !SHELL_CMD_ROOT_LVL,
163 cmd_idx++, &entry, &static_entry);
164
165 if (!entry) {
166 break;
167 }
168
169 u16_t len = shell_strlen(entry->syntax);
170
171 longest_syntax = longest_syntax > len ? longest_syntax : len;
172 } while (cmd_idx != 0); /* too many commands */
173
174 if (cmd_idx == 1) {
175 return;
176 }
177
Jakub Rzeszutko4d491b22018-12-13 09:58:17 +0100178 shell_fprintf(shell, SHELL_NORMAL, "Subcommands:\n");
Jakub Rzeszutko3064ca42018-11-26 17:09:56 +0100179
180 /* Printing subcommands and help string (if exists). */
181 cmd_idx = 0;
182
183 while (true) {
184 shell_cmd_get(shell->ctx->active_cmd.subcmd,
185 !SHELL_CMD_ROOT_LVL,
186 cmd_idx++, &entry, &static_entry);
187
188 if (entry == NULL) {
189 break;
190 }
191
192 help_item_print(shell, entry->syntax, longest_syntax,
193 entry->help);
194 }
195}
196
197void shell_help_cmd_print(const struct shell *shell)
198{
199 static const char cmd_sep[] = " - "; /* commands separator */
200
201 u16_t field_width = shell_strlen(shell->ctx->active_cmd.syntax) +
202 shell_strlen(cmd_sep);
203
204 shell_fprintf(shell, SHELL_NORMAL, "%s%s",
205 shell->ctx->active_cmd.syntax, cmd_sep);
206
207 formatted_text_print(shell, shell->ctx->active_cmd.help,
208 field_width, false);
209}
210