@fugood/llama.node 0.3.9 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/bin/darwin/arm64/llama-node.node +0 -0
  2. package/bin/darwin/x64/llama-node.node +0 -0
  3. package/bin/linux/arm64/llama-node.node +0 -0
  4. package/bin/linux/x64/llama-node.node +0 -0
  5. package/bin/linux-cuda/arm64/llama-node.node +0 -0
  6. package/bin/linux-cuda/x64/llama-node.node +0 -0
  7. package/bin/linux-vulkan/arm64/llama-node.node +0 -0
  8. package/bin/linux-vulkan/x64/llama-node.node +0 -0
  9. package/bin/win32/arm64/llama-node.node +0 -0
  10. package/bin/win32/arm64/node.lib +0 -0
  11. package/bin/win32/x64/llama-node.node +0 -0
  12. package/bin/win32/x64/node.lib +0 -0
  13. package/bin/win32-vulkan/arm64/llama-node.node +0 -0
  14. package/bin/win32-vulkan/arm64/node.lib +0 -0
  15. package/bin/win32-vulkan/x64/llama-node.node +0 -0
  16. package/bin/win32-vulkan/x64/node.lib +0 -0
  17. package/lib/binding.js +2 -2
  18. package/lib/binding.ts +47 -8
  19. package/lib/index.js +21 -1
  20. package/lib/index.ts +31 -1
  21. package/package.json +12 -3
  22. package/src/LlamaCompletionWorker.cpp +33 -6
  23. package/src/LlamaCompletionWorker.h +3 -1
  24. package/src/LlamaContext.cpp +336 -28
  25. package/src/LlamaContext.h +2 -0
  26. package/src/common.hpp +19 -2
  27. package/src/llama.cpp/.github/workflows/build.yml +289 -107
  28. package/src/llama.cpp/.github/workflows/close-issue.yml +1 -1
  29. package/src/llama.cpp/.github/workflows/docker.yml +2 -1
  30. package/src/llama.cpp/.github/workflows/server.yml +25 -2
  31. package/src/llama.cpp/CMakeLists.txt +10 -19
  32. package/src/llama.cpp/cmake/build-info.cmake +1 -1
  33. package/src/llama.cpp/common/CMakeLists.txt +32 -0
  34. package/src/llama.cpp/common/arg.cpp +66 -16
  35. package/src/llama.cpp/common/chat-template.hpp +515 -0
  36. package/src/llama.cpp/common/chat.cpp +966 -0
  37. package/src/llama.cpp/common/chat.hpp +52 -0
  38. package/src/llama.cpp/common/common.cpp +159 -36
  39. package/src/llama.cpp/common/common.h +56 -14
  40. package/src/llama.cpp/common/json-schema-to-grammar.cpp +46 -66
  41. package/src/llama.cpp/common/json-schema-to-grammar.h +15 -1
  42. package/src/llama.cpp/common/llguidance.cpp +270 -0
  43. package/src/llama.cpp/common/log.cpp +1 -10
  44. package/src/llama.cpp/common/log.h +10 -0
  45. package/src/llama.cpp/common/minja.hpp +2868 -0
  46. package/src/llama.cpp/common/sampling.cpp +22 -1
  47. package/src/llama.cpp/common/sampling.h +3 -0
  48. package/src/llama.cpp/docs/build.md +54 -9
  49. package/src/llama.cpp/examples/export-lora/export-lora.cpp +12 -2
  50. package/src/llama.cpp/examples/gbnf-validator/gbnf-validator.cpp +1 -1
  51. package/src/llama.cpp/examples/llava/CMakeLists.txt +7 -0
  52. package/src/llama.cpp/examples/llava/clip-quantize-cli.cpp +59 -0
  53. package/src/llama.cpp/examples/llava/clip.cpp +133 -14
  54. package/src/llama.cpp/examples/llava/clip.h +2 -0
  55. package/src/llama.cpp/examples/llava/llava.cpp +22 -8
  56. package/src/llama.cpp/examples/llava/minicpmv-cli.cpp +9 -1
  57. package/src/llama.cpp/examples/main/main.cpp +26 -25
  58. package/src/llama.cpp/examples/run/linenoise.cpp/linenoise.cpp +136 -137
  59. package/src/llama.cpp/examples/run/linenoise.cpp/linenoise.h +18 -4
  60. package/src/llama.cpp/examples/run/run.cpp +224 -69
  61. package/src/llama.cpp/examples/server/server.cpp +252 -81
  62. package/src/llama.cpp/examples/server/utils.hpp +73 -21
  63. package/src/llama.cpp/examples/simple-chat/simple-chat.cpp +6 -4
  64. package/src/llama.cpp/examples/simple-cmake-pkg/CMakeLists.txt +11 -0
  65. package/src/llama.cpp/ggml/CMakeLists.txt +78 -1
  66. package/src/llama.cpp/ggml/include/ggml.h +1 -1
  67. package/src/llama.cpp/ggml/src/CMakeLists.txt +21 -4
  68. package/src/llama.cpp/ggml/src/ggml-alloc.c +1 -13
  69. package/src/llama.cpp/ggml/src/ggml-cpu/ggml-cpu-quants.c +91 -78
  70. package/src/llama.cpp/ggml/src/ggml-cpu/ggml-cpu.c +7 -7
  71. package/src/llama.cpp/ggml/src/ggml-cpu/ggml-cpu.cpp +2 -1
  72. package/src/llama.cpp/ggml/src/ggml-cuda/CMakeLists.txt +1 -1
  73. package/src/llama.cpp/ggml/src/ggml-cuda/vendors/hip.h +46 -0
  74. package/src/llama.cpp/ggml/src/ggml-hip/CMakeLists.txt +16 -1
  75. package/src/llama.cpp/ggml/src/ggml-musa/CMakeLists.txt +1 -1
  76. package/src/llama.cpp/ggml/src/ggml-rpc/ggml-rpc.cpp +28 -8
  77. package/src/llama.cpp/ggml/src/ggml-sycl/ggml-sycl.cpp +5 -7
  78. package/src/llama.cpp/ggml/src/ggml-sycl/softmax.cpp +33 -23
  79. package/src/llama.cpp/ggml/src/ggml-sycl/softmax.hpp +1 -5
  80. package/src/llama.cpp/ggml/src/ggml-vulkan/ggml-vulkan.cpp +323 -121
  81. package/src/llama.cpp/ggml/src/ggml-vulkan/vulkan-shaders/vulkan-shaders-gen.cpp +13 -3
  82. package/src/llama.cpp/ggml/src/ggml.c +23 -13
  83. package/src/llama.cpp/include/llama.h +14 -1
  84. package/src/llama.cpp/models/ggml-vocab-deepseek-r1-qwen.gguf.inp +112 -0
  85. package/src/llama.cpp/models/ggml-vocab-deepseek-r1-qwen.gguf.out +46 -0
  86. package/src/llama.cpp/src/CMakeLists.txt +1 -1
  87. package/src/llama.cpp/src/llama-arch.cpp +7 -2
  88. package/src/llama.cpp/src/llama-arch.h +3 -1
  89. package/src/llama.cpp/src/llama-chat.cpp +11 -2
  90. package/src/llama.cpp/src/llama-chat.h +1 -0
  91. package/src/llama.cpp/src/llama-grammar.cpp +86 -6
  92. package/src/llama.cpp/src/llama-grammar.h +22 -1
  93. package/src/llama.cpp/src/llama-mmap.cpp +1 -0
  94. package/src/llama.cpp/src/llama-model-loader.cpp +1 -1
  95. package/src/llama.cpp/src/llama-model.cpp +76 -6
  96. package/src/llama.cpp/src/llama-sampling.cpp +47 -4
  97. package/src/llama.cpp/src/llama-vocab.cpp +10 -4
  98. package/src/llama.cpp/src/llama.cpp +181 -123
  99. package/src/llama.cpp/tests/CMakeLists.txt +4 -0
  100. package/src/llama.cpp/tests/test-backend-ops.cpp +158 -57
  101. package/src/llama.cpp/tests/test-chat-template.cpp +154 -31
  102. package/src/llama.cpp/tests/test-chat.cpp +607 -0
  103. package/src/llama.cpp/tests/test-grammar-integration.cpp +2 -2
  104. package/src/llama.cpp/tests/test-grammar-llguidance.cpp +1140 -0
  105. package/src/llama.cpp/tests/test-json-schema-to-grammar.cpp +1 -1
  106. package/src/llama.cpp/examples/main-cmake-pkg/CMakeLists.txt +0 -32
@@ -140,6 +140,9 @@ static void process_image(struct llava_context * ctx_llava, struct llava_image_e
140
140
  else if (has_minicpmv_projector == 3) {
141
141
  system_prompt = "<|im_start|>user\n";
142
142
  }
143
+ else if (has_minicpmv_projector == 4) {
144
+ system_prompt = "<|im_start|>user\n";
145
+ }
143
146
  LOG_INF("%s: image token past: %d\n", __func__, n_past);
144
147
  eval_string(ctx_llava->ctx_llama, (system_prompt+"<image>").c_str(), params->n_batch, &n_past, false);
145
148
  process_eval_image_embed(ctx_llava, embeds, params->n_batch, &n_past, idx++);
@@ -227,6 +230,9 @@ static struct common_sampler * llama_init(struct llava_context * ctx_llava, comm
227
230
  else if (has_minicpmv_projector == 3) {
228
231
  user_prompt = "<|im_start|>user\n" + prompt;
229
232
  }
233
+ else if (has_minicpmv_projector == 4) {
234
+ user_prompt = "<|im_start|>user\n" + prompt;
235
+ }
230
236
  }
231
237
 
232
238
  eval_string(ctx_llava->ctx_llama, user_prompt.c_str(), params->n_batch, &n_past, false);
@@ -236,6 +242,9 @@ static struct common_sampler * llama_init(struct llava_context * ctx_llava, comm
236
242
  else if (has_minicpmv_projector == 3) {
237
243
  eval_string(ctx_llava->ctx_llama, "<|im_end|><|im_start|>assistant\n", params->n_batch, &n_past, false);
238
244
  }
245
+ else if (has_minicpmv_projector == 4) {
246
+ eval_string(ctx_llava->ctx_llama, "<|im_end|><|im_start|>assistant\n", params->n_batch, &n_past, false);
247
+ }
239
248
 
240
249
  // generate the response
241
250
 
@@ -308,7 +317,6 @@ int main(int argc, char ** argv) {
308
317
  const auto * tmp = llama_loop(ctx_llava, smpl, n_past);
309
318
  response += tmp;
310
319
  if (strcmp(tmp, "</s>") == 0) break;
311
- if (strstr(tmp, "###")) break; // Yi-VL behavior
312
320
  printf("%s", tmp);// mistral llava-1.6
313
321
  if (strstr(response.c_str(), "<user>")) break; // minicpm-v
314
322
  fflush(stdout);
@@ -4,6 +4,7 @@
4
4
  #include "log.h"
5
5
  #include "sampling.h"
6
6
  #include "llama.h"
7
+ #include "chat-template.hpp"
7
8
 
8
9
  #include <cstdio>
9
10
  #include <cstring>
@@ -84,14 +85,6 @@ static void sigint_handler(int signo) {
84
85
  }
85
86
  #endif
86
87
 
87
- static std::string chat_add_and_format(struct llama_model * model, std::vector<common_chat_msg> & chat_msgs, const std::string & role, const std::string & content) {
88
- common_chat_msg new_msg{role, content};
89
- auto formatted = common_chat_format_single(model, g_params->chat_template, chat_msgs, new_msg, role == "user");
90
- chat_msgs.push_back({role, content});
91
- LOG_DBG("formatted: '%s'\n", formatted.c_str());
92
- return formatted;
93
- }
94
-
95
88
  int main(int argc, char ** argv) {
96
89
  common_params params;
97
90
  g_params = &params;
@@ -165,6 +158,7 @@ int main(int argc, char ** argv) {
165
158
  }
166
159
 
167
160
  const llama_vocab * vocab = llama_model_get_vocab(model);
161
+ auto chat_templates = common_chat_templates_from_model(model, params.chat_template);
168
162
 
169
163
  LOG_INF("%s: llama threadpool init, n_threads = %d\n", __func__, (int) params.cpuparams.n_threads);
170
164
 
@@ -207,7 +201,7 @@ int main(int argc, char ** argv) {
207
201
  }
208
202
 
209
203
  // auto enable conversation mode if chat template is available
210
- const bool has_chat_template = !common_get_builtin_chat_template(model).empty() || !params.chat_template.empty();
204
+ const bool has_chat_template = chat_templates.has_explicit_template && chat_templates.template_default;
211
205
  if (params.conversation_mode == COMMON_CONVERSATION_MODE_AUTO) {
212
206
  if (has_chat_template) {
213
207
  LOG_INF("%s: chat template is available, enabling conversation mode (disable it with -no-cnv)\n", __func__);
@@ -225,7 +219,7 @@ int main(int argc, char ** argv) {
225
219
  // print chat template example in conversation mode
226
220
  if (params.conversation_mode) {
227
221
  if (params.enable_chat_template) {
228
- LOG_INF("%s: chat template example:\n%s\n", __func__, common_chat_format_example(model, params.chat_template).c_str());
222
+ LOG_INF("%s: chat template example:\n%s\n", __func__, common_chat_format_example(*chat_templates.template_default, params.use_jinja).c_str());
229
223
  } else {
230
224
  LOG_INF("%s: in-suffix/prefix is specified, chat template will be disabled\n", __func__);
231
225
  }
@@ -260,7 +254,7 @@ int main(int argc, char ** argv) {
260
254
  }
261
255
  }
262
256
 
263
- const bool add_bos = llama_vocab_get_add_bos(vocab);
257
+ const bool add_bos = llama_vocab_get_add_bos(vocab) && !params.use_jinja;
264
258
  if (!llama_model_has_encoder(model)) {
265
259
  GGML_ASSERT(!llama_vocab_get_add_eos(vocab));
266
260
  }
@@ -269,10 +263,18 @@ int main(int argc, char ** argv) {
269
263
 
270
264
  std::vector<llama_token> embd_inp;
271
265
 
266
+ auto chat_add_and_format = [&chat_msgs, &chat_templates](const std::string & role, const std::string & content) {
267
+ common_chat_msg new_msg{role, content, {}};
268
+ auto formatted = common_chat_format_single(*chat_templates.template_default, chat_msgs, new_msg, role == "user", g_params->use_jinja);
269
+ chat_msgs.push_back({role, content, {}});
270
+ LOG_DBG("formatted: '%s'\n", formatted.c_str());
271
+ return formatted;
272
+ };
273
+
272
274
  {
273
275
  auto prompt = (params.conversation_mode && params.enable_chat_template)
274
276
  // format the system prompt in conversation mode (fallback to default if empty)
275
- ? chat_add_and_format(model, chat_msgs, "system", params.prompt.empty() ? DEFAULT_SYSTEM_MESSAGE : params.prompt)
277
+ ? chat_add_and_format("system", params.prompt.empty() ? DEFAULT_SYSTEM_MESSAGE : params.prompt)
276
278
  // otherwise use the prompt as is
277
279
  : params.prompt;
278
280
  if (params.interactive_first || !params.prompt.empty() || session_tokens.empty()) {
@@ -501,12 +503,14 @@ int main(int argc, char ** argv) {
501
503
 
502
504
  std::vector<llama_token> embd;
503
505
 
504
- // tokenized antiprompts
505
- std::vector<std::vector<llama_token>> antiprompt_ids;
506
+ // single-token antiprompts
507
+ std::vector<llama_token> antiprompt_token;
506
508
 
507
- antiprompt_ids.reserve(params.antiprompt.size());
508
509
  for (const std::string & antiprompt : params.antiprompt) {
509
- antiprompt_ids.emplace_back(::common_tokenize(ctx, antiprompt, false, true));
510
+ auto ids = ::common_tokenize(ctx, antiprompt, false, true);
511
+ if (ids.size() == 1) {
512
+ antiprompt_token.push_back(ids[0]);
513
+ }
510
514
  }
511
515
 
512
516
  if (llama_model_has_encoder(model)) {
@@ -751,14 +755,11 @@ int main(int argc, char ** argv) {
751
755
 
752
756
  // check for reverse prompt using special tokens
753
757
  llama_token last_token = common_sampler_last(smpl);
754
- for (std::vector<llama_token> ids : antiprompt_ids) {
755
- if (ids.size() == 1 && last_token == ids[0]) {
756
- if (params.interactive) {
757
- is_interacting = true;
758
- }
759
- is_antiprompt = true;
760
- break;
758
+ if (std::find(antiprompt_token.begin(), antiprompt_token.end(), last_token) != antiprompt_token.end()) {
759
+ if (params.interactive) {
760
+ is_interacting = true;
761
761
  }
762
+ is_antiprompt = true;
762
763
  }
763
764
 
764
765
  if (is_antiprompt) {
@@ -779,7 +780,7 @@ int main(int argc, char ** argv) {
779
780
  }
780
781
 
781
782
  if (params.enable_chat_template) {
782
- chat_add_and_format(model, chat_msgs, "assistant", assistant_ss.str());
783
+ chat_add_and_format("assistant", assistant_ss.str());
783
784
  }
784
785
  is_interacting = true;
785
786
  LOG("\n");
@@ -844,7 +845,7 @@ int main(int argc, char ** argv) {
844
845
 
845
846
  bool format_chat = params.conversation_mode && params.enable_chat_template;
846
847
  std::string user_inp = format_chat
847
- ? chat_add_and_format(model, chat_msgs, "user", std::move(buffer))
848
+ ? chat_add_and_format("user", std::move(buffer))
848
849
  : std::move(buffer);
849
850
  // TODO: one inconvenient of current chat template implementation is that we can't distinguish between user input and special tokens (prefix/postfix)
850
851
  const auto line_pfx = common_tokenize(ctx, params.input_prefix, false, true);
@@ -103,24 +103,26 @@
103
103
  *
104
104
  */
105
105
 
106
- #include <termios.h>
107
- #include <unistd.h>
108
- #include <stdlib.h>
109
- #include <stdio.h>
110
- #include <errno.h>
111
- #include <string.h>
112
- #include <stdlib.h>
113
- #include <ctype.h>
114
- #include <sys/stat.h>
115
- #include <sys/types.h>
116
- #include <sys/ioctl.h>
117
- #include <unistd.h>
118
- #include <vector>
119
- #include "linenoise.h"
120
-
121
- #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
122
- #define LINENOISE_MAX_LINE 4096
123
- static std::vector<const char*> unsupported_term = {"dumb","cons25","emacs",nullptr};
106
+ # include "linenoise.h"
107
+
108
+ # include <ctype.h>
109
+ # include <errno.h>
110
+ # include <stdio.h>
111
+ # include <string.h>
112
+ # include <sys/file.h>
113
+ # include <sys/ioctl.h>
114
+ # include <sys/stat.h>
115
+ # include <sys/types.h>
116
+ # include <termios.h>
117
+ # include <unistd.h>
118
+
119
+ # include <memory>
120
+ # include <string>
121
+ # include <vector>
122
+
123
+ # define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
124
+ # define LINENOISE_MAX_LINE 4096
125
+ static std::vector<const char *> unsupported_term = { "dumb", "cons25", "emacs" };
124
126
  static linenoiseCompletionCallback *completionCallback = NULL;
125
127
  static linenoiseHintsCallback *hintsCallback = NULL;
126
128
  static linenoiseFreeHintsCallback *freeHintsCallback = NULL;
@@ -166,21 +168,58 @@ int linenoiseHistoryAdd(const char *line);
166
168
  #define REFRESH_ALL (REFRESH_CLEAN|REFRESH_WRITE) // Do both.
167
169
  static void refreshLine(struct linenoiseState *l);
168
170
 
171
+ class File {
172
+ public:
173
+ FILE * file = nullptr;
174
+
175
+ FILE * open(const std::string & filename, const char * mode) {
176
+ file = fopen(filename.c_str(), mode);
177
+
178
+ return file;
179
+ }
180
+
181
+ int lock() {
182
+ if (file) {
183
+ fd = fileno(file);
184
+ if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
185
+ fd = -1;
186
+
187
+ return 1;
188
+ }
189
+ }
190
+
191
+ return 0;
192
+ }
193
+
194
+ ~File() {
195
+ if (fd >= 0) {
196
+ flock(fd, LOCK_UN);
197
+ }
198
+
199
+ if (file) {
200
+ fclose(file);
201
+ }
202
+ }
203
+
204
+ private:
205
+ int fd = -1;
206
+ };
207
+
169
208
  __attribute__((format(printf, 1, 2)))
170
209
  /* Debugging function. */
171
210
  #if 0
172
211
  static void lndebug(const char *fmt, ...) {
173
- static FILE *lndebug_fp = NULL;
174
- if (lndebug_fp == NULL) {
175
- lndebug_fp = fopen("/tmp/lndebug.txt", "a");
212
+ static File file;
213
+ if (file.file == nullptr) {
214
+ file.open("/tmp/lndebug.txt", "a");
176
215
  }
177
216
 
178
- if (lndebug_fp != NULL) {
217
+ if (file.file != nullptr) {
179
218
  va_list args;
180
219
  va_start(args, fmt);
181
- vfprintf(lndebug_fp, fmt, args);
220
+ vfprintf(file.file, fmt, args);
182
221
  va_end(args);
183
- fflush(lndebug_fp);
222
+ fflush(file.file);
184
223
  }
185
224
  }
186
225
  #else
@@ -213,8 +252,11 @@ void linenoiseSetMultiLine(int ml) {
213
252
  static int isUnsupportedTerm(void) {
214
253
  char *term = getenv("TERM");
215
254
  if (term == NULL) return 0;
216
- for (int j = 0; unsupported_term[j]; ++j)
217
- if (!strcasecmp(term, unsupported_term[j])) return 1;
255
+ for (size_t j = 0; j < unsupported_term.size(); ++j) {
256
+ if (!strcasecmp(term, unsupported_term[j])) {
257
+ return 1;
258
+ }
259
+ }
218
260
  return 0;
219
261
  }
220
262
 
@@ -334,17 +376,6 @@ static void linenoiseBeep(void) {
334
376
  fflush(stderr);
335
377
  }
336
378
 
337
- /* ============================== Completion ================================ */
338
-
339
- /* Free a list of completion option populated by linenoiseAddCompletion(). */
340
- static void freeCompletions(linenoiseCompletions *lc) {
341
- size_t i;
342
- for (i = 0; i < lc->len; i++)
343
- free(lc->cvec[i]);
344
- if (lc->cvec != NULL)
345
- free(lc->cvec);
346
- }
347
-
348
379
  /* Called by completeLine() and linenoiseShow() to render the current
349
380
  * edited line with the proposed completion. If the current completion table
350
381
  * is already available, it is passed as second argument, otherwise the
@@ -353,9 +384,9 @@ static void freeCompletions(linenoiseCompletions *lc) {
353
384
  * Flags are the same as refreshLine*(), that is REFRESH_* macros. */
354
385
  static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseCompletions *lc, int flags) {
355
386
  /* Obtain the table of completions if the caller didn't provide one. */
356
- linenoiseCompletions ctable = { 0, NULL };
387
+ linenoiseCompletions ctable;
357
388
  if (lc == NULL) {
358
- completionCallback(ls->buf,&ctable);
389
+ completionCallback(ls->buf, &ctable);
359
390
  lc = &ctable;
360
391
  }
361
392
 
@@ -364,16 +395,17 @@ static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseComple
364
395
  struct linenoiseState saved = *ls;
365
396
  ls->len = ls->pos = strlen(lc->cvec[ls->completion_idx]);
366
397
  ls->buf = lc->cvec[ls->completion_idx];
367
- refreshLineWithFlags(ls,flags);
398
+ refreshLineWithFlags(ls, flags);
368
399
  ls->len = saved.len;
369
400
  ls->pos = saved.pos;
370
401
  ls->buf = saved.buf;
371
402
  } else {
372
- refreshLineWithFlags(ls,flags);
403
+ refreshLineWithFlags(ls, flags);
373
404
  }
374
405
 
375
- /* Free the completions table if needed. */
376
- if (lc != &ctable) freeCompletions(&ctable);
406
+ if (lc == &ctable) {
407
+ ctable.to_free = false;
408
+ }
377
409
  }
378
410
 
379
411
  /* This is an helper function for linenoiseEdit*() and is called when the
@@ -391,11 +423,11 @@ static void refreshLineWithCompletion(struct linenoiseState *ls, linenoiseComple
391
423
  * possible completions, and the caller should read for the next characters
392
424
  * from stdin. */
393
425
  static int completeLine(struct linenoiseState *ls, int keypressed) {
394
- linenoiseCompletions lc = { 0, NULL };
426
+ linenoiseCompletions lc;
395
427
  int nwritten;
396
428
  char c = keypressed;
397
429
 
398
- completionCallback(ls->buf,&lc);
430
+ completionCallback(ls->buf, &lc);
399
431
  if (lc.len == 0) {
400
432
  linenoiseBeep();
401
433
  ls->in_completion = 0;
@@ -406,7 +438,7 @@ static int completeLine(struct linenoiseState *ls, int keypressed) {
406
438
  ls->in_completion = 1;
407
439
  ls->completion_idx = 0;
408
440
  } else {
409
- ls->completion_idx = (ls->completion_idx+1) % (lc.len+1);
441
+ ls->completion_idx = (ls->completion_idx + 1) % (lc.len + 1);
410
442
  if (ls->completion_idx == lc.len) linenoiseBeep();
411
443
  }
412
444
  c = 0;
@@ -420,8 +452,7 @@ static int completeLine(struct linenoiseState *ls, int keypressed) {
420
452
  default:
421
453
  /* Update buffer and return */
422
454
  if (ls->completion_idx < lc.len) {
423
- nwritten = snprintf(ls->buf,ls->buflen,"%s",
424
- lc.cvec[ls->completion_idx]);
455
+ nwritten = snprintf(ls->buf, ls->buflen, "%s", lc.cvec[ls->completion_idx]);
425
456
  ls->len = ls->pos = nwritten;
426
457
  }
427
458
  ls->in_completion = 0;
@@ -430,13 +461,12 @@ static int completeLine(struct linenoiseState *ls, int keypressed) {
430
461
 
431
462
  /* Show completion or original buffer */
432
463
  if (ls->in_completion && ls->completion_idx < lc.len) {
433
- refreshLineWithCompletion(ls,&lc,REFRESH_ALL);
464
+ refreshLineWithCompletion(ls, &lc, REFRESH_ALL);
434
465
  } else {
435
466
  refreshLine(ls);
436
467
  }
437
468
  }
438
469
 
439
- freeCompletions(&lc);
440
470
  return c; /* Return last read character */
441
471
  }
442
472
 
@@ -462,53 +492,25 @@ void linenoiseSetFreeHintsCallback(linenoiseFreeHintsCallback *fn) {
462
492
  * user typed <tab>. See the example.c source code for a very easy to
463
493
  * understand example. */
464
494
  void linenoiseAddCompletion(linenoiseCompletions *lc, const char *str) {
465
- size_t len = strlen(str);
466
- char *copy, **cvec;
467
-
468
- copy = (char*) malloc(len + 1);
469
- if (copy == NULL) return;
470
- memcpy(copy,str,len+1);
471
- cvec = (char**) realloc(lc->cvec,sizeof(char*)*(lc->len+1));
472
- if (cvec == NULL) {
473
- free(copy);
495
+ const size_t len = strlen(str);
496
+ auto copy = std::make_unique<char[]>(len + 1);
497
+ if (!copy) {
474
498
  return;
475
499
  }
476
- lc->cvec = cvec;
477
- lc->cvec[lc->len++] = copy;
478
- }
479
500
 
480
- /* =========================== Line editing ================================= */
481
-
482
- /* We define a very simple "append buffer" structure, that is an heap
483
- * allocated string where we can append to. This is useful in order to
484
- * write all the escape sequences in a buffer and flush them to the standard
485
- * output in a single call, to avoid flickering effects. */
486
- struct abuf {
487
- char *b;
488
- int len;
489
- };
490
-
491
- static void abInit(struct abuf *ab) {
492
- ab->b = NULL;
493
- ab->len = 0;
494
- }
495
-
496
- static void abAppend(struct abuf *ab, const char *s, int len) {
497
- char *new_ptr = (char*) realloc(ab->b,ab->len+len);
498
-
499
- if (new_ptr == NULL) return;
500
- memcpy(new_ptr+ab->len,s,len);
501
- ab->b = new_ptr;
502
- ab->len += len;
503
- }
501
+ memcpy(copy.get(), str, len + 1);
502
+ char ** cvec = static_cast<char **>(std::realloc(lc->cvec, sizeof(char *) * (lc->len + 1)));
503
+ if (cvec == nullptr) {
504
+ return;
505
+ }
504
506
 
505
- static void abFree(struct abuf *ab) {
506
- free(ab->b);
507
+ lc->cvec = cvec;
508
+ lc->cvec[lc->len++] = copy.release();
507
509
  }
508
510
 
509
511
  /* Helper of refreshSingleLine() and refreshMultiLine() to show hints
510
512
  * to the right of the prompt. */
511
- static void refreshShowHints(struct abuf * ab, struct linenoiseState * l, int plen) {
513
+ static void refreshShowHints(std::string & ab, struct linenoiseState * l, int plen) {
512
514
  char seq[64];
513
515
  if (hintsCallback && plen+l->len < l->cols) {
514
516
  int color = -1, bold = 0;
@@ -522,10 +524,11 @@ static void refreshShowHints(struct abuf * ab, struct linenoiseState * l, int pl
522
524
  snprintf(seq,64,"\033[%d;%d;49m",bold,color);
523
525
  else
524
526
  seq[0] = '\0';
525
- abAppend(ab,seq,strlen(seq));
526
- abAppend(ab,hint,hintlen);
527
+ ab.append(seq);
528
+ ab.append(hint, hintlen);
527
529
  if (color != -1 || bold != 0)
528
- abAppend(ab,"\033[0m",4);
530
+ ab.append("\033[0m");
531
+
529
532
  /* Call the function to free the hint returned. */
530
533
  if (freeHintsCallback) freeHintsCallback(hint);
531
534
  }
@@ -546,8 +549,7 @@ static void refreshSingleLine(struct linenoiseState *l, int flags) {
546
549
  char *buf = l->buf;
547
550
  size_t len = l->len;
548
551
  size_t pos = l->pos;
549
- struct abuf ab;
550
-
552
+ std::string ab;
551
553
  while((plen+pos) >= l->cols) {
552
554
  buf++;
553
555
  len--;
@@ -557,35 +559,34 @@ static void refreshSingleLine(struct linenoiseState *l, int flags) {
557
559
  len--;
558
560
  }
559
561
 
560
- abInit(&ab);
561
562
  /* Cursor to left edge */
562
563
  snprintf(seq,sizeof(seq),"\r");
563
- abAppend(&ab,seq,strlen(seq));
564
+ ab.append(seq);
564
565
 
565
566
  if (flags & REFRESH_WRITE) {
566
567
  /* Write the prompt and the current buffer content */
567
- abAppend(&ab,l->prompt,strlen(l->prompt));
568
+ ab.append(l->prompt);
568
569
  if (maskmode == 1) {
569
- while (len--) abAppend(&ab,"*",1);
570
+ while (len--) {
571
+ ab.append("*");
572
+ }
570
573
  } else {
571
- abAppend(&ab,buf,len);
574
+ ab.append(buf, len);
572
575
  }
573
576
  /* Show hits if any. */
574
- refreshShowHints(&ab,l,plen);
577
+ refreshShowHints(ab, l, plen);
575
578
  }
576
579
 
577
580
  /* Erase to right */
578
581
  snprintf(seq,sizeof(seq),"\x1b[0K");
579
- abAppend(&ab,seq,strlen(seq));
580
-
582
+ ab.append(seq);
581
583
  if (flags & REFRESH_WRITE) {
582
584
  /* Move cursor to original position. */
583
585
  snprintf(seq,sizeof(seq),"\r\x1b[%dC", (int)(pos+plen));
584
- abAppend(&ab,seq,strlen(seq));
586
+ ab.append(seq);
585
587
  }
586
588
 
587
- if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
588
- abFree(&ab);
589
+ (void) !write(fd, ab.c_str(), ab.size()); /* Can't recover from write error. */
589
590
  }
590
591
 
591
592
  /* Multi line low level line refresh.
@@ -604,26 +605,23 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) {
604
605
  int col; /* colum position, zero-based. */
605
606
  int old_rows = l->oldrows;
606
607
  int fd = l->ofd, j;
607
- struct abuf ab;
608
-
608
+ std::string ab;
609
609
  l->oldrows = rows;
610
610
 
611
611
  /* First step: clear all the lines used before. To do so start by
612
612
  * going to the last row. */
613
- abInit(&ab);
614
-
615
613
  if (flags & REFRESH_CLEAN) {
616
614
  if (old_rows-rpos > 0) {
617
615
  lndebug("go down %d", old_rows-rpos);
618
616
  snprintf(seq,64,"\x1b[%dB", old_rows-rpos);
619
- abAppend(&ab,seq,strlen(seq));
617
+ ab.append(seq);
620
618
  }
621
619
 
622
620
  /* Now for every row clear it, go up. */
623
621
  for (j = 0; j < old_rows-1; j++) {
624
622
  lndebug("clear+up");
625
623
  snprintf(seq,64,"\r\x1b[0K\x1b[1A");
626
- abAppend(&ab,seq,strlen(seq));
624
+ ab.append(seq);
627
625
  }
628
626
  }
629
627
 
@@ -631,21 +629,22 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) {
631
629
  /* Clean the top line. */
632
630
  lndebug("clear");
633
631
  snprintf(seq,64,"\r\x1b[0K");
634
- abAppend(&ab,seq,strlen(seq));
632
+ ab.append(seq);
635
633
  }
636
634
 
637
635
  if (flags & REFRESH_WRITE) {
638
636
  /* Write the prompt and the current buffer content */
639
- abAppend(&ab,l->prompt,strlen(l->prompt));
637
+ ab.append(l->prompt);
640
638
  if (maskmode == 1) {
641
- unsigned int i;
642
- for (i = 0; i < l->len; i++) abAppend(&ab,"*",1);
639
+ for (unsigned int i = 0; i < l->len; ++i) {
640
+ ab.append("*");
641
+ }
643
642
  } else {
644
- abAppend(&ab,l->buf,l->len);
643
+ ab.append(l->buf, l->len);
645
644
  }
646
645
 
647
646
  /* Show hits if any. */
648
- refreshShowHints(&ab,l,plen);
647
+ refreshShowHints(ab, l, plen);
649
648
 
650
649
  /* If we are at the very end of the screen with our prompt, we need to
651
650
  * emit a newline and move the prompt to the first column. */
@@ -654,9 +653,9 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) {
654
653
  (l->pos+plen) % l->cols == 0)
655
654
  {
656
655
  lndebug("<newline>");
657
- abAppend(&ab,"\n",1);
656
+ ab.append("\n");
658
657
  snprintf(seq,64,"\r");
659
- abAppend(&ab,seq,strlen(seq));
658
+ ab.append(seq);
660
659
  rows++;
661
660
  if (rows > (int)l->oldrows) l->oldrows = rows;
662
661
  }
@@ -669,7 +668,7 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) {
669
668
  if (rows-rpos2 > 0) {
670
669
  lndebug("go-up %d", rows-rpos2);
671
670
  snprintf(seq,64,"\x1b[%dA", rows-rpos2);
672
- abAppend(&ab,seq,strlen(seq));
671
+ ab.append(seq);
673
672
  }
674
673
 
675
674
  /* Set column. */
@@ -679,14 +678,12 @@ static void refreshMultiLine(struct linenoiseState *l, int flags) {
679
678
  snprintf(seq,64,"\r\x1b[%dC", col);
680
679
  else
681
680
  snprintf(seq,64,"\r");
682
- abAppend(&ab,seq,strlen(seq));
681
+ ab.append(seq);
683
682
  }
684
683
 
685
684
  lndebug("\n");
686
685
  l->oldpos = l->pos;
687
-
688
- if (write(fd,ab.b,ab.len) == -1) {} /* Can't recover from write error. */
689
- abFree(&ab);
686
+ (void) !write(fd, ab.c_str(), ab.size()); /* Can't recover from write error. */
690
687
  }
691
688
 
692
689
  /* Calls the two low level functions refreshSingleLine() or
@@ -1313,16 +1310,17 @@ int linenoiseHistorySetMaxLen(int len) {
1313
1310
  * otherwise -1 is returned. */
1314
1311
  int linenoiseHistorySave(const char *filename) {
1315
1312
  mode_t old_umask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
1316
- FILE *fp;
1317
- int j;
1318
-
1319
- fp = fopen(filename,"w");
1313
+ File file;
1314
+ file.open(filename, "w");
1320
1315
  umask(old_umask);
1321
- if (fp == NULL) return -1;
1316
+ if (file.file == NULL) {
1317
+ return -1;
1318
+ }
1322
1319
  chmod(filename,S_IRUSR|S_IWUSR);
1323
- for (j = 0; j < history_len; j++)
1324
- fprintf(fp,"%s\n",history[j]);
1325
- fclose(fp);
1320
+ for (int j = 0; j < history_len; ++j) {
1321
+ fprintf(file.file, "%s\n", history[j]);
1322
+ }
1323
+
1326
1324
  return 0;
1327
1325
  }
1328
1326
 
@@ -1332,12 +1330,14 @@ int linenoiseHistorySave(const char *filename) {
1332
1330
  * If the file exists and the operation succeeded 0 is returned, otherwise
1333
1331
  * on error -1 is returned. */
1334
1332
  int linenoiseHistoryLoad(const char *filename) {
1335
- FILE *fp = fopen(filename,"r");
1333
+ File file;
1334
+ file.open(filename, "r");
1336
1335
  char buf[LINENOISE_MAX_LINE];
1336
+ if (file.file == NULL) {
1337
+ return -1;
1338
+ }
1337
1339
 
1338
- if (fp == NULL) return -1;
1339
-
1340
- while (fgets(buf,LINENOISE_MAX_LINE,fp) != NULL) {
1340
+ while (fgets(buf, LINENOISE_MAX_LINE, file.file) != NULL) {
1341
1341
  char *p;
1342
1342
 
1343
1343
  p = strchr(buf,'\r');
@@ -1345,7 +1345,6 @@ int linenoiseHistoryLoad(const char *filename) {
1345
1345
  if (p) *p = '\0';
1346
1346
  linenoiseHistoryAdd(buf);
1347
1347
  }
1348
- fclose(fp);
1349
1348
  return 0;
1350
1349
  }
1351
1350
  #endif