1 /*
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
12 /* Function prints a string on terminal screen with requested margin.
13 * It takes care to not divide words.
14 * shell Pointer to shell instance.
15 * p_str Pointer to string to be printed.
16 * terminal_offset Requested left margin.
17 * offset_first_line Add margin to the first printed line.
18 */
formatted_text_print(const struct shell * sh,const char * str,size_t terminal_offset,bool offset_first_line)19 static void formatted_text_print(const struct shell *sh, const char *str,
20 size_t terminal_offset, bool offset_first_line)
21 {
22 size_t offset = 0;
23 size_t length;
24
25 if (str == NULL) {
26 return;
27 }
28
29 if (offset_first_line) {
30 z_shell_op_cursor_horiz_move(sh, terminal_offset);
31 }
32
33
34 /* Skipping whitespace. */
35 while (isspace((int) *(str + offset)) != 0) {
36 ++offset;
37 }
38
39 while (true) {
40 size_t idx = 0;
41
42 length = z_shell_strlen(str) - offset;
43
44 if (length <=
45 sh->ctx->vt100_ctx.cons.terminal_wid - terminal_offset) {
46 for (idx = 0; idx < length; idx++) {
47 if (*(str + offset + idx) == '\n') {
48 z_transport_buffer_flush(sh);
49 z_shell_write(sh, str + offset, idx);
50 offset += idx + 1;
51 z_cursor_next_line_move(sh);
52 z_shell_op_cursor_horiz_move(sh,
53 terminal_offset);
54 break;
55 }
56 }
57
58 /* String will fit in one line. */
59 z_shell_raw_fprintf(sh->fprintf_ctx, str + offset);
60
61 break;
62 }
63
64 /* String is longer than terminal line so text needs to
65 * divide in the way to not divide words.
66 */
67 length = sh->ctx->vt100_ctx.cons.terminal_wid
68 - terminal_offset;
69
70 while (true) {
71 /* Determining line break. */
72 if (isspace((int) (*(str + offset + idx))) != 0) {
73 length = idx;
74 if (*(str + offset + idx) == '\n') {
75 break;
76 }
77 }
78
79 if ((idx + terminal_offset) >=
80 sh->ctx->vt100_ctx.cons.terminal_wid) {
81 /* End of line reached. */
82 break;
83 }
84
85 ++idx;
86 }
87
88 /* Writing one line, fprintf IO buffer must be flushed
89 * before calling shell_write.
90 */
91 z_transport_buffer_flush(sh);
92 z_shell_write(sh, str + offset, length);
93 offset += length;
94
95 /* Calculating text offset to ensure that next line will
96 * not begin with a space.
97 */
98 while (isspace((int) (*(str + offset))) != 0) {
99 ++offset;
100 }
101
102 z_cursor_next_line_move(sh);
103 z_shell_op_cursor_horiz_move(sh, terminal_offset);
104
105 }
106 z_cursor_next_line_move(sh);
107 }
108
help_item_print(const struct shell * sh,const char * item_name,uint16_t item_name_width,const char * item_help)109 static void help_item_print(const struct shell *sh, const char *item_name,
110 uint16_t item_name_width, const char *item_help)
111 {
112 static const uint8_t tabulator[] = " ";
113 static const char sub_cmd_sep[] = ": "; /* subcommands separator */
114 const uint16_t offset = 2 * strlen(tabulator) + item_name_width + strlen(sub_cmd_sep);
115
116 if ((item_name == NULL) || (item_name[0] == '\0')) {
117 return;
118 }
119
120 if (!IS_ENABLED(CONFIG_NEWLIB_LIBC) &&
121 !IS_ENABLED(CONFIG_ARCH_POSIX)) {
122 /* print option name */
123 z_shell_fprintf(sh, SHELL_NORMAL, "%s%-*s", tabulator,
124 item_name_width, item_name);
125 } else {
126 uint16_t tmp = item_name_width - strlen(item_name);
127 char space = ' ';
128
129 z_shell_fprintf(sh, SHELL_NORMAL, "%s%s", tabulator,
130 item_name);
131
132 if (item_help) {
133 for (uint16_t i = 0; i < tmp; i++) {
134 z_shell_write(sh, &space, 1);
135 }
136 }
137 }
138
139 if (item_help == NULL) {
140 z_cursor_next_line_move(sh);
141 return;
142 } else {
143 z_shell_fprintf(sh, SHELL_NORMAL, "%s: ", tabulator);
144 }
145 /* print option help */
146 formatted_text_print(sh, item_help, offset, false);
147 }
148
149 /* Function prints all subcommands of the parent command together with their
150 * help string
151 */
z_shell_help_subcmd_print(const struct shell * sh,const struct shell_static_entry * parent,const char * description)152 void z_shell_help_subcmd_print(const struct shell *sh,
153 const struct shell_static_entry *parent,
154 const char *description)
155 {
156 const struct shell_static_entry *entry = NULL;
157 struct shell_static_entry dloc;
158 uint16_t longest = 0U;
159 size_t idx = 0;
160
161 /* Searching for the longest subcommand to print. */
162 while ((entry = z_shell_cmd_get(parent, idx++, &dloc)) != NULL) {
163 longest = Z_MAX(longest, z_shell_strlen(entry->syntax));
164 }
165
166 /* No help to print */
167 if (longest == 0) {
168 return;
169 }
170
171 if (description != NULL) {
172 z_shell_fprintf(sh, SHELL_NORMAL, description);
173 }
174
175 /* Printing subcommands and help string (if exists). */
176 idx = 0;
177
178 while ((entry = z_shell_cmd_get(parent, idx++, &dloc)) != NULL) {
179 help_item_print(sh, entry->syntax, longest, entry->help);
180 }
181 }
182
z_shell_help_cmd_print(const struct shell * sh,const struct shell_static_entry * cmd)183 void z_shell_help_cmd_print(const struct shell *sh,
184 const struct shell_static_entry *cmd)
185 {
186 static const char cmd_sep[] = " - "; /* commands separator */
187 uint16_t field_width;
188
189 field_width = z_shell_strlen(cmd->syntax) + z_shell_strlen(cmd_sep);
190
191 z_shell_fprintf(sh, SHELL_NORMAL, "%s%s", cmd->syntax, cmd_sep);
192
193 formatted_text_print(sh, cmd->help, field_width, false);
194 }
195
z_shell_help_request(const char * str)196 bool z_shell_help_request(const char *str)
197 {
198 if (!IS_ENABLED(CONFIG_SHELL_HELP_OPT_PARSE)) {
199 return false;
200 }
201
202 if (!strcmp(str, "-h") || !strcmp(str, "--help")) {
203 return true;
204 }
205
206 return false;
207 }
208