globales.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. {
  2. Unidad con declaraciones globales del proyecto
  3. Creado por Tito Hinostroza - 01/08/2014
  4. }
  5. unit Globales; {$mode objfpc}{$H+}
  6. interface
  7. uses Classes, SysUtils, Forms, SynEdit, SynEditKeyCmds, MisUtils,
  8. SynEditTypes, StrUtils, lclType, FileUtil,
  9. types, LazLogger, LazUTF8, Menus, ComCtrls ;
  10. const
  11. NOM_PROG ='Tito''s Terminal'; //nombre de programa
  12. {$I ../version.txt} //versión del programa
  13. type
  14. //Tipos de conexiones
  15. TTipCon = (
  16. TCON_TELNET, //Conexión telnet común
  17. TCON_SSH, //Conexión ssh
  18. TCON_SERIAL, //Serial
  19. TCON_OTHER //Otro proceso
  20. );
  21. var
  22. //Variables globales
  23. MsjError : String; // Bandera - Mensaje de error.
  24. patApp : string; // Ruta de la aplicación.
  25. patMacros : string; // Ruta de la carpeta de macros.
  26. patTemp : string; // Ruta de la carpeta temporal
  27. patSyntax : string; // Ruta para guardar las sintaxis.
  28. patSessions : string; // Ruta para guardar las sesiones.
  29. inputFile : string; // Archivo de entrada.
  30. showError : Boolean; // Bandera para mostrar mensajesde error.
  31. //Funciones para control del editor
  32. function IdFromTTreeNode(node: TTreeNode): string;
  33. function TTreeNodeFromId(Id: string; tree: TTreeView): TTreeNode;
  34. procedure SubirCursorBloque(ed: TSynEdit; Shift: TShiftState);
  35. procedure BajarCursorBloque(ed: TSynEdit; Shift: TShiftState);
  36. procedure InsertaColumnasBloque(ed: TsynEdit; var key: TUTF8Char);
  37. function LeerParametros: boolean;
  38. function NombDifArc(nomBase: String): String;
  39. procedure LeeArchEnMenu(arc: string; mn: TMenuItem; accion: TNotifyEvent);
  40. procedure CopiarMemu(menOrig, menDest: TMenuItem);
  41. implementation
  42. function IdFromTTreeNode(node: TTreeNode): string;
  43. //Returns an ID with indication of the position of a TTreeNode'.
  44. //It has the form: 1, 1.1, 1.2. Only works for two levels.
  45. var
  46. nivel: Integer;
  47. begin
  48. nivel := node.Level;
  49. if nivel = 1 then //de dos niveles
  50. Result := IntToStr(node.Parent.Index+1) + '.' +
  51. IntToStr(node.Index+1)
  52. else //de un nivel
  53. Result := IntToStr(node.Index+1);
  54. end;
  55. function TTreeNodeFromId(Id: string; tree: TTreeView): TTreeNode;
  56. //Returns a TreeNode, given the ID position. If not found, returns NIL.
  57. //Only works for two levels.
  58. var
  59. list: TStringList;
  60. it: TTreeNode;
  61. Padre: TTreeNode;
  62. i: Integer;
  63. begin
  64. Result := nil; //por defecto
  65. if Id='' then exit;
  66. list := TStringList.Create;
  67. list.Delimiter:='.';
  68. list.DelimitedText:=Id;
  69. if list.Count = 1 then begin //de un solo nivel
  70. //ubica el nodo
  71. for it in Tree.Items do if it.Level=0 then begin
  72. if IntToStr(it.Index+1) = list[0] then Result := it;
  73. end;
  74. end else begin //de dos o más niveles
  75. //ubica al nodo padre
  76. Padre := nil;
  77. for it in Tree.Items do begin
  78. if it.Level=0 then begin
  79. if IntToStr(it.Index+1) = list[0] then Padre := it;
  80. end;
  81. end;
  82. if Padre = nil then begin
  83. list.Destroy;
  84. exit; //no lo ubica
  85. end;
  86. //ubica al nodo hijo
  87. for i := 0 to Padre.Count-1 do begin
  88. it := Padre.Items[i];
  89. if it.Level=1 then begin
  90. if IntToStr(it.Index+1) = list[1] then Result := it;
  91. end;
  92. end;
  93. end;
  94. list.Destroy;
  95. end;
  96. //Funciones para control del editor
  97. procedure EdSubirCursor(ed: TSynEdit; Shift: TShiftState);
  98. //Sube el cursor del SynEdit, una psoición, considerando el estado de <Shift>
  99. { TODO : Es muy lento para varias líneas (>100) }
  100. begin
  101. if ed.SelectionMode = smColumn then //en modo columna
  102. ed.ExecuteCommand(ecColSelUp, #0, nil) //solo se puede mover con selección
  103. else //en modo normal
  104. if ssShift in Shift then
  105. ed.ExecuteCommand(ecSelUp, #0, nil) //sube
  106. else
  107. ed.ExecuteCommand(ecUp, #0, nil); //sube
  108. end;
  109. procedure EdBajarCursor(ed: TSynEdit; Shift: TShiftState);
  110. //Baja el cursor del SynEdit, una psoición, considerando el estado de <Shift>
  111. begin
  112. if ed.SelectionMode = smColumn then //en modo columna
  113. ed.ExecuteCommand(ecColSelDown, #0, nil) //solo se puede mover con selección
  114. else //en modo normal
  115. if ssShift in Shift then
  116. ed.ExecuteCommand(ecSelDown, #0, nil) //sube
  117. else
  118. ed.ExecuteCommand(ecDown, #0, nil); //sube
  119. end;
  120. procedure SubirCursorBloque(ed: TSynEdit; Shift: TShiftState);
  121. //Sube el cursor hasta encontrar una línea en blanco (si estaba en una diferente de blanco)
  122. //o hasta encontrar una línea diferente de blanco (si estaba en una línea en blanco)
  123. var
  124. curY : longint;
  125. begin
  126. CurY := ed.CaretY; //Lee posición de cursor
  127. if CurY = 1 then exit; //no se puede subir más
  128. if CurY = 2 then begin
  129. EdSubirCursor(ed, Shift); //solo puede subir una posición.
  130. exit;
  131. end;
  132. if trim(ed.lines[CurY-2]) = '' then begin
  133. //busca línea diferente de blanco
  134. while CurY > 1 do begin
  135. if trim(ed.lines[Cury-2]) <> '' then Exit; //pone y sale
  136. Dec(CurY);
  137. EdSubirCursor(ed, Shift);
  138. end;
  139. end else begin
  140. //busca línea en blanco hacia abajo
  141. while CurY > 1 do begin
  142. if trim(ed.lines[CurY-2]) = '' then Exit; //pone y sale
  143. Dec(CurY);
  144. EdSubirCursor(ed, Shift);
  145. end;
  146. end;
  147. end;
  148. procedure BajarCursorBloque(ed: TSynEdit; Shift: TShiftState);
  149. //Baja el cursor hasta encontrar una línea en blanco (si estaba en una diferente de blanco)
  150. //o hasta encontrar una línea diferente de blanco (si estaba en una línea en blanco)
  151. var
  152. curY : longint;
  153. begin
  154. CurY := ed.CaretY; //Lee posición de cursor
  155. if CurY = ed.Lines.Count then exit; //no se puede bajar más
  156. if CurY = ed.Lines.Count - 1 then begin
  157. EdBajarCursor(ed, Shift); //solo puede bajar una posición.
  158. exit;
  159. end;
  160. if trim(ed.lines[CurY-1]) = '' then begin
  161. //busca línea diferente de blanco
  162. while CurY < ed.Lines.Count do begin
  163. if trim(ed.lines[CurY-1]) <> '' then Exit; //pone y sale
  164. Inc(CurY);
  165. EdBajarCursor(ed, Shift);
  166. end;
  167. end else begin
  168. //busca línea en blanco hacia abajo
  169. while CurY < ed.Lines.Count do begin
  170. if trim(ed.lines[CurY-1]) = '' then Exit; //pone y sale
  171. Inc(CurY);
  172. EdBajarCursor(ed, Shift);
  173. end;
  174. end;
  175. end;
  176. procedure InsertaColumnasBloque(ed: TsynEdit; var key: TUTF8Char);
  177. //Inserta un caracter en un bloque de selección en modo columna.
  178. //El editor debe estar en modo columna con un bloque de selección activo.
  179. //El texto se insertará en todas las filas de la selección.
  180. { TODO : Verificar funcionamiento en líneas con tabulaciones.}
  181. var
  182. curX,curY : longint;
  183. p1,p2:TPoint;
  184. tmp: pchar;
  185. begin
  186. (*Verifica el caso particular en que se tiene solo una fila de selección en modo columna*)
  187. if ed.BlockBegin.y = ed.BlockEnd.y then begin
  188. //no hay mucho que procesar en modo columna
  189. ed.ExecuteCommand(ecChar,key,nil);
  190. //cancela procesamiento, para que no procese de nuevo el caracter
  191. key := #0;
  192. Exit;
  193. end;
  194. (*Verifica ancho de selección. Debe dejarse en ancho nulo, antes de pegar el caracter en
  195. la selección *)
  196. if ed.SelAvail then begin //se podría haber usado "if BlockBegin.x <> BlockEnd.x", pero se
  197. //se tendría problemas porque las posiciones físicas pueden
  198. //coincidir aún cuando las posiciones lógcas, no.
  199. p2 := ed.BlockEnd; //Lee final de selección
  200. //hay selección de por lo menos un caracter de ancho
  201. ed.ExecuteCommand(ecDeleteChar, #0, nil); //limpia selección
  202. //Ahora el bloque de selección tiene ancho cero, alto 1 y el cursor está dentro.
  203. //Ahora se debe restaurar la altura del bloque, modificando BlockEnd.
  204. //Se usa la posición horizontal del cursor, que coincide con el bloque
  205. //Se usa transformación, porque BlockEnd, trabaja en coordenada lógica
  206. p2.x:=ed.PhysicalToLogicalCol(ed.Lines[p2.y-1],p2.y-1,ed.CaretX);
  207. ed.BlockEnd:=p2; //restaura también, la altura original del bloque
  208. ed.SelectionMode := smColumn; //restaura el modo columna
  209. end;
  210. //El bloque de selección tiene ahora ancho cero y alto original.
  211. (* la idea aquí es poner en el portapapeles, una estructura con varias filas (tantas cono haya
  212. seleccionada) del caracter que se quiera insertar. *)
  213. //Guarda cursor
  214. curX := ed.CaretX;
  215. curY := ed.CaretY;
  216. //Lee coordenadas del bloque nulo
  217. p1 := ed.BlockBegin;
  218. p2 := ed.BlockEnd;
  219. tmp := PChar(DupeString(key+#13#10,p2.y-p1.y)+key); //construye texto
  220. ed.DoCopyToClipboard(tmp,''); //pone en portapapeles
  221. (*Aquí ya se tiene en el portapapeles, la estructura repetida del caracter a insertar*)
  222. //pega la selección modificada
  223. ed.CaretY := p1.y; //pone cursor arriba para pegar
  224. // ed.SelectionMode := smNormal; //debería poder trabajar en Normal
  225. //Si la estructura en el portapapeles, es correcta, se copiará correctamente en columnas.
  226. ed.ExecuteCommand(ecPaste,#0,nil);
  227. //desplaza Cursor y bloque, para escribir siguiente caracter a la derecha
  228. curX += 1;
  229. // p1.x += 1;
  230. // p2.x += 1;
  231. p1.x := ed.PhysicalToLogicalCol(ed.Lines[p1.y-1],p1.y-1,curX);
  232. p2.x := ed.PhysicalToLogicalCol(ed.Lines[p2.y-1],p2.y-1,curX);
  233. //calcula nuevamente la posición física del cursor, para evitar que el cursor
  234. //pueda caer en medio de una tabulación.
  235. CurX := ed.LogicalToPhysicalCol(ed.Lines[p1.y-1],p1.y-1,p1.x);
  236. //restaura posición de cursor
  237. ed.CaretX := curX;
  238. ed.CaretY := curY;
  239. //restaura bloque de selección, debe hacerse después de posicionar el cursor
  240. ed.BlockBegin := p1;
  241. ed.BlockEnd := p2;
  242. ed.SelectionMode := smColumn; //mantiene modo de columna
  243. key := #0; //cancela procesamiento de teclado
  244. end;
  245. function LeerParametros: boolean;
  246. {lee la linea de comandos
  247. Si hay error devuelve TRUE}
  248. var
  249. par : String;
  250. i : Integer;
  251. begin
  252. Result := false; //valor por defecto
  253. //valores por defecto
  254. inputFile := '';
  255. showError := True;
  256. //Lee parámetros de entrada
  257. par := ParamStr(1);
  258. if par = '' then begin
  259. MsgErr('Nombre de archivo vacío.');
  260. Result := true;
  261. exit; //sale con error
  262. end;
  263. if par[1] = '/' then begin //es parámetro
  264. i := 1; //para que explore desde el principio
  265. end else begin //es archivo
  266. inputFile := par; //el primer elemento es el archivo de entrada
  267. i := 2; //explora siguientes
  268. end;
  269. while i <= ParamCount do begin
  270. par := ParamStr(i);
  271. If par[1] = '/' Then begin
  272. Case UpCase(par) of
  273. '/NOERROR': showError := False;
  274. '/ERROR': showError := True;
  275. Else begin
  276. MsgErr('Error. Parámetro desconocido: ' + par);
  277. Result := true;
  278. exit; //sale con error
  279. End
  280. End
  281. end Else begin
  282. // archivoSal := par;
  283. End;
  284. inc(i); //pasa al siguiente
  285. end;
  286. End;
  287. function NombDifArc(nomBase: String): String;
  288. {Genera un nombre diferente de archivo, tomando el nombre dado como raiz.}
  289. const MAX_ARCH = 10;
  290. var i : Integer; //Número de intentos con el nombre de archivo de salida
  291. cadBase : String; //Cadena base del nombre base
  292. extArc: string; //extensión
  293. function NombArchivo(i: integer): string;
  294. begin
  295. Result := cadBase + '-' + IntToStr(i) + extArc;
  296. end;
  297. begin
  298. Result := nomBase; //nombre por defecto
  299. extArc := ExtractFileExt(nomBase);
  300. if ExtractFilePath(nomBase) = '' then exit; //protección
  301. //quita ruta y cambia extensión
  302. cadBase := ChangeFileExt(nomBase,'');
  303. //busca archivo libre
  304. for i := 0 to MAX_ARCH-1 do begin
  305. If not FileExists(NombArchivo(i)) then begin
  306. //Se encontró nombre libre
  307. Exit(NombArchivo(i)); //Sale con nombre
  308. end;
  309. end;
  310. //todos los nombres estaban ocupados. Sale con el mismo nombre
  311. End;
  312. procedure LeeArchEnMenu(arc: string; mn: TMenuItem; accion: TNotifyEvent);
  313. {Lee la carpeta de macros y actualiza un menú con el nombre de los archivos
  314. Devuelve la cantidad de ítems leidos. }
  315. var
  316. Hay: Boolean;
  317. SR: TSearchRec;
  318. item: TMenuItem;
  319. n : integer;
  320. begin
  321. // mn.Clear;
  322. // Crear la lista de ficheos en el dir. StartDir (no directorios!)
  323. n := 0; //contador
  324. Hay := FindFirst(arc,faAnyFile - faDirectory, SR) = 0;
  325. while Hay do begin
  326. //encontró. Crea entrada
  327. item := TMenuItem.Create(nil);
  328. item.Caption:= SysToUTF8(SR.Name); //nombre
  329. item.OnClick:=accion;
  330. mn.Add(item);
  331. //busca siguiente
  332. Hay := FindNext(SR) = 0;
  333. inc(n);
  334. end;
  335. if n = 0 then begin //no encontró
  336. //encontró. Crea entrada
  337. item := TMenuItem.Create(nil);
  338. item.Caption:= 'vacío'; //nombre
  339. item.Enabled := false;
  340. mn.Add(item);
  341. end;
  342. // Result := n;
  343. end;
  344. procedure CopiarMemu(menOrig, menDest: TMenuItem);
  345. //Copìa los ítems de un menú a otro
  346. var
  347. it: TMenuItem;
  348. i: Integer;
  349. begin
  350. menDest.Caption:=menOrig.Caption;
  351. menDest.Clear;
  352. for i := 0 To menOrig.Count - 1 do begin
  353. it := TMenuItem.Create(nil);
  354. it.Caption:= menOrig[i].Caption;
  355. it.OnClick:=menOrig[i].OnClick;
  356. it.Checked:=menOrig[i].Checked;
  357. menDest.Add(it);
  358. end;
  359. end;
  360. initialization
  361. //inicia directorios de la aplicación
  362. patApp := ExtractFilePath(Application.ExeName); //incluye el '\' final
  363. patSyntax := patApp + 'languages';
  364. patMacros := patApp + 'macros';
  365. patTemp := patApp + 'temp';
  366. patSessions:= patApp + 'sessions';
  367. inputFile := ''; //Archivo de entrada
  368. //Verifica existencia de carpetas de trabajo
  369. try
  370. if not DirectoryExists(patTemp) then begin
  371. msgexc('Folder /temp doesn''t exist. It will be created.');
  372. CreateDir(patTemp);
  373. end;
  374. if not DirectoryExists(patMacros) then begin
  375. msgexc('Folder /macros doesn''t exist. It will be created.');
  376. CreateDir(patMacros);
  377. end;
  378. if not DirectoryExists(patSyntax) then begin
  379. msgexc('Folder /lenguages doesn''t exist. It will be created.');
  380. CreateDir(patSyntax);
  381. end;
  382. if not DirectoryExists(patSessions) then begin
  383. msgexc('Folder /sessions doesn''t exist. It will be created.');
  384. CreateDir(patSessions);
  385. end;
  386. if not FileExists(patApp+'plink.exe') then begin
  387. msgErr('No se encuentra archivo plink.exe');
  388. end;
  389. except
  390. msgErr('Error. No se puede leer o crear directorios.');
  391. end;
  392. finalization
  393. {Por algún motivo, la unidad HeapTrc indica que hay gotera de memoria si no se liberan
  394. estas cadenas: }
  395. patApp := '';
  396. patMacros := '';
  397. patTemp := '';
  398. patSyntax := '';
  399. patSessions := '';
  400. end.